diff --git a/data/default_config.cfg b/data/default_config.cfg index cbab6f64..19f435bc 100644 --- a/data/default_config.cfg +++ b/data/default_config.cfg @@ -347,11 +347,29 @@ display_tune_notifications = false # in the roster). # If this is set to false, then the display_tune_notifications # option will be ignored. -receive_user_tune = true +enable_user_tune = true + +# Display user mood notifications as information messages or not +display_mood_notifications = false + +# Receive the mood notifications or not (in order to display informations +# in the roster). +# If this is set to false, then the display_mood_notifications +# option will be ignored. +enable_user_mood = true + +# Display user activity notifications as information messages or not +display_activity_notifications = false + +# Receive the activity notifications or not (in order to display informations +# in the roster). +# If this is set to false, then the display_activity_notifications +# option will be ignored. +enable_user_activity = true # If set to true, use the nickname broadcasted by the user if none has been # set manually. -use_pep_nick = true +enable_user_nick = true # if true, chat states will be sent to the people you are talking to. # Chat states are, for example, messages informing that you are composing diff --git a/doc/en/configure.txt b/doc/en/configure.txt index ecd1fc40..a11b7e66 100644 --- a/doc/en/configure.txt +++ b/doc/en/configure.txt @@ -118,11 +118,40 @@ section of this documentation. If set to true, notifications about the music your contacts listen to will be displayed in the info buffer as 'Tune' messages. +*display_mood_notifications*:: false + + If set to true, notifications about the mood of your contacts + will be displayed in the info buffer as 'Mood' messages. + +*display_activity_notifications*:: false + + If set to true, notifications about the current activity of your contacts + will be displayed in the info buffer as 'Activity' messages. + *display_user_color_in_join_part*:: false If set to true, the color of the nick will be used in MUCs information messages, instead of the default color from the theme. +*enable_user_activity*:: true + + Set this to false if you don’t want to receive the mood of your contacts + anymore. + +*enable_user_mood*:: true + + Set this to false if you don’t want to receive the mood of your contacts + anymore. + +*enable_user_nick*:: true + + Set to false if you don’t want your contacts to hint you their identity. + +*enable_user_tune*:: true + + If this is set to false, you will no longer be subscribed to tune events, + and the display_tune_notifications option will be ignored. + *enable_vertical_tab_list*:: false If true, a vertical list of tabs, with their name, is displayed on the left of @@ -281,11 +310,6 @@ section of this documentation. If the message takes more than one line, the popup will stay visible two more second per additional lines. -*receive_user_tune*:: true - - If this is set to false, you will no longer be subscribed to tune events, - and the display_tune_notifications option will be ignored. - *remote_fifo_path*:: ./poezio.fifo The path of the FIFO used to send the commands (see the exec_remote option). @@ -543,11 +567,26 @@ bar = false Disable the beeps triggered by this conversation. Works in MucTab, PrivateTab and ConversationTab. +*display_activity_notifications*:: false + + If set to true, notifications about the current activity of your contacts + will be displayed in the info buffer as 'Activity' messages. + +*display_mood_notifications*:: false + + If set to true, notifications about the mood of your contacts + will be displayed in the info buffer as 'Mood' messages. + *display_user_color_in_join_part*:: false If set to true, the color of the nick will be used in MUCs information messages, instead of the default color from the theme. +*display_tune_notifications*:: false + + If set to true, notifications about the music your contacts listen to + will be displayed in the info buffer as 'Tune' messages. + *hide_exit_join*:: -1 Exact same thing than hide_status_change, except that it concerns diff --git a/src/connection.py b/src/connection.py index d5a393c5..8565a616 100644 --- a/src/connection.py +++ b/src/connection.py @@ -72,10 +72,18 @@ class Connection(sleekxmpp.ClientXMPP): self.register_plugin('xep_0115') self.register_plugin('xep_0191') - if config.get('receive_user_tune', 'true') != 'false': + if config.get('enable_user_tune', 'true') != 'false': self.register_plugin('xep_0118') - if config.get('use_pep_nick', 'true') != 'false': + + if config.get('enable_user_nick', 'true') != 'false': self.register_plugin('xep_0172') + + if config.get('enable_user_mood', 'true') != 'false': + self.register_plugin('xep_0107') + + if config.get('enable_user_activity', 'true') != 'false': + self.register_plugin('xep_0108') + if config.get('send_poezio_info', 'true') == 'true': info = {'name':'poezio', 'version': options.version} diff --git a/src/contact.py b/src/contact.py index 46cf8e6f..8e6595db 100644 --- a/src/contact.py +++ b/src/contact.py @@ -68,6 +68,8 @@ class Contact(object): self._name = '' self.error = None self.tune = {} + self.mood = '' + self.activity = '' @property def groups(self): diff --git a/src/core.py b/src/core.py index 1a53baa7..0b041f2d 100644 --- a/src/core.py +++ b/src/core.py @@ -20,6 +20,7 @@ from threading import Event from datetime import datetime from xml.etree import cElementTree as ET +import pep import common import theming import logging @@ -230,7 +231,6 @@ class Core(object): self.key_func.update(key_func) # Add handlers - self.xmpp.add_event_handler("user_tune_publish", self.on_tune_event) self.xmpp.add_event_handler('connected', self.on_connected) self.xmpp.add_event_handler('disconnected', self.on_disconnected) self.xmpp.add_event_handler('no_auth', self.on_failed_auth) @@ -260,8 +260,14 @@ class Core(object): self.xmpp.add_event_handler("attention", self.on_attention) self.xmpp.add_event_handler("ssl_cert", self.validate_ssl) self.all_stanzas = Callback('custom matcher', connection.MatchAll(None), self.incoming_stanza) - if config.get('use_pep_nick', 'true') != 'false': + if config.get('enable_user_tune', 'true') != 'false': + self.xmpp.add_event_handler("user_tune_publish", self.on_tune_event) + if config.get('enable_user_nick', 'true') != 'false': self.xmpp.add_event_handler("user_nick_publish", self.on_nick_received) + if config.get('enable_user_mood', 'true') != 'false': + self.xmpp.add_event_handler("user_mood_publish", self.on_mood) + if config.get('enable_user_activity', 'true') != 'false': + self.xmpp.add_event_handler("user_activity_publish", self.on_activity) self.xmpp.register_handler(self.all_stanzas) self.initial_joins = [] @@ -2132,7 +2138,7 @@ class Core(object): serv_list.add(serv) return the_input.auto_completion(list(serv_list), ' ') - def command_activity(self, arg): + def command_last_activity(self, arg): """ /activity """ @@ -2158,12 +2164,72 @@ class Core(object): self.information(msg, 'Info') jid = safeJID(arg) if jid == '': - return self.command_help('activity') + return self.command_help('last_activity') self.xmpp.plugin['xep_0012'].get_last_activity(jid, block=False, callback=callback) - def completion_activity(self, the_input): + def completion_last_activity(self, the_input): return the_input.auto_completion([jid for jid in roster.jids()], '', quotify=False) + def command_mood(self, arg): + """ + /mood [ [text]] + """ + args = common.shell_split(arg) + if not args: + return self.xmpp.plugin['xep_0107'].stop(block=False) + mood = args[0] + if mood not in pep.MOODS: + return self.information('%s is not a correct value for a mood.' % mood, 'Error') + if len(args) > 1: + text = args[1] + else: + text = None + self.xmpp.plugin['xep_0107'].publish_mood(mood, text, block=False) + + def completion_mood(self, the_input): + """Completion for /mood""" + return the_input.auto_completion(list(pep.MOODS.keys()), '', quotify=False) + + def command_activity(self, arg): + """ + /activity [ [specific] [text]] + """ + args = common.shell_split(arg) + length = len(args) + if not length: + return self.xmpp.plugin['xep_0108'].stop(block=False) + general = args[0] + if general not in pep.ACTIVITIES: + return self.information('%s is not a correct value for an activity' % general, 'Error') + specific = None + text = None + if length == 2: + if args[1] in pep.ACTIVITIES[general]: + specific = args[1] + else: + text = args[1] + elif length == 3: + specific = args[1] + text = args[2] + if specific and specific not in pep.ACTIVITIES[general]: + return self.information('%s is not a correct value for an activity' % specific, 'Error') + self.xmpp.plugin['xep_0108'].publish_activity(general, specific, text, block=False) + + def completion_activity(self, the_input): + """Completion for /activity""" + txt = the_input.get_text() + args = common.shell_split(txt) + n = len(args) + if txt.endswith(' '): + n += 1 + if n == 2: + return the_input.auto_completion(list(pep.ACTIVITIES.keys()), '', quotify=False) + elif n == 3: + if args[1] in pep.ACTIVITIES: + l = list(pep.ACTIVITIES[args[1]]) + l.remove('category') + return the_input.auto_completion(l, '', quotify=False) + def command_invite(self, arg): """/invite [reason]""" args = common.shell_split(arg) @@ -2233,6 +2299,10 @@ class Core(object): msg = arg else: msg = None + if config.get('enable_user_mood', 'true') != 'false': + self.xmpp.plugin['xep_0107'].stop(block=False) + if config.get('enable_user_activity', 'true') != 'false': + self.xmpp.plugin['xep_0108'].stop(block=False) self.plugin_manager.disable_plugins() self.disconnect(msg) self.running = False @@ -2489,11 +2559,25 @@ class Core(object): completion=self.completion_runkey) self.register_command('self', self.command_self, shortdesc=_('Remind you of who you are.')) - self.register_command('activity', self.command_activity, + self.register_command('last_activity', self.command_last_activity, usage='', desc=_('Informs you of the last activity of a JID.'), shortdesc=_('Get the activity of someone.'), - completion=self.completion_activity) + completion=self.completion_last_activity) + if config.get('enable_user_mood', 'true') != 'false': + self.register_command('activity', self.command_activity, + usage='[ [specific] [text]]', + desc=_('Send your current activity to your contacts (use the completion).' + ' Nothing means "stop broadcasting an activity".'), + shortdesc=_('Send your activity.'), + completion=self.completion_activity) + if config.get('eanble_user_activity', 'true') != 'false': + self.register_command('mood', self.command_mood, + usage='[ [text]]', + desc=_('Send your current mood to your contacts (use the completion).' + ' Nothing means "stop broadcasting a mood".'), + shortdesc=_('Send your mood.'), + completion=self.completion_mood) ####################### XMPP Event Handlers ################################## @@ -2555,7 +2639,7 @@ class Core(object): else: remote_nick = '' # check for a received nick - if not remote_nick and config.get('use_pep_nick', 'true') != 'false': + if not remote_nick and config.get('enable_user_nick', 'true') != 'false': if message.xml.find('{http://jabber.org/protocol/nick}nick') is not None: remote_nick = message['nick']['nick'] # bind the nick to the conversation @@ -2633,6 +2717,68 @@ class Core(object): item = message['pubsub_event']['items']['item'] if item.xml.find('{http://jabber.org/protocol/nick}nick') is not None: contact.name = item['nick']['nick'] + else: + contact.name= '' + + def on_mood(self, message): + """ + Called when a pep notification for an user mood + is received. + """ + contact = roster[message['from'].bare] + if not contact: + return + item = message['pubsub_event']['items']['item'] + if item.xml.find('{http://jabber.org/protocol/mood}mood') is not None: + mood = item['mood']['value'] + if mood: + mood = pep.MOODS.get(mood, mood) + text = item['mood']['text'] + if text: + mood = '%s (%s)' % (mood, text) + contact.mood = mood + else: + contact.mood = '' + else: + contact.mood = '' + if config.get_by_tabname('display_mood_notifications', 'false', contact.bare_jid) == 'true': + if contact.mood: + self.information('Mood from '+ contact.bare_jid + ': ' + contact.mood, 'Mood') + else: + self.information(contact.bare_jid + ' stopped having his/her mood.', 'Mood') + + def on_activity(self, message): + """ + Called when a pep notification for an user activity + is received. + """ + contact = roster[message['from'].bare] + if not contact: + return + item = message['pubsub_event']['items']['item'] + if item.xml.find('{http://jabber.org/protocol/activity}activity') is not None: + try: + activity = item['activity']['value'] + except ValueError: + return + if activity[0]: + general = pep.ACTIVITIES.get(activity[0]) + s = general['category'] + if activity[1]: + s = s + '/' + general.get(activity[1], 'other') + text = item['activity']['text'] + if text: + s = '%s (%s)' % (s, text) + contact.activity = s + else: + contact.activity = '' + else: + contact.activity = '' + if config.get_by_tabname('display_activity_notifications', 'false', contact.bare_jid) == 'true': + if contact.activity: + self.information('Activity from '+ contact.bare_jid + ': ' + contact.activity, 'Activity') + else: + self.information(contact.bare_jid + ' stopped doing his/her activity.', 'Activity') def on_tune_event(self, message): """ @@ -2656,10 +2802,13 @@ class Core(object): } else: contact.tune = {} - if config.get('display_tune_notifications', 'false') == 'true' and contact.tune: - self.information( - 'Tune from '+ message['from'].bare + ': ' + common.format_tune_string(contact.tune), - 'Tune') + if config.get_by_tabname('display_tune_notifications', 'false', contact.bare_jid) == 'true': + if contact.tune: + self.information( + 'Tune from '+ message['from'].bare + ': ' + common.format_tune_string(contact.tune), + 'Tune') + else: + self.information(contact.bare_jid + ' stopped listening to music.', 'Tune') def on_groupchat_message(self, message): """ @@ -3068,7 +3217,7 @@ class Core(object): status=self.status.message, show=self.status.show) - if config.get('use_pep_nick', 'true') != 'false': + if config.get('enable_user_nick', 'true') != 'false': self.xmpp.plugin['xep_0172'].publish_nick(nick=self.own_nick) ### Other handlers ### diff --git a/src/pep.py b/src/pep.py new file mode 100644 index 00000000..e077a315 --- /dev/null +++ b/src/pep.py @@ -0,0 +1,215 @@ +# -*- coding:utf-8 -*- +## src/common/pep.py +## +## Copyright (C) 2007 Piotr Gaczkowski +## Copyright (C) 2007-2012 Yann Leboulanger +## Copyright (C) 2008 Brendan Taylor +## Jean-Marie Traissard +## Jonathan Schleifer +## Stephan Erb +## +## 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 . +## +from gettext import gettext as _ + +MOODS = { + 'afraid': _('Afraid'), + 'amazed': _('Amazed'), + 'amorous': _('Amorous'), + 'angry': _('Angry'), + 'annoyed': _('Annoyed'), + 'anxious': _('Anxious'), + 'aroused': _('Aroused'), + 'ashamed': _('Ashamed'), + 'bored': _('Bored'), + 'brave': _('Brave'), + 'calm': _('Calm'), + 'cautious': _('Cautious'), + 'cold': _('Cold'), + 'confident': _('Confident'), + 'confused': _('Confused'), + 'contemplative': _('Contemplative'), + 'contented': _('Contented'), + 'cranky': _('Cranky'), + 'crazy': _('Crazy'), + 'creative': _('Creative'), + 'curious': _('Curious'), + 'dejected': _('Dejected'), + 'depressed': _('Depressed'), + 'disappointed': _('Disappointed'), + 'disgusted': _('Disgusted'), + 'dismayed': _('Dismayed'), + 'distracted': _('Distracted'), + 'embarrassed': _('Embarrassed'), + 'envious': _('Envious'), + 'excited': _('Excited'), + 'flirtatious': _('Flirtatious'), + 'frustrated': _('Frustrated'), + 'grateful': _('Grateful'), + 'grieving': _('Grieving'), + 'grumpy': _('Grumpy'), + 'guilty': _('Guilty'), + 'happy': _('Happy'), + 'hopeful': _('Hopeful'), + 'hot': _('Hot'), + 'humbled': _('Humbled'), + 'humiliated': _('Humiliated'), + 'hungry': _('Hungry'), + 'hurt': _('Hurt'), + 'impressed': _('Impressed'), + 'in_awe': _('In Awe'), + 'in_love': _('In Love'), + 'indignant': _('Indignant'), + 'interested': _('Interested'), + 'intoxicated': _('Intoxicated'), + 'invincible': _('Invincible'), + 'jealous': _('Jealous'), + 'lonely': _('Lonely'), + 'lost': _('Lost'), + 'lucky': _('Lucky'), + 'mean': _('Mean'), + 'moody': _('Moody'), + 'nervous': _('Nervous'), + 'neutral': _('Neutral'), + 'offended': _('Offended'), + 'outraged': _('Outraged'), + 'playful': _('Playful'), + 'proud': _('Proud'), + 'relaxed': _('Relaxed'), + 'relieved': _('Relieved'), + 'remorseful': _('Remorseful'), + 'restless': _('Restless'), + 'sad': _('Sad'), + 'sarcastic': _('Sarcastic'), + 'satisfied': _('Satisfied'), + 'serious': _('Serious'), + 'shocked': _('Shocked'), + 'shy': _('Shy'), + 'sick': _('Sick'), + 'sleepy': _('Sleepy'), + 'spontaneous': _('Spontaneous'), + 'stressed': _('Stressed'), + 'strong': _('Strong'), + 'surprised': _('Surprised'), + 'thankful': _('Thankful'), + 'thirsty': _('Thirsty'), + 'tired': _('Tired'), + 'undefined': _('Undefined'), + 'weak': _('Weak'), + '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')}} + +LOCATION_DATA = { + 'accuracy': _('accuracy'), + 'alt': _('alt'), + 'area': _('area'), + 'bearing': _('bearing'), + 'building': _('building'), + 'country': _('country'), + 'countrycode': _('countrycode'), + 'datum': _('datum'), + 'description': _('description'), + 'error': _('error'), + 'floor': _('floor'), + 'lat': _('lat'), + 'locality': _('locality'), + 'lon': _('lon'), + 'postalcode': _('postalcode'), + 'region': _('region'), + 'room': _('room'), + 'speed': _('speed'), + 'street': _('street'), + 'text': _('text'), + 'timestamp': _('timestamp'), + 'uri': _('uri')} diff --git a/src/tabs.py b/src/tabs.py index 3805a690..ed2a5998 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2076,7 +2076,7 @@ class RosterInfoTab(Tab): self.key_func["M-Y"] = self.move_cursor_to_prev_group self.key_func["M-[1;5B"] = self.move_cursor_to_next_group self.key_func["M-[1;5A"] = self.move_cursor_to_prev_group - self.key_func["l"] = self.command_activity + self.key_func["l"] = self.command_last_activity self.key_func["o"] = self.toggle_offline_show self.key_func["v"] = self.get_contact_version self.key_func["i"] = self.show_contact_info @@ -2139,11 +2139,11 @@ class RosterInfoTab(Tab): completion=self.completion_file) self.register_command('clear_infos', self.command_clear_infos, shortdesc=_('Clear the info buffer.')) - self.register_command('activity', self.command_activity, + self.register_command('last_activity', self.command_last_activity, usage=_(''), desc=_('Informs you of the last activity of a JID.'), shortdesc=_('Get the activity of someone.'), - completion=self.core.completion_activity) + completion=self.core.completion_last_activity) self.core.xmpp.add_event_handler('session_start', lambda event: self.core.xmpp.plugin['xep_0030'].get_info( jid=self.core.xmpp.boundjid.domain, @@ -2274,11 +2274,10 @@ class RosterInfoTab(Tab): """ self.core.disconnect() - def command_activity(self, arg=None): + def command_last_activity(self, arg=None): """ /activity [jid] """ - item = self.roster_win.selected_row if arg: jid = arg @@ -2289,7 +2288,7 @@ class RosterInfoTab(Tab): else: self.core.information('No JID selected.', 'Error') return - self.core.command_activity(jid) + self.core.command_last_activity(jid) def resize(self): if not self.visible: @@ -2845,14 +2844,18 @@ class RosterInfoTab(Tab): if isinstance(selected_row, Contact): cont = selected_row res = selected_row.get_highest_priority_resource() - msg = 'Contact: %s (%s)\n%s connected resource%s\nCurrent status: %s\nCurrent tune: %s' % ( - cont.bare_jid, - res.presence if res else 'unavailable', - len(cont), - '' if len(cont) == 1 else 's', - res.status if res else '', - common.format_tune_string(cont.tune), - ) + acc = [] + acc.append('Contact: %s (%s)' % (cont.bare_jid, res.presence if res else 'unavailable')) + if res: + acc.append('%s connected resource%s' % (len(cont), '' if len(cont) == 1 else 's')) + acc.append('Current status: %s' % res.status) + if cont.tune: + acc.append('Tune: %s' % common.format_tune_string(cont.tune)) + if cont.mood: + acc.append('Mood: %s' % cont.mood) + if cont.activity: + acc.append('Activity: %s' % cont.activity) + msg = '\n'.join(acc) elif isinstance(selected_row, Resource): res = selected_row msg = 'Resource: %s (%s)\nCurrent status: %s\nPriority: %s' % ( @@ -2959,11 +2962,11 @@ class ConversationTab(ChatTab): shortdesc=_('Get the software version of the user.')) self.register_command('info', self.command_info, shortdesc=_('Get the status of the contact.')) - self.register_command('activity', self.command_activity, + self.register_command('last_activity', self.command_last_activity, usage=_('[jid]'), desc=_('Get the last activity of the given or the current contact.'), shortdesc=_('Get the activity.'), - completion=self.core.completion_activity) + completion=self.core.completion_last_activity) self.resize() self.update_commands() self.update_keys() @@ -3023,12 +3026,12 @@ class ConversationTab(ChatTab): self.text_win.refresh() self.input.refresh() - def command_activity(self, arg): + def command_last_activity(self, arg): """ /activity [jid] """ if arg.strip(): - return self.core.command_activity(arg) + return self.core.command_last_activity(arg) def callback(iq): if iq['type'] != 'result': diff --git a/src/theming.py b/src/theming.py index b95596c2..26b66377 100644 --- a/src/theming.py +++ b/src/theming.py @@ -202,7 +202,11 @@ class Theme(object): CHAR_ROSTER_ERROR = '✖' CHAR_ROSTER_TUNE = '♪' CHAR_ROSTER_ASKED = '?' + CHAR_ROSTER_ACTIVITY = '☃' + CHAR_ROSTER_MOOD = '☺' + COLOR_ROSTER_MOOD = (2, -1) + COLOR_ROSTER_ACTIVITY = (3, -1) COLOR_ROSTER_TUNE = (6, -1) COLOR_ROSTER_ERROR = (1, -1) COLOR_JOIN_CHAR = (4, -1) @@ -221,6 +225,8 @@ class Theme(object): 'help': (10, -1), 'headline': (11, -1, 'b'), 'tune': (6, -1), + 'mood': (2, -1), + 'activity': (3, -1), 'default': (7, -1), } diff --git a/src/windows.py b/src/windows.py index 78b3c5e5..c4927a6d 100644 --- a/src/windows.py +++ b/src/windows.py @@ -1938,6 +1938,10 @@ class RosterWin(Win): added += len(get_theme().CHAR_ROSTER_ERROR) if contact.tune: added += len(get_theme().CHAR_ROSTER_TUNE) + if contact.mood: + added += len(get_theme().CHAR_ROSTER_MOOD) + if contact.activity: + added += len(get_theme().CHAR_ROSTER_ACTIVITY) if config.getl('show_roster_jids', 'true') == 'false' and contact.name: display_name = '%s' % contact.name @@ -1958,7 +1962,10 @@ class RosterWin(Win): self.addstr(get_theme().CHAR_ROSTER_ERROR, to_curses_attr(get_theme().COLOR_ROSTER_ERROR)) if contact.tune: self.addstr(get_theme().CHAR_ROSTER_TUNE, to_curses_attr(get_theme().COLOR_ROSTER_TUNE)) - + if contact.activity: + self.addstr(get_theme().CHAR_ROSTER_ACTIVITY, to_curses_attr(get_theme().COLOR_ROSTER_ACTIVITY)) + if contact.mood: + self.addstr(get_theme().CHAR_ROSTER_MOOD, to_curses_attr(get_theme().COLOR_ROSTER_MOOD)) self.finish_line() def draw_resource_line(self, y, resource, colored): @@ -2028,6 +2035,14 @@ class ContactInfoWin(Win): self.addstr(i, 0, 'Current Tune: %s' % common.format_tune_string(contact.tune), to_curses_attr(get_theme().COLOR_NORMAL_TEXT)) i += 1 + if contact.mood: + self.addstr(i, 0, 'Mood: %s' % contact.mood, to_curses_attr(get_theme().COLOR_NORMAL_TEXT)) + i += 1 + + if contact.activity: + self.addstr(i, 0, 'Activity: %s' % contact.activity, to_curses_attr(get_theme().COLOR_NORMAL_TEXT)) + i += 1 + def draw_group_info(self, group): """ draw the group information