diff options
Diffstat (limited to 'src/core.py')
-rw-r--r-- | src/core.py | 159 |
1 files changed, 119 insertions, 40 deletions
diff --git a/src/core.py b/src/core.py index e2ba8ce1..1f93324d 100644 --- a/src/core.py +++ b/src/core.py @@ -15,6 +15,7 @@ import threading import traceback from datetime import datetime +from xml.etree import cElementTree as ET from inspect import getargspec @@ -25,6 +26,7 @@ import singleton import collections from sleekxmpp.xmlstream.stanzabase import JID +from sleekxmpp.xmlstream.stanzabase import StanzaBase log = logging.getLogger(__name__) @@ -131,6 +133,8 @@ class Core(object): 'load': (self.command_load, _('Usage: /load <plugin>\nLoad: Load the specified plugin'), self.plugin_manager.completion_load), 'unload': (self.command_unload, _('Usage: /unload <plugin>\nUnload: Unload the specified plugin'), self.plugin_manager.completion_unload), 'plugins': (self.command_plugins, _('Usage: /plugins\nPlugins: Show the plugins in use.'), None), + 'presence': (self.command_presence, _('Usage: /presence <JID> [type] [status]\nPresence: Send a directed presence to <JID> and using [type] and [status] if provided.'), None), + 'rawxml': (self.command_rawxml, _('Usage: /rawxml\nRawXML: Send a custom xml stanza.'), None), } self.key_func = { @@ -177,8 +181,6 @@ class Core(object): self.connected_events = {} - self.autoload_plugins() - def autoload_plugins(self): plugins = config.get('plugins_autoload', '') for plugin in plugins.split(): @@ -325,6 +327,7 @@ class Core(object): tab = self.get_tab_of_conversation_with_jid(message['from'], False) if not tab: return False + self.events.trigger('normal_chatstate', message, tab) tab.chatstate = state if tab == self.current_tab(): tab.refresh_info_header() @@ -335,6 +338,7 @@ class Core(object): tab = self.get_tab_by_name(message['from'].full, tabs.PrivateTab) if not tab: return + self.events.trigger('private_chatstate', message, tab) tab.chatstate = state if tab == self.current_tab(): tab.refresh_info_header() @@ -346,6 +350,7 @@ class Core(object): room_from = message.getMucroom() tab = self.get_tab_by_name(room_from, tabs.MucTab) if tab and tab.get_user_by_name(nick): + self.events.trigger('muc_chatstate', message, tab) tab.get_user_by_name(nick).chatstate = state if tab == self.current_tab(): tab.user_win.refresh(tab.users) @@ -372,13 +377,13 @@ class Core(object): return # If a resource got offline, display the message in the conversation with this # precise resource. - self.add_information_message_to_conversation_tab(jid.full, '\x195}%s is \x191}offline' % (resource.get_jid().full)) + self.add_information_message_to_conversation_tab(jid.full, '\x195}%s is \x191}offline' % (resource.jid.full)) contact.remove_resource(resource) # Display the message in the conversation with the bare JID only if that was # the only resource online (i.e. now the contact is completely disconnected) if not contact.get_highest_priority_resource(): # No resource left: that was the last one self.add_information_message_to_conversation_tab(jid.bare, '\x195}%s is \x191}offline' % (jid.bare)) - self.information('\x193}%s \x195}is \x191}offline' % (resource.get_jid().bare), "Roster") + self.information('\x193}%s \x195}is \x191}offline' % (resource.jid.bare), "Roster") if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window() @@ -392,21 +397,22 @@ class Core(object): resource = contact.get_resource_by_fulljid(jid.full) assert not resource resource = Resource(jid.full) + self.events.trigger('normal_presence', presence, resource) status = presence['type'] status_message = presence['status'] priority = presence.getPriority() or 0 - resource.set_status(status_message) - resource.set_presence(status) - resource.set_priority(priority) + resource.status = status_message + resource.presence = status + resource.priority = priority self.add_information_message_to_conversation_tab(jid.full, '\x195}%s is \x194}online' % (jid.full)) if not contact.get_highest_priority_resource(): # No connected resource yet: the user's just connecting if time.time() - self.connection_time > 12: # We do not display messages if we recently logged in if status_message: - self.information("\x193}%s \x195}is \x194}online\x195} (\x19o%s\x195})" % (resource.get_jid().bare, status_message), "Roster") + self.information("\x193}%s \x195}is \x194}online\x195} (\x19o%s\x195})" % (resource.jid.bare, status_message), "Roster") else: - self.information("\x193}%s \x195}is \x194}online\x195}" % resource.get_jid().bare, "Roster") + self.information("\x193}%s \x195}is \x194}online\x195}" % resource.jid.bare, "Roster") self.add_information_message_to_conversation_tab(jid.bare, '\x195}%s is \x194}online' % (jid.bare)) contact.add_resource(resource) if isinstance(self.current_tab(), tabs.RosterInfoTab): @@ -453,13 +459,16 @@ class Core(object): Called when we are connected and authenticated """ self.connection_time = time.time() + self.autoload_plugins() self.information(_("Authentication success.")) self.information(_("Your JID is %s") % self.xmpp.boundjid.full) if not self.xmpp.anon: # request the roster self.xmpp.getRoster() # send initial presence - self.xmpp.makePresence().send() + pres = self.xmpp.make_presence() + self.events.trigger('send_normal_presence', pres) + pres.send() rooms = config.get('rooms', '') if rooms == '' or not isinstance(rooms, str): return @@ -487,6 +496,7 @@ class Core(object): from_room = presence['from'].bare tab = self.get_tab_by_name(from_room, tabs.MucTab) if tab: + self.events.trigger('muc_presence', presence, tab) tab.handle_presence(presence) def rename_private_tabs(self, room_name, old_nick, new_nick): @@ -560,13 +570,14 @@ class Core(object): jid = message['from'] nick_from = jid.resource room_from = jid.bare + body = xhtml.get_body_from_message_stanza(message) tab = self.get_tab_by_name(jid.full, tabs.PrivateTab) # get the tab with the private conversation if not tab: # It's the first message we receive: create the tab - tab = self.open_private_window(room_from, nick_from, False) + if body: + tab = self.open_private_window(room_from, nick_from, False) if not tab: return - self.events.trigger('private_msg', message) - body = xhtml.get_body_from_message_stanza(message) + self.events.trigger('private_msg', message, tab) if not body: return tab.add_message(body, time=None, nickname=nick_from, @@ -604,8 +615,8 @@ class Core(object): conversation = self.get_tab_by_name(jid.bare, tabs.ConversationTab) if not conversation: if create: - # We create the conversation with the bare Jid if nothing was found - conversation = self.open_conversation_window(jid.bare, False) + # We create the conversation with the full Jid if nothing was found + conversation = self.open_conversation_window(jid.full, False) else: conversation = None return conversation @@ -615,15 +626,17 @@ class Core(object): When receiving "normal" messages (from someone in our roster) """ jid = message['from'] - self.events.trigger('conversation_msg', message) body = xhtml.get_body_from_message_stanza(message) + conversation = self.get_tab_of_conversation_with_jid(jid, create=False) if not body: if message['type'] == 'error': self.information(self.get_error_message_from_error_stanza(message), 'Error') return conversation = self.get_tab_of_conversation_with_jid(jid, create=True) + self.events.trigger('conversation_msg', message, conversation) + body = xhtml.get_body_from_message_stanza(message) if roster.get_contact_by_jid(jid.bare): - remote_nick = roster.get_contact_by_jid(jid.bare).get_name() or jid.user + remote_nick = roster.get_contact_by_jid(jid.bare).name or jid.user else: remote_nick = jid.user conversation._text_buffer.add_message(body, nickname=remote_nick, nick_color=get_theme().COLOR_REMOTE_USER) @@ -645,18 +658,24 @@ class Core(object): jid = presence['from'] contact = roster.get_contact_by_jid(jid.bare) if not contact: - return - resource = contact.get_resource_by_fulljid(jid.full) + resource = None + else: + resource = contact.get_resource_by_fulljid(jid.full) + self.events.trigger('normal_presence', presence, resource) if not resource: return status = presence['type'] status_message = presence['status'] priority = presence.getPriority() or 0 - resource.set_presence(status) - resource.set_priority(priority) - resource.set_status(status_message) + resource.presence = status + resource.priority = priority + resource.status = status_message + tab = self.get_tab_of_conversation_with_jid(jid, create=False) if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window() + elif self.current_tab() == tab: + tab.refresh() + self.doupdate() def on_roster_update(self, iq): """ @@ -670,19 +689,19 @@ class Core(object): contact = Contact(jid) roster.add_contact(contact, jid) if 'ask' in item.attrib: - contact.set_ask(item.attrib['ask']) + contact.ask = item.attrib['ask'] else: - contact.set_ask(None) + contact.ask = None if 'name' in item.attrib: - contact.set_name(item.attrib['name']) + contact.name = item.attrib['name'] else: - contact.set_name(None) + contact.name = None if item.attrib['subscription']: - contact.set_subscription(item.attrib['subscription']) + contact.subscription = item.attrib['subscription'] groups = item.findall('{jabber:iq:roster}group') roster.edit_groups_of_contact(contact, [group.text for group in groups]) if item.attrib['subscription'] == 'remove': - roster.remove_contact(contact.get_bare_jid()) + roster.remove_contact(contact.bare_jid) if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window() @@ -690,16 +709,30 @@ class Core(object): """ Triggered whenever a presence stanza with a type of subscribe, subscribed, unsubscribe, or unsubscribed is received. """ + jid = presence['from'].bare + contact = roster.get_contact_by_jid(jid) if presence['type'] == 'subscribe': - jid = presence['from'].bare - contact = roster.get_contact_by_jid(jid) if not contact: contact = Contact(jid) roster.add_contact(contact, jid) + log.debug("CONTACT: %s" % contact) + if contact.subscription in ('from', 'both'): + log.debug('FROM OR BOTH') + return + elif contact.subscription in ('to'): + log.debug('TO') + self.xmpp.sendPresence(pto=jid, ptype='subscribed') + self.xmpp.sendPresence(pto=jid, ptype='') + return roster.edit_groups_of_contact(contact, []) - contact.set_ask('asked') + contact.ask = 'asked' self.get_tab_by_number(0).state = 'highlight' self.information('%s wants to subscribe to your presence'%jid, 'Roster') + elif presence['type'] == 'unsubscribed': + self.information('%s unsubscribed you from his presence'%jid, 'Roster') + elif presence['type'] == 'unsubscribe': + self.information('%s unsubscribed from your presence'%jid, 'Roster') + if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window() @@ -1056,7 +1089,7 @@ class Core(object): if tab.get_user_by_name(nick_from) and\ tab.get_user_by_name(nick_from) in tab.ignores: return - self.events.trigger('muc_msg', message) + self.events.trigger('muc_msg', message, tab) body = xhtml.get_body_from_message_stanza(message) if body: date = date if delayed == True else None @@ -1124,6 +1157,7 @@ class Core(object): if msg: pres['status'] = msg pres['type'] = show + self.events.trigger('send_normal_presence', pres) pres.send() current = self.current_tab() if isinstance(current, tabs.MucTab) and current.joined and show in ('away', 'xa'): @@ -1135,6 +1169,44 @@ class Core(object): if isinstance(current, tabs.MucTab) and current.joined and show not in ('away', 'xa'): current.send_chat_state('active') + def command_rawxml(self, arg): + """" + /rawxml <xml stanza> + """ + if not arg: + return + + try: + StanzaBase(self.xmpp, xml=ET.fromstring(arg)).send() + except: + import traceback + self.information(_('Could not send custom stanza'), 'Error') + log.debug(_("Could not send custom stanza:\n") + traceback.format_exc()) + + def command_presence(self, arg): + """ + /presence <JID> [type] [status] + """ + args = common.shell_split(arg) + if len(args) == 1: + jid, type, status = args[0], None, None + elif len(args) == 2: + jid, type, status = args[0], args[1], None + elif len(args) == 3: + jid, type, status = args[0], args[1], args[2] + else: + return + if type == 'available': + type = None + try: + pres = self.xmpp.make_presence(pto=jid, ptype=type, pstatus=status) + self.events.trigger('send_normal_presence', pres) + pres.send() + except : + import traceback + self.information(_('Could not send directed presence'), 'Error') + log.debug(_("Could not send directed presence:\n") + traceback.format_exc()) + def completion_status(self, the_input): return the_input.auto_completion([status for status in possible_show], ' ') @@ -1371,7 +1443,12 @@ class Core(object): else: tab.own_nick = nick tab.users = [] - self.enable_private_tabs(room) + if tab and tab.joined: + self.enable_private_tabs(room) + tab.state = "normal" + if tab == self.current_tab(): + tab.refresh() + self.doupdate() def get_bookmark_nickname(self, room_name): """ @@ -1532,7 +1609,9 @@ class Core(object): Displays an informational message in the "Info" buffer """ nb_lines = self.information_buffer.add_message(msg, nickname=typ) - if typ != '' and typ.lower() in config.get('information_buffer_popup_on', + if isinstance(self.current_tab(), tabs.RosterInfoTab): + self.refresh_window() + elif typ != '' and typ.lower() in config.get('information_buffer_popup_on', 'error roster warning help info').split(): popup_time = config.get('popup_time', 4) + (nb_lines - 1) * 2 self.pop_information_win_up(nb_lines, popup_time) @@ -1585,15 +1664,15 @@ class Core(object): when enter is pressed on the roster window """ if isinstance(roster_row, Contact): - if not self.get_conversation_by_jid(roster_row.get_bare_jid()): - self.open_conversation_window(roster_row.get_bare_jid()) + if not self.get_conversation_by_jid(roster_row.bare_jid): + self.open_conversation_window(roster_row.bare_jid) else: - self.focus_tab_named(roster_row.get_bare_jid()) + self.focus_tab_named(roster_row.bare_jid) if isinstance(roster_row, Resource): - if not self.get_conversation_by_jid(roster_row.get_jid().full): - self.open_conversation_window(roster_row.get_jid().full) + if not self.get_conversation_by_jid(roster_row.jid.full): + self.open_conversation_window(roster_row.jid.full) else: - self.focus_tab_named(roster_row.get_jid().full) + self.focus_tab_named(roster_row.jid.full) self.refresh_window() def remove_timed_event(self, event): |