diff --git a/gotr/otrmodule.py b/gotr/otrmodule.py index 5daa0fbecd3e82ab903a10fb1283aeeacc528448..64638e0aa9a468ad621f9194b05ae6b82e99b4bb 100644 --- a/gotr/otrmodule.py +++ b/gotr/otrmodule.py @@ -74,148 +74,147 @@ try: import potr if not hasattr(potr, 'VERSION') or potr.VERSION < MINVERSION: raise ImportError('old / unsupported python-otr version') -except ImportError: - HAS_POTR = False -def get_jid_from_fjid(fjid): - return gajim.get_room_and_nick_from_fjid(fjid)[0] - -class GajimContext(potr.context.Context): - # self.peer is fjid - # self.jid does not contain resource - __slots__ = ['smpWindow', 'jid'] - - def __init__(self, account, peer): - super(GajimContext, self).__init__(account, peer) - self.jid = get_jid_from_fjid(peer) - self.trustName = self.jid - self.smpWindow = ui.ContactOtrSmpWindow(self) - - def inject(self, msg, appdata=None): - log.debug('inject(appdata=%s)', appdata) - msg = unicode(msg) - account = self.user.accountname - - stanza = common.xmpp.Message(to=self.peer, body=msg, typ='chat') - if appdata is not None: - session = appdata.get('session', None) - if session is not None: - stanza.setThread(session.thread_id) - gajim.connections[account].connection.send(stanza, now=True) - - def setState(self, newstate): - if self.state == potr.context.STATE_ENCRYPTED: - # we were encrypted - if newstate == potr.context.STATE_ENCRYPTED: - # and are still -> it's just a refresh - OtrPlugin.gajim_log( - _('Private conversation with %s refreshed.') % self.peer, - self.user.accountname, self.peer) - elif newstate == potr.context.STATE_FINISHED: - # and aren't anymore -> other side disconnected - OtrPlugin.gajim_log(_('%s has ended his/her private ' - 'conversation with you. You should do the same.') - % self.peer, self.user.accountname, self.peer) - else: - if newstate == potr.context.STATE_ENCRYPTED: - # we are now encrypted - trust = self.getCurrentTrust() - if trust is None: - fpr = str(self.getCurrentKey()) - OtrPlugin.gajim_log(_('New fingerprint for %(peer)s: %(fpr)s') - % {'peer': self.peer, 'fpr': fpr}, + def get_jid_from_fjid(fjid): + return gajim.get_room_and_nick_from_fjid(fjid)[0] + + class GajimContext(potr.context.Context): + # self.peer is fjid + # self.jid does not contain resource + __slots__ = ['smpWindow', 'jid'] + + def __init__(self, account, peer): + super(GajimContext, self).__init__(account, peer) + self.jid = get_jid_from_fjid(peer) + self.trustName = self.jid + self.smpWindow = ui.ContactOtrSmpWindow(self) + + def inject(self, msg, appdata=None): + log.debug('inject(appdata=%s)', appdata) + msg = unicode(msg) + account = self.user.accountname + + stanza = common.xmpp.Message(to=self.peer, body=msg, typ='chat') + if appdata is not None: + session = appdata.get('session', None) + if session is not None: + stanza.setThread(session.thread_id) + gajim.connections[account].connection.send(stanza, now=True) + + def setState(self, newstate): + if self.state == potr.context.STATE_ENCRYPTED: + # we were encrypted + if newstate == potr.context.STATE_ENCRYPTED: + # and are still -> it's just a refresh + OtrPlugin.gajim_log( + _('Private conversation with %s refreshed.') % self.peer, self.user.accountname, self.peer) - self.setCurrentTrust('') - trustStr = 'authenticated' if bool(trust) else '*unauthenticated*' + elif newstate == potr.context.STATE_FINISHED: + # and aren't anymore -> other side disconnected + OtrPlugin.gajim_log(_('%s has ended his/her private ' + 'conversation with you. You should do the same.') + % self.peer, self.user.accountname, self.peer) + else: + if newstate == potr.context.STATE_ENCRYPTED: + # we are now encrypted + trust = self.getCurrentTrust() + if trust is None: + fpr = str(self.getCurrentKey()) + OtrPlugin.gajim_log(_('New fingerprint for %(peer)s: %(fpr)s') + % {'peer': self.peer, 'fpr': fpr}, + self.user.accountname, self.peer) + self.setCurrentTrust('') + trustStr = 'authenticated' if bool(trust) else '*unauthenticated*' + OtrPlugin.gajim_log( + _('%(trustStr)s secured OTR conversation with %(peer)s started') + % {'trustStr': trustStr, 'peer': self.peer}, + self.user.accountname, self.peer) + + if self.state != potr.context.STATE_PLAINTEXT and \ + newstate == potr.context.STATE_PLAINTEXT: + # we are now plaintext OtrPlugin.gajim_log( - _('%(trustStr)s secured OTR conversation with %(peer)s started') - % {'trustStr': trustStr, 'peer': self.peer}, - self.user.accountname, self.peer) - - if self.state != potr.context.STATE_PLAINTEXT and \ - newstate == potr.context.STATE_PLAINTEXT: - # we are now plaintext - OtrPlugin.gajim_log( - _('Private conversation with %s lost.') % self.peer, - self.user.accountname, self.peer) - - super(GajimContext, self).setState(newstate) - OtrPlugin.update_otr(self.peer, self.user.accountname) - self.user.plugin.update_context_list() - - def getPolicy(self, key): - ret = self.user.plugin.get_flags(self.user.accountname, self.jid)[key] - log.debug('getPolicy(key=%s) = %s', key, ret) - return ret - -class GajimOtrAccount(potr.context.Account): - contextclass = GajimContext - 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 dropPrivkey(self): - try: - os.remove(self.keyFilePath + '.key3') - except IOError, e: - if e.errno != 2: - log.exception('IOError occurred when removing key file for %s', - self.name) - self.privkey = None + _('Private conversation with %s lost.') % self.peer, + self.user.accountname, self.peer) - def loadPrivkey(self): - try: - with open(self.keyFilePath + '.key3', 'rb') as keyFile: - return potr.crypt.PK.parsePrivateKey(keyFile.read())[0] - except IOError, e: - if e.errno != 2: + super(GajimContext, self).setState(newstate) + OtrPlugin.update_otr(self.peer, self.user.accountname) + self.user.plugin.update_context_list() + + def getPolicy(self, key): + ret = self.user.plugin.get_flags(self.user.accountname, self.jid)[key] + log.debug('getPolicy(key=%s) = %s', key, ret) + return ret + + class GajimOtrAccount(potr.context.Account): + contextclass = GajimContext + 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 dropPrivkey(self): + try: + os.remove(self.keyFilePath + '.key3') + except IOError, e: + if e.errno != 2: + log.exception('IOError occurred when removing key file for %s', + self.name) + self.privkey = None + + def loadPrivkey(self): + try: + with open(self.keyFilePath + '.key3', 'rb') as keyFile: + return potr.crypt.PK.parsePrivateKey(keyFile.read())[0] + except IOError, e: + if e.errno != 2: + log.exception('IOError occurred when loading key file for %s', + self.name) + return None + + def savePrivkey(self): + try: + with open(self.keyFilePath + '.key3', 'wb') as keyFile: + keyFile.write(self.getPrivkey().serializePrivateKey()) + except IOError, e: log.exception('IOError occurred when loading key file for %s', self.name) - return None - - def savePrivkey(self): - try: - with open(self.keyFilePath + '.key3', 'wb') as keyFile: - keyFile.write(self.getPrivkey().serializePrivateKey()) - except IOError, e: - log.exception('IOError occurred when loading key file for %s', - self.name) - - def loadTrusts(self, newCtxCb=None): - ''' load the fingerprint trustdb ''' - # it has the same format as libotr, therefore the - # redundant account / proto field - try: - with open(self.keyFilePath + '.fpr', 'r') as fprFile: - for line in fprFile: - ctx, acc, proto, fpr, trust = line[:-1].split('\t') - - if acc != self.name or proto != PROTOCOL: - continue - jid = get_jid_from_fjid(ctx) - self.setTrust(jid, fpr, trust) - except IOError, e: - if e.errno != 2: + def loadTrusts(self, newCtxCb=None): + ''' load the fingerprint trustdb ''' + # it has the same format as libotr, therefore the + # redundant account / proto field + try: + with open(self.keyFilePath + '.fpr', 'r') as fprFile: + for line in fprFile: + ctx, acc, proto, fpr, trust = line[:-1].split('\t') + + if acc != self.name or proto != PROTOCOL: + continue + + jid = get_jid_from_fjid(ctx) + self.setTrust(jid, fpr, trust) + except IOError, e: + if e.errno != 2: + log.exception('IOError occurred when loading fpr file for %s', + self.name) + + def saveTrusts(self): + try: + with open(self.keyFilePath + '.fpr', 'w') as fprFile: + for uid, trusts in self.trusts.iteritems(): + for fpr, trustVal in trusts.iteritems(): + fprFile.write('\t'.join( + (uid, self.name, PROTOCOL, fpr, trustVal))) + fprFile.write('\n') + except IOError, e: log.exception('IOError occurred when loading fpr file for %s', self.name) - - def saveTrusts(self): - try: - with open(self.keyFilePath + '.fpr', 'w') as fprFile: - for uid, trusts in self.trusts.iteritems(): - for fpr, trustVal in trusts.iteritems(): - fprFile.write('\t'.join( - (uid, self.name, PROTOCOL, fpr, trustVal))) - fprFile.write('\n') - except IOError, e: - log.exception('IOError occurred when loading fpr file for %s', - self.name) - +except ImportError: + HAS_POTR = False def otr_dialog_destroy(widget, *args, **kwargs): widget.destroy() @@ -236,15 +235,19 @@ class OtrPlugin(GajimPlugin): self.gui_extension_points = { 'chat_control' : (self.cc_connect, self.cc_disconnect) } - - for acc in gajim.contacts.get_accounts(): - self.us[acc] = GajimOtrAccount(self, acc) - self.us[acc].loadTrusts() - - acc = str(acc) - if acc not in self.config or None not in self.config[acc]: - self.config[acc] = {None:DEFAULTFLAGS.copy()} - self.update_context_list() + if not HAS_POTR: + self.activatable = False + self.available_text = 'potr is not installed. Get it from %s' % \ + 'https://github.com/afflux/pure-python-otr' + else: + for acc in gajim.contacts.get_accounts(): + self.us[acc] = GajimOtrAccount(self, acc) + self.us[acc].loadTrusts() + + acc = str(acc) + if acc not in self.config or None not in self.config[acc]: + self.config[acc] = {None:DEFAULTFLAGS.copy()} + self.update_context_list() @log_calls('OtrPlugin') def activate(self): diff --git a/gotr/ui.py b/gotr/ui.py index 17459714dbc0562c7706a3be42308a634d69fd5d..75e77d88c59f1a2cc4564a2cae66cfff57bdf4a2 100644 --- a/gotr/ui.py +++ b/gotr/ui.py @@ -24,7 +24,11 @@ from common import gajim from plugins.gui import GajimPluginConfigDialog import otrmodule -import potr +HAS_PORT = True +try: + import potr +except: + HAS_POTR = False class OtrPluginConfigDialog(GajimPluginConfigDialog):