def assert_contact_is_in_roster(self, jid, account): contacts = gajim.contacts.get_contacts(account, jid) # check for all resources for contact in contacts: iters = self.roster._get_contact_iter(jid, account, model=self.roster.model) if jid != gajim.get_jid_from_account(account): # We don't care for groups of SelfContact self.assertTrue(len(iters) == len(contact.get_shown_groups()), msg='Contact is not in all his groups') # Are we big brother? bb_jid = None bb_account = None family = gajim.contacts.get_metacontacts_family(account, jid) if family: nearby_family, bb_jid, bb_account = \ self.roster._get_nearby_family_and_big_brother(family, account) is_in_nearby_family = (jid, account) in ( (data['jid'], data['account']) for data in nearby_family) self.assertTrue(is_in_nearby_family, msg='Contact not in his own nearby family') is_big_brother = (bb_jid, bb_account) == (jid, account) # check for each group tag for titerC in iters: self.assertTrue(self.roster.model.iter_is_valid(titerC), msg='Contact iter invalid') c_model = self.roster.model[titerC] # name can be stricked if contact or group is blocked # self.assertEquals(contact.get_shown_name(), c_model[self.C_NAME], # msg='Contact name missmatch') self.assertEquals(contact.jid, c_model[self.C_JID], msg='Jid missmatch') if not self.roster.regroup: self.assertEquals(account, c_model[self.C_ACCOUNT], msg='Account missmatch') # Check for correct nesting parent_iter = self.roster.model.iter_parent(titerC) p_model = self.roster.model[parent_iter] if family: if is_big_brother: self.assertTrue(p_model[self.C_TYPE] == 'group', msg='Big Brother is not on top') else: self.assertTrue(p_model[self.C_TYPE] == 'contact', msg='Little Brother brother has no BigB') else: if jid == gajim.get_jid_from_account(account): self.assertTrue(p_model[self.C_TYPE] == 'account', msg='SelfContact is not on top') else: self.assertTrue(p_model[self.C_TYPE] == 'group', msg='Contact not found in a group')
def delete_pep(jid, name): (user, resource) = gajim.get_room_and_nick_from_fjid(jid) if jid == gajim.get_jid_from_account(name): acc = gajim.connections[name] del acc.activity acc.activity = {} del acc.tune acc.tune = {} del acc.mood acc.mood = {} for contact in gajim.contacts.get_contacts(name, user): del contact.activity contact.activity = {} del contact.tune contact.tune = {} del contact.mood contact.mood = {} if jid == gajim.get_jid_from_account(name): gajim.interface.roster.draw_account(name) gajim.interface.roster.draw_activity(user, name) gajim.interface.roster.draw_tune(user, name) gajim.interface.roster.draw_mood(user, name) ctrl = gajim.interface.msg_win_mgr.get_control(user, name) if ctrl: ctrl.update_activity() ctrl.update_tune() ctrl.update_mood()
def user_mood(items, name, jid): has_child = False retract = False mood = None text = None for item in items.getTags('item'): child = item.getTag('mood') if child is not None: has_child = True for ch in child.getChildren(): if ch.getName() != 'text': mood = ch.getName() else: text = ch.getData() if items.getTag('retract') is not None: retract = True if jid == gajim.get_jid_from_account(name): acc = gajim.connections[name] if has_child: if 'mood' in acc.mood: del acc.mood['mood'] if 'text' in acc.mood: del acc.mood['text'] if mood is not None: acc.mood['mood'] = mood if text is not None: acc.mood['text'] = text elif retract: if 'mood' in acc.mood: del acc.mood['mood'] if 'text' in acc.mood: del acc.mood['text'] (user, resource) = gajim.get_room_and_nick_from_fjid(jid) for contact in gajim.contacts.get_contacts(name, user): if has_child: if 'mood' in contact.mood: del contact.mood['mood'] if 'text' in contact.mood: del contact.mood['text'] if mood is not None: contact.mood['mood'] = mood if text is not None: contact.mood['text'] = text elif retract: if 'mood' in contact.mood: del contact.mood['mood'] if 'text' in contact.mood: del contact.mood['text'] if jid == gajim.get_jid_from_account(name): gajim.interface.roster.draw_account(name) gajim.interface.roster.draw_mood(user, name) ctrl = gajim.interface.msg_win_mgr.get_control(user, name) if ctrl: ctrl.update_mood()
def handle_devicelist_result(self, account, stanza): """ If query was successful add own device to the list. Parameters ---------- account : str the account name stanza The stanza object received from callback """ my_jid = gajim.get_jid_from_account(account) state = self.get_omemo_state(account) if successful(stanza): log.info(account + ' => Devicelistquery was successful') devices_list = unpack_device_list_update(stanza, account) if len(devices_list) == 0: return False contact_jid = stanza.getAttr('from') if contact_jid == my_jid: state.set_own_devices(devices_list) state.store.sessionStore.setActiveState(devices_list, my_jid) if not state.own_device_id_published() or anydup( state.own_devices): # Our own device_id is not in the list, it could be # overwritten by some other client? # Is a Device ID duplicated? self.publish_own_devices_list(account, state) else: log.error(account + ' => Devicelistquery was NOT successful') self.publish_own_devices_list(account, state)
def handle_outgoing_stanza(self, event): if not event.msg_iq.getTag('body'): return plaintext = event.msg_iq.getBody().encode('utf8') account = event.conn.name state = self.get_omemo_state(account) full_jid = str(event.msg_iq.getAttr('to')) to_jid = gajim.get_jid_without_resource(full_jid) if not state.encryption.is_active(to_jid): return False if not state.store.identityKeyStore.getTrustedFingerprints(to_jid): msg = "To send an encrypted message, you have to " \ "first trust the fingerprint of your contact!" if account in self.ui_list and \ to_jid in self.ui_list[account]: self.ui_list[account][to_jid].chat_control. \ print_conversation_line(msg, 'status', '', None) return True try: msg_dict = state.create_msg( gajim.get_jid_from_account(account), to_jid, plaintext) if not msg_dict: return True encrypted_node = OmemoMessage(msg_dict) event.msg_iq.delChild('body') event.msg_iq.addChild(node=encrypted_node) store = Node('store', attrs={'xmlns': NS_HINTS}) event.msg_iq.addChild(node=store) log.debug(account + ' => ' + str(event.msg_iq)) except: return True
def __init__(self, plugin, accountname): global PROTOCOL, MMS self.plugin = plugin self.accountname = accountname name = gajim.get_jid_from_account(accountname) super(GajimOtrAccount, self).__init__(name, PROTOCOL, MMS) self.keyFilePath = os.path.join(gajim.gajimpaths.data_root, accountname)
def get_omemo_state(self, account): """ Returns the the OmemoState for the specified account. Creates the OmemoState if it does not exist yet. Parameters ---------- account : str the account name Returns ------- OmemoState """ if account in self.disabled_accounts: return if account not in self.omemo_states: self.deactivate_gajim_e2e(account) my_jid = gajim.get_jid_from_account(account) db_path = self.migrate_dbpath(account, my_jid) conn = sqlite3.connect(db_path, check_same_thread=False) self.omemo_states[account] = OmemoState(my_jid, conn, account, self.plugin) return self.omemo_states[account]
def omemo_send_gc_message(message, xhtml=None, process_commands=True): self.new_fingerprints_available() if self.encryption_active(): missing = True own_jid = gajim.get_jid_from_account(self.account) for nick in self.plugin.groupchat[self.room]: real_jid = self.plugin.groupchat[self.room][nick] if real_jid == own_jid: continue if not self.plugin.are_keys_missing(self.account, real_jid): missing = False if missing: log.debug(self.account + ' => No Trusted Fingerprints for ' + self.room) self.no_trusted_fingerprints_warning() else: self.chat_control.orig_send_message(message, xhtml, process_commands) log.debug(self.account + ' => Sending Message to ' + self.room) else: self.chat_control.orig_send_message(message, xhtml, process_commands) log.debug(self.account + ' => Sending Message to ' + self.room)
def replace_roster(self, account_name, roster_version, roster): """ Replace current roster in DB by a new one accout_name is the name of the account to change. roster_version is the version of the new roster. roster is the new version. """ # First we must reset roster_version value to ensure that the server # sends back all the roster at the next connexion if the replacement # didn't work properly. gajim.config.set_per('accounts', account_name, 'roster_version', '') account_jid = gajim.get_jid_from_account(account_name) account_jid_id = self.get_jid_id(account_jid) # Delete old roster self.remove_roster(account_jid) # Fill roster tables with the new roster for jid in roster: self.add_or_update_contact(account_jid, jid, roster[jid]['name'], roster[jid]['subscription'], roster[jid]['ask'], roster[jid]['groups'], commit=False) self._timeout_commit() # At this point, we are sure the replacement works properly so we can # set the new roster_version value. gajim.config.set_per('accounts', account_name, 'roster_version', roster_version)
def connect_ui(self, chat_control): """ Method called from Gajim when a Chat Window is opened Parameters ---------- chat_control : ChatControl Gajim ChatControl object """ account = chat_control.contact.account.name if account in self.disabled_accounts: return contact_jid = chat_control.contact.jid if account not in self.ui_list: self.ui_list[account] = {} state = self.get_omemo_state(account) my_jid = gajim.get_jid_from_account(account) omemo_enabled = state.encryption.is_active(contact_jid) if omemo_enabled: log.debug(account + " => Adding OMEMO ui for " + contact_jid) self.ui_list[account][contact_jid] = Ui(self, chat_control, omemo_enabled, state) self.ui_list[account][contact_jid].new_fingerprints_available() return if contact_jid in state.device_ids or contact_jid == my_jid: log.debug(account + " => Adding OMEMO ui for " + contact_jid) self.ui_list[account][contact_jid] = Ui(self, chat_control, omemo_enabled, state) self.ui_list[account][contact_jid].new_fingerprints_available() else: log.warning(account + " => No devices for " + contact_jid) if chat_control.type_id == message_control.TYPE_GC: self.ui_list[account][contact_jid] = Ui(self, chat_control, omemo_enabled, state) self.ui_list[account][contact_jid].sensitive(False)
def __init__(self, account, transient_for=None): self.xml = gtkgui_helpers.get_gtk_builder('profile_window.ui') self.window = self.xml.get_object('profile_window') self.window.set_transient_for(transient_for) self.progressbar = self.xml.get_object('progressbar') self.statusbar = self.xml.get_object('statusbar') self.context_id = self.statusbar.get_context_id('profile') self.account = account self.jid = gajim.get_jid_from_account(account) self.dialog = None self.avatar_mime_type = None self.avatar_encoded = None self.message_id = self.statusbar.push(self.context_id, _('Retrieving profile...')) self.update_progressbar_timeout_id = GLib.timeout_add(100, self.update_progressbar) self.remove_statusbar_timeout_id = None # Create Image for avatar button image = Gtk.Image() self.xml.get_object('PHOTO_button').set_image(image) self.xml.connect_signals(self) gajim.ged.register_event_handler('vcard-published', ged.GUI1, self._nec_vcard_published) gajim.ged.register_event_handler('vcard-not-published', ged.GUI1, self._nec_vcard_not_published) gajim.ged.register_event_handler('vcard-received', ged.GUI1, self._nec_vcard_received) self.window.show_all() self.xml.get_object('ok_button').grab_focus()
def handle_device_list_update(self, event): """ Check if the passed event is a device list update and store the new device ids. Parameters ---------- event : MessageReceivedEvent Returns ------- bool True if the given event was a valid device list update event See also -------- 4.2 Discovering peer support http://conversations.im/xeps/multi-end.html#usecases-discovering """ if event.pep_type != 'headline': return False devices_list = unpack_device_list_update(event.stanza, event.conn.name) if len(devices_list) == 0: return False account_name = event.conn.name contact_jid = gajim.get_jid_without_resource(event.fjid) state = self.get_omemo_state(account_name) my_jid = gajim.get_jid_from_account(account_name) if contact_jid == my_jid: log.info(account_name + ' => Received own device list:' + str( devices_list)) state.set_own_devices(devices_list) state.store.sessionStore.setActiveState(devices_list, my_jid) if not state.own_device_id_published() or anydup( state.own_devices): # Our own device_id is not in the list, it could be # overwritten by some other client? # Is a Device ID duplicated? self.publish_own_devices_list(account_name, state) else: log.info(account_name + ' => Received device list for ' + contact_jid + ':' + str(devices_list)) state.set_devices(contact_jid, set(devices_list)) state.store.sessionStore.setActiveState(devices_list, contact_jid) if (account_name in self.ui_list and contact_jid not in self.ui_list[account_name]): chat_control = gajim.interface.msg_win_mgr.get_control( contact_jid, account_name) if chat_control is not None: self.connect_ui(chat_control) # Look if Device Keys are missing and fetch them self.are_keys_missing(account_name, contact_jid) return True
def forget_button_clicked_cb(self, button, *args): accounts = {} for acc in gajim.connections.iterkeys(): accounts[gajim.get_jid_from_account(acc)] = acc tw = self.B.get_object('fingerprint_view') mod, paths = tw.get_selection().get_selected_rows() for path in paths: it = mod.get_iter(path) user, human_fpr, a, fpr = mod.get(it, 0, 3, 4, 6) dlg = gtk.Dialog('Confirm removal of fingerprint', self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_YES, gtk.RESPONSE_YES, gtk.STOCK_NO, gtk.RESPONSE_NO) ) l = gtk.Label() l.set_markup('Are you sure you want remove the following ' 'fingerprint for the contact %s on the account %s?' '\n\n%s' % (user, a, human_fpr)) l.set_line_wrap(True) dlg.vbox.pack_start(l) dlg.show_all() if dlg.run() == gtk.RESPONSE_YES: ctx = self.plugin.us[accounts[a]].getContext(user) ctx.removeFingerprint(fpr) dlg.destroy() self.plugin.us[accounts[a]].saveTrusts() self.plugin.update_context_list()
def query_own_devicelist(self, account): my_jid = gajim.get_jid_from_account(account) iq = DevicelistQuery(my_jid) gajim.connections[account].connection.send(iq) log.info(account + ' => Querry own devicelist ...') id_ = str(iq.getAttr("id")) iq_ids_to_callbacks[id_] = lambda stanza: \ self.handle_devicelist_result(account, stanza)
def __init__(self, account, plugin): self.account = account self.plugin = plugin self.conn = gajim.connections[self.account] # get our jid with resource ourjid = gajim.get_jid_from_account(self.account) Protocol.__init__(self, ourjid) self.fsw = None
def are_keys_missing(self, contact): """ Used by the ui to set the state of the PreKeyButton. """ account = contact.account.name my_jid = gajim.get_jid_from_account(account) state = self.get_omemo_state(account) result = 0 result += len(state.devices_without_sessions(str(contact.jid))) result += len(state.own_devices_without_sessions(my_jid)) return result
def fill_treeview(self): # Account-JID, RoomName, Room-JID, Autojoin, Minimize, Passowrd, Nick, # Show_Status self.treestore = gtk.TreeStore(str, str, str, bool, bool, str, str, str) self.treestore.set_sort_column_id(1, gtk.SORT_ASCENDING) self.accounts = [] self.jids = [] # Store bookmarks in treeview. for account in gajim.connections: if gajim.connections[account].connected <= 1: continue if gajim.connections[account].is_zeroconf: continue self.accounts.append(account) self.jids.append(gajim.get_jid_from_account(account)) iter_ = self.treestore.append(None, [None, account, None, None, None, None, None, None]) for bookmark in gajim.connections[account].bookmarks: if bookmark['name'] == '': # No name was given for this bookmark. # Use the first part of JID instead... name = bookmark['jid'].split("@")[0] bookmark['name'] = name from common import helpers # make '1', '0', 'true', 'false' (or other) to True/False autojoin = helpers.from_xs_boolean_to_python_boolean( bookmark['autojoin']) minimize = helpers.from_xs_boolean_to_python_boolean( bookmark['minimize']) print_status = bookmark.get('print_status', '') if print_status not in ('', 'all', 'in_and_out', 'none'): print_status = '' self.treestore.append(iter_, [ account, bookmark['name'], bookmark['jid'], autojoin, minimize, bookmark['password'], bookmark['nick'], print_status ]) self.view = self.xml.get_object('bookmarks_treeview') self.view.set_model(self.treestore) self.view.expand_all() renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('Bookmarks', renderer, text=1) if self.view.get_column(0): self.view.remove_column(self.view.get_column(0)) self.view.append_column(column)
def query_prekey(self, contact): account = contact.account.name state = self.get_omemo_state(account) to_jid = contact.jid my_jid = gajim.get_jid_from_account(account) for device_id in state.devices_without_sessions(to_jid): self.fetch_device_bundle_information(state, to_jid, device_id) for device_id in state.own_devices_without_sessions(my_jid): self.fetch_device_bundle_information(state, my_jid, device_id)
def handle_device_list_update(self, event): """ Check if the passed event is a device list update and store the new device ids. Parameters ---------- event : MessageReceivedEvent Returns ------- bool True if the given event was a valid device list update event See also -------- 4.2 Discovering peer support http://conversations.im/xeps/multi-end.html#usecases-discovering """ if event.pep_type != 'headline': return False devices_list = unpack_device_list_update(event) if len(devices_list) == 0: return False account = event.conn.name contact_jid = gajim.get_jid_without_resource(event.fjid) state = self.get_omemo_state(account) my_jid = gajim.get_jid_from_account(account) log.debug(account + ' ⇒ Received OMEMO pep for jid ' + contact_jid) if contact_jid == my_jid: log.debug(state.name + ' ⇒ Received own device_list ' + str( devices_list)) state.add_own_devices(devices_list) if not state.own_device_id_published() or anydup( state.own_devices): # Our own device_id is not in the list, it could be # overwritten by some other client? # also remove duplicates devices_list = list(set(state.own_devices)) devices_list.append(state.own_device_id) self.publish_own_devices_list(state) else: state.add_devices(contact_jid, devices_list) if account in self.ui_list and contact_jid in self.ui_list[ account]: self.ui_list[account][contact_jid].toggle_omemo(True) self.update_prekeys(account, contact_jid) return True
def send_pb_unsubscribe(self, jid, node, cb, *args, **kwargs): if not self.connection or self.connected < 2: return our_jid = gajim.get_jid_from_account(self.name) query = nbxmpp.Iq('set', to=jid) pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB) pb.addChild('unsubscribe', {'node': node, 'jid': our_jid}) id_ = self.connection.send(query) self.__callbacks[id_] = (cb, args, kwargs)
def get_omemo_state(self, account): """ Returns the the OmemoState for specified account. Creates the OmemoState if it does not exist yet. """ if account not in self.omemo_states: self.deactivate_gajim_e2e(account) db_path = os.path.join(DB_DIR, 'omemo_' + account + '.db') conn = sqlite3.connect(db_path, check_same_thread=False) my_jid = gajim.get_jid_from_account(account) self.omemo_states[account] = OmemoState(my_jid, conn, account) return self.omemo_states[account]
def are_keys_missing(self, account, contact_jid): """ Checks if devicekeys are missing and querys the bundles Parameters ---------- account : str the account name contact_jid : str bare jid of the contact Returns ------- bool Returns True if there are no trusted Fingerprints """ state = self.get_omemo_state(account) my_jid = gajim.get_jid_from_account(account) # Fetch Bundles of own other Devices if my_jid not in self.query_for_bundles: devices_without_session = state \ .devices_without_sessions(my_jid) self.query_for_bundles.append(my_jid) if devices_without_session: for device_id in devices_without_session: self.fetch_device_bundle_information(account, my_jid, device_id) # Fetch Bundles of contacts devices if contact_jid not in self.query_for_bundles: devices_without_session = state \ .devices_without_sessions(contact_jid) self.query_for_bundles.append(contact_jid) if devices_without_session: for device_id in devices_without_session: self.fetch_device_bundle_information(account, contact_jid, device_id) if state.getTrustedFingerprints(contact_jid): return False else: return True
def account_info(self, account): '''show info on account: resource, jid, nick, prio, message''' result = DBUS_DICT_SS() if account in gajim.connections: # account is valid con = gajim.connections[account] index = con.connected result['status'] = DBUS_STRING(gajim.SHOW_LIST[index]) result['name'] = DBUS_STRING(con.name) result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name)) result['message'] = DBUS_STRING(con.status) result['priority'] = DBUS_STRING(unicode(con.priority)) result['resource'] = DBUS_STRING(unicode(gajim.config.get_per( 'accounts', con.name, 'resource'))) return result
def query_prekey(self, recipient): """ Calls OmemoPlugin.fetch_device_bundle_information() for each own or recipient device key missing. """ account = recipient.account.name state = self.get_omemo_state(account) to_jid = recipient.jid my_jid = gajim.get_jid_from_account(account) for device_id in state.devices_without_sessions(to_jid): self.fetch_device_bundle_information(account, state, to_jid, device_id) for device_id in state.own_devices_without_sessions(my_jid): self.fetch_device_bundle_information(account, state, my_jid, device_id)
def query_own_devicelist(self, account): """ Query own devicelist from the server. Parameters ---------- account : str the account name """ my_jid = gajim.get_jid_from_account(account) iq = DevicelistQuery(my_jid) gajim.connections[account].connection.send(iq) log.info(account + ' => Querry own devicelist ...') id_ = str(iq.getAttr("id")) IQ_CALLBACK[id_] = lambda stanza: \ self.handle_devicelist_result(account, stanza)
def assert_account_is_in_roster(self, acc): titerA = self.roster._get_account_iter(acc, model=self.roster.model) self.assertTrue(self.roster.model.iter_is_valid(titerA), msg='Account iter is invalid') acc_model = self.roster.model[titerA] self.assertEquals(acc_model[self.C_TYPE], 'account', msg='No account found') if not self.roster.regroup: self.assertEquals(acc_model[self.C_ACCOUNT], acc, msg='Account not found') self_jid = gajim.get_jid_from_account(acc) self.assertEquals(acc_model[self.C_JID], self_jid, msg='Account JID not found in account row')
def handle_incoming_msg(self, event): ctx = None account = event.conn.name accjid = gajim.get_jid_from_account(account) if event.encrypted is not False or not event.stanza.getTag('body') \ or not isinstance(event.stanza.getBody(), unicode): return PASS try: ctx = self.us[account].getContext(event.fjid) msgtxt, tlvs = ctx.receiveMessage(event.msgtxt, appdata={'session':event.session}) except potr.context.NotOTRMessage, e: # received message was not OTR - pass it on return PASS
def pep_received(self, obj): if obj.jid != gajim.get_jid_from_account(obj.conn.name): return pep_dict = gajim.connections[obj.conn.name].pep if obj.pep_type == 'mood': img = self.xml.get_object('mood_image') if 'mood' in pep_dict: img.set_from_pixbuf(pep_dict['mood'].asPixbufIcon()) else: img.set_from_stock('gtk-stop', gtk.ICON_SIZE_MENU) if obj.pep_type == 'activity': img = self.xml.get_object('activity_image') if 'activity' in pep_dict: img.set_from_pixbuf(pep_dict['activity'].asPixbufIcon()) else: img.set_from_stock('gtk-stop', gtk.ICON_SIZE_MENU)
def verify_button_clicked_cb(self, button, *args): accounts = {} for acc in gajim.connections.iterkeys(): accounts[gajim.get_jid_from_account(acc)] = acc mod, paths = self.fpr_view.get_selection().get_selected_rows() # open the window for the first selected row for path in paths[0:1]: it = mod.get_iter(path) fjid, fpr, a = mod.get(it, 0, 6, 4) ctx = self.plugin.us[accounts[a]].getContext(fjid) dlg = ContactOtrWindow(self.plugin, ctx, fpr=fpr, parent=self) dlg.run() dlg.destroy() break
def handle_incoming_msg(self, event): ctx = None account = event.conn.name accjid = gajim.get_jid_from_account(account) if event.encrypted is not False or not event.stanza.getTag('body') \ or not isinstance(event.stanza.getBody(), unicode): return PASS try: ctx = self.us[account].getContext(event.fjid) msgtxt, tlvs = ctx.receiveMessage(event.msgtxt, appdata={'session':event.session}) except potr.context.UnencryptedMessage, e: tlvs = [] msgtxt = _('The following message received from %(jid)s was ' '*not encrypted*: [%(error)s]') % {'jid': event.fjid, 'error': e.args[0]}
def __init__(self, con, weinitiate, jid, iq_id=None, sid=None, werequest=False): """ con -- connection object, weinitiate -- boolean, are we the initiator? jid - jid of the other entity """ self.contents = {} # negotiated contents self.connection = con # connection to use # our full jid self.ourjid = gajim.get_jid_from_account(self.connection.name) if con.server_resource: self.ourjid = self.ourjid + '/' + con.server_resource self.peerjid = jid # jid we connect to # jid we use as the initiator self.initiator = weinitiate and self.ourjid or self.peerjid # jid we use as the responder self.responder = weinitiate and self.peerjid or self.ourjid # are we an initiator? self.weinitiate = weinitiate # Are we requesting or offering a file? self.werequest = werequest self.request = False # what state is session in? (one from JingleStates) self.state = JingleStates.ended if not sid: sid = con.connection.getAnID() self.sid = sid # sessionid # iq stanza id, used to determine which sessions to summon callback # later on when iq-result stanza arrives if iq_id is not None: self.iq_ids = [iq_id] else: self.iq_ids = [] self.accepted = True # is this session accepted by user # Tells whether this session is a file transfer or not self.session_type_FT = False # callbacks to call on proper contents # use .prepend() to add new callbacks, especially when you're going # to send error instead of ack self.callbacks = { 'content-accept': [self.__ack, self.__on_content_accept, self.__broadcast], 'content-add': [self.__ack, self.__on_content_add, self.__broadcast ], #TODO 'content-modify': [self.__ack], #TODO 'content-reject': [self.__ack, self.__on_content_remove], 'content-remove': [self.__ack, self.__on_content_remove], 'description-info': [self.__ack, self.__broadcast], #TODO 'security-info': [self.__ack], #TODO 'session-accept': [self.__ack, self.__on_session_accept, self.__on_content_accept, self.__broadcast], 'session-info': [self.__ack, self.__broadcast, self.__on_session_info ], 'session-initiate': [self.__ack, self.__on_session_initiate, self.__broadcast], 'session-terminate': [self.__ack,self.__on_session_terminate, self.__broadcast_all], 'transport-info': [self.__ack, self.__broadcast], 'transport-replace': [self.__ack, self.__broadcast, self.__on_transport_replace], #TODO 'transport-accept': [self.__ack], #TODO 'transport-reject': [self.__ack], #TODO 'iq-result': [self.__broadcast], 'iq-error': [self.__on_error], }
def _ft_get_our_jid(self): our_jid = gajim.get_jid_from_account(self.name) resource = self.server_resource return our_jid + '/' + resource
def update_button_state(self, chat_control): global jid_to_servers global iq_ids_to_callbacks global last_info_query if gajim.connections[chat_control.account].connection == None and \ gajim.get_jid_from_account(chat_control.account) in jid_to_servers: # maybe don't delete this and detect vanished upload components when actually trying to upload something log.info("Deleting %s from jid_to_servers (disconnected)" % gajim.get_jid_from_account(chat_control.account)) del jid_to_servers[gajim.get_jid_from_account( chat_control.account)] #pass # query info at most every 60 seconds in case something goes wrong if (not chat_control.account in last_info_query or \ last_info_query[chat_control.account] + 60 < time.time()) and \ not gajim.get_jid_from_account(chat_control.account) in jid_to_servers and \ gajim.account_is_connected(chat_control.account): log.info( "Account %s: Using dicovery to find jid of httpupload component" % chat_control.account) id_ = gajim.get_an_id() iq = nbxmpp.Iq(typ='get', to=gajim.get_server_from_jid( gajim.get_jid_from_account( chat_control.account)), queryNS="http://jabber.org/protocol/disco#items") iq.setID(id_) def query_info(stanza): global last_info_query for item in stanza.getTag("query").getTags("item"): id_ = gajim.get_an_id() iq = nbxmpp.Iq( typ='get', to=item.getAttr("jid"), queryNS="http://jabber.org/protocol/disco#info") iq.setID(id_) last_info_query[chat_control.account] = time.time() gajim.connections[chat_control.account].connection.send(iq) iq_ids_to_callbacks[str(id_)] = query_info gajim.connections[chat_control.account].connection.send(iq) #send disco query to main server jid id_ = gajim.get_an_id() iq = nbxmpp.Iq(typ='get', to=gajim.get_server_from_jid( gajim.get_jid_from_account( chat_control.account)), queryNS="http://jabber.org/protocol/disco#info") iq.setID(id_) last_info_query[chat_control.account] = time.time() gajim.connections[chat_control.account].connection.send(iq) for base in self.controls: if base.chat_control == chat_control: is_supported = gajim.get_jid_from_account(chat_control.account) in jid_to_servers and \ gajim.connections[chat_control.account].connection != None log.info("Account %s: httpupload is_supported: %s" % (str(chat_control.account), str(is_supported))) if not is_supported: text = _('Your server does not support http uploads') image_text = text else: text = _('Send file via http upload') image_text = _('Send image via http upload') base.button.set_sensitive(is_supported) base.button.set_tooltip_text(text) base.image_button.set_sensitive(is_supported) base.image_button.set_tooltip_text(image_text)
def on_file_dialog_ok(self, widget, path_to_file=None): global jid_to_servers try: self.encrypted_upload = self.encryption_activated() except Exception as e: log.debug(e) self.encrypted_upload = False if not path_to_file: path_to_file = self.dlg.get_filename() if not path_to_file: self.dlg.destroy() return path_to_file = gtkgui_helpers.decode_filechooser_file_paths( (path_to_file, ))[0] self.dlg.destroy() if not os.path.exists(path_to_file): return if self.encrypted_upload: filesize = os.path.getsize(path_to_file) + TAGSIZE # in bytes else: filesize = os.path.getsize(path_to_file) invalid_file = False msg = '' if os.path.isfile(path_to_file): stat = os.stat(path_to_file) if stat[6] == 0: invalid_file = True msg = _('File is empty') else: invalid_file = True msg = _('File does not exist') if invalid_file: ErrorDialog(_('Could not open file'), msg, transient_for=self.chat_control.parent_win.window) return mime_type = mimetypes.MimeTypes().guess_type(path_to_file)[0] if not mime_type: mime_type = 'application/octet-stream' # fallback mime type log.info("Detected MIME Type of file: " + str(mime_type)) progress_messages = Queue(8) event = threading.Event() progress_window = ProgressWindow(_('Requesting HTTP Upload Slot...'), progress_messages, self.plugin, event) def upload_file(stanza): if stanza.getType() == 'error': ErrorDialog(_('Could not request upload slot'), stanza.getErrorMsg(), transient_for=self.chat_control.parent_win.window) log.error(stanza) progress_window.close_dialog() return slot = stanza.getTag("slot") if slot: put = slot.getTag("put") get = slot.getTag("get") else: progress_window.close_dialog() log.error("got unexpected stanza: " + str(stanza)) ErrorDialog(_('Could not request upload slot'), _('Got unexpected response from server (see log)'), transient_for=self.chat_control.parent_win.window) return try: if self.encrypted_upload: key = os.urandom(32) iv = os.urandom(16) data = StreamFileWithProgress( path_to_file, "rb", progress_window.update_progress, event, self.encrypted_upload, key, iv) else: data = StreamFileWithProgress( path_to_file, "rb", progress_window.update_progress, event) except: progress_window.close_dialog() ErrorDialog( _('Could not open file'), _('Exception raised while opening file (see error log for more information)' ), transient_for=self.chat_control.parent_win.window) raise # fill error log with useful information def upload_complete(response_code): if isinstance(response_code, str): # We got a error Message ErrorDialog( _('Error'), response_code, transient_for=self.chat_control.parent_win.window) return if response_code >= 200 and response_code < 300: log.info("Upload completed successfully") xhtml = None is_image = mime_type.split('/', 1)[0] == 'image' if (not isinstance(self.chat_control, chat_control.ChatControl) or not self.chat_control.gpg_is_active) and \ self.dialog_type == 'image' and is_image and not self.encrypted_upload: progress_messages.put( _('Calculating (possible) image thumbnail...')) thumb = None quality_steps = (100, 80, 60, 50, 40, 35, 30, 25, 23, 20, 18, 15, 13, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) with open(path_to_file, 'rb') as content_file: thumb = urllib2.quote( base64.standard_b64encode(content_file.read()), '') if thumb and len(thumb) < max_thumbnail_size: quality = 100 log.info( "Image small enough (%d bytes), not resampling" % len(thumb)) elif pil_available: log.info( "PIL available, using it for image downsampling" ) try: for quality in quality_steps: thumb = Image.open(path_to_file) thumb.thumbnail((max_thumbnail_dimension, max_thumbnail_dimension), Image.ANTIALIAS) output = BytesIO() thumb.save(output, format='JPEG', quality=quality, optimize=True) thumb = output.getvalue() output.close() thumb = urllib2.quote( base64.standard_b64encode(thumb), '') log.debug( "pil thumbnail jpeg quality %d produces an image of size %d..." % (quality, len(thumb))) if len(thumb) < max_thumbnail_size: break except: thumb = None else: thumb = None if not thumb: log.info( "PIL not available, using GTK for image downsampling" ) temp_file = None try: with open(path_to_file, 'rb') as content_file: thumb = content_file.read() loader = gtk.gdk.PixbufLoader() loader.write(thumb) loader.close() pixbuf = loader.get_pixbuf() scaled_pb = self.get_pixbuf_of_size( pixbuf, max_thumbnail_dimension) handle, temp_file = tempfile.mkstemp( suffix='.jpeg', prefix='gajim_httpupload_scaled_tmp', dir=gajim.TMP) log.debug( "Saving temporary jpeg image to '%s'..." % temp_file) os.close(handle) for quality in quality_steps: scaled_pb.save(temp_file, "jpeg", {"quality": str(quality)}) with open(temp_file, 'rb') as content_file: thumb = content_file.read() thumb = urllib2.quote( base64.standard_b64encode(thumb), '') log.debug( "gtk thumbnail jpeg quality %d produces an image of size %d..." % (quality, len(thumb))) if len(thumb) < max_thumbnail_size: break except: thumb = None finally: if temp_file: os.unlink(temp_file) if thumb: if len(thumb) > max_thumbnail_size: log.info( "Couldn't compress image enough, not sending any thumbnail" ) else: log.info( "Using thumbnail jpeg quality %d (image size: %d bytes)" % (quality, len(thumb))) xhtml = '<body><br/><a href="%s"> <img alt="%s" src="data:image/png;base64,%s"/> </a></body>' % \ (get.getData(), get.getData(), thumb) progress_window.close_dialog() id_ = gajim.get_an_id() def add_oob_tag(): pass if self.encrypted_upload: keyAndIv = '#' + binascii.hexlify( iv) + binascii.hexlify(key) self.chat_control.send_message(message=get.getData() + keyAndIv, xhtml=None) else: self.chat_control.send_message(message=get.getData(), xhtml=xhtml) self.chat_control.msg_textview.grab_focus() else: progress_window.close_dialog() log.error("got unexpected http upload response code: " + str(response_code)) ErrorDialog( _('Could not upload file'), _('Got unexpected http response code from server: ') + str(response_code), transient_for=self.chat_control.parent_win.window) def uploader(): progress_messages.put(_('Uploading file via HTTP...')) try: headers = { 'User-Agent': 'Gajim %s' % gajim.version, 'Content-Type': mime_type } request = urllib2.Request(put.getData().encode("utf-8"), data=data, headers=headers) request.get_method = lambda: 'PUT' log.debug("opening urllib2 upload request...") transfer = urllib2.urlopen(request, timeout=30) log.debug("urllib2 upload request done, response code: " + str(transfer.getcode())) return transfer.getcode() except UploadAbortedException as error: log.info('Upload Aborted') except Exception as error: gobject.idle_add(progress_window.close_dialog) log.exception('Error') return str(error) log.info("Uploading file to '%s'..." % str(put.getData())) log.info("Please download from '%s' later..." % str(get.getData())) gajim.thread_interface(uploader, [], upload_complete) is_supported = gajim.get_jid_from_account(self.chat_control.account) in jid_to_servers and \ gajim.connections[self.chat_control.account].connection != None log.info( "jid_to_servers of %s: %s ; connection: %s" % (gajim.get_jid_from_account(self.chat_control.account), str(jid_to_servers[gajim.get_jid_from_account( self.chat_control.account)]), str(gajim.connections[self.chat_control.account].connection))) if not is_supported: progress_window.close_dialog() log.error("upload component vanished, account got disconnected??") ErrorDialog(_( 'Your server does not support http uploads or you just got disconnected.\nPlease try to reconnect or reopen the chat window to fix this.' ), transient_for=self.chat_control.parent_win.window) return # create iq for slot request id_ = gajim.get_an_id() iq = nbxmpp.Iq(typ='get', to=jid_to_servers[gajim.get_jid_from_account( self.chat_control.account)], queryNS=None) iq.setID(id_) request = iq.addChild(name="request", namespace=NS_HTTPUPLOAD) filename = request.addChild(name="filename", ) filename.addData(os.path.basename(path_to_file)) size = request.addChild(name="size", ) size.addData(filesize) content_type = request.addChild(name="content-type", ) content_type.addData(mime_type) # send slot request and register callback log.debug("sending httpupload slot request iq...") iq_ids_to_callbacks[str(id_)] = upload_file gajim.connections[self.chat_control.account].connection.send(iq) self.chat_control.msg_textview.grab_focus()
def populate(self, contacts, account, typ): """ Populate the Tooltip Grid with data of from the contact """ self.current_row = 0 self.account = account if self.last_widget: self.last_widget.set_vexpand(False) self.clear_tooltip() if account == 'all': # Tooltip for merged accounts row accounts = helpers.get_notification_icon_tooltip_dict() self.spacer_label = '' self.fill_table_with_accounts(accounts) self.tooltip_grid.attach(self.table, 0, 3, 2, 1) self.table.show_all() return if typ == 'account': jid = gajim.get_jid_from_account(account) contacts = [] connection = gajim.connections[account] # get our current contact info nbr_on, nbr_total = gajim.\ contacts.get_nb_online_total_contacts( accounts=[account]) account_name = account if gajim.account_is_connected(account): account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total)) contact = gajim.contacts.create_self_contact(jid=jid, account=account, name=account_name, show=connection.get_status(), status=connection.status, resource=connection.server_resource, priority=connection.priority) if gajim.connections[account].gpg: contact.keyID = gajim.config.get_per('accounts', connection.name, 'keyid') contacts.append(contact) # if we're online ... if connection.connection: roster = connection.connection.getRoster() # in threadless connection when no roster stanza is sent # 'roster' is None if roster and roster.getItem(jid): resources = roster.getResources(jid) # ...get the contact info for our other online # resources for resource in resources: # Check if we already have this resource found = False for contact_ in contacts: if contact_.resource == resource: found = True break if found: continue show = roster.getShow(jid + '/' + resource) if not show: show = 'online' contact = gajim.contacts.create_self_contact( jid=jid, account=account, show=show, status=roster.getStatus( jid + '/' + resource), priority=roster.getPriority( jid + '/' + resource), resource=resource) contacts.append(contact) # Username/Account/Groupchat self.prim_contact = gajim.contacts.get_highest_prio_contact_from_contacts( contacts) self.contact_jid = self.prim_contact.jid name = GLib.markup_escape_text(self.prim_contact.get_shown_name()) name_markup = '<b>{}</b>'.format(name) if gajim.config.get('mergeaccounts'): color = gajim.config.get('tooltip_account_name_color') account_name = GLib.markup_escape_text(self.prim_contact.account.name) name_markup += " <span foreground='{}'>({})</span>".format( color, account_name) if account and helpers.jid_is_blocked(account, self.prim_contact.jid): name_markup += _(' [blocked]') try: if self.prim_contact.jid in gajim.interface.minimized_controls[account]: name_markup += _(' [minimized]') except KeyError: pass self.name.set_markup(name_markup) self.name.show() self.num_resources = 0 # put contacts in dict, where key is priority contacts_dict = {} for contact in contacts: if contact.resource: self.num_resources += 1 priority = int(contact.priority) if priority in contacts_dict: contacts_dict[priority].append(contact) else: contacts_dict[priority] = [contact] if self.num_resources > 1: self.status_label.show() transport = gajim.get_transport_name_from_jid(self.prim_contact.jid) if transport: file_path = os.path.join(helpers.get_transport_path(transport), '16x16') else: iconset = gajim.config.get('iconset') if not iconset: iconset = 'dcraven' file_path = os.path.join(helpers.get_iconset_path(iconset), '16x16') contact_keys = sorted(contacts_dict.keys()) contact_keys.reverse() for priority in contact_keys: for acontact in contacts_dict[priority]: icon_name = self._get_icon_name_for_tooltip(acontact) if acontact.status and len(acontact.status) > 25: status = '' add_text = True else: status = acontact.status add_text = False status_line = self.get_status_info(acontact.resource, acontact.priority, acontact.show, status) self.add_status_row(file_path, icon_name, status_line, acontact.last_status_time) if add_text: self.add_text_row(acontact.status, 2) self.tooltip_grid.attach(self.table, 0, 3, 2, 1) self.table.show_all() else: # only one resource if contact.show: request_time = False try: last_time = self.check_last_time[contact] if isinstance(last_time, float) and last_time < time.time() - 60: request_time = True except KeyError: request_time = True if request_time: if contact.show == 'offline': gajim.connections[account].\ request_last_status_time(contact.jid, '') elif contact.resource: gajim.connections[account].\ request_last_status_time( contact.jid, contact.resource) self.check_last_time[contact] = time.time() if contact.status: status = contact.status.strip() if status: self.status.set_text(status) self.status.show() self.status_label.show() # PEP Info self._append_pep_info(contact) # JID self.jid.set_text(self.prim_contact.jid) self.jid.show() self.jid_label.show() # contact has only one ressource if self.num_resources == 1 and contact.resource: res = GLib.markup_escape_text(contact.resource) prio = str(contact.priority) self.resource.set_text("{} ({})".format(res, prio)) self.resource.show() self.resource_label.show() if self.prim_contact.jid not in gajim.gc_connected[account]: if (account and self.prim_contact.sub and self.prim_contact.sub != 'both'): # ('both' is the normal sub so we don't show it) self.sub.set_text(helpers.get_uf_sub(self.prim_contact.sub)) self.sub.show() self.sub_label.show() if self.prim_contact.keyID: keyID = None if len(self.prim_contact.keyID) == 8: keyID = self.prim_contact.keyID elif len(self.prim_contact.keyID) == 16: keyID = self.prim_contact.keyID[8:] if keyID: self.pgp.set_text(keyID) self.pgp.show() self.pgp_label.show() self._set_idle_time(contact) # Avatar puny_jid = helpers.sanitize_filename(self.prim_contact.jid) file_ = helpers.get_avatar_path(os.path.join(gajim.AVATAR_PATH, puny_jid)) if file_: with open(file_, 'rb') as file_data: pix = gtkgui_helpers.get_pixbuf_from_data(file_data.read()) pix = gtkgui_helpers.get_scaled_pixbuf(pix, 'tooltip') self.avatar.set_from_pixbuf(pix) self.avatar.show() # Sets the Widget that is at the bottom to expand. # This is needed in case the Picture takes more Space then the Labels i = 1 while i < 15: if self.tooltip_grid.get_child_at(0, i): if self.tooltip_grid.get_child_at(0, i).get_visible(): self.last_widget = self.tooltip_grid.get_child_at(0, i) i += 1 self.last_widget.set_vexpand(True)
def _ft_get_our_jid(self): return gajim.get_jid_from_account(self.name)
def update_context_list(self): self.fpr_model.clear() self.device_model.clear() self.qrcode = self.B.get_object('qrcode') self.qrinfo = self.B.get_object('qrinfo') if len(self.account_store) == 0: self.B.get_object('ID').set_markup('') self.B.get_object('fingerprint_label').set_markup('') self.B.get_object('trust_button').set_sensitive(False) self.B.get_object('delfprbutton').set_sensitive(False) self.B.get_object('refresh').set_sensitive(False) self.B.get_object('cleardevice_button').set_sensitive(False) self.B.get_object('qrcode').clear() return active = self.B.get_object('account_combobox').get_active() account = self.account_store[active][0].decode() # Set buttons active self.B.get_object('trust_button').set_sensitive(True) self.B.get_object('delfprbutton').set_sensitive(True) self.B.get_object('refresh').set_sensitive(True) if account == 'Local': self.B.get_object('cleardevice_button').set_sensitive(False) else: self.B.get_object('cleardevice_button').set_sensitive(True) # Set FPR Label and DeviceID state = self.plugin.get_omemo_state(account) deviceid = state.own_device_id self.B.get_object('ID').set_markup('<tt>%s</tt>' % deviceid) ownfpr = binascii.hexlify(state.store.getIdentityKeyPair() .getPublicKey().serialize()) human_ownfpr = human_hash(ownfpr[2:]) self.B.get_object('fingerprint_label').set_markup('<tt>%s</tt>' % human_ownfpr) # Set Fingerprint List trust_str = {0: 'False', 1: 'True', 2: 'Undecided'} session_db = state.store.getAllSessions() for item in session_db: color = {0: '#FF0040', # red 1: '#2EFE2E', # green 2: '#FF8000'} # orange _id, jid, deviceid, record, active = item active = bool(active) identity_key = SessionRecord(serialized=record). \ getSessionState().getRemoteIdentityKey() fpr = binascii.hexlify(identity_key.getPublicKey().serialize()) fpr = human_hash(fpr[2:]) trust = state.store.isTrustedIdentity(jid, identity_key) if not active: color[trust] = '#585858' # grey self.fpr_model.append( (_id, jid, trust_str[trust], '<tt><span foreground="{}">{}</span></tt>'. format(color[trust], fpr), deviceid)) # Set Device ID List for item in state.own_devices: self.device_model.append([item]) # Set QR Verification Code if PILLOW: path = self.get_qrcode( gajim.get_jid_from_account(account), deviceid, ownfpr[2:]) self.qrcode.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file(path)) self.qrinfo.hide() else: self.qrinfo.show()
def getOurBareJID(self): return gajim.get_jid_from_account(self.name)
def handle_outgoing_stanza(self, event): """ Manipulates the outgoing stanza The body is getting encrypted Parameters ---------- event : StanzaMessageOutgoingEvent Returns ------- Return if encryption is not activated or any other exception or error occurs """ account = event.conn.name if account in self.disabled_accounts: return try: if not event.msg_iq.getTag('body'): return state = self.get_omemo_state(account) full_jid = str(event.msg_iq.getAttr('to')) to_jid = gajim.get_jid_without_resource(full_jid) if not state.encryption.is_active(to_jid): return # Delete previous Message out of Correction Message Stanza if event.msg_iq.getTag('replace', namespace=NS_CORRECT): event.msg_iq.delChild('encrypted', attrs={'xmlns': NS_OMEMO}) plaintext = event.msg_iq.getBody().encode('utf8') msg_dict = state.create_msg( gajim.get_jid_from_account(account), to_jid, plaintext) if not msg_dict: return True encrypted_node = OmemoMessage(msg_dict) # Check if non-OMEMO resource is online contacts = gajim.contacts.get_contacts(account, to_jid) non_omemo_resource_online = False for contact in contacts: if contact.show == 'offline': continue if not contact.supports(NS_NOTIFY): log.debug(contact.get_full_jid() + ' => Contact doesnt support OMEMO, ' 'adding Info Message to Body') support_msg = 'You received a message encrypted with ' \ 'OMEMO but your client doesnt support OMEMO.' event.msg_iq.setBody(support_msg) non_omemo_resource_online = True if not non_omemo_resource_online: event.msg_iq.delChild('body') event.msg_iq.addChild(node=encrypted_node) # XEP-xxxx: Explicit Message Encryption if not event.msg_iq.getTag('encrypted', attrs={'xmlns': NS_EME}): eme_node = Node('encrypted', attrs={'xmlns': NS_EME, 'name': 'OMEMO', 'namespace': NS_OMEMO}) event.msg_iq.addChild(node=eme_node) # Store Hint for MAM store = Node('store', attrs={'xmlns': NS_HINTS}) event.msg_iq.addChild(node=store) self.print_msg_to_log(event.msg_iq) except Exception as e: log.debug(e) return True
def handle_device_list_update(self, event): """ Check if the passed event is a device list update and store the new device ids. Parameters ---------- event : PEPReceivedEvent Returns ------- bool True if the given event was a valid device list update event See also -------- 4.2 Discovering peer support http://conversations.im/xeps/multi-end.html#usecases-discovering """ account = event.conn.name if account in self.disabled_accounts: return False if event.pep_type != 'headline': return False devices_list = list(set(unpack_device_list_update(event.stanza, event.conn.name))) contact_jid = gajim.get_jid_without_resource(event.fjid) if len(devices_list) == 0: log.error(account + ' => Received empty or invalid Devicelist from: ' + contact_jid) return False state = self.get_omemo_state(account) my_jid = gajim.get_jid_from_account(account) if contact_jid == my_jid: log.info(account + ' => Received own device list:' + str( devices_list)) state.set_own_devices(devices_list) state.store.sessionStore.setActiveState(devices_list, my_jid) # remove contact from list, so on send button pressed # we query for bundle and build a session if contact_jid in self.query_for_bundles: self.query_for_bundles.remove(contact_jid) if not state.own_device_id_published(): # Our own device_id is not in the list, it could be # overwritten by some other client self.publish_own_devices_list(account) else: log.info(account + ' => Received device list for ' + contact_jid + ':' + str(devices_list)) state.set_devices(contact_jid, devices_list) state.store.sessionStore.setActiveState(devices_list, contact_jid) # remove contact from list, so on send button pressed # we query for bundle and build a session if contact_jid in self.query_for_bundles: self.query_for_bundles.remove(contact_jid) # Enable Encryption on receiving first Device List if not state.encryption.exist(contact_jid): if account in self.ui_list and \ contact_jid in self.ui_list[account]: log.debug(account + ' => Switch encryption ON automatically ...') self.ui_list[account][contact_jid].activate_omemo() else: log.debug(account + ' => Switch encryption ON automatically ...') self.omemo_enable_for(contact_jid, account) if account in self.ui_list and \ contact_jid not in self.ui_list[account]: chat_control = gajim.interface.msg_win_mgr.get_control( contact_jid, account) if chat_control: self.connect_ui(chat_control) return True
def handle_outgoing_gc_stanza(self, event): """ Manipulates the outgoing groupchat stanza The body is getting encrypted Parameters ---------- event : StanzaMessageOutgoingEvent Returns ------- Return if encryption is not activated or any other exception or error occurs """ account = event.conn.name if account in self.disabled_accounts: return try: # If we send a correction msg, the stanza is saved # in correction_msg if event.correction_msg: event.msg_iq = event.correction_msg if not event.msg_iq.getTag('body'): return state = self.get_omemo_state(account) full_jid = str(event.msg_iq.getAttr('to')) to_jid = gajim.get_jid_without_resource(full_jid) if to_jid not in self.groupchat: return if not state.encryption.is_active(to_jid): return # Setting the ID here first for the old stanza object, which # Gajim uses for message correction later. # after cleanup_stanza() we have a new stanza object so we # have to set the same ID so the ID we send matches with the # ID from the correction stanza that Gajim hands us on a correction # This is a nasty workaround, dont remove this or LMC in Groupchat # will break for everything <= 0.16.8 new_id = gajim.connections[account].connection.getAnID() event.msg_iq.setID(new_id) self.cleanup_stanza(event) event.msg_iq.setID(new_id) plaintext = event.message msg_dict = state.create_gc_msg(gajim.get_jid_from_account(account), to_jid, plaintext.encode('utf8')) if not msg_dict: return True self.gc_message[msg_dict['payload']] = plaintext encrypted_node = OmemoMessage(msg_dict) event.msg_iq.addChild(node=encrypted_node) # XEP-0380: Explicit Message Encryption eme_node = Node('encryption', attrs={ 'xmlns': NS_EME, 'name': 'OMEMO', 'namespace': NS_OMEMO }) event.msg_iq.addChild(node=eme_node) # Add Message for devices that dont support OMEMO support_msg = 'You received a message encrypted with ' \ 'OMEMO but your client doesnt support OMEMO.' event.msg_iq.setBody(support_msg) # Store Hint for MAM store = Node('store', attrs={'xmlns': NS_HINTS}) event.msg_iq.addChild(node=store) if event.correction_msg: event.correction_msg = event.msg_iq event.msg_iq = None self.print_msg_to_log(event.correction_msg) else: self.print_msg_to_log(event.msg_iq) except Exception as e: log.debug(e) return True event.xhtml = None
def handle_outgoing_gc_stanza(self, event): """ Manipulates the outgoing groupchat stanza The body is getting encrypted Parameters ---------- event : StanzaMessageOutgoingEvent Returns ------- Return if encryption is not activated or any other exception or error occurs """ account = event.conn.name if account in self.disabled_accounts: return try: # If we send a correction msg, the stanza is saved # in correction_msg if event.correction_msg: event.msg_iq = event.correction_msg if not event.msg_iq.getTag('body'): return state = self.get_omemo_state(account) full_jid = str(event.msg_iq.getAttr('to')) to_jid = gajim.get_jid_without_resource(full_jid) if to_jid not in self.groupchat: return if not state.encryption.is_active(to_jid): return # Delete previous Message out of Correction Message Stanza if event.msg_iq.getTag('replace', namespace=NS_CORRECT): event.msg_iq.delChild('encrypted', attrs={'xmlns': NS_OMEMO}) plaintext = event.msg_iq.getBody() msg_dict = state.create_gc_msg( gajim.get_jid_from_account(account), to_jid, plaintext.encode('utf8')) if not msg_dict: return True self.gc_message[msg_dict['payload']] = plaintext encrypted_node = OmemoMessage(msg_dict) event.msg_iq.delChild('body') event.msg_iq.addChild(node=encrypted_node) # XEP-xxxx: Explicit Message Encryption if not event.msg_iq.getTag('encrypted', attrs={'xmlns': NS_EME}): eme_node = Node('encrypted', attrs={'xmlns': NS_EME, 'name': 'OMEMO', 'namespace': NS_OMEMO}) event.msg_iq.addChild(node=eme_node) # Add Message for devices that dont support OMEMO support_msg = 'You received a message encrypted with ' \ 'OMEMO but your client doesnt support OMEMO.' event.msg_iq.setBody(support_msg) # Store Hint for MAM store = Node('store', attrs={'xmlns': NS_HINTS}) event.msg_iq.addChild(node=store) if event.correction_msg: event.correction_msg = event.msg_iq event.msg_iq = None self.print_msg_to_log(event.correction_msg) else: self.print_msg_to_log(event.msg_iq) except Exception as e: log.debug(e) return True