Refactor UserActivity and PEP into own modules

This commit is contained in:
Philipp Hörist 2018-07-03 00:10:55 +02:00
parent 0b5bb998c3
commit b7775afd0c
11 changed files with 440 additions and 195 deletions

View File

@ -75,7 +75,9 @@ from gajim.common.modules.vcard_temp import VCardTemp
from gajim.common.modules.vcard_avatars import VCardAvatars from gajim.common.modules.vcard_avatars import VCardAvatars
from gajim.common.modules.pubsub import PubSub from gajim.common.modules.pubsub import PubSub
from gajim.common.modules.bookmarks import Bookmarks from gajim.common.modules.bookmarks import Bookmarks
from gajim.common.modules.pep import PEP
from gajim.common.modules.user_avatar import UserAvatar from gajim.common.modules.user_avatar import UserAvatar
from gajim.common.modules.user_activity import UserActivity
from gajim.common.connection_handlers import * from gajim.common.connection_handlers import *
from gajim.common.contacts import GC_Contact from gajim.common.contacts import GC_Contact
from gajim.gtkgui_helpers import get_action from gajim.gtkgui_helpers import get_action
@ -179,7 +181,10 @@ class CommonConnection:
return self._modules[name] return self._modules[name]
def get_module_handlers(self): def get_module_handlers(self):
return self._modules.values() handlers = []
for module in self._modules.values():
handlers += module.handlers
return handlers
def register_module(self, name, cls, *args, **kwargs): def register_module(self, name, cls, *args, **kwargs):
self._modules[name] = cls(*args, **kwargs) self._modules[name] = cls(*args, **kwargs)
@ -661,8 +666,10 @@ class Connection(CommonConnection, ConnectionHandlers):
self.register_module('VCardTemp', VCardTemp, self) self.register_module('VCardTemp', VCardTemp, self)
self.register_module('VCardAvatars', VCardAvatars, self) self.register_module('VCardAvatars', VCardAvatars, self)
self.register_module('PubSub', PubSub, self) self.register_module('PubSub', PubSub, self)
self.register_module('PEP', PEP, self)
self.register_module('Bookmarks', Bookmarks, self) self.register_module('Bookmarks', Bookmarks, self)
self.register_module('UserAvatar', UserAvatar, self) self.register_module('UserAvatar', UserAvatar, self)
self.register_module('UserActivity', UserActivity, self)
app.ged.register_event_handler('privacy-list-received', ged.CORE, app.ged.register_event_handler('privacy-list-received', ged.CORE,
self._nec_privacy_list_received) self._nec_privacy_list_received)
@ -749,6 +756,7 @@ class Connection(CommonConnection, ConnectionHandlers):
def disconnect(self, on_purpose=False): def disconnect(self, on_purpose=False):
app.interface.music_track_changed(None, None, self.name) app.interface.music_track_changed(None, None, self.name)
self.reset_awaiting_pep() self.reset_awaiting_pep()
self.get_module('PEP').reset_stored_publish()
self.on_purpose = on_purpose self.on_purpose = on_purpose
self.connected = 0 self.connected = 0
self.time_to_reconnect = None self.time_to_reconnect = None

View File

