Changeset 9602

Show
Ignore:
Timestamp:
05/09/08 14:35:25 (3 months ago)
Author:
js
Message:

Added OTR support.
Work done by Kjell Braden <fnord@…>.
Some fixes done by me.

Location:
trunk
Files:
2 added
9 modified

Legend:

Unmodified
Added
Removed
  • trunk/data/glade/chat_control_popup_menu.glade

    r8891 r9602  
    7373    </child> 
    7474    <child> 
     75      <widget class="GtkMenuItem" id="otr_submenu"> 
     76        <property name="no_show_all">True</property> 
     77        <property name="label" translatable="yes">Off-the-Record Encryption</property> 
     78        <property name="use_underline">True</property> 
     79        <child> 
     80          <widget class="GtkMenu" id="otr_submenu_menu"> 
     81            <child> 
     82              <widget class="GtkMenuItem" id="otr_settings_menuitem"> 
     83                <property name="visible">True</property> 
     84                <property name="label" translatable="yes">OTR settings / fingerprint</property> 
     85                <property name="use_underline">True</property> 
     86                <signal name="activate" handler="_on_otr_settings_menuitem_activate"/> 
     87              </widget> 
     88            </child> 
     89            <child> 
     90              <widget class="GtkMenuItem" id="smp_otr_menuitem"> 
     91                <property name="visible">True</property> 
     92                <property name="label" translatable="yes">Authenticate contact</property> 
     93                <property name="use_underline">True</property> 
     94                <signal name="activate" handler="_on_smp_otr_menuitem_activate"/> 
     95              </widget> 
     96            </child> 
     97            <child> 
     98              <widget class="GtkMenuItem" id="start_otr_menuitem"> 
     99                <property name="visible">True</property> 
     100                <property name="label" translatable="yes">Start / Refresh OTR</property> 
     101                <property name="use_underline">True</property> 
     102                <signal name="activate" handler="_on_start_otr_menuitem_activate"/> 
     103              </widget> 
     104            </child> 
     105            <child> 
     106              <widget class="GtkMenuItem" id="end_otr_menuitem"> 
     107                <property name="visible">True</property> 
     108                <property name="sensitive">False</property> 
     109                <property name="label" translatable="yes">End OTR </property> 
     110                <property name="use_underline">True</property> 
     111                <signal name="activate" handler="_on_end_otr_menuitem_activate"/> 
     112              </widget> 
     113            </child> 
     114          </widget> 
     115        </child> 
     116      </widget> 
     117    </child> 
     118    <child> 
    75119      <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> 
    76120        <property name="visible">True</property> 
  • trunk/src/chat_control.py

    r9601 r9602  
    11771177 
    11781178        def update_ui(self): 
     1179                if gajim.otr_module: 
     1180                        self.update_otr(True) 
    11791181                # The name banner is drawn here 
    11801182                ChatControlBase.update_ui(self) 
     1183 
     1184        def update_otr(self, print_status=False): 
     1185                # retrieve the OTR context from the chat's contact data 
     1186                ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account], 
     1187                        self.contact.get_full_jid().encode(), 
     1188                        gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1, 
     1189                        (gajim.otr_add_appdata, self.account))[0] 
     1190                 
     1191                enc_status = False 
     1192                otr_status_text = "" 
     1193                if ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED: 
     1194                        enc_status = True 
     1195                        if ctx.active_fingerprint.trust: 
     1196                                otr_status_text = u"authenticated secure OTR connection" 
     1197                        else: 
     1198                                otr_status_text = u'*unauthenticated* secure OTR connection' 
     1199                elif ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_FINISHED: 
     1200                        enc_status = True 
     1201                        otr_status_text = u"finished OTR connection" 
     1202                else: 
     1203                        # nothing to print 
     1204                        print_status = False 
     1205                self._show_lock_image(enc_status, u'OTR', enc_status, True) 
     1206                if print_status: 
     1207                        self.print_conversation_line(u" [OTR] %s"%otr_status_text, 'status', 
     1208                                        '', None) 
    11811209 
    11821210        def _update_banner_state_image(self): 
     
    16971725                toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem') 
    16981726                toggle_e2e_menuitem = xml.get_widget('toggle_e2e_menuitem') 
     1727                otr_submenu = xml.get_widget('otr_submenu') 
     1728                otr_settings_menuitem = xml.get_widget('otr_settings_menuitem') 
     1729                smp_otr_menuitem = xml.get_widget('smp_otr_menuitem') 
     1730                start_otr_menuitem = xml.get_widget('start_otr_menuitem') 
     1731                end_otr_menuitem = xml.get_widget('end_otr_menuitem') 
    16991732                add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') 
    17001733                send_file_menuitem = xml.get_widget('send_file_menuitem') 
     
    17821815                        self._on_convert_to_gc_menuitem_activate) 
    17831816                self.handlers[id] = convert_to_gc_menuitem 
     1817 
     1818                if gajim.otr_module: 
     1819                        otr_submenu.show() 
     1820                        id = otr_settings_menuitem.connect('activate', 
     1821                                self._on_otr_settings_menuitem_activate) 
     1822                        self.handlers[id] = otr_settings_menuitem 
     1823                        id = start_otr_menuitem.connect('activate', 
     1824                                self._on_start_otr_menuitem_activate) 
     1825                        self.handlers[id] = start_otr_menuitem 
     1826                        id = end_otr_menuitem.connect('activate', 
     1827                                self._on_end_otr_menuitem_activate) 
     1828                        self.handlers[id] = end_otr_menuitem 
     1829                        id = smp_otr_menuitem.connect('activate', 
     1830                                self._on_smp_otr_menuitem_activate) 
     1831                        self.handlers[id] = smp_otr_menuitem 
     1832 
     1833                        ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account], 
     1834                                self.contact.get_full_jid().encode(), 
     1835                                gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1, 
     1836                                (gajim.otr_add_appdata, self.account))[0] 
     1837                        # can end only when PLAINTEXT 
     1838                        end_otr_menuitem.set_sensitive(ctx.msgstate != 
     1839                                gajim.otr_module.OTRL_MSGSTATE_PLAINTEXT) 
     1840                        # can SMP only when ENCRYPTED 
     1841                        smp_otr_menuitem.set_sensitive(ctx.msgstate == 
     1842                                gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED) 
     1843 
    17841844                menu.connect('selection-done', self.destroy_menu, history_menuitem, 
    17851845                        information_menuitem) 
     
    22602320                        self.session.negotiate_e2e(False) 
    22612321 
     2322        def _on_start_otr_menuitem_activate(self, widget): 
     2323                # ?OTR? gets replaced with a better message internally in otrl_message_sending 
     2324                MessageControl.send_message(self, u"?OTR?", type="chat") 
     2325        def _on_end_otr_menuitem_activate(self, widget): 
     2326                fjid = self.contact.get_full_jid() 
     2327                gajim.otr_module.otrl_message_disconnect(gajim.otr_userstates[self.account], 
     2328                                (gajim.otr_ui_ops, {'account':self.account,'urgent':True}), 
     2329                                gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 
     2330                                fjid.encode()) 
     2331                gajim.otr_ui_ops.gajim_log("Private conversation with %s lost."%fjid, 
     2332                                self.account, fjid.encode()) 
     2333                self.update_ui() 
     2334        def _on_otr_settings_menuitem_activate(self, widget): 
     2335                gajim.otr_windows.ContactOtrWindow(self.contact, self.account, self) 
     2336        def _on_smp_otr_menuitem_activate(self, widget): 
     2337                ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account], 
     2338                        self.contact.get_full_jid().encode(), 
     2339                        gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1, 
     2340                        (gajim.otr_add_appdata, self.account))[0] 
     2341                ctx.app_data.show(False) 
     2342 
    22622343        def got_connected(self): 
    22632344                ChatControlBase.got_connected(self) 
  • trunk/src/common/config.py

    r9585 r9602  
    320320                        'zeroconf_email': [ opt_str, '', '', True ], 
    321321                        'use_env_http_proxy' : [opt_bool, False], 
     322                        'otr_flags': [opt_int, 59 ], 
    322323                }, {}), 
    323324                'statusmsg': ({ 
     
    370371                        'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')], 
    371372                        'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')], 
     373                        'otr_flags': [opt_int, -1 ], 
    372374                }, {}), 
    373375                'rooms': ({ 
  • trunk/src/common/connection_handlers.py

    r9585 r9602  
    16781678                        return 
    16791679                elif mtype == 'chat': # it's type 'chat' 
     1680 
     1681                        if gajim.otr_module and isinstance(msgtxt, unicode): 
     1682                                otr_msg_tuple = gajim.otr_module.otrl_message_receiving( 
     1683                                        gajim.otr_userstates[self.name], 
     1684                                        (gajim.otr_ui_ops, {'account':self.name}), 
     1685                                        gajim.get_jid_from_account(self.name).encode(), 
     1686                                        gajim.OTR_PROTO, frm.encode(), msgtxt.encode(), 
     1687                                        (gajim.otr_add_appdata, self.name)) 
     1688                                msgtxt = unicode(otr_msg_tuple[1]) 
     1689                                # OTR messages are unformatted, or rather contain the same 
     1690                                # text in <body> and <html> 
     1691                                msghtml = msgtxt 
     1692 
     1693                                if gajim.otr_module.otrl_tlv_find(otr_msg_tuple[2], 
     1694                                                gajim.otr_module.OTRL_TLV_DISCONNECTED) != None: 
     1695                                        gajim.otr_ui_ops.gajim_log("%s has ended his/her private conversation" 
     1696                                                        " with you; you should do the same."%frm, self.name, 
     1697                                                        frm) 
     1698                                        ctrl = gajim.interface.msg_win_mgr.get_control(frm, self.name) 
     1699                                        if ctrl: 
     1700                                                ctrl.update_ui() 
     1701 
     1702                                ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.name], frm.encode(), 
     1703                                                gajim.get_jid_from_account(self.name).encode(), gajim.OTR_PROTO, 1, 
     1704                                                (gajim.otr_add_appdata, self.name))[0] 
     1705                                tlvs = otr_msg_tuple[2] 
     1706                                ctx.app_data.handle_tlv(tlvs) 
     1707 
    16801708                        if not msg.getTag('body') and chatstate is None: #no <body> 
    16811709                                return 
  • trunk/src/common/connection.py

    r9579 r9602  
    10251025        def send_message(self, jid, msg, keyID, type='chat', subject='', 
    10261026        chatstate=None, msg_id=None, composing_xep=None, resource=None, 
    1027         user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None): 
     1027        user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None, original_message=None): 
    10281028                if not self.connection: 
    10291029                        return 1 
     
    11171117                                msg_iq = session.encrypt_stanza(msg_iq) 
    11181118 
     1119 
    11191120                self.connection.send(msg_iq) 
    1120                 if not forward_from and session.is_loggable(): 
     1121                if not forward_from and session and session.is_loggable(): 
    11211122                        no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')\ 
    11221123                                .split() 
     
    11241125                        if self.name not in no_log_for and ji not in no_log_for: 
    11251126                                log_msg = msg 
     1127                                if original_message != None: 
     1128                                        log_msg = original_message 
    11261129                                if subject: 
    11271130                                        log_msg = _('Subject: %s\n%s') % (subject, msg) 
  • trunk/src/common/gajim.py

    r9508 r9602  
    165165        if system('gpg -h >/dev/null 2>&1'): 
    166166                HAVE_GPG = False 
     167 
     168OTR_PROTO = "xmpp" 
     169otr_userstates = {} 
     170otr_policy = {} 
    167171 
    168172gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'} 
  • trunk/src/gajim.py

    r9579 r9602  
    253253from common import optparser 
    254254from common import dataforms 
     255 
     256from common.xmpp import Message as XmppMessage 
     257 
     258try: 
     259        import otr, otr_windows 
     260         
     261        gajim.otr_module = otr 
     262        gajim.otr_windows = otr_windows 
     263except ImportError: 
     264        gajim.otr_module = None 
     265        gajim.otr_windows = None 
     266 
     267def add_appdata(data=None, context=None): 
     268        account = data 
     269        context.app_data = otr_windows.ContactOtrSMPWindow(unicode(context.username), 
     270                account) 
     271 
     272gajim.otr_add_appdata = add_appdata 
     273 
     274 
     275def otr_dialog_destroy(widget, *args, **kwargs): 
     276        widget.destroy() 
     277 
     278class OtrlMessageAppOps: 
     279 
     280        def gajim_log(self, msg, account, fjid, no_print=False): 
     281                if not isinstance(fjid, unicode): 
     282                        fjid = unicode(fjid) 
     283                if not isinstance(account, unicode): 
     284                        account = unicode(account) 
     285                resource=gajim.get_resource_from_jid(fjid) 
     286                tim = time.localtime() 
     287 
     288                if not no_print: 
     289                        ctrl = gajim.interface.msg_win_mgr.get_control( 
     290                                        gajim.get_jid_without_resource(fjid), account) 
     291                        if ctrl: 
     292                                ctrl.print_conversation_line(u" [OTR] %s"%msg, 'status', '', None) 
     293                id = gajim.logger.write('chat_msg_recv', fjid, message=msg, tim=tim) 
     294                gajim.logger.set_read_messages([id]) 
     295 
     296        def policy(self, opdata=None, context=None): 
     297                policy = gajim.config.get_per("contacts", 
     298                        gajim.get_jid_without_resource(context.username), "otr_flags") 
     299                if policy <= 0: 
     300                        policy = gajim.config.get_per("accounts", opdata['account'], "otr_flags") 
     301                return policy 
     302 
     303        def create_privkey(self, opdata="", accountname="", protocol=""): 
     304                dialog = gtk.Dialog(title=_("Generating..."), parent=gajim.interface.roster.window, 
     305                        flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) 
     306                permlabel = gtk.Label("Generating a private key for %s..."%accountname) 
     307                permlabel.set_padding(20,20) 
     308                dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, False) 
     309                dialog.connect("destroy", otr_dialog_destroy) 
     310                dialog.connect("response", otr_dialog_destroy) 
     311                dialog.vbox.pack_start(permlabel) 
     312                dialog.get_root_window().raise_() 
     313                dialog.show_all() 
     314                dialog.map() 
     315                for c in dialog.get_children(): 
     316                        c.show_now() 
     317                        c.map() 
     318 
     319                while gtk.events_pending(): 
     320                        gtk.main_iteration(block=False) 
     321 
     322                otr.otrl_privkey_generate(gajim.otr_userstates[opdata['account']], 
     323                        os.path.join(gajimpaths.root, "%s.key"%opdata['account']).encode(), 
     324                        accountname, gajim.OTR_PROTO) 
     325                permlabel.set_text("Generating a private key for %s...\ndone."%accountname) 
     326                dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, True) 
     327 
     328        def is_logged_in(self, opdata={}, accountname="", protocol="", recipient=""): 
     329                return gajim.contacts.get_contact_from_full_jid(opdata['account'], recipient).show \ 
     330                        in ['dnd', 'xa', 'chat', 'online', 'away', 'invisible'] 
     331 
     332        def inject_message(self, opdata=None, accountname="", protocol="", recipient="", 
     333                        message=""): 
     334                msg_type = otr.otrl_proto_message_type(message) 
     335 
     336                if 'kwargs' not in opdata or 'urgent' in opdata: 
     337                        # don't use send_message here to have the message sent immediatly. 
     338                        # this results in being able to disconnect from OTR sessions before 
     339                        # quitting 
     340                        stanza = XmppMessage(to=recipient, body=message, typ="chat") 
     341                        gajim.connections[opdata['account']].connection.send(stanza, now=True) 
     342                        return 
     343 
     344                if msg_type == otr.OTRL_MSGTYPE_QUERY: 
     345                        # split away XHTML-contaminated explanatory message 
     346                        message = unicode(message.splitlines()[0]) 
     347                        message += u"\n%s has requested an Off-the-Record private " \ 
     348                                "conversation.  However, you do not have a plugin to " \ 
     349                                "support that.\nSee http://otr.cypherpunks.ca/ for more "\ 
     350                                "information."%gajim.get_jid_from_account(opdata['account']) 
     351 
     352                gajim.connections[opdata['account']].send_message(recipient, message, 
     353                        **opdata['kwargs']) 
     354 
     355        def notify(sef, opdata=None, username="", **kwargs): 
     356                self.gajim_log("Notify: "+str(kwargs), opdata['account'], username) 
     357 
     358        def display_otr_message(self, opdata=None, username="", msg="", **kwargs): 
     359                self.gajim_log("OTR Message: "+msg, opdata['account'], username) 
     360                return 0 
     361 
     362        def update_context_list(self, **kwargs): 
     363                # FIXME stub FIXME # 
     364                pass 
     365 
     366        def protocol_name(self, opdata=None, protocol=""): 
     367                return "XMPP" 
     368 
     369        def new_fingerprint(self, opdata=None, username="", fingerprint="", **kwargs): 
     370                self.gajim_log("New fingerprint for %s: %s"%(username, 
     371                        otr.otrl_privkey_hash_to_human(fingerprint)), opdata['account'], username) 
     372 
     373        def write_fingerprints(self, opdata=""): 
     374                otr.otrl_privkey_write_fingerprints(gajim.otr_userstates[opdata['account']], 
     375                        os.path.join(gajimpaths.root, "%s.fpr"%opdata['account']).encode()) 
     376 
     377        def gone_secure(self, opdata="", context=None): 
     378                trust = context.active_fingerprint.trust 
     379                if trust: 
     380                        trust = "verified" 
     381                else: 
     382                        trust = "unverified" 
     383                self.gajim_log("%s secured OTR connection started"%trust, 
     384                                opdata['account'], context.username, no_print=True) 
     385                 
     386                ctrl = gajim.interface.msg_win_mgr.get_control( 
     387                        gajim.get_jid_without_resource(unicode(context.username)), 
     388                                opdata['account']) 
     389                if ctrl: 
     390                        ctrl.update_otr(True) 
     391 
     392        def gone_insecure(self, opdata="", context=None): 
     393                self.gajim_log("Private conversation with %s lost.", opdata['account'], context.username) 
     394 
     395                ctrl = gajim.interface.msg_win_mgr.get_control( 
     396                        gajim.get_jid_without_resource(unicode(context.username)), 
     397                        opdata['account']) 
     398                if ctrl: 
     399                        ctrl.update_otr() 
     400 
     401        def still_secure(self, opdata=None, context=None, is_reply=0): 
     402                ctrl = gajim.interface.msg_win_mgr.get_control( 
     403                        gajim.get_jid_without_resource(unicode(context.username)), 
     404                        opdata['account']) 
     405                if ctrl: 
     406                        ctrl.update_otr(True) 
     407 
     408                self.gajim_log("OTR connection was refreshed", opdata['account'], 
     409                                context.username) 
     410 
     411        def log_message(self, opdata=None, message=""): 
     412                gajim.log.debug(message) 
     413 
     414        def max_message_size(self, **kwargs): 
     415                return 0 
     416 
     417        def account_name(self, opdata=None, account="",protocol=""): 
     418                return gajim.get_name_from_jid(opdata['account'], unicode(account)) 
     419 
     420gajim.otr_ui_ops = OtrlMessageAppOps() 
    255421 
    256422if verbose: gajim.verbose = True 
     
    31613327                        gajim.transport_avatar[a] = {} 
    31623328 
     3329                        if gajim.otr_module: 
     3330                                gajim.otr_userstates[a] = otr.otrl_userstate_create() 
     3331                                try: 
     3332                                        otr.otrl_privkey_read(gajim.otr_userstates[a], 
     3333                                                os.path.join(gajimpaths.root, "%s.key"%a).encode()) 
     3334                                except Exception, e: 
     3335                                        if hasattr(e,"os_errno") and e.os_errno == 2: 
     3336                                                print "didn't find otr keyfile "+ \ 
     3337                                                        (os.path.join(gajimpaths.root, "%s.key"%a).encode()) 
     3338                                                pass 
     3339                                try: 
     3340                                        otr.otrl_privkey_read_fingerprints(gajim.otr_userstates[a], 
     3341                                                os.path.join(gajimpaths.root, "%s.fpr"%a).encode(), (add_appdata, a)) 
     3342                                except Exception, e: 
     3343                                        if hasattr(e,"os_errno") and e.os_errno == 2: 
     3344                                                print "didn't find otr fingerprint file "+ \ 
     3345                                                        (os.path.join(gajimpaths.root, "%s.fpr"%a).encode()) 
     3346                                                pass 
     3347 
    31633348                if gajim.config.get('remote_control'): 
    31643349                        try: 
  • trunk/src/message_control.py

    r9178 r9602  
    144144                ''' 
    145145                jid = self.contact.jid 
     146                original_message = message 
    146147 
    147148                if not self.session: 
     
    151152                        self.set_session(new_session) 
    152153 
     154                if gajim.otr_module: 
     155                        if type == 'chat' and isinstance(message, unicode): 
     156                                d = {'kwargs':{'keyID':keyID, 'type':type, 
     157                                                'chatstate':chatstate, 'msg_id':msg_id, 
     158                                                'composing_xep':composing_xep, 'resource':self.resource, 
     159                                                'user_nick':user_nick, 'session':self.session, 
     160                                                'original_message':original_message}, 'account':self.account} 
     161         
     162                                new_msg = gajim.otr_module.otrl_message_sending( 
     163                                        gajim.otr_userstates[self.account], 
     164                                        (gajim.otr_ui_ops, d), 
     165                                        gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 
     166                                        self.contact.get_full_jid().encode(), message.encode(), None) 
     167 
     168                                context = gajim.otr_module.otrl_context_find( 
     169                                                gajim.otr_userstates[self.account], 
     170                                                self.contact.get_full_jid().encode(), 
     171                                                gajim.get_jid_from_account(self.account).encode(), 
     172                                                gajim.OTR_PROTO, 1)[0] 
     173 
     174                                print repr(context.accountname), repr(context.username) 
     175 
     176                                # we send all because inject_message can filter on HTML stuff then 
     177                                gajim.otr_module.otrl_message_fragment_and_send( 
     178                                                (gajim.otr_ui_ops, d), 
     179                                                context, new_msg, gajim.otr_module.OTRL_FRAGMENT_SEND_ALL) 
     180                                return 
     181 
    153182                # Send and update history 
    154183                return gajim.connections[self.account].send_message(jid, message, keyID, 
    155184                        type = type, chatstate = chatstate, msg_id = msg_id, 
    156185                        composing_xep = composing_xep, resource = self.resource, 
    157                         user_nick = user_nick, session = self.session) 
     186                        user_nick = user_nick, session = self.session, original_message = original_message) 
  • trunk/src/roster_window.py

    r9600 r9602  
    17721772                        elif gajim.sleeper_state[account] not in ('autoaway', 'autoxa'): 
    17731773                                gajim.sleeper_state[account] = 'off' 
     1774 
     1775                        if gajim.otr_module: 
     1776                                # disconnect from ENCRYPTED OTR contexts when going 
     1777                                # offline/invisible 
     1778                                if status == 'offline' or status == 'invisible': 
     1779                                        ctx = gajim.otr_userstates[account].context_root 
     1780                                        while ctx is not None: 
     1781                                                if ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED: 
     1782                                                        disconnected = True 
     1783                                                        gajim.otr_module.otrl_message_disconnect(gajim.otr_userstates[account], 
     1784                                                                        (gajim.otr_ui_ops, 
     1785                                                                        {'account':account,'urgent':True}), ctx.accountname, 
     1786                                                                        ctx.protocol, ctx.username) 
     1787                                                ctx = ctx.next 
    17741788                if to: 
    17751789                        gajim.connections[account].send_custom_status(status, txt, to)