Philipp Hörist pushed to branch master at gajim / gajim

Commits:

11 changed files:

Changes:

  • gajim/common/connection.py
    ... ... @@ -75,7 +75,9 @@ from gajim.common.modules.vcard_temp import VCardTemp
    75 75
     from gajim.common.modules.vcard_avatars import VCardAvatars
    
    76 76
     from gajim.common.modules.pubsub import PubSub
    
    77 77
     from gajim.common.modules.bookmarks import Bookmarks
    
    78
    +from gajim.common.modules.pep import PEP
    
    78 79
     from gajim.common.modules.user_avatar import UserAvatar
    
    80
    +from gajim.common.modules.user_activity import UserActivity
    
    79 81
     from gajim.common.connection_handlers import *
    
    80 82
     from gajim.common.contacts import GC_Contact
    
    81 83
     from gajim.gtkgui_helpers import get_action
    
    ... ... @@ -179,7 +181,10 @@ class CommonConnection:
    179 181
             return self._modules[name]
    
    180 182
     
    
    181 183
         def get_module_handlers(self):
    
    182
    -        return self._modules.values()
    
    184
    +        handlers = []
    
    185
    +        for module in self._modules.values():
    
    186
    +            handlers += module.handlers
    
    187
    +        return handlers
    
    183 188
     
    
    184 189
         def register_module(self, name, cls, *args, **kwargs):
    
    185 190
             self._modules[name] = cls(*args, **kwargs)
    
    ... ... @@ -661,8 +666,10 @@ class Connection(CommonConnection, ConnectionHandlers):
    661 666
             self.register_module('VCardTemp', VCardTemp, self)
    
    662 667
             self.register_module('VCardAvatars', VCardAvatars, self)
    
    663 668
             self.register_module('PubSub', PubSub, self)
    
    669
    +        self.register_module('PEP', PEP, self)
    
    664 670
             self.register_module('Bookmarks', Bookmarks, self)
    
    665 671
             self.register_module('UserAvatar', UserAvatar, self)
    
    672
    +        self.register_module('UserActivity', UserActivity, self)
    
    666 673
     
    
    667 674
             app.ged.register_event_handler('privacy-list-received', ged.CORE,
    
    668 675
                 self._nec_privacy_list_received)
    
    ... ... @@ -749,6 +756,7 @@ class Connection(CommonConnection, ConnectionHandlers):
    749 756
         def disconnect(self, on_purpose=False):
    
    750 757
             app.interface.music_track_changed(None, None, self.name)
    
    751 758
             self.reset_awaiting_pep()
    
    759
    +        self.get_module('PEP').reset_stored_publish()
    
    752 760
             self.on_purpose = on_purpose
    
    753 761
             self.connected = 0
    
    754 762
             self.time_to_reconnect = None
    

  • gajim/common/connection_handlers.py
    ... ... @@ -295,7 +295,6 @@ class ConnectionPEP(object):
    295 295
             self._account = new_name
    
    296 296
     
    
    297 297
         def reset_awaiting_pep(self):
    
    298
    -        self.to_be_sent_activity = None
    
    299 298
             self.to_be_sent_mood = None
    
    300 299
             self.to_be_sent_tune = None
    
    301 300
             self.to_be_sent_nick = None
    
    ... ... @@ -305,8 +304,6 @@ class ConnectionPEP(object):
    305 304
             """
    
    306 305
             Send pep info that were waiting for connection
    
    307 306
             """
    
    308
    -        if self.to_be_sent_activity:
    
    309
    -            self.send_activity(*self.to_be_sent_activity)
    
    310 307
             if self.to_be_sent_mood:
    
    311 308
                 self.send_mood(*self.to_be_sent_mood)
    
    312 309
             if self.to_be_sent_tune:
    
    ... ... @@ -317,37 +314,6 @@ class ConnectionPEP(object):
    317 314
                 self.send_location(self.to_be_sent_location)
    
    318 315
             self.reset_awaiting_pep()
    
    319 316
     
    
    320
    -    def _pubsubEventCB(self, xmpp_dispatcher, msg):
    
    321
    -        ''' Called when we receive <message /> with pubsub event. '''
    
    322
    -        app.nec.push_incoming_event(PEPReceivedEvent(None, conn=self,
    
    323
    -            stanza=msg))
    
    324
    -
    
    325
    -    def send_activity(self, activity, subactivity=None, message=None):
    
    326
    -        if self.connected == 1:
    
    327
    -            # We are connecting, keep activity in mem and send it when we'll be
    
    328
    -            # connected
    
    329
    -            self.to_be_sent_activity = (activity, subactivity, message)
    
    330
    -            return
    
    331
    -        if not self.pep_supported:
    
    332
    -            return
    
    333
    -        item = nbxmpp.Node('activity', {'xmlns': nbxmpp.NS_ACTIVITY})
    
    334
    -        if activity:
    
    335
    -            i = item.addChild(activity)
    
    336
    -        if subactivity:
    
    337
    -            i.addChild(subactivity)
    
    338
    -        if message:
    
    339
    -            i = item.addChild('text')
    
    340
    -            i.addData(message)
    
    341
    -        self.get_module('PubSub').send_pb_publish(
    
    342
    -            '', nbxmpp.NS_ACTIVITY, item, '0')
    
    343
    -
    
    344
    -    def retract_activity(self):
    
    345
    -        if not self.pep_supported:
    
    346
    -            return
    
    347
    -        self.send_activity(None)
    
    348
    -        # not all client support new XEP, so we still retract
    
    349
    -        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
    
    350
    -
    
    351 317
         def send_mood(self, mood, message=None):
    
    352 318
             if self.connected == 1:
    
    353 319
                 # We are connecting, keep mood in mem and send it when we'll be
    
    ... ... @@ -1187,14 +1153,16 @@ ConnectionHTTPUpload):
    1187 1153
                 app.config.set_per('accounts', self.name, 'roster_version',
    
    1188 1154
                     obj.version)
    
    1189 1155
     
    
    1190
    -    def _messageCB(self, con, msg):
    
    1156
    +    def _messageCB(self, con, stanza):
    
    1191 1157
             """
    
    1192 1158
             Called when we receive a message
    
    1193 1159
             """
    
    1160
    +        if nbxmpp.NS_PUBSUB_EVENT in stanza.getProperties():
    
    1161
    +            return
    
    1194 1162
             log.debug('MessageCB')
    
    1195 1163
     
    
    1196 1164
             app.nec.push_incoming_event(NetworkEvent('raw-message-received',
    
    1197
    -            conn=self, stanza=msg, account=self.name))
    
    1165
    +            conn=self, stanza=stanza, account=self.name))
    
    1198 1166
     
    
    1199 1167
         def _dispatch_gc_msg_with_captcha(self, stanza, msg_obj):
    
    1200 1168
             msg_obj.stanza = stanza
    
    ... ... @@ -1518,6 +1486,7 @@ ConnectionHTTPUpload):
    1518 1486
             # Inform GUI we just signed in
    
    1519 1487
             app.nec.push_incoming_event(SignedInEvent(None, conn=self))
    
    1520 1488
             self.send_awaiting_pep()
    
    1489
    +        self.get_module('PEP').send_stored_publish()
    
    1521 1490
             self.continue_connect_info = None
    
    1522 1491
     
    
    1523 1492
         def _PubkeyGetCB(self, con, iq_obj):
    
    ... ... @@ -1583,11 +1552,6 @@ ConnectionHTTPUpload):
    1583 1552
             # that defines handlers
    
    1584 1553
             con.RegisterHandler('message', self._messageCB)
    
    1585 1554
             con.RegisterHandler('presence', self._presenceCB)
    
    1586
    -        # We use makefirst so that this handler is called before _messageCB, and
    
    1587
    -        # can prevent calling it when it's not needed.
    
    1588
    -        # We also don't check for namespace, else it cannot stop _messageCB to
    
    1589
    -        # be called
    
    1590
    -        con.RegisterHandler('message', self._pubsubEventCB, makefirst=True)
    
    1591 1555
             con.RegisterHandler('iq', self._rosterSetCB, 'set', nbxmpp.NS_ROSTER)
    
    1592 1556
             con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
    
    1593 1557
             con.RegisterHandler('iq', self._siErrorCB, 'error', nbxmpp.NS_SI)
    
    ... ... @@ -1645,6 +1609,5 @@ ConnectionHTTPUpload):
    1645 1609
             con.RegisterHandler('iq', self._BlockingResultCB, 'result',
    
    1646 1610
                 nbxmpp.NS_BLOCKING)
    
    1647 1611
     
    
    1648
    -        for module in self.get_module_handlers():
    
    1649
    -            for handler in module.handlers:
    
    1650
    -                con.RegisterHandler(*handler)
    1612
    +        for handler in self.get_module_handlers():
    
    1613
    +            con.RegisterHandler(*handler)

  • gajim/common/connection_handlers_events.py
    ... ... @@ -1780,7 +1780,6 @@ class PEPReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
    1780 1780
                     if entry:
    
    1781 1781
                         app.nec.push_incoming_event(AtomEntryReceived(None,
    
    1782 1782
                             conn=self.conn, node=entry))
    
    1783
    -        raise nbxmpp.NodeProcessed
    
    1784 1783
     
    
    1785 1784
     class AtomEntryReceived(nec.NetworkIncomingEvent):
    
    1786 1785
         name = 'atom-entry-received'
    

  • gajim/common/const.py
    ... ... @@ -124,6 +124,108 @@ class BookmarkStorageType(IntEnum):
    124 124
         PRIVATE = 0
    
    125 125
         PUBSUB = 1
    
    126 126
     
    
    127
    +@unique
    
    128
    +class PEPHandlerType(IntEnum):
    
    129
    +    NOTIFY = 0
    
    130
    +    RETRACT = 1
    
    131
    +
    
    132
    +@unique
    
    133
    +class PEPEventType(IntEnum):
    
    134
    +    ACTIVITY = 0
    
    135
    +
    
    136
    +
    
    137
    +ACTIVITIES = {
    
    138
    +    'doing_chores': {
    
    139
    +        'category': _('Doing Chores'),
    
    140
    +        'buying_groceries': _('Buying Groceries'),
    
    141
    +        'cleaning': _('Cleaning'),
    
    142
    +        'cooking': _('Cooking'),
    
    143
    +        'doing_maintenance': _('Doing Maintenance'),
    
    144
    +        'doing_the_dishes': _('Doing the Dishes'),
    
    145
    +        'doing_the_laundry': _('Doing the Laundry'),
    
    146
    +        'gardening': _('Gardening'),
    
    147
    +        'running_an_errand': _('Running an Errand'),
    
    148
    +        'walking_the_dog': _('Walking the Dog')},
    
    149
    +    'drinking': {
    
    150
    +        'category': _('Drinking'),
    
    151
    +        'having_a_beer': _('Having a Beer'),
    
    152
    +        'having_coffee': _('Having Coffee'),
    
    153
    +        'having_tea': _('Having Tea')},
    
    154
    +    'eating': {
    
    155
    +        'category': _('Eating'),
    
    156
    +        'having_a_snack': _('Having a Snack'),
    
    157
    +        'having_breakfast': _('Having Breakfast'),
    
    158
    +        'having_dinner': _('Having Dinner'),
    
    159
    +        'having_lunch': _('Having Lunch')},
    
    160
    +    'exercising': {
    
    161
    +        'category': _('Exercising'),
    
    162
    +        'cycling': _('Cycling'),
    
    163
    +        'dancing': _('Dancing'),
    
    164
    +        'hiking': _('Hiking'),
    
    165
    +        'jogging': _('Jogging'),
    
    166
    +        'playing_sports': _('Playing Sports'),
    
    167
    +        'running': _('Running'),
    
    168
    +        'skiing': _('Skiing'),
    
    169
    +        'swimming': _('Swimming'),
    
    170
    +        'working_out': _('Working out')},
    
    171
    +    'grooming': {
    
    172
    +        'category': _('Grooming'),
    
    173
    +        'at_the_spa': _('At the Spa'),
    
    174
    +        'brushing_teeth': _('Brushing Teeth'),
    
    175
    +        'getting_a_haircut': _('Getting a Haircut'),
    
    176
    +        'shaving': _('Shaving'),
    
    177
    +        'taking_a_bath': _('Taking a Bath'),
    
    178
    +        'taking_a_shower': _('Taking a Shower')},
    
    179
    +    'having_appointment': {
    
    180
    +        'category': _('Having an Appointment')},
    
    181
    +    'inactive': {
    
    182
    +        'category': _('Inactive'),
    
    183
    +        'day_off': _('Day Off'),
    
    184
    +        'hanging_out': _('Hanging out'),
    
    185
    +        'hiding': _('Hiding'),
    
    186
    +        'on_vacation': _('On Vacation'),
    
    187
    +        'praying': _('Praying'),
    
    188
    +        'scheduled_holiday': _('Scheduled Holiday'),
    
    189
    +        'sleeping': _('Sleeping'),
    
    190
    +        'thinking': _('Thinking')},
    
    191
    +    'relaxing': {
    
    192
    +        'category': _('Relaxing'),
    
    193
    +        'fishing': _('Fishing'),
    
    194
    +        'gaming': _('Gaming'),
    
    195
    +        'going_out': _('Going out'),
    
    196
    +        'partying': _('Partying'),
    
    197
    +        'reading': _('Reading'),
    
    198
    +        'rehearsing': _('Rehearsing'),
    
    199
    +        'shopping': _('Shopping'),
    
    200
    +        'smoking': _('Smoking'),
    
    201
    +        'socializing': _('Socializing'),
    
    202
    +        'sunbathing': _('Sunbathing'),
    
    203
    +        'watching_tv': _('Watching TV'),
    
    204
    +        'watching_a_movie': _('Watching a Movie')},
    
    205
    +    'talking': {
    
    206
    +        'category': _('Talking'),
    
    207
    +        'in_real_life': _('In Real Life'),
    
    208
    +        'on_the_phone': _('On the Phone'),
    
    209
    +        'on_video_phone': _('On Video Phone')},
    
    210
    +    'traveling': {
    
    211
    +        'category': _('Traveling'),
    
    212
    +        'commuting': _('Commuting'),
    
    213
    +        'cycling': _('Cycling'),
    
    214
    +        'driving': _('Driving'),
    
    215
    +        'in_a_car': _('In a Car'),
    
    216
    +        'on_a_bus': _('On a Bus'),
    
    217
    +        'on_a_plane': _('On a Plane'),
    
    218
    +        'on_a_train': _('On a Train'),
    
    219
    +        'on_a_trip': _('On a Trip'),
    
    220
    +        'walking': _('Walking')},
    
    221
    +    'working': {
    
    222
    +        'category': _('Working'),
    
    223
    +        'coding': _('Coding'),
    
    224
    +        'in_a_meeting': _('In a Meeting'),
    
    225
    +        'studying': _('Studying'),
    
    226
    +        'writing': _('Writing')}}
    
    227
    +
    
    228
    +
    
    127 229
     SSLError = {
    
    128 230
         2: _("Unable to get issuer certificate"),
    
    129 231
         3: _("Unable to get certificate CRL"),
    

  • gajim/common/modules/pep.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# XEP-0163: Personal Eventing Protocol
    
    16
    +
    
    17
    +import logging
    
    18
    +
    
    19
    +import nbxmpp
    
    20
    +
    
    21
    +from gajim.common import app
    
    22
    +from gajim.common.nec import NetworkIncomingEvent
    
    23
    +from gajim.common.const import PEPHandlerType, PEPEventType
    
    24
    +
    
    25
    +log = logging.getLogger('gajim.c.m.pep')
    
    26
    +
    
    27
    +
    
    28
    +class PEP:
    
    29
    +    def __init__(self, con):
    
    30
    +        self._con = con
    
    31
    +        self._account = con.name
    
    32
    +
    
    33
    +        self.handlers = [
    
    34
    +            ('message', self._pep_event_received,
    
    35
    +             'headline', nbxmpp.NS_PUBSUB_EVENT)
    
    36
    +        ]
    
    37
    +
    
    38
    +        self._pep_handlers = {}
    
    39
    +        self._store_publish_modules = []
    
    40
    +
    
    41
    +    def register_pep_handler(self, namespace, notify_handler, retract_handler):
    
    42
    +        if namespace in self._pep_handlers:
    
    43
    +            self._pep_handlers[namespace].append(
    
    44
    +                (notify_handler, retract_handler))
    
    45
    +        else:
    
    46
    +            self._pep_handlers[namespace] = [(notify_handler, retract_handler)]
    
    47
    +        if notify_handler:
    
    48
    +            module_instance = notify_handler.__self__
    
    49
    +            if hasattr(module_instance, 'send_stored_publish'):
    
    50
    +                if module_instance not in self._store_publish_modules:
    
    51
    +                    self._store_publish_modules.append(module_instance)
    
    52
    +
    
    53
    +    def _pep_event_received(self, conn, stanza):
    
    54
    +        jid = stanza.getFrom()
    
    55
    +        event = stanza.getTag('event', namespace=nbxmpp.NS_PUBSUB_EVENT)
    
    56
    +        items = event.getTag('items')
    
    57
    +        if items is None:
    
    58
    +            log.warning('Malformed PEP event (no items node): %s', stanza)
    
    59
    +            raise nbxmpp.NodeProcessed
    
    60
    +
    
    61
    +        namespace = items.getAttr('node')
    
    62
    +        if namespace is None:
    
    63
    +            log.warning('Malformed PEP event (no node attr): %s', stanza)
    
    64
    +            raise nbxmpp.NodeProcessed
    
    65
    +
    
    66
    +        log.info('PEP notification received: %s %s', jid, namespace)
    
    67
    +
    
    68
    +        handlers = self._pep_handlers.get(namespace, None)
    
    69
    +        if handlers is None:
    
    70
    +            # Old Fallback
    
    71
    +            from gajim.common.connection_handlers_events import PEPReceivedEvent as OldPEPReceivedEvent
    
    72
    +            app.nec.push_incoming_event(
    
    73
    +                OldPEPReceivedEvent(None, conn=self._con, stanza=stanza))
    
    74
    +            raise nbxmpp.NodeProcessed
    
    75
    +        else:
    
    76
    +            # Check if this is a retraction
    
    77
    +            retract = items.getTag('retract')
    
    78
    +            if retract is not None:
    
    79
    +                for handler in handlers:
    
    80
    +                    handler[PEPHandlerType.RETRACT](jid, retract.getID())
    
    81
    +                    raise nbxmpp.NodeProcessed
    
    82
    +
    
    83
    +            # Check if we have items
    
    84
    +            items_ = items.getTags('item')
    
    85
    +            if items_ is None:
    
    86
    +                log.warning('Malformed PEP event received: %s', stanza)
    
    87
    +                raise nbxmpp.NodeProcessed
    
    88
    +            for handler in handlers:
    
    89
    +                handler[PEPHandlerType.NOTIFY](jid, items_[0])
    
    90
    +                raise nbxmpp.NodeProcessed
    
    91
    +
    
    92
    +    def send_stored_publish(self):
    
    93
    +        for module in self._store_publish_modules:
    
    94
    +            module.send_stored_publish()
    
    95
    +
    
    96
    +    def reset_stored_publish(self):
    
    97
    +        for module in self._store_publish_modules:
    
    98
    +            module.reset_stored_publish()
    
    99
    +
    
    100
    +
    
    101
    +class PEPEvent:
    
    102
    +
    
    103
    +    name = ''
    
    104
    +
    
    105
    +    def __init__(self, con, account):
    
    106
    +        self.__account = account
    
    107
    +        self.__con = con
    
    108
    +
    
    109
    +    def _update_contacts(self, jid, user_pep):
    
    110
    +        for contact in app.contacts.get_contacts(self.__account, str(jid)):
    
    111
    +            if user_pep:
    
    112
    +                contact.pep[self.name] = user_pep
    
    113
    +            else:
    
    114
    +                contact.pep.pop(self.name, None)
    
    115
    +
    
    116
    +        if jid == self.__con.get_own_jid().getStripped():
    
    117
    +            if user_pep:
    
    118
    +                self.__con.pep[self.name] = user_pep
    
    119
    +            else:
    
    120
    +                self.__con.pep.pop(self.name, None)
    
    121
    +
    
    122
    +
    
    123
    +class AbstractPEP:
    
    124
    +
    
    125
    +    type_ = PEPEventType
    
    126
    +
    
    127
    +    def __eq__(self, other):
    
    128
    +        return other == self.type_
    
    129
    +
    
    130
    +    def __bool__(self):
    
    131
    +        return self._pep_specific_data is not None
    
    132
    +
    
    133
    +    def __str__(self):
    
    134
    +        return str(self._pep_specific_data)
    
    135
    +
    
    136
    +
    
    137
    +class PEPReceivedEvent(NetworkIncomingEvent):
    
    138
    +    name = 'pep-received'
    
    139
    +    base_network_events = []

  • gajim/common/modules/user_activity.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# XEP-0108: User Activity
    
    16
    +
    
    17
    +import logging
    
    18
    +
    
    19
    +import nbxmpp
    
    20
    +from gi.repository import GLib
    
    21
    +
    
    22
    +from gajim.common import app
    
    23
    +from gajim.common.const import PEPEventType, ACTIVITIES
    
    24
    +from gajim.common.exceptions import StanzaMalformed
    
    25
    +from gajim.common.modules.pep import PEPReceivedEvent, PEPEvent, AbstractPEP
    
    26
    +
    
    27
    +log = logging.getLogger('gajim.c.m.user_activity')
    
    28
    +
    
    29
    +
    
    30
    +class UserActivity(PEPEvent):
    
    31
    +
    
    32
    +    name = 'activity'
    
    33
    +
    
    34
    +    def __init__(self, con):
    
    35
    +        PEPEvent.__init__(self, con, con.name)
    
    36
    +        self._con = con
    
    37
    +        self._account = con.name
    
    38
    +
    
    39
    +        self.handlers = []
    
    40
    +
    
    41
    +        self._stored_publish = None
    
    42
    +
    
    43
    +        self._con.get_module('PEP').register_pep_handler(
    
    44
    +            nbxmpp.NS_ACTIVITY,
    
    45
    +            self._pep_notify_received,
    
    46
    +            self._pep_retract_received)
    
    47
    +
    
    48
    +    def _pep_notify_received(self, jid, item):
    
    49
    +        try:
    
    50
    +            activity = self._extract_info(item)
    
    51
    +        except StanzaMalformed as error:
    
    52
    +            log.warning('%s, %s: %s', jid, error, item)
    
    53
    +            return
    
    54
    +
    
    55
    +        log.info('Received: %s %s', jid, activity)
    
    56
    +        self._push_event(jid, UserActivityPEP(activity))
    
    57
    +
    
    58
    +    def _pep_retract_received(self, jid, id_):
    
    59
    +        log.info('Retract: %s %s', jid, id_)
    
    60
    +        self._push_event(jid, UserActivityPEP(None))
    
    61
    +
    
    62
    +    def _push_event(self, jid, user_pep):
    
    63
    +        self._update_contacts(jid, user_pep)
    
    64
    +        app.nec.push_incoming_event(
    
    65
    +            PEPReceivedEvent(None, conn=self._con,
    
    66
    +                             jid=str(jid),
    
    67
    +                             pep_type=self.name))
    
    68
    +
    
    69
    +    def _extract_info(self, item):
    
    70
    +        activity_dict = {}
    
    71
    +        activity_tag = item.getTag('activity', namespace=nbxmpp.NS_ACTIVITY)
    
    72
    +        if activity_tag is None:
    
    73
    +            raise StanzaMalformed('No activity node')
    
    74
    +
    
    75
    +        for child in activity_tag.getChildren():
    
    76
    +            name = child.getName().strip()
    
    77
    +            data = child.getData().strip()
    
    78
    +            if name == 'text':
    
    79
    +                activity_dict['text'] = data
    
    80
    +            else:
    
    81
    +                activity_dict['activity'] = name
    
    82
    +                for subactivity in child.getChildren():
    
    83
    +                    subactivity_name = subactivity.getName().strip()
    
    84
    +                    activity_dict['subactivity'] = subactivity_name
    
    85
    +
    
    86
    +        return activity_dict or None
    
    87
    +
    
    88
    +    def send_stored_publish(self):
    
    89
    +        if self._stored_publish is not None:
    
    90
    +            log.info('Send stored publish')
    
    91
    +            self.send_activity(*self._stored_publish)
    
    92
    +            self._stored_publish = None
    
    93
    +
    
    94
    +    def reset_stored_publish(self):
    
    95
    +        log.info('Reset stored publish')
    
    96
    +        self._stored_publish = None
    
    97
    +
    
    98
    +    def send_activity(self, activity=None, subactivity=None, message=None):
    
    99
    +        if not self._con.pep_supported:
    
    100
    +            return
    
    101
    +
    
    102
    +        if self._con.connected == 1:
    
    103
    +            # We are connecting, save activity and send it later
    
    104
    +            self._stored_publish = (activity, subactivity, message)
    
    105
    +            return
    
    106
    +
    
    107
    +        if activity:
    
    108
    +            log.info('Send activity: %s %s %s', activity, subactivity, message)
    
    109
    +        else:
    
    110
    +            log.info('Remove activity')
    
    111
    +
    
    112
    +        item = self._build_activity_node(activity, subactivity, message)
    
    113
    +
    
    114
    +        self._con.get_module('PubSub').send_pb_publish(
    
    115
    +            '', nbxmpp.NS_ACTIVITY, item, 'current')
    
    116
    +
    
    117
    +    def _build_activity_node(self, activity, subactivity=None, message=None):
    
    118
    +        item = nbxmpp.Node('activity', {'xmlns': nbxmpp.NS_ACTIVITY})
    
    119
    +        if activity:
    
    120
    +            i = item.addChild(activity)
    
    121
    +            if subactivity:
    
    122
    +                i.addChild(subactivity)
    
    123
    +        if message:
    
    124
    +            i = item.addChild('text')
    
    125
    +            i.addData(message)
    
    126
    +        return item
    
    127
    +
    
    128
    +    def retract_activity(self):
    
    129
    +        if not self._con.pep_supported:
    
    130
    +            return
    
    131
    +        self.send_activity()
    
    132
    +        self._con.get_module('PubSub').send_pb_retract(
    
    133
    +            '', nbxmpp.NS_ACTIVITY, 'current')
    
    134
    +
    
    135
    +
    
    136
    +class UserActivityPEP(AbstractPEP):
    
    137
    +
    
    138
    +    type_ = PEPEventType.ACTIVITY
    
    139
    +
    
    140
    +    def __init__(self, activity):
    
    141
    +        self._pep_specific_data = activity
    
    142
    +
    
    143
    +    def asMarkupText(self):
    
    144
    +        pep = self._pep_specific_data
    
    145
    +        activity = pep['activity']
    
    146
    +        subactivity = pep['subactivity'] if 'subactivity' in pep else None
    
    147
    +        text = pep['text'] if 'text' in pep else None
    
    148
    +
    
    149
    +        if activity in ACTIVITIES:
    
    150
    +            # Translate standard activities
    
    151
    +            if subactivity in ACTIVITIES[activity]:
    
    152
    +                subactivity = ACTIVITIES[activity][subactivity]
    
    153
    +            activity = ACTIVITIES[activity]['category']
    
    154
    +
    
    155
    +        markuptext = '<b>' + GLib.markup_escape_text(activity)
    
    156
    +        if subactivity:
    
    157
    +            markuptext += ': ' + GLib.markup_escape_text(subactivity)
    
    158
    +        markuptext += '</b>'
    
    159
    +        if text:
    
    160
    +            markuptext += ' (%s)' % GLib.markup_escape_text(text)
    
    161
    +        return markuptext

  • gajim/common/pep.py
    ... ... @@ -109,86 +109,6 @@ MOODS = {
    109 109
             'weak':                         _('Weak'),
    
    110 110
             'worried':                      _('Worried')}
    
    111 111
     
    
    112
    -ACTIVITIES = {
    
    113
    -        'doing_chores': {'category':            _('Doing Chores'),
    
    114
    -                'buying_groceries':                     _('Buying Groceries'),
    
    115
    -                'cleaning':                             _('Cleaning'),
    
    116
    -                'cooking':                              _('Cooking'),
    
    117
    -                'doing_maintenance':                    _('Doing Maintenance'),
    
    118
    -                'doing_the_dishes':                     _('Doing the Dishes'),
    
    119
    -                'doing_the_laundry':                    _('Doing the Laundry'),
    
    120
    -                'gardening':                            _('Gardening'),
    
    121
    -                'running_an_errand':                    _('Running an Errand'),
    
    122
    -                'walking_the_dog':                      _('Walking the Dog')},
    
    123
    -        'drinking': {'category':                _('Drinking'),
    
    124
    -                'having_a_beer':                         _('Having a Beer'),
    
    125
    -                'having_coffee':                        _('Having Coffee'),
    
    126
    -                'having_tea':                           _('Having Tea')},
    
    127
    -        'eating': {'category':                  _('Eating'),
    
    128
    -                'having_a_snack':                       _('Having a Snack'),
    
    129
    -                'having_breakfast':                     _('Having Breakfast'),
    
    130
    -                'having_dinner':                        _('Having Dinner'),
    
    131
    -                'having_lunch':                         _('Having Lunch')},
    
    132
    -        'exercising': {'category':              _('Exercising'),
    
    133
    -                'cycling':                              _('Cycling'),
    
    134
    -                'dancing':                              _('Dancing'),
    
    135
    -                'hiking':                               _('Hiking'),
    
    136
    -                'jogging':                              _('Jogging'),
    
    137
    -                'playing_sports':                       _('Playing Sports'),
    
    138
    -                'running':                              _('Running'),
    
    139
    -                'skiing':                               _('Skiing'),
    
    140
    -                'swimming':                             _('Swimming'),
    
    141
    -                'working_out':                          _('Working out')},
    
    142
    -        'grooming': {'category':                _('Grooming'),
    
    143
    -                'at_the_spa':                           _('At the Spa'),
    
    144
    -                'brushing_teeth':                       _('Brushing Teeth'),
    
    145
    -                'getting_a_haircut':                    _('Getting a Haircut'),
    
    146
    -                'shaving':                              _('Shaving'),
    
    147
    -                'taking_a_bath':                        _('Taking a Bath'),
    
    148
    -                'taking_a_shower':                      _('Taking a Shower')},
    
    149
    -        'having_appointment': {'category':      _('Having an Appointment')},
    
    150
    -        'inactive': {'category':                _('Inactive'),
    
    151
    -                'day_off':                              _('Day Off'),
    
    152
    -                'hanging_out':                          _('Hanging out'),
    
    153
    -                'hiding':                               _('Hiding'),
    
    154
    -                'on_vacation':                          _('On Vacation'),
    
    155
    -                'praying':                              _('Praying'),
    
    156
    -                'scheduled_holiday':                    _('Scheduled Holiday'),
    
    157
    -                'sleeping':                             _('Sleeping'),
    
    158
    -                'thinking':                             _('Thinking')},
    
    159
    -        'relaxing': {'category':                _('Relaxing'),
    
    160
    -                'fishing':                               _('Fishing'),
    
    161
    -                'gaming':                                _('Gaming'),
    
    162
    -                'going_out':                             _('Going out'),
    
    163
    -                'partying':                              _('Partying'),
    
    164
    -                'reading':                               _('Reading'),
    
    165
    -                'rehearsing':                            _('Rehearsing'),
    
    166
    -                'shopping':                              _('Shopping'),
    
    167
    -                'smoking':                               _('Smoking'),
    
    168
    -                'socializing':                           _('Socializing'),
    
    169
    -                'sunbathing':                            _('Sunbathing'),
    
    170
    -                'watching_tv':                           _('Watching TV'),
    
    171
    -                'watching_a_movie':                      _('Watching a Movie')},
    
    172
    -        'talking': {'category':                  _('Talking'),
    
    173
    -                'in_real_life':                          _('In Real Life'),
    
    174
    -                'on_the_phone':                          _('On the Phone'),
    
    175
    -                'on_video_phone':                        _('On Video Phone')},
    
    176
    -        'traveling': {'category':                _('Traveling'),
    
    177
    -                'commuting':                             _('Commuting'),
    
    178
    -                'cycling':                               _('Cycling'),
    
    179
    -                'driving':                               _('Driving'),
    
    180
    -                'in_a_car':                              _('In a Car'),
    
    181
    -                'on_a_bus':                              _('On a Bus'),
    
    182
    -                'on_a_plane':                            _('On a Plane'),
    
    183
    -                'on_a_train':                            _('On a Train'),
    
    184
    -                'on_a_trip':                             _('On a Trip'),
    
    185
    -                'walking':                               _('Walking')},
    
    186
    -        'working': {'category':                  _('Working'),
    
    187
    -                'coding':                                _('Coding'),
    
    188
    -                'in_a_meeting':                          _('In a Meeting'),
    
    189
    -                'studying':                              _('Studying'),
    
    190
    -                'writing':                               _('Writing')}}
    
    191
    -
    
    192 112
     TUNE_DATA = ['artist', 'title', 'source', 'track', 'length']
    
    193 113
     
    
    194 114
     LOCATION_DATA = {
    
    ... ... @@ -355,54 +275,6 @@ class UserTunePEP(AbstractPEP):
    355 275
             return tune_string
    
    356 276
     
    
    357 277
     
    
    358
    -class UserActivityPEP(AbstractPEP):
    
    359
    -    '''XEP-0108: User Activity'''
    
    360
    -
    
    361
    -    type_ = 'activity'
    
    362
    -    namespace = nbxmpp.NS_ACTIVITY
    
    363
    -
    
    364
    -    def _extract_info(self, items):
    
    365
    -        activity_dict = {}
    
    366
    -
    
    367
    -        for item in items.getTags('item'):
    
    368
    -            activity_tag = item.getTag('activity')
    
    369
    -            if activity_tag:
    
    370
    -                for child in activity_tag.getChildren():
    
    371
    -                    name = child.getName().strip()
    
    372
    -                    data = child.getData().strip()
    
    373
    -                    if name == 'text':
    
    374
    -                        activity_dict['text'] = data
    
    375
    -                    else:
    
    376
    -                        activity_dict['activity'] = name
    
    377
    -                        for subactivity in child.getChildren():
    
    378
    -                            subactivity_name = subactivity.getName().strip()
    
    379
    -                            activity_dict['subactivity'] = subactivity_name
    
    380
    -
    
    381
    -        retracted = items.getTag('retract') or not 'activity' in activity_dict
    
    382
    -        return (activity_dict, retracted)
    
    383
    -
    
    384
    -    def asMarkupText(self):
    
    385
    -        assert not self._retracted
    
    386
    -        pep = self._pep_specific_data
    
    387
    -        activity = pep['activity']
    
    388
    -        subactivity = pep['subactivity'] if 'subactivity' in pep else None
    
    389
    -        text = pep['text'] if 'text' in pep else None
    
    390
    -
    
    391
    -        if activity in ACTIVITIES:
    
    392
    -            # Translate standard activities
    
    393
    -            if subactivity in ACTIVITIES[activity]:
    
    394
    -                subactivity = ACTIVITIES[activity][subactivity]
    
    395
    -            activity = ACTIVITIES[activity]['category']
    
    396
    -
    
    397
    -        markuptext = '<b>' + GLib.markup_escape_text(activity)
    
    398
    -        if subactivity:
    
    399
    -            markuptext += ': ' + GLib.markup_escape_text(subactivity)
    
    400
    -        markuptext += '</b>'
    
    401
    -        if text:
    
    402
    -            markuptext += ' (%s)' % GLib.markup_escape_text(text)
    
    403
    -        return markuptext
    
    404
    -
    
    405
    -
    
    406 278
     class UserNicknamePEP(AbstractPEP):
    
    407 279
         '''XEP-0172: User Nickname'''
    
    408 280
     
    
    ... ... @@ -518,5 +390,5 @@ class AvatarNotificationPEP(AbstractPEP):
    518 390
     
    
    519 391
     
    
    520 392
     SUPPORTED_PERSONAL_USER_EVENTS = [
    
    521
    -    UserMoodPEP, UserTunePEP, UserActivityPEP,
    
    393
    +    UserMoodPEP, UserTunePEP,
    
    522 394
         UserNicknamePEP, UserLocationPEP, AvatarNotificationPEP]

  • gajim/dialogs.py
    ... ... @@ -51,7 +51,7 @@ from gajim.common import pep
    51 51
     from gajim.common import ged
    
    52 52
     from gajim.common import const
    
    53 53
     from gajim.options_dialog import OptionsDialog
    
    54
    -from gajim.common.const import Option, OptionKind, OptionType
    
    54
    +from gajim.common.const import Option, OptionKind, OptionType, ACTIVITIES
    
    55 55
     
    
    56 56
     from gajim.common import app
    
    57 57
     from gajim.common import helpers
    
    ... ... @@ -371,11 +371,11 @@ class ChangeActivityDialog:
    371 371
             rbtns = {}
    
    372 372
             group = None
    
    373 373
     
    
    374
    -        for category in pep.ACTIVITIES:
    
    374
    +        for category in ACTIVITIES:
    
    375 375
                 item = self.xml.get_object(category + '_image')
    
    376 376
                 item.set_from_pixbuf(
    
    377 377
                         gtkgui_helpers.load_activity_icon(category).get_pixbuf())
    
    378
    -            item.set_tooltip_text(pep.ACTIVITIES[category]['category'])
    
    378
    +            item.set_tooltip_text(ACTIVITIES[category]['category'])
    
    379 379
     
    
    380 380
                 vbox = self.xml.get_object(category + '_vbox')
    
    381 381
                 vbox.set_border_width(5)
    
    ... ... @@ -392,7 +392,7 @@ class ChangeActivityDialog:
    392 392
                 hbox = Gtk.HBox(homogeneous=False, spacing=5)
    
    393 393
                 hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
    
    394 394
                     activity), False, False, 0)
    
    395
    -            lbl = Gtk.Label(label='<b>' + pep.ACTIVITIES[category]['category'] \
    
    395
    +            lbl = Gtk.Label(label='<b>' + ACTIVITIES[category]['category'] \
    
    396 396
                     + '</b>')
    
    397 397
                 lbl.set_use_markup(True)
    
    398 398
                 hbox.pack_start(lbl, False, False, 0)
    
    ... ... @@ -402,7 +402,7 @@ class ChangeActivityDialog:
    402 402
                 vbox.pack_start(rbtns[act], False, False, 0)
    
    403 403
     
    
    404 404
                 activities = []
    
    405
    -            for activity in pep.ACTIVITIES[category]:
    
    405
    +            for activity in ACTIVITIES[category]:
    
    406 406
                     activities.append(activity)
    
    407 407
                 activities.sort()
    
    408 408
                 for activity in activities:
    
    ... ... @@ -420,7 +420,7 @@ class ChangeActivityDialog:
    420 420
                     hbox = Gtk.HBox(homogeneous=False, spacing=5)
    
    421 421
                     hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
    
    422 422
                             activity), False, False, 0)
    
    423
    -                hbox.pack_start(Gtk.Label(label=pep.ACTIVITIES[category][activity]),
    
    423
    +                hbox.pack_start(Gtk.Label(label=ACTIVITIES[category][activity]),
    
    424 424
                             False, False, 0)
    
    425 425
                     rbtns[act].connect('toggled', self.on_rbtn_toggled,
    
    426 426
                             [category, activity])
    
    ... ... @@ -430,8 +430,8 @@ class ChangeActivityDialog:
    430 430
     
    
    431 431
             self.default_radio = rbtns['doing_chores_other']
    
    432 432
     
    
    433
    -        if self.activity in pep.ACTIVITIES:
    
    434
    -            if not self.subactivity in pep.ACTIVITIES[self.activity]:
    
    433
    +        if self.activity in ACTIVITIES:
    
    434
    +            if not self.subactivity in ACTIVITIES[self.activity]:
    
    435 435
                     self.subactivity = 'other'
    
    436 436
     
    
    437 437
                 rbtns[self.activity + '_' + self.subactivity].set_active(True)
    
    ... ... @@ -682,9 +682,9 @@ class ChangeStatusMessageDialog(TimeoutDialog):
    682 682
             img = self.xml.get_object('activity_image')
    
    683 683
             label = self.xml.get_object('activity_button_label')
    
    684 684
             if 'activity' in self.pep_dict and self.pep_dict['activity'] in \
    
    685
    -           pep.ACTIVITIES:
    
    685
    +           ACTIVITIES:
    
    686 686
                 if 'subactivity' in self.pep_dict and self.pep_dict['subactivity'] \
    
    687
    -            in pep.ACTIVITIES[self.pep_dict['activity']]:
    
    687
    +            in ACTIVITIES[self.pep_dict['activity']]:
    
    688 688
                     img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
    
    689 689
                         self.pep_dict['activity'], self.pep_dict['subactivity']).\
    
    690 690
                             get_pixbuf())
    

  • gajim/gtkgui_helpers.py
    ... ... @@ -52,6 +52,7 @@ from gajim.common import i18n
    52 52
     from gajim.common import app
    
    53 53
     from gajim.common import pep
    
    54 54
     from gajim.common import configpaths
    
    55
    +from gajim.common.const import PEPEventType, ACTIVITIES
    
    55 56
     from gajim.filechoosers import AvatarSaveDialog
    
    56 57
     
    
    57 58
     gtk_icon_theme = Gtk.IconTheme.get_default()
    
    ... ... @@ -635,14 +636,13 @@ def get_pep_as_pixbuf(pep_class):
    635 636
                     'music.png')
    
    636 637
                 return GdkPixbuf.Pixbuf.new_from_file(path)
    
    637 638
             return icon
    
    638
    -    elif isinstance(pep_class, pep.UserActivityPEP):
    
    639
    -        assert not pep_class._retracted
    
    639
    +    elif pep_class == PEPEventType.ACTIVITY:
    
    640 640
             pep_ = pep_class._pep_specific_data
    
    641 641
             activity = pep_['activity']
    
    642 642
     
    
    643
    -        has_known_activity = activity in pep.ACTIVITIES
    
    643
    +        has_known_activity = activity in ACTIVITIES
    
    644 644
             has_known_subactivity = (has_known_activity  and ('subactivity' in pep_)
    
    645
    -                and (pep_['subactivity'] in pep.ACTIVITIES[activity]))
    
    645
    +                and (pep_['subactivity'] in ACTIVITIES[activity]))
    
    646 646
     
    
    647 647
             if has_known_activity:
    
    648 648
                 if has_known_subactivity:
    

  • gajim/gui_interface.py
    ... ... @@ -99,7 +99,7 @@ from gajim.common.connection import Connection
    99 99
     from gajim.common.file_props import FilesProp
    
    100 100
     from gajim.common import pep
    
    101 101
     from gajim import emoticons
    
    102
    -from gajim.common.const import AvatarSize, SSLError
    
    102
    +from gajim.common.const import AvatarSize, SSLError, PEPEventType, ACTIVITIES
    
    103 103
     
    
    104 104
     from gajim import roster_window
    
    105 105
     from gajim import profile_window
    
    ... ... @@ -2481,13 +2481,13 @@ class Interface:
    2481 2481
                 path = os.path.join(
    
    2482 2482
                     configpaths.get('DATA'), 'emoticons', 'static', 'music.png')
    
    2483 2483
                 return GdkPixbuf.Pixbuf.new_from_file(path)
    
    2484
    -        elif isinstance(pep_obj, pep.UserActivityPEP):
    
    2484
    +        elif pep_obj == PEPEventType.ACTIVITY:
    
    2485 2485
                 pep_ = pep_obj._pep_specific_data
    
    2486 2486
                 activity = pep_['activity']
    
    2487 2487
     
    
    2488
    -            has_known_activity = activity in pep.ACTIVITIES
    
    2488
    +            has_known_activity = activity in ACTIVITIES
    
    2489 2489
                 has_known_subactivity = (has_known_activity  and ('subactivity' in
    
    2490
    -                pep_) and (pep_['subactivity'] in pep.ACTIVITIES[activity]))
    
    2490
    +                pep_) and (pep_['subactivity'] in ACTIVITIES[activity]))
    
    2491 2491
     
    
    2492 2492
                 if has_known_activity:
    
    2493 2493
                     if has_known_subactivity:
    

  • gajim/roster_window.py
    ... ... @@ -2099,9 +2099,10 @@ class RosterWindow:
    2099 2099
                 activity = pep_dict['activity']
    
    2100 2100
                 subactivity = pep_dict.get('subactivity', None)
    
    2101 2101
                 activity_text = pep_dict.get('activity_text', None)
    
    2102
    -            connection.send_activity(activity, subactivity, activity_text)
    
    2102
    +            connection.get_module('UserActivity').send_activity(
    
    2103
    +                activity, subactivity, activity_text)
    
    2103 2104
             else:
    
    2104
    -            connection.retract_activity()
    
    2105
    +            connection.get_module('UserActivity').retract_activity()
    
    2105 2106
     
    
    2106 2107
             if 'mood' in pep_dict:
    
    2107 2108
                 mood = pep_dict['mood']