@ -295,7 +295,6 @@ class ConnectionPEP(object):
self._account = new_name self._account = new_name
def reset_awaiting_pep(self): def reset_awaiting_pep(self):
self.to_be_sent_activity = None
self.to_be_sent_mood = None self.to_be_sent_mood = None
self.to_be_sent_tune = None self.to_be_sent_tune = None
self.to_be_sent_nick = None self.to_be_sent_nick = None
@ -305,8 +304,6 @@ class ConnectionPEP(object):
""" """
Send pep info that were waiting for connection Send pep info that were waiting for connection
""" """
if self.to_be_sent_activity:
self.send_activity(*self.to_be_sent_activity)
if self.to_be_sent_mood: if self.to_be_sent_mood:
self.send_mood(*self.to_be_sent_mood) self.send_mood(*self.to_be_sent_mood)
if self.to_be_sent_tune: if self.to_be_sent_tune:
@ -317,37 +314,6 @@ class ConnectionPEP(object):
self.send_location(self.to_be_sent_location) self.send_location(self.to_be_sent_location)
self.reset_awaiting_pep() self.reset_awaiting_pep()
def _pubsubEventCB(self, xmpp_dispatcher, msg):
''' Called when we receive <message /> with pubsub event. '''
app.nec.push_incoming_event(PEPReceivedEvent(None, conn=self,
stanza=msg))
def send_activity(self, activity, subactivity=None, message=None):
if self.connected == 1:
# We are connecting, keep activity in mem and send it when we'll be
# connected
self.to_be_sent_activity = (activity, subactivity, message)
return
if not self.pep_supported:
return
item = nbxmpp.Node('activity', {'xmlns': nbxmpp.NS_ACTIVITY})
if activity:
i = item.addChild(activity)
if subactivity:
i.addChild(subactivity)
if message:
i = item.addChild('text')
i.addData(message)
self.get_module('PubSub').send_pb_publish(
'', nbxmpp.NS_ACTIVITY, item, '0')
def retract_activity(self):
if not self.pep_supported:
return
self.send_activity(None)
# not all client support new XEP, so we still retract
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
def send_mood(self, mood, message=None): def send_mood(self, mood, message=None):
if self.connected == 1: if self.connected == 1:
# We are connecting, keep mood in mem and send it when we'll be # We are connecting, keep mood in mem and send it when we'll be
@ -1187,14 +1153,16 @@ ConnectionHTTPUpload):
app.config.set_per('accounts', self.name, 'roster_version', app.config.set_per('accounts', self.name, 'roster_version',
obj.version) obj.version)
def _messageCB(self, con, msg): def _messageCB(self, con, stanza):
""" """
Called when we receive a message Called when we receive a message
""" """
if nbxmpp.NS_PUBSUB_EVENT in stanza.getProperties():
return
log.debug('MessageCB') log.debug('MessageCB')
app.nec.push_incoming_event(NetworkEvent('raw-message-received', app.nec.push_incoming_event(NetworkEvent('raw-message-received',
conn=self, stanza=msg, account=self.name)) conn=self, stanza=stanza, account=self.name))
def _dispatch_gc_msg_with_captcha(self, stanza, msg_obj): def _dispatch_gc_msg_with_captcha(self, stanza, msg_obj):
msg_obj.stanza = stanza msg_obj.stanza = stanza
@ -1518,6 +1486,7 @@ ConnectionHTTPUpload):
# Inform GUI we just signed in # Inform GUI we just signed in
app.nec.push_incoming_event(SignedInEvent(None, conn=self)) app.nec.push_incoming_event(SignedInEvent(None, conn=self))
self.send_awaiting_pep() self.send_awaiting_pep()
self.get_module('PEP').send_stored_publish()
self.continue_connect_info = None self.continue_connect_info = None
def _PubkeyGetCB(self, con, iq_obj): def _PubkeyGetCB(self, con, iq_obj):
@ -1583,11 +1552,6 @@ ConnectionHTTPUpload):
# that defines handlers # that defines handlers
con.RegisterHandler('message', self._messageCB) con.RegisterHandler('message', self._messageCB)
con.RegisterHandler('presence', self._presenceCB) con.RegisterHandler('presence', self._presenceCB)
# We use makefirst so that this handler is called before _messageCB, and
# can prevent calling it when it's not needed.
# We also don't check for namespace, else it cannot stop _messageCB to
# be called
con.RegisterHandler('message', self._pubsubEventCB, makefirst=True)
con.RegisterHandler('iq', self._rosterSetCB, 'set', nbxmpp.NS_ROSTER) con.RegisterHandler('iq', self._rosterSetCB, 'set', nbxmpp.NS_ROSTER)
con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI) con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
con.RegisterHandler('iq', self._siErrorCB, 'error', nbxmpp.NS_SI) con.RegisterHandler('iq', self._siErrorCB, 'error', nbxmpp.NS_SI)
@ -1645,6 +1609,5 @@ ConnectionHTTPUpload):
con.RegisterHandler('iq', self._BlockingResultCB, 'result', con.RegisterHandler('iq', self._BlockingResultCB, 'result',
nbxmpp.NS_BLOCKING) nbxmpp.NS_BLOCKING)
for module in self.get_module_handlers(): for handler in self.get_module_handlers():
for handler in module.handlers: con.RegisterHandler(*handler)
con.RegisterHandler(*handler)

View File

