Newer
Older
exec python -OOt "$0" ${1+"$@"}
## - Yann Le Boulanger <asterix@lagaule.org>
## - Vincent Hanquez <tab@snarc.org>

nicfit
committed
## - Travis Shirk <travis@pobox.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
from common import i18n
i18n.init()
_ = i18n._
try:
import gtk
except RuntimeError, msg:
if str(msg) == 'could not open display':
print >> sys.stderr, _('Gajim needs Xserver to run. Quiting...')
if gtk.pygtk_version < (2, 6, 0):
print >> sys.stderr, _('Gajim needs PyGTK 2.6+ to run. Quiting...')
sys.exit()
elif gtk.gtk_version < (2, 6, 0):
print >> sys.stderr, _('Gajim needs GTK 2.6+ to run. Quiting...')
sys.exit()
try:
import gtk.glade # check if user has libglade (in pygtk and in gtk)
except ImportError:
pritext = _('GTK+ runtime is missing libglade support')
if os.name == 'nt':
sectext = _('Please remove your current GTK+ runtime and install the latest stable version from %s') % 'http://gladewin32.sourceforge.net'
else:
sectext = _('Please make sure that gtk and pygtk have libglade support in your system.')
dlg = gtk.MessageDialog(None,
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message_format = pritext)
dlg.format_secondary_text(sectext)
dlg.run()
dlg.destroy()
sys.exit()
path = os.getcwd()
if '.svn' in os.listdir(path):
# import gtkexcepthook only for those that run svn
# those than run with --verbose run from terminal so no need to care
# about those
import gtkexcepthook
del path
if sys.version[:4] >= '2.4':
gobject.threads_init()
import signal
import getopt
import time
import base64
import gtkgui_helpers
import notify
import common.sleepy
import check_for_new_version
from common import socks5
from common import gajim
from common import connection
from common import helpers
from common import optparser
profile = ''
try:
opts, args = getopt.getopt(sys.argv[1:], 'hvp:', ['help', 'verbose',
'profile=', 'sm-config-prefix=', 'sm-client-id='])
except getopt.error, msg:
print msg
print 'for help use --help'
sys.exit(2)
for o, a in opts:
elif o in ('-v', '--verbose'):
gajim.verbose = True
elif o in ('-p', '--profile'): # gajim --profile name
profile = a

nkour
committed
config_filename = os.path.expanduser('~/.gajim/config')
if os.name == 'nt':
try:
# Documents and Settings\[User Name]\Application Data\Gajim\logs
config_filename = os.environ['appdata'] + '/Gajim/config'
except KeyError:

nkour
committed
if profile:

nkour
committed
parser = optparser.OptionsParser(config_filename)
'''Information concerning each contact'''
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
ask='', resource='', priority=5, keyID='', role='', affiliation='',
self.jid = jid
self.name = name
self.groups = groups
self.show = show
self.status = status
self.sub = sub
self.ask = ask
self.resource = resource
self.priority = priority
self.keyID = keyID
self.role = role
self.affiliation = affiliation
# please read jep-85 http://www.jabber.org/jeps/jep-0085.html
# we keep track of jep85 support by the peer by three extra states:
# None, False and 'ask'
# None if no info about peer
# False if peer does not support jep85
# 'ask' if we sent the first 'active' chatstate and are waiting for reply
# this holds what WE SEND to contact (the current chatstate)
import roster_window
import systray
import dialogs
import config
GTKGUI_GLADE = 'gtkgui.glade'
class Interface:

Yann Leboulanger
committed
def handle_event_roster(self, account, data):
self.roster.fill_contacts_and_groups_dicts(data, account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Roster', (account, data))

Yann Leboulanger
committed
def handle_event_warning(self, unused, data):
#('WARNING', account, (title_text, section_text))

nkour
committed
dialogs.WarningDialog(data[0], data[1]).get_response()

Yann Leboulanger
committed
def handle_event_error(self, unused, data):
#('ERROR', account, (title_text, section_text))

nkour
committed
dialogs.ErrorDialog(data[0], data[1]).get_response()
def handle_event_information(self, unused, data):
#('INFORMATION', account, (title_text, section_text))
dialogs.InformationDialog(data[0], data[1])
def handle_event_ask_new_nick(self, account, data):
#('ASK_NEW_NICK', account, (room_jid, title_text, prompt_text, proposed_nick))

nkour
committed
room_jid = data[0]
title = data[1]
prompt = data[2]
proposed_nick = data[3]
w = self.windows[account]['gc']
if w.has_key(room_jid): # user may close the window before we are here
w[room_jid].show_change_nick_input_dialog(title, prompt, proposed_nick,
room_jid)
def handle_event_http_auth(self, account, data):

nicfit
committed
#('HTTP_AUTH', account, (method, url, transaction_id, iq_obj))
dialog = dialogs.ConfirmationDialog(_('HTTP (%s) Authorization for %s (id: %s)') \
% (data[0], data[1], data[2]), _('Do you accept this request?'))
if dialog.get_response() == gtk.RESPONSE_OK:
answer = 'yes'
else:
answer = 'no'
gajim.connections[account].build_http_auth_answer(data[2], answer)
def handle_event_error_answer(self, account, array):
#('ERROR_ANSWER', account, (id, jid_from. errmsg, errcode))
id, jid_from, errmsg, errcode = array
if unicode(errcode) in ('403', '406') and id:
ft = self.windows['file_transfers']
sid = id
if len(id) > 3 and id[2] == '_':
sid = id[3:]
if ft.files_props['s'].has_key(sid):
file_props = ft.files_props['s'][sid]
file_props['error'] = -4
self.handle_event_file_request_error(account,
(jid_from, file_props))
conn = gajim.connections[account]
conn.disconnect_transfer(file_props)
return
elif unicode(errcode) == '404':
sid = id
if len(id) > 3 and id[2] == '_':
sid = id[3:]
if conn.files_props.has_key(sid):
file_props = conn.files_props[sid]
self.handle_event_file_send_error(account,
(jid_from, file_props))
conn.disconnect_transfer(file_props)
return
if jid_from in self.windows[account]['gc']:
self.windows[account]['gc'][jid_from].print_conversation(
def handle_event_con_type(self, account, con_type):
# ('CON_TYPE', account, con_type) which can be 'ssl', 'tls', 'tcp'

Yann Leboulanger
committed
gajim.con_types[account] = con_type

Yann Leboulanger
committed
gajim.allow_notifications[account] = True
def handle_event_status(self, account, status): # OUR status
model = self.roster.status_combobox.get_model()
if status == 'offline':
model[self.roster.status_message_menuitem_iter][3] = False # sensitivity for this menuitem

Yann Leboulanger
committed
gajim.allow_notifications[account] = False
# we are disconnected from all gc
for room_jid in gajim.gc_connected[account]:
if self.windows[account]['gc'].has_key(room_jid):
self.windows[account]['gc'][room_jid].got_disconnected(room_jid)
else:
gobject.timeout_add(30000, self.allow_notif, account)
model[self.roster.status_message_menuitem_iter][3] = True # sensitivity for this menuitem
self.roster.on_status_changed(account, status)

Yann Leboulanger
committed
if account in self.show_vcard_when_connect:
jid = gajim.get_jid_from_account(account)
if not self.windows[account]['infos'].has_key('vcard'):
self.windows[account]['infos'][jid] = \
dialogs.VcardWindow(jid, account, True)
gajim.connections[account].request_vcard(jid)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('AccountPresence', (status, account))
def handle_event_notify(self, account, array):
#('NOTIFY', account, (jid, status, message, resource, priority, keyID))
# if we're here it means contact changed show
statuss = ['offline', 'error', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible']
jid = array[0].split('/')[0]
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
resource = array[3]
if not resource:
resource = ''
priority = array[4]
if jid.find('@') <= 0:
# It must be an agent
ji = jid.replace('@', '')

Yann Leboulanger
committed
if gajim.contacts[account].has_key(ji):
lcontact = gajim.contacts[account][ji]
contact1 = None
for c in lcontact:
if c.resource == resource:
contact1 = c
if contact1:
if contact1.show in statuss:
old_show = statuss.index(contact1.show)
if old_show == new_show and contact1.status == array[2]: #no change

Yann Leboulanger
committed
return
contact1 = gajim.contacts[account][ji][0]
if contact1.show in statuss:
old_show = statuss.index(contact1.show)
if (resources != [''] and (len(lcontact) != 1 or
lcontact[0].show != 'offline')) and jid.find('@') > 0:
contact1 = Contact(jid = contact1.jid, name = contact1.name,
groups = contact1.groups, show = contact1.show,
status = contact1.status, sub = contact1.sub, ask = contact1.ask,
resource = contact1.resource, priority = contact1.priority,
keyID = contact1.keyID)
lcontact.append(contact1)
contact1.resource = resource
if contact1.jid.find('@') > 0 and len(lcontact) == 1: # It's not an agent
if not contact1.jid in gajim.newly_added[account]:
gajim.newly_added[account].append(contact1.jid)
if contact1.jid in gajim.to_be_removed[account]:
gajim.to_be_removed[account].remove(contact1.jid)
gobject.timeout_add(5000, self.roster.remove_newly_added,
contact1.jid, account)
if old_show > 1 and new_show == 0 and gajim.connections[account].\
connected > 1:
if not contact1.jid in gajim.to_be_removed[account]:
gajim.to_be_removed[account].append(contact1.jid)
if contact1.jid in gajim.newly_added[account]:
gajim.newly_added[account].remove(contact1.jid)
self.roster.draw_contact(contact1.jid, account)
if not gajim.awaiting_events[account].has_key(jid):
gobject.timeout_add(5000, self.roster.really_remove_contact,
contact1, account)
contact1.show = array[1]
contact1.status = array[2]
contact1.priority = priority
contact1.keyID = keyID
if jid.find('@') <= 0:
# It must be an agent

Yann Leboulanger
committed
if gajim.contacts[account].has_key(ji):
# Update existing iter
self.roster.draw_contact(ji, account)
elif jid == gajim.get_jid_from_account(account):
# It's another of our resources. We don't need to see that!

Yann Leboulanger
committed
elif gajim.contacts[account].has_key(ji):
# reset chatstate if needed:
# (when contact signs out or has errors)
if array[1] in ('offline', 'error'):
contact1.chatstate = None
self.roster.chg_contact_status(contact1, array[1], array[2], account)
if old_show < 2 and new_show > 1:
if gajim.config.get_per('soundevents', 'contact_connected',
helpers.play_sound('contact_connected')
if not self.windows[account]['chats'].has_key(jid) and \
not gajim.awaiting_events[account].has_key(jid) and \
gajim.config.get('notify_on_signin') and \

Yann Leboulanger
committed
gajim.allow_notifications[account]:
show_notification = False
# check OUR status and if we allow notifications for that status
if gajim.config.get('autopopupaway'): # always notify
show_notification = True
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True
if show_notification:
notify.notify(_('Contact Signed In'), jid, account)
if self.remote and self.remote.is_enabled():

Yann Leboulanger
committed
elif old_show > 1 and new_show < 2:
if gajim.config.get_per('soundevents', 'contact_disconnected',
helpers.play_sound('contact_disconnected')
if not self.windows[account]['chats'].has_key(jid) and \
not gajim.awaiting_events[account].has_key(jid) and \
gajim.config.get('notify_on_signout'):
show_notification = False
# check OUR status and if we allow notifications for that status
if gajim.config.get('autopopupaway'): # always notify
show_notification = True
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True
if show_notification:
notify.notify(_('Contact Signed Out'), jid, account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('ContactAbsence', (account, array))
# FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) doesn't follow the JEP
# remove in 2007
# It's maybe a GC_NOTIFY (specialy for MSN gc)
self.handle_event_gc_notify(account, (jid, array[1], array[2], array[3], None, None, None, None, None, None, None))
def handle_event_msg(self, account, array):
#('MSG', account, (jid, msg, time, encrypted, msg_type, subject, chatstate))
jid = gajim.get_jid_without_resource(array[0])
resource = gajim.get_resource_from_jid(array[0])
msg_type = array[4]
if jid.find('@') <= 0:
jid = jid.replace('@', '')

Yann Leboulanger
committed

Yann Leboulanger
committed
show_notification = False
if gajim.config.get('notify_on_new_message'):
# check OUR status and if we allow notifications for that status
if gajim.config.get('autopopupaway'): # always show notification
show_notification = True
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True

Yann Leboulanger
committed
if self.windows[account]['gc'].has_key(jid): # it's a Private Message
fjid = array[0]

Yann Leboulanger
committed
if not self.windows[account]['chats'].has_key(fjid) and \
not gajim.awaiting_events[account].has_key(fjid):

Yann Leboulanger
committed
if show_notification:
notify.notify(

Yann Leboulanger
committed
_('New Private Message'), fjid, account, 'pm')
self.windows[account]['gc'][jid].on_private_message(jid, nick,
array[1], array[2])

Yann Leboulanger
committed
return
if gajim.config.get('ignore_unknown_contacts') and \

Yann Leboulanger
committed
not gajim.contacts[account].has_key(jid):
return
# Handle chat states
contact = gajim.get_first_contact_instance_from_jid(account, jid)
if self.windows[account]['chats'].has_key(jid):
chat_win = self.windows[account]['chats'][jid]
if chatstate is not None: # he or she sent us reply, so he supports jep85
if contact.chatstate == 'ask': # we were jep85 disco?
contact.chatstate = 'active' # no more
chat_win.handle_incoming_chatstate(account, jid, chatstate)

nicfit
committed
elif contact.chatstate != 'active':
# got no valid jep85 answer, peer does not support it
else:
# Brand new message, incoming.
if contact and chatstate == 'active':
contact.chatstate = chatstate
first = False
if not self.windows[account]['chats'].has_key(jid) and \
not gajim.awaiting_events[account].has_key(jid):
first = True

nkour
committed
if gajim.config.get('notify_on_new_message'):
show_notification = False
# check OUR status and if we allow notifications for that status
if gajim.config.get('autopopupaway'): # always show notification
show_notification = True
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True
if show_notification:
if msg_type == 'normal': # single message
notify.notify(
_('New Single Message'), jid, account, msg_type)
else: # chat message
notify.notify(
_('New Message'), jid, account, msg_type)
# array : (contact, msg, time, encrypted, msg_type, subject)
self.roster.on_message(jid, array[1], array[2], account, array[3],
msg_type, array[5], resource)
if gajim.config.get_per('soundevents', 'first_message_received',

Yann Leboulanger
committed
'enabled') and first:
helpers.play_sound('first_message_received')
if gajim.config.get_per('soundevents', 'next_message_received',

Yann Leboulanger
committed
'enabled') and not first:
helpers.play_sound('next_message_received')
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('NewMessage', (account, array))
def handle_event_msgerror(self, account, array):

Yann Leboulanger
committed
#('MSGERROR', account, (jid, error_code, error_msg, msg, time))
jid = jids[0]
gcs = self.windows[account]['gc']
if jid in gcs:
nick = jids[1]
if not self.windows[account]['chats'].has_key(fjid):
gc = gcs[jid]
tv = gc.list_treeview[jid]
model = tv.get_model()

Yann Leboulanger
committed
i = gc.get_contact_iter(jid, nick)
if i:
show = model[i][3]
else:
show = 'offline'
c = Contact(jid = fjid, name = nick, groups = ['none'],
self.roster.new_chat(c, account)
self.windows[account]['chats'][fjid].print_conversation(
'Error %s: %s' % (array[1], array[2]), fjid, 'status')
return
gcs[jid].print_conversation('Error %s: %s' % \

Yann Leboulanger
committed
(array[1], array[2]), jid)
if gcs[jid].get_active_jid() == jid:
gcs[jid].set_subject(jid,
gcs[jid].subjects[jid])
return
if jid.find('@') <= 0:
jid = jid.replace('@', '')

Yann Leboulanger
committed
self.roster.on_message(jid, _('error while sending') + \
' \"%s\" ( %s )' % (array[3], array[2]), array[4], account, \
msg_type='error')
def handle_event_msgsent(self, account, array):
msg = array[1]
# do not play sound when standalone chatstate message (eg no msg)
if msg and gajim.config.get_per('soundevents', 'message_sent', 'enabled'):
helpers.play_sound('message_sent')
def handle_event_subscribe(self, account, array):
#('SUBSCRIBE', account, (jid, text))

Yann Leboulanger
committed
dialogs.SubscriptionRequestWindow(array[0], array[1], account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Subscribe', (account, array))
def handle_event_subscribed(self, account, array):
#('SUBSCRIBED', account, (jid, resource))

Yann Leboulanger
committed
if gajim.contacts[account].has_key(jid):
c = gajim.get_first_contact_instance_from_jid(account, jid)
c.resource = array[1]
self.roster.remove_contact(c, account)
if _('not in the roster') in c.groups:
c.groups.remove(_('not in the roster'))
if len(c.groups) == 0:
c.groups = [_('General')]
self.roster.add_contact_to_roster(c.jid, account)
gajim.connections[account].update_contact(c.jid, c.name, c.groups)
keyID = ''
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
name = jid.split('@', 1)[0]
name = name.split('%', 1)[0]
contact1 = Contact(jid = jid, name = name, groups = [_('General')],
show = 'online', status = 'online', ask = 'to',
resource = array[1], keyID = keyID)
self.roster.add_contact_to_roster(jid, account)

nkour
committed
dialogs.InformationDialog(_('Authorization accepted'),
_('The contact "%s" has authorized you to see his or her status.')
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Subscribed', (account, array))
def handle_event_unsubscribed(self, account, jid):
dialogs.InformationDialog(_('Contact "%s" removed subscription from you') % jid,
if self.remote and self.remote.is_enabled():

Yann Leboulanger
committed
self.remote.raise_signal('Unsubscribed', (account, jid))
def handle_event_agent_info_error(self, account, agent):
#('AGENT_ERROR_INFO', account, (agent))
try:
gajim.connections[account].services_cache.agent_info_error(agent)
except AttributeError:
return
def handle_event_agent_items_error(self, account, agent):
#('AGENT_ERROR_INFO', account, (agent))
try:
gajim.connections[account].services_cache.agent_items_error(agent)
except AttributeError:
return
def handle_event_register_agent_info(self, account, array):
#('REGISTER_AGENT_INFO', account, (agent, infos, is_form))
if array[1].has_key('instructions'):

Yann Leboulanger
committed
config.ServiceRegistrationWindow(array[0], array[1], account,

nkour
committed
dialogs.ErrorDialog(_('Contact with "%s" cannot be established'\
% array[0]), _('Check your connection or try again later.')).get_response()

Yann Leboulanger
committed
def handle_event_agent_info_items(self, account, array):
#('AGENT_INFO_ITEMS', account, (agent, node, items))
try:
gajim.connections[account].services_cache.agent_items(array[0],
array[1], array[2])
except AttributeError:
return

Yann Leboulanger
committed
def handle_event_agent_info_info(self, account, array):
#('AGENT_INFO_INFO', account, (agent, node, identities, features, data))
try:
gajim.connections[account].services_cache.agent_info(array[0],
array[1], array[2], array[3], array[4])
except AttributeError:
return

Yann Leboulanger
committed
def handle_event_acc_ok(self, account, array):
#('ACC_OK', account, (config))
if self.windows.has_key('account_creation_wizard'):
self.windows['account_creation_wizard'].acc_is_ok(array)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('NewAccount', (account, array))
def handle_event_acc_not_ok(self, account, array):
#('ACC_NOT_OK', account, (reason))
if self.windows.has_key('account_creation_wizard'):
self.windows['account_creation_wizard'].acc_is_not_ok(array)
def handle_event_quit(self, p1, p2):

Yann Leboulanger
committed
self.roster.quit_gtkgui_interface()
def handle_event_myvcard(self, account, array):
if array.has_key('NICKNAME'):
nick = array['NICKNAME']

Yann Leboulanger
committed
gajim.nicks[account] = nick
if self.windows[account]['infos'].has_key(array['jid']):

Yann Leboulanger
committed
win = self.windows[account]['infos'][array['jid']]
win.set_values(array)
if account in self.show_vcard_when_connect:
win.xml.get_widget('information_notebook').set_current_page(-1)
win.xml.get_widget('set_avatar_button').clicked()
self.show_vcard_when_connect.remove(account)
def handle_event_vcard(self, account, vcard):
'''vcard holds the vcard data'''
jid = vcard['jid']
# vcard window
if self.windows[account]['infos'].has_key(jid):
win = self.windows[account]['infos'][jid]
elif self.windows[account]['infos'].has_key(jid + '/' + resource):
win = self.windows[account]['infos'][jid + '/' + resource]

Yann Leboulanger
committed
if win:
# show avatar in chat
if self.windows[account]['chats'].has_key(jid):
win = self.windows[account]['chats'][jid]
elif self.windows[account]['chats'].has_key(jid + '/' + resource):
win = self.windows[account]['chats'][jid + '/' + resource]
# FIXME: this will be removed when we have the thread working
self.remote.raise_signal('VcardInfo', (account, vcard))
def handle_event_os_info(self, account, array):
if self.windows[account]['infos'].has_key(array[0]):
win = self.windows[account]['infos'][array[0]]
elif self.windows[account]['infos'].has_key(array[0] + '/' + array[1]):
win = self.windows[account]['infos'][array[0] + '/' + array[1]]
if win:
win.set_os_info(array[1], array[2], array[3])
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('OsInfo', (account, array))
def handle_event_gc_notify(self, account, array):
#('GC_NOTIFY', account, (jid, status, message, resource,
# role, affiliation, jid, reason, actor, statusCode, newNick))
jid = array[0].split('/')[0]
resource = array[3]
if not resource:
resource = ''
if self.windows[account]['gc'].has_key(jid): # ji is then room_jid
#FIXME: upgrade the chat instances (for pm)
#FIXME: real_jid can be None
self.windows[account]['gc'][jid].chg_contact_status(jid, resource,
array[1], array[2], array[4], array[5], array[6], array[7],
array[8], array[9], array[10], account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('GCPresence', (account, array))
def handle_event_gc_msg(self, account, array):

Yann Leboulanger
committed
# ('GC_MSG', account, (jid, msg, time))

Yann Leboulanger
committed
room_jid = jids[0]
if not self.windows[account]['gc'].has_key(room_jid):

Yann Leboulanger
committed
# message from server
nick = ''

Yann Leboulanger
committed
# message from someone
nick = jids[1]
self.windows[account]['gc'][room_jid].on_message(room_jid, nick, array[1],
array[2])
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('GCMessage', (account, array))
def handle_event_gc_subject(self, account, array):
#('GC_SUBJECT', account, (jid, subject))
jid = jids[0]
if not self.windows[account]['gc'].has_key(jid):
return
self.windows[account]['gc'][jid].set_subject(jid, array[1])
if len(jids) > 1:
'%s has set the subject to %s' % (jids[1], array[1]), jid)
def handle_event_gc_config(self, account, array):
#('GC_CONFIG', account, (jid, config)) config is a dict
jid = array[0].split('/')[0]
if not self.windows[account]['gc_config'].has_key(jid):
self.windows[account]['gc_config'][jid] = \

Yann Leboulanger
committed
config.GroupchatConfigWindow(account, jid, array[1])
def handle_event_gc_invitation(self, account, array):
#('GC_INVITATION', (room_jid, jid_from, reason, password))

Yann Leboulanger
committed
dialogs.InvitationReceivedDialog(account, array[0], array[1],
def handle_event_bad_passphrase(self, account, array):
use_gpg_agent = gajim.config.get('use_gpg_agent')
if use_gpg_agent:
return
keyID = gajim.config.get_per('accounts', account, 'keyid')
self.roster.forget_gpg_passphrase(keyID)
dialogs.WarningDialog(_('Your passphrase is incorrect'),
_('You are currently connected without your OpenPGP key.')).get_response()

Yann Leboulanger
committed
def handle_event_roster_info(self, account, array):
#('ROSTER_INFO', account, (jid, name, sub, ask, groups))
jid = array[0]

Yann Leboulanger
committed
if not gajim.contacts[account].has_key(jid):

Yann Leboulanger
committed
return
contacts = gajim.contacts[account][jid]

Yann Leboulanger
committed
if not (array[2] or array[3]):
self.roster.remove_contact(contacts[0], account)

Yann Leboulanger
committed
del gajim.contacts[account][jid]

Yann Leboulanger
committed
#TODO if it was the only one in its group, remove the group
return
for contact in contacts:
contact.name = name
contact.sub = array[2]
contact.ask = array[3]
contact.groups = array[4]
self.roster.draw_contact(jid, account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('RosterInfo', (account, array))

Yann Leboulanger
committed
def handle_event_bookmarks(self, account, bms):
# ('BOOKMARKS', account, [{name,jid,autojoin,password,nick}, {}])
# We received a bookmark item from the server (JEP48)
# Auto join GC windows if neccessary
if bm['autojoin'] in ('1', 'true'):
self.roster.join_gc_room(account, bm['jid'], bm['nick'],
bm['password'])
self.roster.make_menu()
def handle_event_file_send_error(self, account, array):
jid = array[0]
file_props = array[1]
ft = self.windows['file_transfers']
ft.set_status(file_props['type'], file_props['sid'], 'stop')
if gajim.popup_window(account):
ft.show_send_error(file_props)
return
self.add_event(account, jid, 'file-send-error', file_props)
if gajim.show_notification(account):
notify.notify(_('File Transfer Error'),
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
def add_event(self, account, jid, typ, args):
'''add an event to the awaiting_events var'''
# We add it to the awaiting_events queue
# Do we have a queue?
qs = gajim.awaiting_events[account]
no_queue = False
if not qs.has_key(jid):
no_queue = True
qs[jid] = []
qs[jid].append((typ, args))
self.roster.nb_unread += 1
self.roster.show_title()
if no_queue: # We didn't have a queue: we change icons
self.roster.draw_contact(jid, account)
if self.systray_enabled:
self.systray.add_jid(jid, account, typ)
def remove_first_event(self, account, jid, typ = None):
qs = gajim.awaiting_events[account]
event = gajim.get_first_event(account, jid, typ)
qs[jid].remove(event)
self.roster.nb_unread -= 1
self.roster.show_title()
# Is it the last event?
if not len(qs[jid]):
del qs[jid]
self.roster.draw_contact(jid, account)
if self.systray_enabled:
self.systray.remove_jid(jid, account, typ)
def handle_event_file_request_error(self, account, array):
jid = array[0]
file_props = array[1]
ft = self.windows['file_transfers']
ft.set_status(file_props['type'], file_props['sid'], 'stop')
errno = file_props['error']
if gajim.popup_window(account):
if errno in (-4, -5):
ft.show_stopped(jid, file_props)
else:
ft.show_request_error(file_props)
return
if errno in (-4, -5):
msg_type = 'file-error'
else:
msg_type = 'file-request-error'
if gajim.show_notification(account):
notify.notify(_('File Transfer Error'),
def handle_event_file_request(self, account, array):
jid = array[0]
if not gajim.contacts[account].has_key(jid):
return
file_props = array[1]

Yann Leboulanger
committed
if gajim.popup_window(account):

Yann Leboulanger
committed
self.windows['file_transfers'].show_file_request(account, contact,
file_props)
return

Yann Leboulanger
committed
if gajim.show_notification(account):
notify.notify(_('File Transfer Request'),
jid, account, 'file-request')

Yann Leboulanger
committed
def handle_event_file_progress(self, account, file_props):
self.windows['file_transfers'].set_progress(file_props['type'],
file_props['sid'], file_props['received-len'])
def handle_event_file_rcv_completed(self, account, file_props):
ft = self.windows['file_transfers']
if file_props['error'] == 0:
ft.set_progress(file_props['type'], file_props['sid'],
file_props['received-len'])
else:
ft.set_status(file_props['type'], file_props['sid'], 'stop')
if file_props.has_key('stalled') and file_props['stalled'] or \
file_props.has_key('paused') and file_props['paused']:
jid = unicode(file_props['sender'])
if gajim.popup_window(account):

Yann Leboulanger
committed
if gajim.config.get('notify_on_file_complete'):
ft.show_completed(jid, file_props)
ft.show_stopped(jid, file_props)
return

Yann Leboulanger
committed
msg_type = ''
if file_props['error'] == 0 and gajim.config.get('notify_on_file_complete'):
msg_type = 'file-completed'
event_type = _('File Transfer Completed')
elif file_props['error'] == -1:
msg_type = 'file-stopped'
event_type = _('File Transfer Stopped')

Yann Leboulanger
committed
if msg_type:
self.add_event(account, jid, msg_type, file_props)
if gajim.config.get('notify_on_file_complete') and \
(gajim.config.get('autopopupaway') or \
gajim.connections[account].connected in (2, 3)):
# we want to be notified and we are online/chat or we don't mind
# bugged when away/na/busy
notify.notify(event_type, jid, account,
msg_type, file_props)
def handle_event_stanza_arrived(self, account, stanza):
if not self.windows.has_key(account):
return
if self.windows[account].has_key('xml_console'):
self.windows[account]['xml_console'].print_stanza(stanza, 'incoming')
def handle_event_stanza_sent(self, account, stanza):
if not self.windows.has_key(account):
return
if self.windows[account].has_key('xml_console'):
self.windows[account]['xml_console'].print_stanza(stanza, 'outgoing')
def handle_event_vcard_published(self, account, array):

nkour
committed
dialogs.InformationDialog(_('vCard publication succeeded'), _('Your personal information has been published successfully.'))
def handle_event_vcard_not_published(self, account, array):

nkour
committed
dialogs.InformationDialog(_('vCard publication failed'), _('There was an error while publishing your personal information, try again later.'))
'''Check idle status and change that status if needed'''
if not self.sleeper.poll():
# idle detection is not supported in that OS
return False # stop looping in vain

Yann Leboulanger
committed
state = self.sleeper.getState()
for account in gajim.connections:
if not gajim.sleeper_state.has_key(account) or \
not gajim.sleeper_state[account]:

Yann Leboulanger
committed
continue
if state == common.sleepy.STATE_AWAKE and \

Yann Leboulanger
committed
self.roster.send_status(account, 'online',
gajim.status_before_autoaway[account])

Yann Leboulanger
committed
elif state == common.sleepy.STATE_AWAY and \
gajim.config.get('autoaway'):

Yann Leboulanger
committed
#we save out online status
gajim.status_before_autoaway[account] = \
gajim.connections[account].status
#we go away (no auto status) [we pass True to auto param]
self.roster.send_status(account, 'away',
gajim.config.get('autoaway_message'), auto=True)
elif state == common.sleepy.STATE_XA and (\
gajim.sleeper_state[account] == 'autoaway' or \
gajim.sleeper_state[account] == 'online') and \
gajim.config.get('autoxa'):
self.roster.send_status(account, 'xa',
gajim.config.get('autoxa_message'), auto=True)
return True # renew timeout (loop for ever)
def autoconnect(self):
'''auto connect at startup'''
for a in gajim.connections:
if gajim.config.get_per('accounts', a, 'autoconnect'):
message = self.roster.get_status_message('online')
if message == -1:
return
for a in gajim.connections:
if gajim.config.get_per('accounts', a, 'autoconnect'):
self.roster.send_status(a, 'online', message)
return False
def show_systray(self):
self.systray.show_icon()
def hide_systray(self):
self.systray.hide_icon()
def image_is_ok(self, image):
if not os.path.exists(image):
return False
img = gtk.Image()
try:
img.set_from_file(image)
except:
return False