PGP support !
This commit is contained in:
parent
c16544c059
commit
66d0415c40
4 changed files with 441 additions and 61 deletions
241
core/core.py
241
core/core.py
|
@ -22,6 +22,7 @@ import sys, os, time, string, logging
|
|||
import common.hub, common.optparser
|
||||
import common.jabber
|
||||
import socket, select, pickle
|
||||
import GnuPGInterface
|
||||
|
||||
|
||||
from common import i18n
|
||||
|
@ -47,6 +48,142 @@ def XMLunescape(txt):
|
|||
txt = txt.replace("&", "&")
|
||||
return txt
|
||||
|
||||
class MyGnuPG(GnuPGInterface.GnuPG):
|
||||
def __init__(self):
|
||||
GnuPGInterface.GnuPG.__init__(self)
|
||||
self.setup_my_options()
|
||||
|
||||
def setup_my_options(self):
|
||||
self.options.armor = 1
|
||||
self.options.meta_interactive = 0
|
||||
self.options.extra_args.append('--no-secmem-warning')
|
||||
|
||||
def _read_response(self, child_stdout):
|
||||
# Internal method: reads all the output from GPG, taking notice
|
||||
# only of lines that begin with the magic [GNUPG:] prefix.
|
||||
# (See doc/DETAILS in the GPG distribution for info on GPG's
|
||||
# output when --status-fd is specified.)
|
||||
#
|
||||
# Returns a dictionary, mapping GPG's keywords to the arguments
|
||||
# for that keyword.
|
||||
|
||||
resp = {}
|
||||
while 1:
|
||||
line = child_stdout.readline()
|
||||
if line == "": break
|
||||
line = string.rstrip( line )
|
||||
if line[0:9] == '[GNUPG:] ':
|
||||
# Chop off the prefix
|
||||
line = line[9:]
|
||||
L = string.split(line, None, 1)
|
||||
keyword = L[0]
|
||||
if len(L) > 1:
|
||||
resp[ keyword ] = L[1]
|
||||
else:
|
||||
resp[ keyword ] = ""
|
||||
return resp
|
||||
|
||||
def encrypt(self, string, recipients):
|
||||
self.options.recipients = recipients # a list!
|
||||
|
||||
proc = self.run(['--encrypt'], create_fhs=['stdin', 'stdout'])
|
||||
proc.handles['stdin'].write(string)
|
||||
proc.handles['stdin'].close()
|
||||
|
||||
output = proc.handles['stdout'].read()
|
||||
proc.handles['stdout'].close()
|
||||
|
||||
try: proc.wait()
|
||||
except IOError: pass
|
||||
return self.stripHeaderFooter(output)
|
||||
|
||||
def decrypt(self, string, keyID):
|
||||
proc = self.run(['--decrypt', '-q', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status'])
|
||||
enc = self.addHeaderFooter(string, 'MESSAGE')
|
||||
proc.handles['stdin'].write(enc)
|
||||
proc.handles['stdin'].close()
|
||||
|
||||
output = proc.handles['stdout'].read()
|
||||
proc.handles['stdout'].close()
|
||||
|
||||
resp = proc.handles['status'].read()
|
||||
proc.handles['status'].close()
|
||||
|
||||
try: proc.wait()
|
||||
except IOError: pass
|
||||
return output
|
||||
|
||||
def sign(self, string, keyID):
|
||||
proc = self.run(['-b', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status', 'stderr'])
|
||||
proc.handles['stdin'].write(string)
|
||||
proc.handles['stdin'].close()
|
||||
|
||||
output = proc.handles['stdout'].read()
|
||||
proc.handles['stdout'].close()
|
||||
proc.handles['stderr'].close()
|
||||
|
||||
stat = proc.handles['status']
|
||||
resp = self._read_response(stat)
|
||||
proc.handles['status'].close()
|
||||
|
||||
try: proc.wait()
|
||||
except IOError: pass
|
||||
if resp.has_key('BAD_PASSPHRASE'):
|
||||
return 'BAD_PASSPHRASE'
|
||||
elif resp.has_key('GOOD_PASSPHRASE'):
|
||||
return self.stripHeaderFooter(output)
|
||||
|
||||
def verify(self, str, sign):
|
||||
file = open('gpg_data', 'w+r')
|
||||
os.remove('gpg_data')
|
||||
fd = file.fileno()
|
||||
file.write(str)
|
||||
file.seek(0)
|
||||
|
||||
proc = self.run(['--verify', '--enable-special-filenames', '-', '-&%s'%fd], create_fhs=['stdin', 'status', 'stderr'])
|
||||
|
||||
file.close
|
||||
sign = self.addHeaderFooter(sign, 'SIGNATURE')
|
||||
proc.handles['stdin'].write(sign)
|
||||
proc.handles['stdin'].close()
|
||||
proc.handles['stderr'].close()
|
||||
|
||||
stat = proc.handles['status']
|
||||
resp = self._read_response(stat)
|
||||
proc.handles['status'].close()
|
||||
|
||||
try: proc.wait()
|
||||
except IOError: pass
|
||||
|
||||
keyid = ''
|
||||
if resp.has_key('GOODSIG'):
|
||||
keyid = string.split(resp['GOODSIG'])[0]
|
||||
return keyid
|
||||
|
||||
def stripHeaderFooter(self, data):
|
||||
"""Remove header and footer from data"""
|
||||
lines = string.split(data, '\n')
|
||||
while lines[0] != '':
|
||||
lines.remove(lines[0])
|
||||
while lines[0] == '':
|
||||
lines.remove(lines[0])
|
||||
i = 0
|
||||
for line in lines:
|
||||
if line:
|
||||
if line[0] == '-': break
|
||||
i = i+1
|
||||
line = string.join(lines[0:i], '\n')
|
||||
return line
|
||||
|
||||
def addHeaderFooter(self, data, type):
|
||||
"""Add header and footer from data"""
|
||||
out = "-----BEGIN PGP %s-----\n" % type
|
||||
out = out + "Version: PGP\n"
|
||||
out = out + "\n"
|
||||
out = out + data + "\n"
|
||||
out = out + "-----END PGP %s-----\n" % type
|
||||
return out
|
||||
|
||||
class GajimCore:
|
||||
"""Core"""
|
||||
def __init__(self, mode='client'):
|
||||
|
@ -65,9 +202,11 @@ class GajimCore:
|
|||
self.connected = {}
|
||||
#connexions {con: name, ...}
|
||||
self.connexions = {}
|
||||
self.gpg = {}
|
||||
for a in self.accounts:
|
||||
self.connected[a] = 0 #0:offline, 1:online, 2:away,
|
||||
#3:xa, 4:dnd, 5:invisible
|
||||
self.gpg[a] = MyGnuPG()
|
||||
self.myVCardID = []
|
||||
self.loadPlugins(self.cfgParser.tab['Core']['modules'])
|
||||
else:
|
||||
|
@ -158,7 +297,7 @@ class GajimCore:
|
|||
def vCardCB(self, con, vc):
|
||||
"""Called when we recieve a vCard
|
||||
Parse the vCard and send it to plugins"""
|
||||
vcard = {'jid': vc.getFrom().getBasic()}
|
||||
vcard = {'jid': vc.getFrom().getStripped()}
|
||||
if vc._getTag('vCard') == common.jabber.NS_VCARD:
|
||||
card = vc.getChildren()[0]
|
||||
for info in card.getChildren():
|
||||
|
@ -179,16 +318,33 @@ class GajimCore:
|
|||
typ = msg.getType()
|
||||
tim = msg.getTimestamp()
|
||||
tim = time.strptime(tim, "%Y%m%dT%H:%M:%S")
|
||||
msgtxt = msg.getBody()
|
||||
xtags = msg.getXNodes()
|
||||
encTag = None
|
||||
decmsg = ''
|
||||
for xtag in xtags:
|
||||
if xtag.getNamespace() == common.jabber.NS_XENCRYPTED:
|
||||
encTag = xtag
|
||||
break
|
||||
if encTag:
|
||||
#decrypt
|
||||
encmsg = encTag.getData()
|
||||
keyID = ''
|
||||
if self.cfgParser.tab[self.connexions[con]].has_key("keyid"):
|
||||
keyID = self.cfgParser.tab[self.connexions[con]]["keyid"]
|
||||
if keyID:
|
||||
decmsg = self.gpg[self.connexions[con]].decrypt(encmsg, keyID)
|
||||
if decmsg:
|
||||
msgtxt = decmsg
|
||||
if typ == 'error':
|
||||
self.hub.sendPlugin('MSGERROR', self.connexions[con], \
|
||||
(str(msg.getFrom()), msg.getErrorCode(), msg.getError(), \
|
||||
msg.getBody(), tim))
|
||||
(str(msg.getFrom()), msg.getErrorCode(), msg.getError(), msgtxt, tim))
|
||||
elif typ == 'groupchat':
|
||||
self.hub.sendPlugin('GC_MSG', self.connexions[con], \
|
||||
(str(msg.getFrom()), msg.getBody(), tim))
|
||||
(str(msg.getFrom()), msgtxt, tim))
|
||||
else:
|
||||
self.hub.sendPlugin('MSG', self.connexions[con], \
|
||||
(str(msg.getFrom()), msg.getBody(), tim))
|
||||
(str(msg.getFrom()), msgtxt, tim))
|
||||
# END messageCB
|
||||
|
||||
def presenceCB(self, con, prs):
|
||||
|
@ -200,19 +356,31 @@ class GajimCore:
|
|||
typ = prs.getType()
|
||||
if typ == None: typ = 'available'
|
||||
log.debug("PresenceCB : %s" % typ)
|
||||
xtags = prs.getXNodes()
|
||||
sigTag = None
|
||||
keyID = ''
|
||||
status = prs.getStatus()
|
||||
for xtag in xtags:
|
||||
if xtag.getNamespace() == common.jabber.NS_XSIGNED:
|
||||
sigTag = xtag
|
||||
break
|
||||
if sigTag:
|
||||
#verify
|
||||
sigmsg = sigTag.getData()
|
||||
keyID = self.gpg[self.connexions[con]].verify(status, sigmsg)
|
||||
if typ == 'available':
|
||||
show = prs.getShow()
|
||||
if not show:
|
||||
show = 'online'
|
||||
self.hub.sendPlugin('NOTIFY', self.connexions[con], \
|
||||
(prs.getFrom().getBasic(), show, prs.getStatus(), \
|
||||
prs.getFrom().getResource(), prio, prs.getRole(), \
|
||||
(prs.getFrom().getStripped(), show, status, \
|
||||
prs.getFrom().getResource(), prio, keyID, prs.getRole(), \
|
||||
prs.getAffiliation(), prs.getJid(), prs.getReason(), \
|
||||
prs.getActor(), prs.getStatusCode()))
|
||||
elif typ == 'unavailable':
|
||||
self.hub.sendPlugin('NOTIFY', self.connexions[con], \
|
||||
(prs.getFrom().getBasic(), 'offline', prs.getStatus(), \
|
||||
prs.getFrom().getResource(), prio, prs.getRole(), \
|
||||
(prs.getFrom().getStripped(), 'offline', status, \
|
||||
prs.getFrom().getResource(), prio, keyID, prs.getRole(), \
|
||||
prs.getAffiliation(), prs.getJid(), prs.getReason(), \
|
||||
prs.getActor(), prs.getStatusCode()))
|
||||
elif typ == 'subscribe':
|
||||
|
@ -222,20 +390,20 @@ class GajimCore:
|
|||
con.send(common.jabber.Presence(who, 'subscribed'))
|
||||
if string.find(who, "@") <= 0:
|
||||
self.hub.sendPlugin('NOTIFY', self.connexions[con], \
|
||||
(prs.getFrom().getBasic(), 'offline', 'offline', \
|
||||
prs.getFrom().getResource(), prio, None, None, None, None, \
|
||||
None, None))
|
||||
(prs.getFrom().getStripped(), 'offline', 'offline', \
|
||||
prs.getFrom().getResource(), prio, keyID, None, None, None, \
|
||||
None, None, None))
|
||||
else:
|
||||
txt = prs.getStatus()
|
||||
if not txt:
|
||||
txt = _("I would like to add you to my roster.")
|
||||
self.hub.sendPlugin('SUBSCRIBE', self.connexions[con], (who, txt))
|
||||
if not status:
|
||||
status = _("I would like to add you to my roster.")
|
||||
self.hub.sendPlugin('SUBSCRIBE', self.connexions[con], (who, \
|
||||
status))
|
||||
elif typ == 'subscribed':
|
||||
jid = prs.getFrom()
|
||||
self.hub.sendPlugin('SUBSCRIBED', self.connexions[con],\
|
||||
(jid.getBasic(), jid.getNode(), jid.getResource()))
|
||||
(jid.getStripped(), jid.getNode(), jid.getResource()))
|
||||
self.hub.queueIn.put(('UPDUSER', self.connexions[con], \
|
||||
(jid.getBasic(), jid.getNode(), ['general'])))
|
||||
(jid.getStripped(), jid.getNode(), ['general'])))
|
||||
#BE CAREFUL : no con.updateRosterItem() in a callback
|
||||
log.debug("we are now subscribed to %s" % who)
|
||||
elif typ == 'unsubscribe':
|
||||
|
@ -243,7 +411,7 @@ class GajimCore:
|
|||
elif typ == 'unsubscribed':
|
||||
log.debug("we are now unsubscribed to %s" % who)
|
||||
self.hub.sendPlugin('UNSUBSCRIBED', self.connexions[con], \
|
||||
prs.getFrom().getBasic())
|
||||
prs.getFrom().getStripped())
|
||||
elif typ == 'error':
|
||||
errmsg = prs.getError()
|
||||
errcode = prs.getErrorCode()
|
||||
|
@ -273,9 +441,9 @@ class GajimCore:
|
|||
self.hub.sendPlugin('WARNING', None, errmsg)
|
||||
else:
|
||||
self.hub.sendPlugin('NOTIFY', self.connexions[con], \
|
||||
(prs.getFrom().getBasic(), 'error', errmsg, \
|
||||
prs.getFrom().getResource(), prio, None, None, None, None, None,\
|
||||
None))
|
||||
(prs.getFrom().getStripped(), 'error', errmsg, \
|
||||
prs.getFrom().getResource(), prio, keyID, None, None, None, \
|
||||
None, None, None))
|
||||
# END presenceCB
|
||||
|
||||
def disconnectedCB(self, con):
|
||||
|
@ -463,6 +631,16 @@ class GajimCore:
|
|||
#('STATUS', account, (status, msg))
|
||||
elif ev[0] == 'STATUS':
|
||||
activ = 1
|
||||
signed = ''
|
||||
keyID = ''
|
||||
if self.cfgParser.tab[ev[1]].has_key("keyid"):
|
||||
keyID = self.cfgParser.tab[ev[1]]["keyid"]
|
||||
if keyID:
|
||||
signed = self.gpg[ev[1]].sign(ev[2][0], keyID)
|
||||
if signed == 'BAD_PASSPHRASE':
|
||||
signed = ''
|
||||
if self.connected[ev[1]] == 0:
|
||||
self.hub.sendPlugin('BAD_PASSPHRASE', ev[1], ())
|
||||
if self.cfgParser.tab[ev[1]].has_key('active'):
|
||||
activ = self.cfgParser.tab[ev[1]]['active']
|
||||
if (ev[2][0] != 'offline') and (self.connected[ev[1]] == 0) and \
|
||||
|
@ -479,7 +657,7 @@ class GajimCore:
|
|||
prio = 0
|
||||
if self.cfgParser.tab[ev[1]].has_key('priority'):
|
||||
prio = str(self.cfgParser.tab[ev[1]]['priority'])
|
||||
con.sendPresence(typ, prio, ev[2][0], ev[2][1])
|
||||
con.sendPresence(typ, prio, ev[2][0], ev[2][1], signed)
|
||||
self.hub.sendPlugin('STATUS', ev[1], ev[2][0])
|
||||
#ask our VCard
|
||||
iq = common.jabber.Iq(type="get")
|
||||
|
@ -502,12 +680,20 @@ class GajimCore:
|
|||
prio = 0
|
||||
if self.cfgParser.tab[ev[1]].has_key('priority'):
|
||||
prio = str(self.cfgParser.tab[ev[1]]['priority'])
|
||||
con.sendPresence(typ, prio, ev[2][0], ev[2][1])
|
||||
con.sendPresence(typ, prio, ev[2][0], ev[2][1], signed)
|
||||
self.hub.sendPlugin('STATUS', ev[1], ev[2][0])
|
||||
#('MSG', account, (jid, msg))
|
||||
#('MSG', account, (jid, msg, keyID))
|
||||
elif ev[0] == 'MSG':
|
||||
msg = common.jabber.Message(ev[2][0], ev[2][1])
|
||||
msgtxt = ev[2][1]
|
||||
msgenc = ''
|
||||
if ev[2][2]:
|
||||
#encrypt
|
||||
msgenc = self.gpg[ev[1]].encrypt(ev[2][1], [ev[2][2]])
|
||||
if msgenc: msgtxt = '[this message is encrypted]'
|
||||
msg = common.jabber.Message(ev[2][0], msgtxt)
|
||||
msg.setType('chat')
|
||||
if msgenc:
|
||||
msg.setX(common.jabber.NS_XENCRYPTED).insertData(msgenc)
|
||||
con.send(msg)
|
||||
self.hub.sendPlugin('MSGSENT', ev[1], ev[2])
|
||||
#('SUB', account, (jid, txt))
|
||||
|
@ -678,6 +864,9 @@ class GajimCore:
|
|||
else:
|
||||
con.send(common.jabber.Presence('%s/%s' % (ev[2][1], ev[2][0]), \
|
||||
'available', show=ev[2][2], status = ev[2][3]))
|
||||
#('PASSPHRASE', account, passphrase)
|
||||
elif ev[0] == 'PASSPHRASE':
|
||||
self.gpg[ev[1]].passphrase = ev[2]
|
||||
else:
|
||||
log.debug(_("Unknown Command %s") % ev[0])
|
||||
if self.mode == 'server':
|
||||
|
|
|
@ -183,7 +183,28 @@ class infoUser_Window:
|
|||
self.xml.signal_connect('on_remove_clicked', self.on_remove)
|
||||
self.xml.signal_connect('on_entry_new_key_press_event', \
|
||||
self.on_new_key_pressed)
|
||||
|
||||
|
||||
class passphrase_Window:
|
||||
"""Class for Passphrase Window"""
|
||||
def run(self):
|
||||
"""Wait for Ok button to be pressed and return passphrase"""
|
||||
rep = self.xml.get_widget("Passphrase").run()
|
||||
if rep == gtk.RESPONSE_OK:
|
||||
msg = self.entry.get_text()
|
||||
else:
|
||||
msg = -1
|
||||
self.xml.get_widget("Passphrase").destroy()
|
||||
return msg
|
||||
|
||||
def on_key_pressed(self, widget, event):
|
||||
if event.keyval == gtk.keysyms.Return:
|
||||
self.xml.get_widget("Passphrase").response(gtk.RESPONSE_OK)
|
||||
|
||||
def __init__(self):
|
||||
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'Passphrase', APP)
|
||||
self.entry = self.xml.get_widget("entry")
|
||||
self.xml.signal_connect('on_Passphrase_key_press_event', \
|
||||
self.on_key_pressed)
|
||||
|
||||
class awayMsg_Window:
|
||||
"""Class for Away Message Window"""
|
||||
|
|
|
@ -536,6 +536,34 @@
|
|||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkToggleButton" id="toggle_gpg">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NONE</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image169">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">4</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button_contact">
|
||||
<property name="visible">True</property>
|
||||
|
@ -7752,4 +7780,123 @@ when NOT online</property>
|
|||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkDialog" id="Passphrase">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Passphrase</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="has_separator">True</property>
|
||||
<signal name="key_press_event" handler="on_Passphrase_key_press_event" last_modification_time="Thu, 07 Oct 2004 14:25:48 GMT"/>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area3">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancelbutton1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-6</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="okbutton2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-5</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox30">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label148">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Enter your passphrase</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">5</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char" translatable="yes">*</property>
|
||||
<property name="activates_default">False</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
|
|
|
@ -163,7 +163,8 @@ class user:
|
|||
self.sub = ''
|
||||
self.resource = ''
|
||||
self.priority = 0
|
||||
elif len(args) == 8:
|
||||
self.keyID = ''
|
||||
elif len(args) == 9:
|
||||
self.jid = args[0]
|
||||
self.name = args[1]
|
||||
self.groups = args[2]
|
||||
|
@ -172,6 +173,7 @@ class user:
|
|||
self.sub = args[5]
|
||||
self.resource = args[6]
|
||||
self.priority = args[7]
|
||||
self.keyID = args[8]
|
||||
else: raise TypeError, _('bad arguments')
|
||||
|
||||
|
||||
|
@ -248,7 +250,10 @@ class message_Window:
|
|||
end_iter = txt_buffer.get_end_iter()
|
||||
txt = txt_buffer.get_text(start_iter, end_iter, 0)
|
||||
if txt != '':
|
||||
self.plugin.send('MSG', self.account, (self.user.jid, txt))
|
||||
keyID = ''
|
||||
if self.xml.get_widget('toggle_gpg').get_active():
|
||||
keyID = self.keyID
|
||||
self.plugin.send('MSG', self.account, (self.user.jid, txt, keyID))
|
||||
txt_buffer.set_text('', -1)
|
||||
self.print_conversation(txt, self.user.jid)
|
||||
widget.grab_focus()
|
||||
|
@ -275,6 +280,7 @@ class message_Window:
|
|||
self.user = user
|
||||
self.plugin = plugin
|
||||
self.account = account
|
||||
self.keyID = self.user.keyID
|
||||
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'Chat', APP)
|
||||
self.window = self.xml.get_widget('Chat')
|
||||
self.window.set_title('Chat with ' + user.name + " (" + account + ")")
|
||||
|
@ -287,6 +293,8 @@ class message_Window:
|
|||
self.xml.get_widget('button_contact').set_label(user.name + ' <'\
|
||||
+ user.jid + '>')
|
||||
self.xml.get_widget('button_contact').set_resize_mode(gtk.RESIZE_QUEUE)
|
||||
if not self.keyID:
|
||||
self.xml.get_widget('toggle_gpg').set_sensitive(False)
|
||||
message = self.xml.get_widget('message')
|
||||
message.grab_focus()
|
||||
conversation = self.xml.get_widget('conversation')
|
||||
|
@ -419,7 +427,6 @@ class gc:
|
|||
start_iter = txt_buffer.get_start_iter()
|
||||
end_iter = txt_buffer.get_end_iter()
|
||||
txt = txt_buffer.get_text(start_iter, end_iter, 0)
|
||||
print self.jid
|
||||
if txt != '':
|
||||
self.plugin.send('GC_MSG', self.account, (self.jid, txt))
|
||||
txt_buffer.set_text('', -1)
|
||||
|
@ -878,7 +885,7 @@ class roster_Window:
|
|||
model.append(None, (self.pixbufs[status], account, 'account', account,\
|
||||
FALSE))
|
||||
|
||||
def add_user_to_roster(self, jid, account):
|
||||
def add_user_to_roster(self, jid, account, keyID):
|
||||
"""Add a user to the roster and add groups if they aren't in roster"""
|
||||
showOffline = self.plugin.config['showoffline']
|
||||
if not self.contacts[account].has_key(jid):
|
||||
|
@ -1009,7 +1016,8 @@ class roster_Window:
|
|||
for acct in self.contacts.keys():
|
||||
self.add_account_to_roster(acct)
|
||||
for jid in self.contacts[acct].keys():
|
||||
self.add_user_to_roster(jid, acct)
|
||||
#TODO: get the good keyID
|
||||
self.add_user_to_roster(jid, acct, '')
|
||||
|
||||
def mklists(self, array, account):
|
||||
"""fill self.contacts and self.groups"""
|
||||
|
@ -1038,7 +1046,7 @@ class roster_Window:
|
|||
show = 'offline'
|
||||
|
||||
user1 = user(ji, name, array[jid]['groups'], show, \
|
||||
array[jid]['status'], array[jid]['sub'], resource, 0)
|
||||
array[jid]['status'], array[jid]['sub'], resource, 0, '')
|
||||
#when we draw the roster, we can't have twice the same user with
|
||||
# 2 resources
|
||||
self.contacts[account][ji] = [user1]
|
||||
|
@ -1067,13 +1075,14 @@ class roster_Window:
|
|||
iters = []
|
||||
else:
|
||||
if not self.get_user_iter(user.jid, account):
|
||||
self.add_user_to_roster(user.jid, account)
|
||||
self.add_user_to_roster(user.jid, account, user.keyID)
|
||||
self.redraw_jid(user.jid, account)
|
||||
users = self.contacts[account][user.jid]
|
||||
for u in users:
|
||||
if u.resource == user.resource:
|
||||
u.show = show
|
||||
u.status = status
|
||||
u.keyID = user.keyID
|
||||
break
|
||||
#Print status in chat window
|
||||
if self.plugin.windows[account]['chats'].has_key(user.jid):
|
||||
|
@ -1299,9 +1308,9 @@ class roster_Window:
|
|||
self.plugin.send('SUB', account, (jid, txt))
|
||||
if not self.contacts[account].has_key(jid):
|
||||
user1 = user(jid, jid, ['general'], 'requested', \
|
||||
'requested', 'sub', '', 0)
|
||||
'requested', 'sub', '', 0, '')
|
||||
self.contacts[account][jid] = [user1]
|
||||
self.add_user_to_roster(jid, account)
|
||||
self.add_user_to_roster(jid, account, '')
|
||||
|
||||
def on_treeview_event(self, widget, event):
|
||||
"""popup user's group's or agent menu"""
|
||||
|
@ -1345,20 +1354,35 @@ class roster_Window:
|
|||
self.remove_user(u, account)
|
||||
del self.contacts[account][u.jid]
|
||||
|
||||
def change_status(self, widget, account, status):
|
||||
if status != 'online' and status != 'offline':
|
||||
w = awayMsg_Window()
|
||||
txt = w.run()
|
||||
if txt != -1:
|
||||
self.plugin.send('STATUS', account, (status, txt))
|
||||
else:
|
||||
txt = status
|
||||
self.plugin.send('STATUS', account, (status, txt))
|
||||
def send_status(self, account, status, txt):
|
||||
if status != 'offline':
|
||||
keyid = None
|
||||
if self.plugin.accounts[account].has_key("keyid"):
|
||||
keyid = self.plugin.accounts[account]["keyid"]
|
||||
if keyid and not self.plugin.connected[account]:
|
||||
passphrase = ''
|
||||
#TODO: ask passphrase
|
||||
w = passphrase_Window()
|
||||
passphrase = w.run()
|
||||
if passphrase == -1:
|
||||
passphrase = ''
|
||||
self.plugin.send('PASSPHRASE', account, passphrase)
|
||||
self.plugin.send('STATUS', account, (status, txt))
|
||||
if status == 'online':
|
||||
self.plugin.sleeper_state[account] = 1
|
||||
else:
|
||||
self.plugin.sleeper_state[account] = 0
|
||||
|
||||
def change_status(self, widget, account, status):
|
||||
if status != 'online' and status != 'offline':
|
||||
w = awayMsg_Window()
|
||||
txt = w.run()
|
||||
if txt == -1:
|
||||
return
|
||||
else:
|
||||
txt = status
|
||||
self.send_status(account, status, txt)
|
||||
|
||||
def on_optionmenu_changed(self, widget):
|
||||
"""When we change our status"""
|
||||
optionmenu = self.xml.get_widget('optionmenu')
|
||||
|
@ -1377,11 +1401,7 @@ class roster_Window:
|
|||
warning_Window(_("You must setup an account before connecting to jabber network."))
|
||||
return
|
||||
for acct in accounts:
|
||||
self.plugin.send('STATUS', acct, (status, txt))
|
||||
if status == 'online':
|
||||
self.plugin.sleeper_state[acct] = 1
|
||||
else:
|
||||
self.plugin.sleeper_state[acct] = 0
|
||||
self.send_status(acct, status, txt)
|
||||
|
||||
def set_optionmenu(self):
|
||||
#table to change index in plugin.connected to index in optionmenu
|
||||
|
@ -1423,9 +1443,9 @@ class roster_Window:
|
|||
"""when we receive a message"""
|
||||
if not self.contacts[account].has_key(jid):
|
||||
user1 = user(jid, jid, ['not in list'], \
|
||||
'not in list', 'not in list', 'none', '', 0)
|
||||
'not in list', 'not in list', 'none', '', 0, '')
|
||||
self.contacts[account][jid] = [user1]
|
||||
self.add_user_to_roster(jid, account)
|
||||
self.add_user_to_roster(jid, account, '')
|
||||
iters = self.get_user_iter(jid, account)
|
||||
if iters:
|
||||
path = self.tree.get_model().get_path(iters[0])
|
||||
|
@ -1445,7 +1465,7 @@ class roster_Window:
|
|||
# tim = time.strftime("[%H:%M:%S]")
|
||||
self.plugin.queues[account][jid].put((msg, tim))
|
||||
if not path:
|
||||
self.add_user_to_roster(jid, account)
|
||||
self.add_user_to_roster(jid, account, '')
|
||||
iters = self.get_user_iter(jid, account)
|
||||
path = self.tree.get_model().get_path(iters[0])
|
||||
self.tree.expand_row(path[0:1], FALSE)
|
||||
|
@ -1747,7 +1767,8 @@ class roster_Window:
|
|||
parent_i = model.iter_parent(iter_source)
|
||||
if model.iter_n_children(parent_i) == 1: #this was the only child
|
||||
model.remove(parent_i)
|
||||
self.add_user_to_roster(data, account)
|
||||
#TODO: get the good keyID
|
||||
self.add_user_to_roster(data, account, '')
|
||||
if context.action == gtk.gdk.ACTION_MOVE:
|
||||
context.finish(True, True, etime)
|
||||
return
|
||||
|
@ -2060,9 +2081,10 @@ class plugin:
|
|||
self.roster.on_status_changed(account, status)
|
||||
|
||||
def handle_event_notify(self, account, array):
|
||||
#('NOTIFY', account, (jid, status, message, resource, priority, role, \
|
||||
#affiliation, real_jid, reason, actor, statusCode))
|
||||
#('NOTIFY', account, (jid, status, message, resource, priority, keyID,
|
||||
# role, affiliation, real_jid, reason, actor, statusCode))
|
||||
jid = string.split(array[0], '/')[0]
|
||||
keyID = array[5]
|
||||
resource = array[3]
|
||||
if not resource:
|
||||
resource = ''
|
||||
|
@ -2088,12 +2110,13 @@ class plugin:
|
|||
luser[0].show != 'offline')) and not string.find(jid, "@") <= 0:
|
||||
user1 = user(user1.jid, user1.name, user1.groups, \
|
||||
user1.show, user1.status, user1.sub, user1.resource, \
|
||||
user1.priority)
|
||||
user1.priority, user1.keyID)
|
||||
luser.append(user1)
|
||||
user1.resource = resource
|
||||
user1.show = array[1]
|
||||
user1.status = array[2]
|
||||
user1.priority = priority
|
||||
user1.keyID = keyID
|
||||
if string.find(jid, "@") <= 0:
|
||||
#It must be an agent
|
||||
if self.roster.contacts[account].has_key(ji):
|
||||
|
@ -2105,8 +2128,8 @@ class plugin:
|
|||
elif self.windows[account]['gc'].has_key(ji):
|
||||
#it is a groupchat presence
|
||||
self.windows[account]['gc'][ji].chg_user_status(resource, array[1],\
|
||||
array[2], array[5], array[6], array[7], array[8], array[9], \
|
||||
array[10], account)
|
||||
array[2], array[6], array[7], array[8], array[9], array[10], \
|
||||
array[11], account)
|
||||
|
||||
def handle_event_msg(self, account, array):
|
||||
#('MSG', account, (user, msg, time))
|
||||
|
@ -2137,9 +2160,9 @@ class plugin:
|
|||
self.roster.redraw_jid(u.jid, account)
|
||||
else:
|
||||
user1 = user(jid, jid, ['general'], 'online', \
|
||||
'online', 'to', array[2], 0)
|
||||
'online', 'to', array[2], 0, '')
|
||||
self.roster.contacts[account][jid] = [user1]
|
||||
self.roster.add_user_to_roster(jid, account)
|
||||
self.roster.add_user_to_roster(jid, account, '')
|
||||
warning_Window(_("You are now authorized by %s") % jid)
|
||||
|
||||
def handle_event_unsubscribed(self, account, jid):
|
||||
|
|
Loading…
Add table
Reference in a new issue