@ -1780,7 +1780,6 @@ class PEPReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
if entry: if entry:
app.nec.push_incoming_event(AtomEntryReceived(None, app.nec.push_incoming_event(AtomEntryReceived(None,
conn=self.conn, node=entry)) conn=self.conn, node=entry))
raise nbxmpp.NodeProcessed
class AtomEntryReceived(nec.NetworkIncomingEvent): class AtomEntryReceived(nec.NetworkIncomingEvent):
name = 'atom-entry-received' name = 'atom-entry-received'

View File

@ -124,6 +124,108 @@ class BookmarkStorageType(IntEnum):
PRIVATE = 0 PRIVATE = 0
PUBSUB = 1 PUBSUB = 1
@unique
class PEPHandlerType(IntEnum):
NOTIFY = 0
RETRACT = 1
@unique
class PEPEventType(IntEnum):
ACTIVITY = 0
ACTIVITIES = {
'doing_chores': {
'category': _('Doing Chores'),
'buying_groceries': _('Buying Groceries'),
'cleaning': _('Cleaning'),
'cooking': _('Cooking'),
'doing_maintenance': _('Doing Maintenance'),
'doing_the_dishes': _('Doing the Dishes'),
'doing_the_laundry': _('Doing the Laundry'),
'gardening': _('Gardening'),
'running_an_errand': _('Running an Errand'),
'walking_the_dog': _('Walking the Dog')},
'drinking': {
'category': _('Drinking'),
'having_a_beer': _('Having a Beer'),
'having_coffee': _('Having Coffee'),
'having_tea': _('Having Tea')},
'eating': {
'category': _('Eating'),
'having_a_snack': _('Having a Snack'),
'having_breakfast': _('Having Breakfast'),
'having_dinner': _('Having Dinner'),
'having_lunch': _('Having Lunch')},
'exercising': {
'category': _('Exercising'),
'cycling': _('Cycling'),
'dancing': _('Dancing'),
'hiking': _('Hiking'),
'jogging': _('Jogging'),
'playing_sports': _('Playing Sports'),
'running': _('Running'),
'skiing': _('Skiing'),
'swimming': _('Swimming'),
'working_out': _('Working out')},
'grooming': {
'category': _('Grooming'),
'at_the_spa': _('At the Spa'),
'brushing_teeth': _('Brushing Teeth'),
'getting_a_haircut': _('Getting a Haircut'),
'shaving': _('Shaving'),
'taking_a_bath': _('Taking a Bath'),
'taking_a_shower': _('Taking a Shower')},
'having_appointment': {
'category': _('Having an Appointment')},
'inactive': {
'category': _('Inactive'),
'day_off': _('Day Off'),
'hanging_out': _('Hanging out'),
'hiding': _('Hiding'),
'on_vacation': _('On Vacation'),
'praying': _('Praying'),
'scheduled_holiday': _('Scheduled Holiday'),
'sleeping': _('Sleeping'),
'thinking': _('Thinking')},
'relaxing': {
'category': _('Relaxing'),
'fishing': _('Fishing'),
'gaming': _('Gaming'),
'going_out': _('Going out'),
'partying': _('Partying'),
'reading': _('Reading'),
'rehearsing': _('Rehearsing'),
'shopping': _('Shopping'),
'smoking': _('Smoking'),
'socializing': _('Socializing'),
'sunbathing': _('Sunbathing'),
'watching_tv': _('Watching TV'),
'watching_a_movie': _('Watching a Movie')},
'talking': {
'category': _('Talking'),
'in_real_life': _('In Real Life'),
'on_the_phone': _('On the Phone'),
'on_video_phone': _('On Video Phone')},
'traveling': {
'category': _('Traveling'),
'commuting': _('Commuting'),
'cycling': _('Cycling'),
'driving': _('Driving'),
'in_a_car': _('In a Car'),
'on_a_bus': _('On a Bus'),
'on_a_plane': _('On a Plane'),
'on_a_train': _('On a Train'),
'on_a_trip': _('On a Trip'),
'walking': _('Walking')},
'working': {
'category': _('Working'),
'coding': _('Coding'),
'in_a_meeting': _('In a Meeting'),
'studying': _('Studying'),
'writing': _('Writing')}}
SSLError = { SSLError = {
2: _("Unable to get issuer certificate"), 2: _("Unable to get issuer certificate"),
3: _("Unable to get certificate CRL"), 3: _("Unable to get certificate CRL"),

139
gajim/common/modules/pep.py Normal file
View File

@ -0,0 +1,139 @@
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0163: Personal Eventing Protocol
import logging
import nbxmpp
from gajim.common import app
from gajim.common.nec import NetworkIncomingEvent
from gajim.common.const import PEPHandlerType, PEPEventType
log = logging.getLogger('gajim.c.m.pep')
class PEP:
def __init__(self, con):
self._con = con
self._account = con.name
self.handlers = [
('message', self._pep_event_received,
'headline', nbxmpp.NS_PUBSUB_EVENT)
]
self._pep_handlers = {}
self._store_publish_modules = []
def register_pep_handler(self, namespace, notify_handler, retract_handler):
if namespace in self._pep_handlers:
self._pep_handlers[namespace].append(
(notify_handler, retract_handler))
else:
self._pep_handlers[namespace] = [(notify_handler, retract_handler)]
if notify_handler:
module_instance = notify_handler.__self__
if hasattr(module_instance, 'send_stored_publish'):
if module_instance not in self._store_publish_modules:
self._store_publish_modules.append(module_instance)
def _pep_event_received(self, conn, stanza):
jid = stanza.getFrom()
event = stanza.getTag('event', namespace=nbxmpp.NS_PUBSUB_EVENT)
items = event.getTag('items')
if items is None:
log.warning('Malformed PEP event (no items node): %s', stanza)
raise nbxmpp.NodeProcessed
namespace = items.getAttr('node')
if namespace is None:
log.warning('Malformed PEP event (no node attr): %s', stanza)
raise nbxmpp.NodeProcessed
log.info('PEP notification received: %s %s', jid, namespace)
handlers = self._pep_handlers.get(namespace, None)
if handlers is None:
# Old Fallback
from gajim.common.connection_handlers_events import PEPReceivedEvent as OldPEPReceivedEvent
app.nec.push_incoming_event(
OldPEPReceivedEvent(None, conn=self._con, stanza=stanza))
raise nbxmpp.NodeProcessed
else:
# Check if this is a retraction
retract = items.getTag('retract')
if retract is not None:
for handler in handlers:
handler[PEPHandlerType.RETRACT](jid, retract.getID())
raise nbxmpp.NodeProcessed
# Check if we have items
items_ = items.getTags('item')
if items_ is None:
log.warning('Malformed PEP event received: %s', stanza)
raise nbxmpp.NodeProcessed
for handler in handlers:
handler[PEPHandlerType.NOTIFY](jid, items_[0])
raise nbxmpp.NodeProcessed
def send_stored_publish(self):
for module in self._store_publish_modules:
module.send_stored_publish()
def reset_stored_publish(self):
for module in self._store_publish_modules:
module.reset_stored_publish()
class PEPEvent:
name = ''
def __init__(self, con, account):
self.__account = account
self.__con = con
def _update_contacts(self, jid, user_pep):
for contact in app.contacts.get_contacts(self.__account, str(jid)):
if user_pep:
contact.pep[self.name] = user_pep
else:
contact.pep.pop(self.name, None)
if jid == self.__con.get_own_jid().getStripped():
if user_pep:
self.__con.pep[self.name] = user_pep
else:
self.__con.pep.pop(self.name, None)
class AbstractPEP:
type_ = PEPEventType
def __eq__(self, other):
return other == self.type_
def __bool__(self):
return self._pep_specific_data is not None
def __str__(self):
return str(self._pep_specific_data)
class PEPReceivedEvent(NetworkIncomingEvent):
name = 'pep-received'
base_network_events = []

View File

@ -0,0 +1,161 @@
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0108: User Activity
import logging
import nbxmpp
from gi.repository import GLib
from gajim.common import app
from gajim.common.const import PEPEventType, ACTIVITIES
from gajim.common.exceptions import StanzaMalformed
from gajim.common.modules.pep import PEPReceivedEvent, PEPEvent, AbstractPEP
log = logging.getLogger('gajim.c.m.user_activity')
class UserActivity(PEPEvent):
name = 'activity'
def __init__(self, con):
PEPEvent.__init__(self, con, con.name)
self._con = con
self._account = con.name
self.handlers = []
self._stored_publish = None
self._con.get_module('PEP').register_pep_handler(
nbxmpp.NS_ACTIVITY,
self._pep_notify_received,
self._pep_retract_received)
def _pep_notify_received(self, jid, item):
try:
activity = self._extract_info(item)
except StanzaMalformed as error:
log.warning('%s, %s: %s', jid, error, item)
return
log.info('Received: %s %s', jid, activity)
self._push_event(jid, UserActivityPEP(activity))
def _pep_retract_received(self, jid, id_):
log.info('Retract: %s %s', jid, id_)
self._push_event(jid, UserActivityPEP(None))
def _push_event(self, jid, user_pep):
self._update_contacts(jid, user_pep)
app.nec.push_incoming_event(
PEPReceivedEvent(None, conn=self._con,
jid=str(jid),
pep_type=self.name))
def _extract_info(self, item):
activity_dict = {}
activity_tag = item.getTag('activity', namespace=nbxmpp.NS_ACTIVITY)
if activity_tag is None:
raise StanzaMalformed('No activity node')
for child in activity_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if name == 'text':
activity_dict['text'] = data
else:
activity_dict['activity'] = name
for subactivity in child.getChildren():
subactivity_name = subactivity.getName().strip()
activity_dict['subactivity'] = subactivity_name
return activity_dict or None
def send_stored_publish(self):
if self._stored_publish is not None:
log.info('Send stored publish')
self.send_activity(*self._stored_publish)
self._stored_publish = None
def reset_stored_publish(self):
log.info('Reset stored publish')
self._stored_publish = None
def send_activity(self, activity=None, subactivity=None, message=None):
if not self._con.pep_supported:
return
if self._con.connected == 1:
# We are connecting, save activity and send it later
self._stored_publish = (activity, subactivity, message)
return
if activity:
log.info('Send activity: %s %s %s', activity, subactivity, message)
else:
log.info('Remove activity')
item = self._build_activity_node(activity, subactivity, message)
self._con.get_module('PubSub').send_pb_publish(
'', nbxmpp.NS_ACTIVITY, item, 'current')
def _build_activity_node(self, activity, subactivity=None, message=None):
item = nbxmpp.Node('activity', {'xmlns': nbxmpp.NS_ACTIVITY})
if activity:
i = item.addChild(activity)
if subactivity:
i.addChild(subactivity)
if message:
i = item.addChild('text')
i.addData(message)
return item
def retract_activity(self):
if not self._con.pep_supported:
return
self.send_activity()
self._con.get_module('PubSub').send_pb_retract(
'', nbxmpp.NS_ACTIVITY, 'current')
class UserActivityPEP(AbstractPEP):
type_ = PEPEventType.ACTIVITY
def __init__(self, activity):
self._pep_specific_data = activity
def asMarkupText(self):
pep = self._pep_specific_data
activity = pep['activity']
subactivity = pep['subactivity'] if 'subactivity' in pep else None
text = pep['text'] if 'text' in pep else None
if activity in ACTIVITIES:
# Translate standard activities
if subactivity in ACTIVITIES[activity]:
subactivity = ACTIVITIES[activity][subactivity]
activity = ACTIVITIES[activity]['category']
markuptext = '<b>' + GLib.markup_escape_text(activity)
if subactivity:
markuptext += ': ' + GLib.markup_escape_text(subactivity)
markuptext += '</b>'
if text:
markuptext += ' (%s)' % GLib.markup_escape_text(text)
return markuptext

View File

@ -109,86 +109,6 @@ MOODS = {
'weak': _('Weak'), 'weak': _('Weak'),
'worried': _('Worried')} 'worried': _('Worried')}
ACTIVITIES = {
'doing_chores': {'category': _('Doing Chores'),
'buying_groceries': _('Buying Groceries'),
'cleaning': _('Cleaning'),
'cooking': _('Cooking'),
'doing_maintenance': _('Doing Maintenance'),
'doing_the_dishes': _('Doing the Dishes'),
'doing_the_laundry': _('Doing the Laundry'),
'gardening': _('Gardening'),
'running_an_errand': _('Running an Errand'),
'walking_the_dog': _('Walking the Dog')},
'drinking': {'category': _('Drinking'),
'having_a_beer': _('Having a Beer'),
'having_coffee': _('Having Coffee'),
'having_tea': _('Having Tea')},
'eating': {'category': _('Eating'),
'having_a_snack': _('Having a Snack'),
'having_breakfast': _('Having Breakfast'),
'having_dinner': _('Having Dinner'),
'having_lunch': _('Having Lunch')},
'exercising': {'category': _('Exercising'),
'cycling': _('Cycling'),
'dancing': _('Dancing'),
'hiking': _('Hiking'),
'jogging': _('Jogging'),
'playing_sports': _('Playing Sports'),
'running': _('Running'),
'skiing': _('Skiing'),
'swimming': _('Swimming'),
'working_out': _('Working out')},
'grooming': {'category': _('Grooming'),
'at_the_spa': _('At the Spa'),
'brushing_teeth': _('Brushing Teeth'),
'getting_a_haircut': _('Getting a Haircut'),
'shaving': _('Shaving'),
'taking_a_bath': _('Taking a Bath'),
'taking_a_shower': _('Taking a Shower')},
'having_appointment': {'category': _('Having an Appointment')},
'inactive': {'category': _('Inactive'),
'day_off': _('Day Off'),
'hanging_out': _('Hanging out'),
'hiding': _('Hiding'),
'on_vacation': _('On Vacation'),
'praying': _('Praying'),
'scheduled_holiday': _('Scheduled Holiday'),
'sleeping': _('Sleeping'),
'thinking': _('Thinking')},
'relaxing': {'category': _('Relaxing'),
'fishing': _('Fishing'),
'gaming': _('Gaming'),
'going_out': _('Going out'),
'partying': _('Partying'),
'reading': _('Reading'),
'rehearsing': _('Rehearsing'),
'shopping': _('Shopping'),
'smoking': _('Smoking'),
'socializing': _('Socializing'),
'sunbathing': _('Sunbathing'),
'watching_tv': _('Watching TV'),
'watching_a_movie': _('Watching a Movie')},
'talking': {'category': _('Talking'),
'in_real_life': _('In Real Life'),
'on_the_phone': _('On the Phone'),
'on_video_phone': _('On Video Phone')},
'traveling': {'category': _('Traveling'),
'commuting': _('Commuting'),
'cycling': _('Cycling'),
'driving': _('Driving'),
'in_a_car': _('In a Car'),
'on_a_bus': _('On a Bus'),
'on_a_plane': _('On a Plane'),
'on_a_train': _('On a Train'),
'on_a_trip': _('On a Trip'),
'walking': _('Walking')},
'working': {'category': _('Working'),
'coding': _('Coding'),
'in_a_meeting': _('In a Meeting'),
'studying': _('Studying'),
'writing': _('Writing')}}
TUNE_DATA = ['artist', 'title', 'source', 'track', 'length'] TUNE_DATA = ['artist', 'title', 'source', 'track', 'length']
LOCATION_DATA = { LOCATION_DATA = {
@ -355,54 +275,6 @@ class UserTunePEP(AbstractPEP):
return tune_string return tune_string
class UserActivityPEP(AbstractPEP):
'''XEP-0108: User Activity'''
type_ = 'activity'
namespace = nbxmpp.NS_ACTIVITY
def _extract_info(self, items):
activity_dict = {}
for item in items.getTags('item'):
activity_tag = item.getTag('activity')
if activity_tag:
for child in activity_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if name == 'text':
activity_dict['text'] = data
else:
activity_dict['activity'] = name
for subactivity in child.getChildren():
subactivity_name = subactivity.getName().strip()
activity_dict['subactivity'] = subactivity_name
retracted = items.getTag('retract') or not 'activity' in activity_dict
return (activity_dict, retracted)
def asMarkupText(self):
assert not self._retracted
pep = self._pep_specific_data
activity = pep['activity']
subactivity = pep['subactivity'] if 'subactivity' in pep else None
text = pep['text'] if 'text' in pep else None
if activity in ACTIVITIES:
# Translate standard activities
if subactivity in ACTIVITIES[activity]:
subactivity = ACTIVITIES[activity][subactivity]
activity = ACTIVITIES[activity]['category']
markuptext = '<b>' + GLib.markup_escape_text(activity)
if subactivity:
markuptext += ': ' + GLib.markup_escape_text(subactivity)
markuptext += '</b>'
if text:
markuptext += ' (%s)' % GLib.markup_escape_text(text)
return markuptext
class UserNicknamePEP(AbstractPEP): class UserNicknamePEP(AbstractPEP):
'''XEP-0172: User Nickname''' '''XEP-0172: User Nickname'''
@ -518,5 +390,5 @@ class AvatarNotificationPEP(AbstractPEP):
SUPPORTED_PERSONAL_USER_EVENTS = [ SUPPORTED_PERSONAL_USER_EVENTS = [
UserMoodPEP, UserTunePEP, UserActivityPEP, UserMoodPEP, UserTunePEP,
UserNicknamePEP, UserLocationPEP, AvatarNotificationPEP] UserNicknamePEP, UserLocationPEP, AvatarNotificationPEP]

View File

@ -51,7 +51,7 @@ from gajim.common import pep
from gajim.common import ged from gajim.common import ged
from gajim.common import const from gajim.common import const
from gajim.options_dialog import OptionsDialog from gajim.options_dialog import OptionsDialog
from gajim.common.const import Option, OptionKind, OptionType from gajim.common.const import Option, OptionKind, OptionType, ACTIVITIES
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
@ -371,11 +371,11 @@ class ChangeActivityDialog:
rbtns = {} rbtns = {}
group = None group = None
for category in pep.ACTIVITIES: for category in ACTIVITIES:
item = self.xml.get_object(category + '_image') item = self.xml.get_object(category + '_image')
item.set_from_pixbuf( item.set_from_pixbuf(
gtkgui_helpers.load_activity_icon(category).get_pixbuf()) gtkgui_helpers.load_activity_icon(category).get_pixbuf())
item.set_tooltip_text(pep.ACTIVITIES[category]['category']) item.set_tooltip_text(ACTIVITIES[category]['category'])
vbox = self.xml.get_object(category + '_vbox') vbox = self.xml.get_object(category + '_vbox')
vbox.set_border_width(5) vbox.set_border_width(5)
@ -392,7 +392,7 @@ class ChangeActivityDialog:
hbox = Gtk.HBox(homogeneous=False, spacing=5) hbox = Gtk.HBox(homogeneous=False, spacing=5)
hbox.pack_start(gtkgui_helpers.load_activity_icon(category, hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
activity), False, False, 0) activity), False, False, 0)
lbl = Gtk.Label(label='<b>' + pep.ACTIVITIES[category]['category'] \ lbl = Gtk.Label(label='<b>' + ACTIVITIES[category]['category'] \
+ '</b>') + '</b>')
lbl.set_use_markup(True) lbl.set_use_markup(True)
hbox.pack_start(lbl, False, False, 0) hbox.pack_start(lbl, False, False, 0)
@ -402,7 +402,7 @@ class ChangeActivityDialog:
vbox.pack_start(rbtns[act], False, False, 0) vbox.pack_start(rbtns[act], False, False, 0)
activities = [] activities = []
for activity in pep.ACTIVITIES[category]: for activity in ACTIVITIES[category]:
activities.append(activity) activities.append(activity)
activities.sort() activities.sort()
for activity in activities: for activity in activities:
@ -420,7 +420,7 @@ class ChangeActivityDialog:
hbox = Gtk.HBox(homogeneous=False, spacing=5) hbox = Gtk.HBox(homogeneous=False, spacing=5)
hbox.pack_start(gtkgui_helpers.load_activity_icon(category, hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
activity), False, False, 0) activity), False, False, 0)
hbox.pack_start(Gtk.Label(label=pep.ACTIVITIES[category][activity]), hbox.pack_start(Gtk.Label(label=ACTIVITIES[category][activity]),
False, False, 0) False, False, 0)
rbtns[act].connect('toggled', self.on_rbtn_toggled, rbtns[act].connect('toggled', self.on_rbtn_toggled,
[category, activity]) [category, activity])
@ -430,8 +430,8 @@ class ChangeActivityDialog:
self.default_radio = rbtns['doing_chores_other'] self.default_radio = rbtns['doing_chores_other']
if self.activity in pep.ACTIVITIES: if self.activity in ACTIVITIES:
if not self.subactivity in pep.ACTIVITIES[self.activity]: if not self.subactivity in ACTIVITIES[self.activity]:
self.subactivity = 'other' self.subactivity = 'other'
rbtns[self.activity + '_' + self.subactivity].set_active(True) rbtns[self.activity + '_' + self.subactivity].set_active(True)
@ -682,9 +682,9 @@ class ChangeStatusMessageDialog(TimeoutDialog):
img = self.xml.get_object('activity_image') img = self.xml.get_object('activity_image')
label = self.xml.get_object('activity_button_label') label = self.xml.get_object('activity_button_label')
if 'activity' in self.pep_dict and self.pep_dict['activity'] in \ if 'activity' in self.pep_dict and self.pep_dict['activity'] in \
pep.ACTIVITIES: ACTIVITIES:
if 'subactivity' in self.pep_dict and self.pep_dict['subactivity'] \ if 'subactivity' in self.pep_dict and self.pep_dict['subactivity'] \
in pep.ACTIVITIES[self.pep_dict['activity']]: in ACTIVITIES[self.pep_dict['activity']]:
img.set_from_pixbuf(gtkgui_helpers.load_activity_icon( img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
self.pep_dict['activity'], self.pep_dict['subactivity']).\ self.pep_dict['activity'], self.pep_dict['subactivity']).\
get_pixbuf()) get_pixbuf())

