def command_accept(self, args): """ Accept a JID from in roster. Authorize it AND subscribe to it """ if not args: item = self.roster_win.selected_row if isinstance(item, Contact): jid = item.bare_jid else: self.core.information('No subscription to accept') return else: jid = safeJID(args[0]).bare nodepart = safeJID(jid).user jid = safeJID(jid) # crappy transports putting resources inside the node part if '\\2f' in nodepart: jid.user = nodepart.split('\\2f')[0] contact = roster[jid] if contact is None: return contact.pending_in = False roster.modified() self.core.xmpp.send_presence(pto=jid, ptype='subscribed') self.core.xmpp.client_roster.send_last_presence() if contact.subscription in ('from', 'none') and not contact.pending_out: self.core.xmpp.send_presence(pto=jid, ptype='subscribe', pnick=self.core.own_nick) self.core.information('%s is now authorized' % jid, 'Roster')
def on_conversation_say(self, msg, tab): """ On message sent """ if isinstance(tab, DynamicConversationTab) and tab.locked_resource: jid = safeJID(tab.name) jid.resource = tab.locked_resource name = jid.full else: name = tab.name jid = safeJID(tab.name) ctx = self.contexts.get(name) if isinstance(tab, DynamicConversationTab) and not tab.locked_resource: log.debug('Unlocked tab %s found, falling back to the first encrypted chat we find.', name) ctx = self.find_encrypted_context_with_matching(jid.bare) if ctx and ctx.state == STATE_ENCRYPTED: ctx.sendMessage(0, msg['body'].encode('utf-8')) if not tab.send_chat_state('active'): tab.send_chat_state('inactive', always_send=True) tab.add_message(msg['body'], nickname=self.core.own_nick or tab.own_nick, nick_color=get_theme().COLOR_OWN_NICK, identifier=msg['id'], jid=self.core.xmpp.boundjid, typ=ctx.log) # remove everything from the message so that it doesn’t get sent del msg['body'] del msg['replace'] del msg['html']
def command_invite(self, args): """/invite <to> <room> [reason]""" if args is None: return self.command_help('invite') reason = args[2] to = safeJID(args[0]) room = safeJID(args[1]).bare self.invite(to.full, room, reason=reason)
def command_muc_ping(self, arg): if not arg.strip(): return user = self.api.current_tab().get_user_by_name(arg) if user: jid = safeJID(self.api.current_tab().name) jid.resource = user.nick else: jid = safeJID(arg) self.command_ping(jid.full)
def set_user_affiliation(xmpp, muc_jid, affiliation, nick=None, jid=None, reason=None): """ (try to) Set the affiliation of a MUC user """ jid = safeJID(jid) muc_jid = safeJID(muc_jid) try: return xmpp.plugin['xep_0045'].set_affiliation(muc_jid, jid, nick, affiliation) except: return False
def command_invite(self, args): """/invite <to> <room> [reason]""" if args is None: return self.command_help('invite') reason = args[2] to = safeJID(args[0]) room = safeJID(args[1]).bare self.invite(to.full, room, reason=reason) self.information('Invited %s to %s' % (to.bare, room), 'Info')
def match(self, xml): from_ = safeJID(xml['from']) to_ = safeJID(xml['to']) if self.jid.full == self.jid.bare: from_ = from_.bare to_ = to_.bare if self.dest == 'from': return from_ == self.jid elif self.dest == 'to': return to_ == self.jid return self.jid in (from_, to_)
def command_smp(self, args): """ /otrsmp <ask|answer|abort> [question] [secret] """ if args is None or not args: return self.core.command_help('otrsmp') length = len(args) action = args.pop(0) if length == 2: question = None secret = args.pop(0).encode('utf-8') elif length == 3: question = args.pop(0).encode('utf-8') secret = args.pop(0).encode('utf-8') else: question = secret = None tab = self.api.current_tab() name = tab.name if isinstance(tab, DynamicConversationTab) and tab.locked_resource: name = safeJID(tab.name) name.resource = tab.locked_resource name = name.full format_dict = { 'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID), 'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT), 'jid': name, 'bare_jid': safeJID(name).bare } ctx = self.get_context(name) if ctx.state != STATE_ENCRYPTED: self.api.information('The current conversation is not encrypted', 'Error') return if action == 'ask': ctx.in_smp = True ctx.smp_own = True if question: ctx.smpInit(secret, question) else: ctx.smpInit(secret) tab.add_message(SMP_INITIATED % format_dict, typ=0) elif action == 'answer': ctx.smpGotSecret(secret) elif action == 'abort': if ctx.in_smp: ctx.smpAbort() tab.add_message(SMP_ABORTED % format_dict, typ=0) self.core.refresh_window()
def command_add(self, args): """ Add the specified JID to the roster, and set automatically accept the reverse subscription """ jid = safeJID(safeJID(args[0]).bare) if not jid: self.core.information(_('No JID specified'), 'Error') return if jid in roster and roster[jid].subscription in ('to', 'both'): return self.core.information('Already subscribed.', 'Roster') roster.add(jid) roster.modified() self.core.information('%s was added to the roster' % jid, 'Roster')
def on_conversation_say(self, msg, tab): """ On message sent """ if isinstance(tab, DynamicConversationTab) and tab.locked_resource: jid = safeJID(tab.name) jid.resource = tab.locked_resource name = jid.full else: name = tab.name jid = safeJID(tab.name) format_dict = { 'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID), 'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT), 'jid': name, } ctx = None default_ctx = self.get_context(name) if isinstance(tab, DynamicConversationTab) and not tab.locked_resource: log.debug('Unlocked tab %s found, falling back to the first encrypted chat we find.', name) ctx = self.find_encrypted_context_with_matching(jid.bare) if ctx is None: ctx = default_ctx if ctx and ctx.state == STATE_ENCRYPTED: ctx.sendMessage(0, msg['body'].encode('utf-8')) if not tab.send_chat_state('active'): tab.send_chat_state('inactive', always_send=True) tab.add_message(msg['body'], nickname=self.core.own_nick or tab.own_nick, nick_color=get_theme().COLOR_OWN_NICK, identifier=msg['id'], jid=self.core.xmpp.boundjid, typ=ctx.log) # remove everything from the message so that it doesn’t get sent del msg['body'] del msg['replace'] del msg['html'] elif ctx and ctx.getPolicy('REQUIRE_ENCRYPTION'): tab.add_message(MESSAGE_NOT_SENT % format_dict, typ=0) del msg['body'] del msg['replace'] del msg['html'] self.otr_start(tab, name, format_dict)
def completion_join(self, the_input): """ Completion for /join Try to complete the MUC JID: if only a resource is provided, complete with the default nick if only a server is provided, complete with the rooms from the disco#items of that server if only a nodepart is provided, complete with the servers of the current joined rooms """ n = the_input.get_argument_position(quoted=True) args = common.shell_split(the_input.text) if n != 1: # we are not on the 1st argument of the command line return False if len(args) == 1: args.append('') jid = safeJID(args[1]) if args[1].endswith('@') and not jid.user and not jid.server: jid.user = args[1][:-1] relevant_rooms = [] relevant_rooms.extend(sorted(self.pending_invites.keys())) bookmarks = {str(elem.jid): False for elem in bookmark.bookmarks} for tab in self.get_tabs(tabs.MucTab): name = tab.name if name in bookmarks and not tab.joined: bookmarks[name] = True relevant_rooms.extend(sorted(room[0] for room in bookmarks.items() if room[1])) if the_input.last_completion: return the_input.new_completion([], 1, quotify=True) if jid.user: # we are writing the server: complete the server serv_list = [] for tab in self.get_tabs(tabs.MucTab): if tab.joined: serv_list.append('%s@%s'% (jid.user, safeJID(tab.name).host)) serv_list.extend(relevant_rooms) return the_input.new_completion(serv_list, 1, quotify=True) elif args[1].startswith('/'): # we completing only a resource return the_input.new_completion(['/%s' % self.own_nick], 1, quotify=True) else: return the_input.new_completion(relevant_rooms, 1, quotify=True) return True
def command_server_cycle(self, args): """ Do a /cycle on each room of the given server. If none, do it on the current tab """ tab = self.current_tab() message = "" if args: domain = args[0] if len(args) == 2: message = args[1] else: if isinstance(tab, tabs.MucTab): domain = safeJID(tab.name).domain else: return self.information(_("No server specified"), "Error") for tab in self.get_tabs(tabs.MucTab): if tab.name.endswith(domain): if tab.joined: muc.leave_groupchat(tab.core.xmpp, tab.name, tab.own_nick, message) tab.joined = False if tab.name == domain: self.command_join('"@%s/%s"' %(tab.name, tab.own_nick)) else: self.command_join('"%s/%s"' %(tab.name, tab.own_nick))
def on_save(self): self.bookmarks_win.save() if find_duplicates(self.new_bookmarks): self.core.information(_('Duplicate bookmarks in list (saving aborted)'), 'Error') return for bm in self.new_bookmarks: if safeJID(bm.jid): if not self.bookmarks[bm.jid]: self.bookmarks.append(bm) else: self.core.information(_('Invalid JID for bookmark: %s/%s') % (bm.jid, bm.nick), 'Error') return for bm in self.removed_bookmarks: if bm in self.bookmarks: self.bookmarks.remove(bm) def send_cb(success): if success: self.core.information(_('Bookmarks saved.'), 'Info') else: self.core.information(_('Remote bookmarks not saved.'), 'Error') log.debug('alerte %s', str(stanza_storage(self.bookmarks.bookmarks))) self.bookmarks.save(self.core.xmpp, callback=send_cb) self.core.close_tab() return True
def on_gain_focus(self): self.state = 'current' curses.curs_set(1) tab = self.core.get_tab_by_name(safeJID(self.name).bare, MucTab) if tab and tab.joined and config.get_by_tabname('send_chat_states', self.general_jid,) and not self.input.get_text() and self.on: self.send_chat_state('active')
def completion_server_cycle(self, the_input): """Completion for /server_cycle""" serv_list = set() for tab in self.get_tabs(tabs.MucTab): serv = safeJID(tab.name).server serv_list.add(serv) return the_input.new_completion(sorted(serv_list), 1, " ")
def command_last_activity(self, args): """ /last_activity <jid> """ def callback(iq): "Callback for the last activity" if iq['type'] != 'result': if iq['error']['type'] == 'auth': self.information(_('You are not allowed to see the ' 'activity of this contact.'), _('Error')) else: self.information(_('Error retrieving the activity'), 'Error') return seconds = iq['last_activity']['seconds'] status = iq['last_activity']['status'] from_ = iq['from'] if not safeJID(from_).user: msg = 'The uptime of %s is %s.' % ( from_, common.parse_secs_to_str(seconds)) else: msg = 'The last activity of %s was %s ago%s' % ( from_, common.parse_secs_to_str(seconds), (' and his/her last status was %s' % status) if status else '') self.information(msg, 'Info') if args is None: return self.command_help('last_activity') jid = safeJID(args[0]) self.xmpp.plugin['xep_0012'].get_last_activity(jid, callback=callback)
def _add_bookmark(self, jid, autojoin, password, method): nick = None if not jid: tab = self.current_tab() roomname = tab.name if tab.joined and tab.own_nick != self.own_nick: nick = tab.own_nick if password is None and tab.password is not None: password = tab.password elif jid == '*': return _add_wildcard_bookmarks(self, method) else: info = safeJID(jid) roomname, nick = info.bare, info.resource if roomname == '': if not isinstance(self.current_tab(), tabs.MucTab): return roomname = self.current_tab().name bookmark = self.bookmarks[roomname] if bookmark is None: bookmark = Bookmark(roomname) self.bookmarks.append(bookmark) bookmark.method = method bookmark.autojoin = autojoin if nick: bookmark.nick = nick if password: bookmark.password = password def callback(iq): if iq["type"] != "error": self.information('Bookmark added.', 'Info') else: self.information("Could not add the bookmarks.", "Info") self.bookmarks.save_local() self.bookmarks.save_remote(self.xmpp, callback)
def log_message(self, txt, nickname, time=None, typ=1): """ Log the messages in the archives. """ name = safeJID(self.name).bare if not logger.log_message(name, nickname, txt, date=time, typ=typ): self.core.information(_('Unable to write in the log file'), 'Error')
def completion_bookmark_local(self, the_input): """Completion for /bookmark_local""" n = the_input.get_argument_position(quoted=True) args = common.shell_split(the_input.text) if n >= 2: return if len(args) == 1: args.append("") jid = safeJID(args[1]) if jid.server and (jid.resource or jid.full.endswith("/")): tab = self.get_tab_by_name(jid.bare, tabs.MucTab) nicks = [tab.own_nick] if tab else [] default = os.environ.get("USER") if os.environ.get("USER") else "poezio" nick = config.get("default_nick") if not nick: if not default in nicks: nicks.append(default) else: if not nick in nicks: nicks.append(nick) jids_list = ["%s/%s" % (jid.bare, nick) for nick in nicks] return the_input.new_completion(jids_list, 1, quotify=True) muc_list = [tab.name for tab in self.get_tabs(tabs.MucTab)] muc_list.append("*") return the_input.new_completion(muc_list, 1, quotify=True)
def command_version(self, args): """ /version <jid> """ def callback(res): "Callback for /version" if not res: return self.information(_('Could not get the software' ' version from %s') % jid, _('Warning')) version = _('%s is running %s version %s on %s') % ( jid, res.get('name') or _('an unknown software'), res.get('version') or _('unknown'), res.get('os') or _('an unknown platform')) self.information(version, 'Info') if args is None: return self.command_help('version') jid = safeJID(args[0]) if jid.resource or jid not in roster: fixes.get_version(self.xmpp, jid, callback=callback) elif jid in roster: for resource in roster[jid].resources: fixes.get_version(self.xmpp, resource.jid, callback=callback) else: fixes.get_version(self.xmpp, jid, callback=callback)
def on_got_online(self, presence): """ A JID got online """ if presence.match('presence/muc') or presence.xml.find('{http://jabber.org/protocol/muc#user}x'): return jid = presence['from'] contact = roster[jid.bare] if contact is None: # Todo, handle presence coming from contacts not in roster return roster.modified() if not logger.log_roster_change(jid.bare, 'got online'): self.information(_('Unable to write in the log file'), 'Error') resource = Resource(jid.full, { 'priority': presence.get_priority() or 0, 'status': presence['status'], 'show': presence['show'], }) self.events.trigger('normal_presence', presence, resource) self.add_information_message_to_conversation_tab(jid.full, '\x195}%s is \x194}online' % (jid.full)) if time.time() - self.connection_time > 10: # We do not display messages if we recently logged in if presence['status']: self.information("\x193}%s \x195}is \x194}online\x195} (\x19o%s\x195})" % (safeJID(resource.jid).bare, presence['status']), "Roster") else: self.information("\x193}%s \x195}is \x194}online\x195}" % safeJID(resource.jid).bare, "Roster") self.add_information_message_to_conversation_tab(jid.bare, '\x195}%s is \x194}online' % (jid.bare)) if isinstance(self.current_tab(), tabs.RosterInfoTab): self.refresh_window()
def refresh(self, jid, contact, window, chatstate, informations): # contact can be None, if we receive a message # from someone not in our roster. In this case, we display # only the maximum information from the message we can get. log.debug('Refresh: %s', self.__class__.__name__) jid = safeJID(jid) if contact: if jid.resource: resource = contact[jid.full] else: resource = contact.get_highest_priority_resource() else: resource = None # if contact is None, then resource is None too: # user is not in the roster so we know almost nothing about it # If contact is a Contact, then # resource can now be a Resource: user is in the roster and online # or resource is None: user is in the roster but offline self._win.erase() self.write_contact_jid(jid) self.write_contact_informations(contact) self.write_resource_information(resource) self.print_scroll_position(window) self.write_chatstate(chatstate) self.write_additional_informations(informations, jid) self.finish_line(get_theme().COLOR_INFORMATION_BAR) self._refresh()
def get_current_tab_irc_info(self): """ Return a tuple with the irc server and the gateway hostnames of the current tab. If the current tab is not an IRC channel or private conversation, a warning is displayed and None is returned """ gateway = self.config.get('gateway', 'irc.poez.io') current = self.core.current_tab() current_jid = common.safeJID(current.name) if not current_jid.server == gateway: self.api.information('The current tab does not appear to be an IRC one', 'Warning') return None if isinstance(current, tabs.OneToOneTab): if not '!' in current_jid.node: server = current_jid.node else: ignored, server = current_jid.node.rsplit('!', 1) elif isinstance(current, tabs.MucTab): if not '%' in current_jid.node: server = current_jid.node else: ignored, server = current_jid.node.rsplit('%', 1) else: self.api.information('The current tab does not appear to be an IRC one', 'Warning') return None return server, gateway
def on_groupchat_direct_invitation(self, message): """ Direct invitation received """ room = safeJID(message['groupchat_invite']['jid']) if room.bare in self.pending_invites: return inviter = message['from'] reason = message['groupchat_invite']['reason'] password = message['groupchat_invite']['password'] continue_ = message['groupchat_invite']['continue'] msg = "You are invited to the room %s by %s" % (room, inviter.full) if password: msg += ' (password: "******")' % password if continue_: msg += '\nto continue the discussion' if reason: msg += "\nreason: %s" % reason self.information(msg, 'Info') if 'invite' in config.get('beep_on').split(): curses.beep() self.pending_invites[room.bare] = inviter.full logger.log_roster_change(inviter.full, 'invited you to %s' % room.bare)
def set_user_affiliation(xmpp, muc_jid, affiliation, nick=None, jid=None, reason=None, callback=None): """ (try to) Set the affiliation of a MUC user """ muc_jid = safeJID(muc_jid) query = ET.Element('{http://jabber.org/protocol/muc#admin}query') if nick: item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'affiliation':affiliation, 'nick':nick}) else: item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'affiliation':affiliation, 'jid':str(jid)}) if reason: reason_item = ET.Element('{http://jabber.org/protocol/muc#admin}reason') reason_item.text = reason item.append(reason_item) query.append(item) iq = xmpp.make_iq_set(query) iq['to'] = muc_jid if callback: return iq.send(callback=callback) try: return xmpp.plugin['xep_0045'].setAffiliation(str(muc_jid), str(jid) if jid else None, nick, affiliation) except: import traceback log.debug('Error setting the affiliation: %s', traceback.format_exc()) return False
def join_room(self, name): """ Join a room with only its name and the current tab """ gateway = self.config.get('gateway', 'irc.poez.io') current = self.core.current_tab() current_jid = common.safeJID(current.name) if not current_jid.server == gateway: self.api.information('The current tab does not appear to be an IRC one', 'Warning') return if isinstance(current, tabs.OneToOneTab): if not '!' in current_jid.node: server = current_jid.node else: ignored, server = current_jid.node.rsplit('!', 1) elif isinstance(current, tabs.MucTab): if not '%' in current_jid.node: server = current_jid.node else: ignored, server = current_jid.node.rsplit('%', 1) else: self.api.information('The current tab does not appear to be an IRC one', 'Warning') return room = '{}%{}@{}'.format(name, server, gateway) if self.config.get_by_tabname('nickname', server): room += '/' + self.config.get_by_tabname('nickname', server) self.core.command_join(room)
def destroy_room(xmpp, room, reason='', altroom=''): """ destroy a room """ room = safeJID(room) if not room: return False iq = xmpp.make_iq_set() iq['to'] = room query = ET.Element('{%s}query' % NS_MUC_OWNER) destroy = ET.Element('{%s}destroy' % NS_MUC_OWNER) if altroom: destroy.attrib['jid'] = altroom if reason: xreason = ET.Element('{%s}reason' % NS_MUC_OWNER) xreason.text = reason destroy.append(xreason) query.append(destroy) iq.append(query) def callback(iq): if not iq or iq['type'] == 'error': xmpp.core.information('Unable to destroy room %s' % room, 'Info') else: xmpp.core.information('Room %s destroyed' % room, 'Info') iq.send(callback=callback) return True
def completion_bookmark(self, the_input): """Completion for /bookmark""" args = common.shell_split(the_input.text) n = the_input.get_argument_position(quoted=True) if n == 2: return the_input.new_completion(['true', 'false'], 2, quotify=True) if n >= 3: return if len(args) == 1: args.append('') jid = safeJID(args[1]) if jid.server and (jid.resource or jid.full.endswith('/')): tab = self.get_tab_by_name(jid.bare, tabs.MucTab) nicks = [tab.own_nick] if tab else [] default = os.environ.get('USER') if os.environ.get('USER') else 'poezio' nick = config.get('default_nick') if not nick: if not default in nicks: nicks.append(default) else: if not nick in nicks: nicks.append(nick) jids_list = ['%s/%s' % (jid.bare, nick) for nick in nicks] return the_input.new_completion(jids_list, 1, quotify=True) muc_list = [tab.name for tab in self.get_tabs(tabs.MucTab)] muc_list.sort() muc_list.append('*') return the_input.new_completion(muc_list, 1, quotify=True)
def __init__(self, name, nick): OneToOneTab.__init__(self, name) self.own_nick = nick self.name = name self.text_win = windows.TextWin() self._text_buffer.add_window(self.text_win) self.info_header = windows.PrivateInfoWin() self.input = windows.MessageInput() # keys self.key_func['^I'] = self.completion # commands self.register_command('info', self.command_info, desc=_('Display some information about the user in the MUC: its/his/her role, affiliation, status and status message.'), shortdesc=_('Info about the user.')) self.register_command('unquery', self.command_unquery, shortdesc=_('Close the tab.')) self.register_command('close', self.command_unquery, shortdesc=_('Close the tab.')) self.register_command('version', self.command_version, desc=_('Get the software version of the current interlocutor (usually its XMPP client and Operating System).'), shortdesc=_('Get the software version of a jid.')) self.resize() self.parent_muc = self.core.get_tab_by_name(safeJID(name).bare, MucTab) self.on = True self.update_commands() self.update_keys()
def change_nick(core, jid, nick, status=None, show=None): """ Change our own nick in a room """ xmpp = core.xmpp presence = xmpp.make_presence(pshow=show, pstatus=status, pto=safeJID('%s/%s' % (jid, nick))) core.events.trigger('changing_nick', presence) presence.send()
def command_bookmark(self, args): """ /bookmark [room][/nick] [autojoin] [password] """ if not config.get('use_remote_bookmarks'): return self.command_bookmark_local(" ".join(args)) nick = None if not args and not isinstance(self.current_tab(), tabs.MucTab): return if not args: tab = self.current_tab() roomname = tab.name if tab.joined: nick = tab.own_nick autojoin = True password = None elif args[0] == '*': if len(args) > 1: autojoin = False if args[1].lower() != 'true' else True else: autojoin = True new_bookmarks = [] for tab in self.get_tabs(tabs.MucTab): b = bookmark.get_by_jid(tab.name) if not b: b = bookmark.Bookmark(tab.name, autojoin=autojoin, method=bookmark.preferred) new_bookmarks.append(b) else: b.method = bookmark.preferred bookmark.bookmarks.remove(b) new_bookmarks.append(b) new_bookmarks.extend(bookmark.bookmarks) bookmark.bookmarks = new_bookmarks def _cb(self, iq): if iq["type"] != "error": bookmark.save_local() self.information("Bookmarks added.", "Info") else: self.information("Could not add the bookmarks.", "Info") bookmark.save_remote(self.xmpp, functools.partial(_cb, self)) return else: info = safeJID(args[0]) if info.resource != '': nick = info.resource roomname = info.bare if roomname == '': if not isinstance(self.current_tab(), tabs.MucTab): return roomname = self.current_tab().name if len(args) > 1: autojoin = False if args[1].lower() != 'true' else True else: autojoin = True if len(args) > 2: password = args[2] else: password = None bm = bookmark.get_by_jid(roomname) if not bm: bm = bookmark.Bookmark(roomname) bookmark.bookmarks.append(bm) bm.method = config.get('use_bookmarks_method') if nick: bm.nick = nick if password: bm.password = password bm.autojoin = autojoin def _cb(self, iq): if iq["type"] != "error": self.information('Bookmark added.', 'Info') else: self.information("Could not add the bookmarks.", "Info") bookmark.save_remote(self.xmpp, functools.partial(_cb, self)) remote = [] for each in bookmark.bookmarks: if each.method in ('pep', 'privatexml'): remote.append(each)
def matching_names(self): return [(3, safeJID(self.name).resource), (4, self.name)]
def get_nick(self): return safeJID(self.name).resource
def add_bookmark(self): new_bookmark = Bookmark(safeJID('[email protected]/nick'), method='local') self.new_bookmarks.append(new_bookmark) self.bookmarks_win.add_bookmark(new_bookmark)
def command_join(self, args): """ /join [room][/nick] [password] """ password = None if len(args) == 0: tab = self.current_tab() if not isinstance(tab, (tabs.MucTab, tabs.PrivateTab)): return room = safeJID(tab.name).bare nick = tab.own_nick else: if args[0].startswith('@'): # we try to join a server directly server_root = True info = safeJID(args[0][1:]) else: info = safeJID(args[0]) server_root = False if info == '' and len(args[0]) > 1 and args[0][0] == '/': nick = args[0][1:] elif info.resource == '': nick = self.own_nick else: nick = info.resource if info.bare == '': # happens with /join /nickname, which is OK tab = self.current_tab() if not isinstance(tab, tabs.MucTab): return room = tab.name if nick == '': nick = tab.own_nick else: room = info.bare # no server is provided, like "/join hello": # use the server of the current room if available # check if the current room's name has a server if room.find('@') == -1 and not server_root: if isinstance(self.current_tab(), tabs.MucTab) and\ self.current_tab().name.find('@') != -1: domain = safeJID(self.current_tab().name).domain room += '@%s' % domain else: room = args[0] room = room.lower() if room in self.pending_invites: del self.pending_invites[room] tab = self.get_tab_by_name(room, tabs.MucTab) if tab is not None and tab.joined: # if we are already in the room self.focus_tab_named(tab.name) if tab.own_nick == nick: self.information('/join: Nothing to do.', 'Info') else: tab.own_nick = nick tab.command_cycle('') return if room.startswith('@'): room = room[1:] if len(args) == 2: # a password is provided password = args[1] if password is None: # try to use a saved password password = config.get_by_tabname('password', room, fallback=False) if tab is not None: if password: tab.password = password tab.join() else: tab = self.open_new_room(room, nick, password=password) tab.join() if tab.joined: self.enable_private_tabs(room) tab.state = "normal" if tab == self.current_tab(): tab.refresh() self.doupdate()
def command_otr(self, arg): """ /otr [start|refresh|end|fpr|ourfpr] """ arg = arg.strip() tab = self.api.current_tab() name = tab.name color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID) color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT) color_normal = '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT) if isinstance(tab, DynamicConversationTab) and tab.locked_resource: name = safeJID(tab.name) name.resource = tab.locked_resource name = name.full if arg == 'end': # close the session context = self.get_context(name) context.disconnect() if isinstance(tab, DynamicConversationTab) and not tab.locked_resource: ctx = self.find_encrypted_context_with_matching( safeJID(name).bare) ctx.disconnect() elif arg == 'start' or arg == 'refresh': otr = self.get_context(name) secs = self.config.get('timeout', 3) if isinstance(tab, DynamicConversationTab) and tab.locked_resource: was_locked = True else: was_locked = False def notify_otr_timeout(): nonlocal otr if isinstance(tab, DynamicConversationTab) and not was_locked: if tab.locked_resource: name = safeJID(tab.name) name.resource = tab.locked_resource name = name.full otr = self.get_context(name) if otr.state != STATE_ENCRYPTED: text = _('%(jid_c)s%(jid)s%(info)s did not enable' ' OTR after %(sec)s seconds.') % { 'jid': tab.name, 'info': color_info, 'jid_c': color_jid, 'sec': secs } tab.add_message(text, typ=0) self.core.refresh_window() if secs > 0: event = self.api.create_delayed_event(secs, notify_otr_timeout) self.api.add_timed_event(event) self.core.xmpp.send_message(mto=name, mtype='chat', mbody=self.contexts[name].sendMessage( 0, b'?OTRv?').decode()) text = _( '%(info)sOTR request to %(jid_c)s%(jid)s%(info)s sent.') % { 'jid': tab.name, 'info': color_info, 'jid_c': color_jid } tab.add_message(text, typ=0) elif arg == 'ourfpr': fpr = self.account.getPrivkey() text = _( '%(info)sYour OTR key fingerprint is %(norm)s%(fpr)s.') % { 'jid': tab.name, 'info': color_info, 'norm': color_normal, 'fpr': fpr } tab.add_message(text, typ=0) elif arg == 'fpr': if name in self.contexts: ctx = self.contexts[name] if ctx.getCurrentKey() is not None: text = _('%(info)sThe key fingerprint for %(jid_c)s' '%(jid)s%(info)s is %(norm)s%(fpr)s%(info)s.') % { 'jid': tab.name, 'info': color_info, 'norm': color_normal, 'jid_c': color_jid, 'fpr': ctx.getCurrentKey() } tab.add_message(text, typ=0) else: text = _('%(jid_c)s%(jid)s%(info)s has no' ' key currently in use.') % { 'jid': tab.name, 'info': color_info, 'jid_c': color_jid } tab.add_message(text, typ=0) elif arg == 'drop': # drop the privkey (and obviously, end the current conversations before that) for context in self.contexts.values(): if context.state not in (STATE_FINISHED, STATE_PLAINTEXT): context.disconnect() self.account.drop_privkey() tab.add_message('%sPrivate key dropped.' % color_info, typ=0) elif arg == 'trust': ctx = self.get_context(name) key = ctx.getCurrentKey() if key: fpr = key.cfingerprint() else: return if not ctx.getCurrentTrust(): ctx.setTrust(fpr, 'verified') self.account.saveTrusts() text = _('%(info)sYou added %(jid_c)s%(jid)s%(info)s with key ' '\x19o%(key)s%(info)s to your trusted list.') % { 'jid': ctx.trustName, 'key': key, 'info': color_info, 'jid_c': color_jid } tab.add_message(text, typ=0) elif arg == 'untrust': ctx = self.get_context(name) key = ctx.getCurrentKey() if key: fpr = key.cfingerprint() else: return if ctx.getCurrentTrust(): ctx.setTrust(fpr, '') self.account.saveTrusts() text = _( '%(info)sYou removed %(jid_c)s%(jid)s%(info)s with ' 'key \x19o%(key)s%(info)s from your trusted list.') % { 'jid': ctx.trustName, 'key': key, 'info': color_info, 'jid_c': color_jid } tab.add_message(text, typ=0) self.core.refresh_window()
def send_groupchat_message(xmpp, jid, line): """ Send a message to the groupchat """ jid = safeJID(jid) xmpp.send_message(mto=jid, mbody=line, mtype='groupchat')
def test_safeJID(): assert safeJID('toto@titi/tata') == JID('toto@titi/tata') assert safeJID('é_è') == JID('')
def __init__(self): resource = config.get('resource') keyfile = config.get('keyfile') certfile = config.get('certfile') if config.get('jid'): # Field used to know if we are anonymous or not. # many features will be handled differently # depending on this setting self.anon = False jid = '%s' % config.get('jid') if resource: jid = '%s/%s' % (jid, resource) password = config.get('password') if not password and not (keyfile and certfile): password = getpass.getpass() else: # anonymous auth self.anon = True jid = config.get('server') if resource: jid = '%s/%s' % (jid, resource) password = None jid = safeJID(jid) # TODO: use the system language slixmpp.ClientXMPP.__init__(self, jid, password, lang=config.get('lang')) force_encryption = config.get('force_encryption') if force_encryption: self['feature_mechanisms'].unencrypted_plain = False self['feature_mechanisms'].unencrypted_digest = False self['feature_mechanisms'].unencrypted_cram = False self['feature_mechanisms'].unencrypted_scram = False self.keyfile = config.get('keyfile') self.certfile = config.get('certfile') if keyfile and not certfile: log.error( 'keyfile is present in configuration file without certfile') elif certfile and not keyfile: log.error( 'certfile is present in configuration file without keyfile') self.core = None self.auto_reconnect = config.get('auto_reconnect') self.reconnect_max_attempts = 0 self.auto_authorize = None # prosody defaults, lowest is AES128-SHA, it should be a minimum # for anything that came out after 2002 self.ciphers = config.get( 'ciphers', 'HIGH+kEDH:HIGH+kEECDH:HIGH:!PSK' ':!SRP:!3DES:!aNULL') self.ca_certs = config.get('ca_cert_path') or None interval = config.get('whitespace_interval') if int(interval) > 0: self.whitespace_keepalive_interval = int(interval) else: self.whitespace_keepalive = False self.register_plugin('xep_0004') self.register_plugin('xep_0012') self.register_plugin('xep_0030') self.register_plugin('xep_0045') self.register_plugin('xep_0048') self.register_plugin('xep_0050') self.register_plugin('xep_0060') self.register_plugin('xep_0066') self.register_plugin('xep_0071') self.register_plugin('xep_0077') self.plugin['xep_0077'].create_account = False self.register_plugin('xep_0085') self.register_plugin('xep_0115') # monkey-patch xep_0184 to avoid requesting receipts for messages # without a body XEP_0184._filter_add_receipt_request = fixes._filter_add_receipt_request self.register_plugin('xep_0184') self.plugin['xep_0184'].auto_ack = config.get('ack_message_receipts') self.plugin['xep_0184'].auto_request = config.get( 'request_message_receipts') self.register_plugin('xep_0191') self.register_plugin('xep_0199') if config.get('enable_user_tune'): self.register_plugin('xep_0118') if config.get('enable_user_nick'): self.register_plugin('xep_0172') if config.get('enable_user_mood'): self.register_plugin('xep_0107') if config.get('enable_user_activity'): self.register_plugin('xep_0108') if config.get('enable_user_gaming'): self.register_plugin('xep_0196') if config.get('send_poezio_info'): info = {'name': 'poezio', 'version': options.version} if config.get('send_os_info'): info['os'] = common.get_os_info() self.plugin['xep_0030'].set_identities( identities=set([('client', 'pc', None, 'Poezio')])) else: info = {'name': '', 'version': ''} self.plugin['xep_0030'].set_identities(identities=set([('client', 'pc', None, '')])) self.register_plugin('xep_0092', pconfig=info) if config.get('send_time'): self.register_plugin('xep_0202') self.register_plugin('xep_0224') self.register_plugin('xep_0249') self.register_plugin('xep_0257') self.register_plugin('xep_0280') self.register_plugin('xep_0297') self.register_plugin('xep_0308') self.init_plugins()
def __init__(self, jid): assert(safeJID(jid).resource) self.info_header = windows.ConversationInfoWin() ConversationTab.__init__(self, jid)
def load_logs(self, log_nb): logs = logger.get_logs( safeJID(self.name).full.replace('/', '\\'), log_nb) return logs
def load_logs(self, log_nb): logs = logger.get_logs(safeJID(self.name).bare, log_nb) return logs
def find_encrypted_context_with_matching(self, bare_jid): for ctx in self.contexts: if safeJID(ctx).bare == bare_jid and self.contexts[ ctx].state == STATE_ENCRYPTED: return self.contexts[ctx] return None
def command_join(self, args, histo_length=None): """ /join [room][/nick] [password] """ password = None if len(args) == 0: tab = self.current_tab() if not isinstance(tab, (tabs.MucTab, tabs.PrivateTab)): return room = safeJID(tab.name).bare nick = tab.own_nick else: if args[0].startswith('@'): # we try to join a server directly server_root = True info = safeJID(args[0][1:]) else: info = safeJID(args[0]) server_root = False if info == '' and len(args[0]) > 1 and args[0][0] == '/': nick = args[0][1:] elif info.resource == '': nick = self.own_nick else: nick = info.resource if info.bare == '': # happens with /join /nickname, which is OK tab = self.current_tab() if not isinstance(tab, tabs.MucTab): return room = tab.name if nick == '': nick = tab.own_nick else: room = info.bare # no server is provided, like "/join hello": # use the server of the current room if available # check if the current room's name has a server if room.find('@') == -1 and not server_root: if isinstance(self.current_tab(), tabs.MucTab) and\ self.current_tab().name.find('@') != -1: domain = safeJID(self.current_tab().name).domain room += '@%s' % domain else: room = args[0] room = room.lower() if room in self.pending_invites: del self.pending_invites[room] tab = self.get_tab_by_name(room, tabs.MucTab) if len(args) == 2: # a password is provided password = args[1] if tab and tab.joined: # if we are already in the room self.focus_tab_named(tab.name) if tab.own_nick == nick: self.information('/join: Nothing to do.', 'Info') else: tab.own_nick = nick tab.command_cycle('') return if room.startswith('@'): room = room[1:] current_status = self.get_status() if not histo_length: histo_length = config.get('muc_history_length') if histo_length == -1: histo_length = None if histo_length is not None: histo_length = str(histo_length) if password is None: # try to use a saved password password = config.get_by_tabname('password', room, fallback=False) if tab and not tab.joined: if tab.last_connection: if tab.last_connection is not None: delta = datetime.now() - tab.last_connection seconds = delta.seconds + delta.days * 24 * 3600 else: seconds = 0 seconds = int(seconds) else: seconds = 0 muc.join_groupchat(self, room, nick, password, histo_length, current_status.message, current_status.show, seconds=seconds) if not tab: self.open_new_room(room, nick) muc.join_groupchat(self, room, nick, password, histo_length, current_status.message, current_status.show) else: tab.own_nick = nick tab.users = [] if tab and tab.joined: self.enable_private_tabs(room) tab.state = "normal" if tab == self.current_tab(): tab.refresh() self.doupdate()
def command_otr(self, arg): """ /otr [start|refresh|end|fpr|ourfpr] """ args = common.shell_split(arg) if not args: return self.core.command_help('otr') action = args.pop(0) tab = self.api.current_tab() name = tab.name if isinstance(tab, DynamicConversationTab) and tab.locked_resource: name = safeJID(tab.name) name.resource = tab.locked_resource name = name.full format_dict = { 'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID), 'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT), 'normal': '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT), 'jid': name, 'bare_jid': safeJID(name).bare } if action == 'end': # close the session context = self.get_context(name) context.disconnect() if isinstance(tab, DynamicConversationTab): ctx = self.find_encrypted_context_with_matching(safeJID(name).bare) while ctx is not None: ctx.disconnect() ctx = self.find_encrypted_context_with_matching(safeJID(name).bare) elif action == 'start' or action == 'refresh': self.otr_start(tab, name, format_dict) elif action == 'ourfpr': format_dict['fpr'] = self.account.getPrivkey() tab.add_message(OTR_OWN_FPR % format_dict, typ=0) elif action == 'fpr': if name in self.contexts: ctx = self.contexts[name] if ctx.getCurrentKey() is not None: format_dict['fpr'] = ctx.getCurrentKey() tab.add_message(OTR_REMOTE_FPR % format_dict, typ=0) else: tab.add_message(OTR_NO_FPR % format_dict, typ=0) elif action == 'drop': # drop the privkey (and obviously, end the current conversations before that) for context in self.contexts.values(): if context.state not in (STATE_FINISHED, STATE_PLAINTEXT): context.disconnect() self.account.drop_privkey() tab.add_message(KEY_DROPPED % format_dict, typ=0) elif action == 'trust': ctx = self.get_context(name) key = ctx.getCurrentKey() if key: fpr = key.cfingerprint() else: return if not ctx.getCurrentTrust(): format_dict['key'] = key ctx.setTrust(fpr, 'verified') self.account.saveTrusts() tab.add_message(TRUST_ADDED % format_dict, typ=0) elif action == 'untrust': ctx = self.get_context(name) key = ctx.getCurrentKey() if key: fpr = key.cfingerprint() else: return if ctx.getCurrentTrust(): format_dict['key'] = key ctx.setTrust(fpr, '') self.account.saveTrusts() tab.add_message(TRUST_REMOVED % format_dict, typ=0) self.core.refresh_window()
def write_room_name(self, name): jid = safeJID(name) room_name, nick = jid.bare, jid.resource self.addstr(nick, to_curses_attr(get_theme().COLOR_PRIVATE_NAME)) txt = ' from room %s' % room_name self.addstr(txt, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def __contains__(self, value): return value in self.__item.resources or safeJID( value).resource in self.__item.resources
def __contains__(self, key): """True if the bare jid is in the roster, false otherwise""" return safeJID(key).bare in self.jids()
def __init__(self, account, peer, xmpp, core): super(PoezioContext, self).__init__(account, peer) self.xmpp = xmpp self.core = core self.flags = {} self.trustName = safeJID(peer).bare
def send_private_message(xmpp, jid, line): """ Send a private message """ jid = safeJID(jid) xmpp.send_message(mto=jid, mbody=line, mtype='chat')
def general_jid(self): return safeJID(self.name).bare
def setState(self, newstate): color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID) color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT) tab = self.core.get_tab_by_name(self.peer) if not tab: tab = self.core.get_tab_by_name( safeJID(self.peer).bare, DynamicConversationTab) if tab and not tab.locked_resource == safeJID(self.peer).resource: tab = None if self.state == STATE_ENCRYPTED: if newstate == STATE_ENCRYPTED: log.debug('OTR conversation with %s refreshed', self.peer) if tab: if self.getCurrentTrust(): msg = _('%(info)sRefreshed \x19btrusted\x19o%(info)s' ' OTR conversation with %(jid_c)s%(jid)s') % { 'info': color_info, 'jid_c': color_jid, 'jid': self.peer } tab.add_message(msg, typ=self.log) else: msg = _('%(info)sRefreshed \x19buntrusted\x19o%(info)s' ' OTR conversation with %(jid_c)s%(jid)s' '%(info)s, key: \x19o%(key)s') % { 'jid': self.peer, 'key': self.getCurrentKey(), 'info': color_info, 'jid_c': color_jid } tab.add_message(msg, typ=self.log) hl(tab) elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT: log.debug('OTR conversation with %s finished', self.peer) if tab: tab.add_message('%sEnded OTR conversation with %s%s' % (color_info, color_jid, self.peer), typ=self.log) hl(tab) else: if newstate == STATE_ENCRYPTED: if tab: if self.getCurrentTrust(): msg = _('%(info)sStarted a \x19btrusted\x19o%(info)s ' 'OTR conversation with %(jid_c)s%(jid)s') % { 'jid': self.peer, 'info': color_info, 'jid_c': color_jid } tab.add_message(msg, typ=self.log) else: msg = _( '%(info)sStarted an \x19buntrusted\x19o%(info)s' ' OTR conversation with %(jid_c)s%(jid)s' '%(info)s, key: \x19o%(key)s') % { 'jid': self.peer, 'key': self.getCurrentKey(), 'info': color_info, 'jid_c': color_jid } tab.add_message(msg, typ=self.log) hl(tab) log.debug('Set encryption state of %s to %s', self.peer, states[newstate]) super(PoezioContext, self).setState(newstate) if tab: self.core.refresh_window() self.core.doupdate()
def save(self): jid = safeJID(self.get_text()) self._field.jid = jid.bare self._field.name = jid.bare self._field.nick = jid.resource
def __getitem__(self, key): """Return the corresponding Resource object, or None""" res = safeJID(key).resource resources = self.__item.resources item = resources.get(res, None) or resources.get(key, None) return Resource(key, item) if item else None