View File

@ -52,6 +52,7 @@ from gajim.common import i18n
from gajim.common import app from gajim.common import app
from gajim.common import pep from gajim.common import pep
from gajim.common import configpaths from gajim.common import configpaths
from gajim.common.const import PEPEventType, ACTIVITIES
from gajim.filechoosers import AvatarSaveDialog from gajim.filechoosers import AvatarSaveDialog
gtk_icon_theme = Gtk.IconTheme.get_default() gtk_icon_theme = Gtk.IconTheme.get_default()
@ -635,14 +636,13 @@ def get_pep_as_pixbuf(pep_class):
'music.png') 'music.png')
return GdkPixbuf.Pixbuf.new_from_file(path) return GdkPixbuf.Pixbuf.new_from_file(path)
return icon return icon
elif isinstance(pep_class, pep.UserActivityPEP): elif pep_class == PEPEventType.ACTIVITY:
assert not pep_class._retracted
pep_ = pep_class._pep_specific_data pep_ = pep_class._pep_specific_data
activity = pep_['activity'] activity = pep_['activity']
has_known_activity = activity in pep.ACTIVITIES has_known_activity = activity in ACTIVITIES
has_known_subactivity = (has_known_activity and ('subactivity' in pep_) has_known_subactivity = (has_known_activity and ('subactivity' in pep_)
and (pep_['subactivity'] in pep.ACTIVITIES[activity])) and (pep_['subactivity'] in ACTIVITIES[activity]))
if has_known_activity: if has_known_activity:
if has_known_subactivity: if has_known_subactivity:

View File

@ -99,7 +99,7 @@ from gajim.common.connection import Connection
from gajim.common.file_props import FilesProp from gajim.common.file_props import FilesProp
from gajim.common import pep from gajim.common import pep
from gajim import emoticons from gajim import emoticons
from gajim.common.const import AvatarSize, SSLError from gajim.common.const import AvatarSize, SSLError, PEPEventType, ACTIVITIES
from gajim import roster_window from gajim import roster_window
from gajim import profile_window from gajim import profile_window
@ -2481,13 +2481,13 @@ class Interface:
path = os.path.join( path = os.path.join(
configpaths.get('DATA'), 'emoticons', 'static', 'music.png') configpaths.get('DATA'), 'emoticons', 'static', 'music.png')
return GdkPixbuf.Pixbuf.new_from_file(path) return GdkPixbuf.Pixbuf.new_from_file(path)
elif isinstance(pep_obj, pep.UserActivityPEP): elif pep_obj == PEPEventType.ACTIVITY:
pep_ = pep_obj._pep_specific_data pep_ = pep_obj._pep_specific_data
activity = pep_['activity'] activity = pep_['activity']
has_known_activity = activity in pep.ACTIVITIES has_known_activity = activity in ACTIVITIES
has_known_subactivity = (has_known_activity and ('subactivity' in has_known_subactivity = (has_known_activity and ('subactivity' in
pep_) and (pep_['subactivity'] in pep.ACTIVITIES[activity])) pep_) and (pep_['subactivity'] in ACTIVITIES[activity]))
if has_known_activity: if has_known_activity:
if has_known_subactivity: if has_known_subactivity:

View File

@ -2099,9 +2099,10 @@ class RosterWindow:
activity = pep_dict['activity'] activity = pep_dict['activity']
subactivity = pep_dict.get('subactivity', None) subactivity = pep_dict.get('subactivity', None)
activity_text = pep_dict.get('activity_text', None) activity_text = pep_dict.get('activity_text', None)
connection.send_activity(activity, subactivity, activity_text) connection.get_module('UserActivity').send_activity(
activity, subactivity, activity_text)
else: else:
connection.retract_activity() connection.get_module('UserActivity').retract_activity()
if 'mood' in pep_dict: if 'mood' in pep_dict:
mood = pep_dict['mood'] mood = pep_dict['mood']