gajim-plural/src/gajim.py

1435 lines
50 KiB
Python
Raw Normal View History

#!/bin/sh
''':'
exec python -OOt "$0" ${1+"$@"}
' '''
## gajim.py
2003-11-30 23:40:24 +01:00
##
## Gajim Team:
2005-03-16 21:48:56 +01:00
## - Yann Le Boulanger <asterix@lagaule.org>
## - Vincent Hanquez <tab@snarc.org>
2005-04-18 13:04:33 +02:00
## - Nikos Kouremenos <kourem@gmail.com>
2005-07-30 16:14:10 +02:00
## - Dimitur Kirov <dkirov@gmail.com>
2003-11-30 23:40:24 +01:00
##
## Copyright (C) 2003-2005 Gajim Team
2003-11-30 23:40:24 +01:00
##
## 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.
##
2005-05-30 14:53:48 +02:00
import sys
2003-11-30 23:40:24 +01:00
import pygtk
2005-08-16 13:55:29 +02:00
import os
2005-09-21 16:42:29 +02:00
from common import i18n
i18n.init()
_ = i18n._
2005-05-30 14:53:48 +02:00
try:
import gtk
except RuntimeError, msg:
if str(msg) == 'could not open display':
2005-09-08 10:54:59 +02:00
print >> sys.stderr, _('Gajim needs Xserver to run. Quiting...')
sys.exit()
2005-09-11 16:20:20 +02:00
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()
2005-09-10 22:08:47 +02:00
import gtkexcepthook
import gobject
2005-09-12 13:23:38 +02:00
if sys.version[:4] >= '2.4':
gobject.threads_init()
import pango
2005-03-20 18:14:55 +01:00
import sre
import signal
import getopt
import time
import base64
2005-08-08 16:53:21 +02:00
2005-08-02 00:58:14 +02:00
from common import socks5
import gtkgui_helpers
import vcard
2005-05-21 18:01:52 +02:00
import common.sleepy
import check_for_new_version
2005-09-09 19:43:39 +02:00
2005-05-21 18:01:52 +02:00
from common import gajim
from common import connection
from common import helpers
2005-05-21 18:01:52 +02:00
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:
if o in ('-h', '--help'):
2005-05-30 14:53:48 +02:00
print 'gajim [--help] [--verbose] [--profile name]'
sys.exit()
elif o in ('-v', '--verbose'):
gajim.verbose = True
elif o in ('-p', '--profile'): # gajim --profile name
profile = a
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:
2005-05-20 20:13:38 +02:00
# win9x so ./config
config_filename = 'config'
if profile:
config_filename += '.%s' % profile
parser = optparser.OptionsParser(config_filename)
2005-06-24 16:28:00 +02:00
class Contact:
'''Information concerning each contact'''
2005-10-19 12:39:23 +02:00
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
ask='', resource='', priority=5, keyID='', role='', affiliation='',
2005-07-22 02:34:08 +02:00
chatstate=None):
2005-06-25 11:18:39 +02:00
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
2003-11-30 23:40:24 +01:00
2005-07-22 02:34:08 +02:00
# 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
2005-08-08 01:04:36 +02:00
# this holds what WE SEND to contact (the current chatstate)
2005-07-22 02:34:08 +02:00
self.chatstate = chatstate
import roster_window
import systray
import dialogs
import config
import disco
2004-06-11 23:36:17 +02:00
GTKGUI_GLADE = 'gtkgui.glade'
2004-06-11 23:36:17 +02:00
2004-03-11 22:14:09 +01:00
class Interface:
def handle_event_roster(self, account, data):
2005-04-26 20:45:54 +02:00
#('ROSTER', account, array)
self.roster.fill_contacts_and_groups_dicts(data, account)
self.roster.draw_roster()
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Roster', (account, data))
def handle_event_warning(self, unused, data):
#('WARNING', account, (title_text, section_text))
dialogs.WarningDialog(data[0], data[1]).get_response()
def handle_event_error(self, unused, data):
#('ERROR', account, (title_text, section_text))
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))
room_jid = data[0]
title = data[1]
prompt = data[2]
proposed_nick = data[3]
2005-10-30 22:41:52 +01:00
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)
2005-08-05 15:29:39 +02:00
def handle_event_http_auth(self, account, data):
#('HTTP_AUTH', account, (method, url, iq_obj))
dialog = dialogs.ConfirmationDialog(_('HTTP (%s) Authorization for %s') \
2005-08-08 17:38:07 +02:00
% (data[0], data[1]), _('Do you accept this request?'))
2005-08-05 15:29:39 +02:00
if dialog.get_response() == gtk.RESPONSE_OK:
answer = 'yes'
else:
answer = 'no'
gajim.connections[account].build_http_auth_answer(data[2], answer)
2005-05-10 18:53:28 +02:00
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:
2005-08-06 18:18:25 +02:00
# show the error dialog
2005-08-11 22:31:44 +02:00
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':
2005-08-06 18:18:25 +02:00
conn = gajim.connections[account]
2005-08-11 22:31:44 +02:00
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
2005-05-10 18:53:28 +02:00
if jid_from in self.windows[account]['gc']:
self.windows[account]['gc'][jid_from].print_conversation(
2005-09-06 15:17:10 +02:00
'Error %s: %s' % (array[2], array[1]), jid_from)
2005-05-10 18:53:28 +02:00
def handle_event_con_type(self, account, con_type):
# ('CON_TYPE', account, con_type) which can be 'ssl', 'tls', 'tcp'
gajim.con_types[account] = con_type
2005-05-12 20:55:01 +02:00
def allow_notif(self, account):
gajim.allow_notifications[account] = True
2005-05-12 20:55:01 +02:00
def handle_event_status(self, account, status): # OUR status
#('STATUS', account, status)
model = self.roster.status_combobox.get_model()
if status == 'offline':
model[self.roster.status_message_menuitem_iter][3] = False # sensitivity for this menuitem
gajim.allow_notifications[account] = False
# we are disconnected from all gc
2005-10-14 20:10:14 +02:00
if not gajim.gc_connected.has_key(account):
return
for room_jid in gajim.gc_connected[account]:
2005-08-03 21:37:23 +02:00
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)
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))
2005-07-21 19:00:05 +02:00
# if we're here it means contact changed show
statuss = ['offline', 'error', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible']
old_show = 0
2005-04-12 17:30:09 +02:00
new_show = statuss.index(array[1])
jid = array[0].split('/')[0]
2004-10-07 16:43:59 +02:00
keyID = array[5]
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('@', '')
else:
ji = jid
# Update contact
if gajim.contacts[account].has_key(ji):
luser = gajim.contacts[account][ji]
user1 = None
resources = []
for u in luser:
resources.append(u.resource)
if u.resource == resource:
user1 = u
break
if user1:
2005-03-12 09:25:45 +01:00
if user1.show in statuss:
old_show = statuss.index(user1.show)
2005-07-19 20:58:50 +02:00
if old_show == new_show and user1.status == array[2]: #no change
return
else:
user1 = gajim.contacts[account][ji][0]
2005-02-16 16:00:28 +01:00
if user1.show in statuss:
old_show = statuss.index(user1.show)
if (resources != [''] and (len(luser) != 1 or
luser[0].show != 'offline')) and jid.find('@') > 0:
old_show = 0
2005-06-25 11:18:39 +02:00
user1 = Contact(jid = user1.jid, name = user1.name,
groups = user1.groups, show = user1.show,
status = user1.status, sub = user1.sub, ask = user1.ask,
resource = user1.resource, priority = user1.priority,
keyID = user1.keyID)
luser.append(user1)
user1.resource = resource
if user1.jid.find('@') > 0 and len(luser) == 1: # It's not an agent
2005-04-12 17:30:09 +02:00
if old_show == 0 and new_show > 1:
if not user1.jid in gajim.newly_added[account]:
gajim.newly_added[account].append(user1.jid)
if user1.jid in gajim.to_be_removed[account]:
gajim.to_be_removed[account].remove(user1.jid)
2005-04-12 17:30:09 +02:00
gobject.timeout_add(5000, self.roster.remove_newly_added, \
user1.jid, account)
if old_show > 1 and new_show == 0 and gajim.connections[account].\
connected > 1:
if not user1.jid in gajim.to_be_removed[account]:
gajim.to_be_removed[account].append(user1.jid)
if user1.jid in gajim.newly_added[account]:
gajim.newly_added[account].remove(user1.jid)
self.roster.draw_contact(user1.jid, account)
if not gajim.awaiting_events[account].has_key(jid):
gobject.timeout_add(5000, self.roster.really_remove_contact, \
2005-04-12 17:30:09 +02:00
user1, account)
user1.show = array[1]
user1.status = array[2]
user1.priority = priority
2004-10-07 16:43:59 +02:00
user1.keyID = keyID
if jid.find('@') <= 0:
# It must be an agent
if gajim.contacts[account].has_key(ji):
# Update existing iter
self.roster.draw_contact(ji, account)
2005-09-13 20:46:21 +02:00
elif jid == gajim.get_jid_from_account(account):
# It's another of our resources. We don't need to see that!
2005-09-13 20:46:21 +02:00
return
elif gajim.contacts[account].has_key(ji):
# It isn't an agent
# reset chatstate if needed:
if array[1] in ('offline', 'error'):
user1.chatstate = None
self.roster.chg_contact_status(user1, array[1], array[2], account)
# play sound
if old_show < 2 and new_show > 1:
if gajim.config.get_per('soundevents', 'contact_connected',
2005-10-31 21:54:40 +01:00
'enabled'):
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 \
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
2005-05-11 19:14:10 +02:00
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True
if show_notification:
2005-10-31 21:54:40 +01:00
instance = dialogs.PopupNotificationWindow(
_('Contact Signed In'), jid, account)
2005-04-21 23:23:41 +02:00
self.roster.popup_notification_windows.append(instance)
if self.remote and self.remote.is_enabled():
2005-07-20 22:39:04 +02:00
self.remote.raise_signal('ContactPresence',
(account, array))
# when contact signs out we reset his chatstate
2005-08-08 17:00:51 +02:00
contact = gajim.get_first_contact_instance_from_jid(account, jid)
contact.chatstate = None
2005-08-10 18:01:40 +02:00
elif old_show > 1 and new_show < 2:
if gajim.config.get_per('soundevents', 'contact_disconnected',
2005-10-31 21:54:40 +01:00
'enabled'):
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
2005-05-11 19:14:10 +02:00
elif gajim.connections[account].connected in (2, 3): # we're online or chat
show_notification = True
if show_notification:
2005-10-29 16:25:05 +02:00
instance = dialogs.PopupNotificationWindow(
2005-10-31 21:54:40 +01:00
_('Contact Signed Out'), jid, account)
2005-04-21 23:23:41 +02:00
self.roster.popup_notification_windows.append(instance)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('ContactAbsence', (account, array))
2005-08-24 01:41:23 +02:00
# stop non active file transfers
2005-10-04 13:33:57 +02:00
else:
2005-10-04 14:26:09 +02:00
# 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)
2005-10-04 13:33:57 +02:00
self.handle_event_gc_notify(account, (jid, array[1], array[2], array[3], None, None, None, None, None, None, None))
2004-06-21 02:12:25 +02:00
def handle_event_msg(self, account, array):
2005-07-22 02:34:08 +02:00
#('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]
2005-07-21 16:56:39 +02:00
chatstate = array[6]
if jid.find('@') <= 0:
jid = jid.replace('@', '')
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
if self.windows[account]['gc'].has_key(jid): # it's a Private Message
2005-10-07 16:09:40 +02:00
nick = gajim.get_nick_from_fjid(array[0])
fjid = array[0]
if not self.windows[account]['chats'].has_key(fjid) and \
not gajim.awaiting_events[account].has_key(fjid):
if show_notification:
2005-10-31 21:54:40 +01:00
instance = dialogs.PopupNotificationWindow(
_('New Private Message'), fjid, account, 'pm')
self.roster.popup_notification_windows.append(instance)
self.windows[account]['gc'][jid].on_private_message(jid, nick,
array[1], array[2])
return
if gajim.config.get('ignore_unknown_contacts') and \
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]
2005-07-21 16:56:39 +02:00
if chatstate is not None: # he sent us reply, so he supports jep85
2005-07-22 02:34:08 +02:00
if contact.chatstate == 'ask': # we were jep85 disco?
contact.chatstate = 'active' # no more
2005-07-21 16:56:39 +02:00
chat_win.handle_incoming_chatstate(account, jid, chatstate)
elif contact.chatstate != 'active':
# got no valid jep85 answer, peer does not support it
2005-07-22 02:34:08 +02:00
contact.chatstate = False
else:
# Brand new message, incoming.
if contact and chatstate == 'active':
contact.chatstate = chatstate
2005-07-22 02:34:08 +02:00
if not array[1]: #empty message text
return
first = False
2005-02-14 23:30:04 +01:00
if not self.windows[account]['chats'].has_key(jid) and \
not gajim.awaiting_events[account].has_key(jid):
first = True
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
2005-05-11 19:14:10 +02:00
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
2005-10-31 21:54:40 +01:00
instance = dialogs.PopupNotificationWindow(
_('New Single Message'), jid, account, msg_type)
else: # chat message
2005-10-31 21:54:40 +01:00
instance = dialogs.PopupNotificationWindow(
_('New Message'), jid, account, msg_type)
2005-04-21 23:23:41 +02:00
self.roster.popup_notification_windows.append(instance)
# 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',
'enabled') and first:
helpers.play_sound('first_message_received')
if gajim.config.get_per('soundevents', 'next_message_received',
'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))
2004-07-08 21:46:24 +02:00
def handle_event_msgerror(self, account, array):
#('MSGERROR', account, (jid, error_code, error_msg, msg, time))
fjid = array[0]
2005-06-29 22:50:30 +02:00
jids = fjid.split('/', 1)
jid = jids[0]
gcs = self.windows[account]['gc']
if jid in gcs:
2005-06-18 16:38:37 +02:00
if len(jids) > 1: # it's a pm
nick = jids[1]
if not self.windows[account]['chats'].has_key(fjid):
gc = gcs[jid]
tv = gc.list_treeview[jid]
model = tv.get_model()
i = gc.get_contact_iter(jid, nick)
if i:
show = model[i][3]
else:
show = 'offline'
c = Contact(jid = fjid, name = nick, groups = ['none'],
2005-06-25 11:18:39 +02:00
show = show, ask = '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' % \
(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('@', '')
self.roster.on_message(jid, _('error while sending') + \
' \"%s\" ( %s )' % (array[3], array[2]), array[4], account, \
msg_type='error')
2004-07-08 21:46:24 +02:00
2005-02-15 01:10:10 +01:00
def handle_event_msgsent(self, account, array):
2005-07-20 13:39:01 +02:00
#('MSGSENT', account, (jid, msg, keyID))
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')
2005-02-15 01:10:10 +01:00
def handle_event_subscribe(self, account, array):
#('SUBSCRIBE', account, (jid, text))
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))
jid = array[0]
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)
else:
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)
2005-07-22 02:34:08 +02:00
gajim.contacts[account][jid] = [contact1]
self.roster.add_contact_to_roster(jid, account)
dialogs.InformationDialog(_('Authorization accepted'),
2005-06-07 03:10:24 +02:00
_('The contact "%s" has authorized you to see his status.')
% jid)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Subscribed', (account, array))
def handle_event_unsubscribed(self, account, jid):
2005-06-15 01:31:13 +02:00
dialogs.InformationDialog(_('Contact "%s" removed subscription from you') % jid,
_('You will always see him as offline.'))
if self.remote and self.remote.is_enabled():
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'):
config.ServiceRegistrationWindow(array[0], array[1], account,
array[2])
else:
dialogs.ErrorDialog(_('Contact with "%s" cannot be established'\
2005-06-07 03:10:24 +02:00
% array[0]), _('Check your connection or try again later.')).get_response()
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
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
def handle_event_acc_ok(self, account, array):
#('ACC_OK', account, (name, config))
name = array[0]
dialogs.InformationDialog(_('Account registration successful'),
_('The account "%s" has been registered with the Jabber server.') % name)
gajim.config.add_per('accounts', name)
for opt in array[1]:
gajim.config.set_per('accounts', name, opt, array[1][opt])
2005-05-12 00:00:48 +02:00
if self.windows.has_key('account_modification'):
self.windows['account_modification'].account_is_ok(array[0])
self.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
self.windows[name]['xml_console'] = dialogs.XMLConsoleWindow(name)
gajim.awaiting_events[name] = {}
# disconnect from server - our status in roster is offline
gajim.connections[name].connected = 1
2005-08-03 23:27:26 +02:00
gajim.gc_contacts[name] = {}
gajim.gc_connected[name] = {}
gajim.nicks[name] = array[1]['name']
gajim.allow_notifications[name] = False
gajim.groups[name] = {}
gajim.contacts[name] = {}
gajim.newly_added[name] = []
gajim.to_be_removed[name] = []
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[name] = 'off'
gajim.encrypted_chats[name] = []
gajim.last_message_time[name] = {}
gajim.status_before_autoaway[name] = ''
gajim.events_for_ui[name] = []
2005-08-03 23:27:26 +02:00
gajim.connections[name].change_status('offline', None, True)
gajim.connections[name].connected = 0
if self.windows.has_key('accounts'):
self.windows['accounts'].init_accounts()
2004-07-01 21:49:26 +02:00
self.roster.draw_roster()
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('NewAccount', (account, array))
def handle_event_quit(self, p1, p2):
self.roster.quit_gtkgui_interface()
2005-04-12 17:30:09 +02:00
2004-06-21 02:12:25 +02:00
def handle_event_myvcard(self, account, array):
nick = ''
2004-06-21 02:12:25 +02:00
if array.has_key('NICKNAME'):
nick = array['NICKNAME']
if nick:
gajim.nicks[account] = nick
2005-08-09 22:33:21 +02:00
if self.windows[account]['infos'].has_key(array['jid']):
win = self.windows[account]['infos'][array['jid']]
win.set_values(array)
def handle_event_vcard(self, account, vcard):
2005-10-12 22:10:42 +02:00
# ('VCARD', account, data)
'''vcard holds the vcard data'''
jid = vcard['jid']
2005-10-03 22:17:55 +02:00
resource = vcard['resource']
# vcard window
2005-06-26 21:59:34 +02:00
win = None
if self.windows[account]['infos'].has_key(jid):
win = self.windows[account]['infos'][jid]
2005-10-03 22:17:55 +02:00
elif self.windows[account]['infos'].has_key(jid + '/' + resource):
win = self.windows[account]['infos'][jid + '/' + resource]
if win:
win.set_values(vcard)
2005-07-20 15:13:52 +02:00
# show avatar in chat
2005-07-20 15:13:52 +02:00
win = None
if self.windows[account]['chats'].has_key(jid):
win = self.windows[account]['chats'][jid]
2005-10-03 22:17:55 +02:00
elif self.windows[account]['chats'].has_key(jid + '/' + resource):
win = self.windows[account]['chats'][jid + '/' + resource]
2005-07-20 15:20:47 +02:00
if win:
# FIXME: this will be removed when we have the thread working
2005-10-03 22:17:55 +02:00
win.show_avatar(jid, resource)
2005-09-06 15:44:29 +02:00
if self.remote is not None:
self.remote.raise_signal('VcardInfo', (account, vcard))
def handle_event_os_info(self, account, array):
2005-07-20 14:48:11 +02:00
win = None
if self.windows[account]['infos'].has_key(array[0]):
2005-07-20 14:48:11 +02:00
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):
# ('GC_MSG', account, (jid, msg, time))
2005-06-29 22:50:30 +02:00
jids = array[0].split('/', 1)
room_jid = jids[0]
if not self.windows[account]['gc'].has_key(room_jid):
return
if len(jids) == 1:
# message from server
nick = ''
else:
# 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))
2005-03-04 22:27:45 +01:00
def handle_event_gc_subject(self, account, array):
#('GC_SUBJECT', account, (jid, subject))
2005-06-29 22:50:30 +02:00
jids = array[0].split('/', 1)
2005-03-04 22:27:45 +01:00
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:
self.windows[account]['gc'][jid].print_conversation(\
'%s has set the subject to %s' % (jids[1], array[1]), jid)
2005-03-04 22:27:45 +01:00
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] = \
config.GroupchatConfigWindow(account, jid, array[1])
def handle_event_gc_invitation(self, account, array):
#('GC_INVITATION', (room_jid, jid_from, reason, password))
dialogs.InvitationReceivedDialog(account, array[0], array[1],
array[3], array[2])
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()
def handle_event_roster_info(self, account, array):
#('ROSTER_INFO', account, (jid, name, sub, ask, groups))
jid = array[0]
if not gajim.contacts[account].has_key(jid):
return
users = gajim.contacts[account][jid]
if not (array[2] or array[3]):
self.roster.remove_contact(users[0], account)
del gajim.contacts[account][jid]
#TODO if it was the only one in its group, remove the group
return
for user in users:
2004-11-18 20:21:20 +01:00
name = array[1]
if name:
user.name = name
user.sub = array[2]
user.ask = array[3]
if array[4]:
user.groups = array[4]
self.roster.draw_contact(jid, account)
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('RosterInfo', (account, array))
2005-06-11 19:21:30 +02:00
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
2005-06-11 19:21:30 +02:00
for bm in bms:
if bm['autojoin'] in ('1', 'true'):
2005-06-13 12:49:48 +02:00
self.roster.join_gc_room(account, bm['jid'], bm['nick'],
2005-06-11 19:21:30 +02:00
bm['password'])
self.roster.make_menu()
2005-08-06 18:18:25 +02:00
def handle_event_file_send_error(self, account, array):
jid = array[0]
file_props = array[1]
2005-08-11 22:31:44 +02:00
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):
instance = dialogs.PopupNotificationWindow(_('File Transfer Error'), jid,
account, 'file-send-error', file_props)
2005-08-06 18:18:25 +02:00
self.roster.popup_notification_windows.append(instance)
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)
2005-08-06 18:18:25 +02:00
def handle_event_file_request_error(self, account, array):
jid = array[0]
file_props = array[1]
2005-08-11 22:31:44 +02:00
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'
self.add_event(account, jid, msg_typ, file_props)
if gajim.show_notification(account):
2005-08-06 18:18:25 +02:00
# check if we should be notified
instance = dialogs.PopupNotificationWindow(_('File Transfer Error'), jid,
account, msg_type, file_props)
2005-08-06 18:18:25 +02:00
self.roster.popup_notification_windows.append(instance)
2005-07-30 12:20:46 +02:00
def handle_event_file_request(self, account, array):
jid = array[0]
if not gajim.contacts[account].has_key(jid):
return
file_props = array[1]
2005-08-17 11:59:59 +02:00
contact = gajim.contacts[account][jid][0]
if gajim.popup_window(account):
self.windows['file_transfers'].show_file_request(account, contact,
file_props)
return
2005-10-19 12:39:23 +02:00
self.add_event(account, jid, 'file-request', file_props)
if gajim.show_notification(account):
instance = dialogs.PopupNotificationWindow(_('File Transfer Request'),
jid, account, 'file-request')
self.roster.popup_notification_windows.append(instance)
2005-08-01 17:02:46 +02:00
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'])
2005-07-30 16:14:10 +02:00
def handle_event_file_rcv_completed(self, account, file_props):
2005-08-01 17:02:46 +02:00
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']:
return
jid = unicode(file_props['sender'])
if gajim.popup_window(account):
if file_props['error'] == 0:
ft.show_completed(jid, file_props)
elif file_props['error'] == -1:
ft.show_stopped(jid, file_props)
return
if file_props['error'] == 0:
msg_type = 'file-completed'
event_type = _('File Transfer Completed')
elif file_props['error'] == -1:
msg_type = 'file-stopped'
event_type = _('File Transfer Stopped')
2005-10-20 19:04:07 +02:00
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):
instance = dialogs.PopupNotificationWindow(event_type, jid, account,
msg_type, file_props)
self.roster.popup_notification_windows.append(instance)
def handle_event_stanza_arrived(self, account, stanza):
2005-08-10 13:52:37 +02:00
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):
2005-08-10 13:52:37 +02:00
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):
dialogs.InformationDialog(_('vCard publication succeeded'), _('Your personal information has been published successfully.'))
def handle_event_vcard_not_published(self, account, array):
dialogs.InformationDialog(_('vCard publication failed'), _('There was an error while publishing your personal information, try again later.'))
def get_avatar_pixbuf_from_cache(self, jid):
'''checks if jid has cached avatar and if that avatar is valid image
(can be shown)
return None if there is no image in vcard
return 'ask' if vcard is too old or if we don't have the vcard'''
if jid not in os.listdir(gajim.VCARDPATH):
return 'ask'
vcard_dict = gajim.connections.values()[0].get_cached_vcard(jid)
if not vcard_dict: # This can happen if cached vcard is too old
return 'ask'
if not vcard_dict.has_key('PHOTO'):
return None
2005-10-31 12:14:11 +01:00
pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0]
2005-10-31 12:09:18 +01:00
return pixbuf
def read_sleepy(self):
2005-07-22 13:07:06 +02:00
'''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
state = self.sleeper.getState()
for account in gajim.connections:
2005-07-19 00:39:59 +02:00
if not gajim.sleeper_state.has_key(account) or \
not gajim.sleeper_state[account]:
continue
if state == common.sleepy.STATE_AWAKE and \
2005-07-23 13:52:53 +02:00
gajim.sleeper_state[account] in ('autoaway', 'autoxa'):
#we go online
self.roster.send_status(account, 'online',
gajim.status_before_autoaway[account])
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[account] = 'online'
elif state == common.sleepy.STATE_AWAY and \
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[account] == 'online' and \
gajim.config.get('autoaway'):
#we save out online status
gajim.status_before_autoaway[account] = \
gajim.connections[account].status
2005-08-30 23:38:59 +02:00
#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)
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[account] = 'autoaway'
elif state == common.sleepy.STATE_XA and (\
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[account] == 'autoaway' or \
gajim.sleeper_state[account] == 'online') and \
gajim.config.get('autoxa'):
2005-08-30 23:38:59 +02:00
#we go extended away [we pass True to auto param]
self.roster.send_status(account, 'xa',
gajim.config.get('autoxa_message'), auto=True)
2005-07-22 13:07:06 +02:00
gajim.sleeper_state[account] = 'autoxa'
return True # renew timeout (loop for ever)
2003-11-30 23:40:24 +01:00
def autoconnect(self):
'''auto connect at startup'''
2005-07-22 13:07:52 +02:00
ask_message = False
for a in gajim.connections:
if gajim.config.get_per('accounts', a, 'autoconnect'):
2005-07-22 13:07:52 +02:00
ask_message = True
break
if ask_message:
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()
2005-03-28 03:20:47 +02:00
self.systray_enabled = True
def hide_systray(self):
self.systray.hide_icon()
2005-03-28 03:20:47 +02:00
self.systray_enabled = False
2005-03-09 22:29:20 +01:00
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
2005-06-18 17:57:06 +02:00
t = img.get_storage_type()
if t != gtk.IMAGE_PIXBUF and t != gtk.IMAGE_ANIMATION:
2005-03-09 22:29:20 +01:00
return False
return True
2005-03-10 19:20:23 +01:00
def make_regexps(self):
2005-03-10 19:20:23 +01:00
# regexp meta characters are: . ^ $ * + ? { } [ ] \ | ( )
# one escapes the metachars with \
# \S matches anything but ' ' '\t' '\n' '\r' '\f' and '\v'
# \s matches any whitespace character
# \w any alphanumeric character
# \W any non-alphanumeric character
# \b means word boundary. This is a zero-width assertion that
# matches only at the beginning or end of a word.
# ^ matches at the beginning of lines
#
2005-03-10 19:20:23 +01:00
# * means 0 or more times
# + means 1 or more times
# ? means 0 or 1 time
2005-03-10 19:20:23 +01:00
# | means or
# [^*] anything but '*' (inside [] you don't have to escape metachars)
# [^\s*] anything but whitespaces and '*'
2005-03-11 17:24:04 +01:00
# (?<!\S) is a one char lookbehind assertion and asks for any leading whitespace
# and mathces beginning of lines so we have correct formatting detection
# even if the the text is just '*foo*'
# (?!\S) is the same thing but it's a lookahead assertion
2005-08-01 16:38:21 +02:00
# \S*[^\s\W] --> in the matching string don't match ? or ) etc.. if at the end
# so http://be) will match http://be and http://be)be) will match http://be)be
2005-11-01 00:31:18 +01:00
prefixes = ('http://', 'https://', 'news://', 'ftp://', 'ed2k://', 'www\.', 'ftp\.')
2005-11-01 00:33:33 +01:00
# NOTE: it's ok to catch www.gr such stuff exist!
2005-11-01 00:31:18 +01:00
prefix_pattern = ''
for prefix in prefixes:
prefix_pattern += prefix + '|'
prefix_pattern = '(' + prefix_pattern + ')'
links = r'\b' + prefix_pattern + r'\S*[^\s\W]|'
2005-03-10 19:20:23 +01:00
#2nd one: at_least_one_char@at_least_one_char.at_least_one_char
2005-08-01 16:38:21 +02:00
mail = r'\bmailto:\S*[^\s\W]|' r'\b\S+@\S+\.\S*[^\s\W]|'
2005-03-10 19:20:23 +01:00
2005-03-11 13:55:38 +01:00
#detects eg. *b* *bold* *bold bold* test *bold*
#doesn't detect (it's a feature :P) * bold* *bold * * bold * test*bold*
formatting = r'(?<!\S)\*[^\s*]([^*]*[^\s*])?\*(?!\S)|' r'(?<!\S)/[^\s/]([^/]*[^\s/])?/(?!\S)|' r'(?<!\S)_[^\s_]([^_]*[^\s_])?_(?!\S)'
2005-03-11 17:24:04 +01:00
basic_pattern = links + mail + formatting
self.basic_pattern_re = sre.compile(basic_pattern, sre.IGNORECASE)
emoticons_pattern = ''
# sort keys by length so :qwe emot is checked before :q
2005-09-08 14:32:42 +02:00
keys = self.emoticons.keys()
keys.sort(self.on_emoticon_sort)
for emoticon in keys: # travel thru emoticons list
emoticon_escaped = sre.escape(emoticon) # espace regexp metachars
2005-09-08 12:52:10 +02:00
emoticons_pattern += emoticon_escaped + '|'# | means or in regexp
emot_and_basic_pattern = emoticons_pattern + basic_pattern
self.emot_and_basic_re = sre.compile(emot_and_basic_pattern,
sre.IGNORECASE)
# at least one character in 3 parts (before @, after @, after .)
self.sth_at_sth_dot_sth_re = sre.compile(r'\S+@\S+\.\S*[^\s)?]')
2005-03-10 19:20:23 +01:00
def on_emoticon_sort (self, emot1, emot2):
len1 = len(emot1)
len2 = len(emot2)
if len1 < len2:
return 1
elif len1 > len2:
return -1
return 0
2005-03-13 00:43:17 +01:00
def on_launch_browser_mailer(self, widget, url, kind):
2005-08-27 16:26:08 +02:00
helpers.launch_browser_mailer(kind, url)
def init_regexp(self):
#initialize emoticons dictionary
self.emoticons = dict()
emots = gajim.config.get_per('emoticons')
for emot in emots:
emot_file = gajim.config.get_per('emoticons', emot, 'path')
if not self.image_is_ok(emot_file):
continue
self.emoticons[emot.upper()] = emot_file
# update regular expressions
self.make_regexps()
def register_handlers(self, con):
self.handlers = {
'ROSTER': self.handle_event_roster,
'WARNING': self.handle_event_warning,
'ERROR': self.handle_event_error,
'INFORMATION': self.handle_event_information,
'ERROR_ANSWER': self.handle_event_error_answer,
'STATUS': self.handle_event_status,
'NOTIFY': self.handle_event_notify,
'MSG': self.handle_event_msg,
'MSGERROR': self.handle_event_msgerror,
'MSGSENT': self.handle_event_msgsent,
'SUBSCRIBED': self.handle_event_subscribed,
'UNSUBSCRIBED': self.handle_event_unsubscribed,
'SUBSCRIBE': self.handle_event_subscribe,
'AGENT_ERROR_INFO': self.handle_event_agent_info_error,
'AGENT_ERROR_ITEMS': self.handle_event_agent_items_error,
'REGISTER_AGENT_INFO': self.handle_event_register_agent_info,
'AGENT_INFO_ITEMS': self.handle_event_agent_info_items,
'AGENT_INFO_INFO': self.handle_event_agent_info_info,
'QUIT': self.handle_event_quit,
'ACC_OK': self.handle_event_acc_ok,
'MYVCARD': self.handle_event_myvcard,
'VCARD': self.handle_event_vcard,
'OS_INFO': self.handle_event_os_info,
'GC_NOTIFY': self.handle_event_gc_notify,
'GC_MSG': self.handle_event_gc_msg,
'GC_SUBJECT': self.handle_event_gc_subject,
'GC_CONFIG': self.handle_event_gc_config,
'GC_INVITATION': self.handle_event_gc_invitation,
'BAD_PASSPHRASE': self.handle_event_bad_passphrase,
'ROSTER_INFO': self.handle_event_roster_info,
'BOOKMARKS': self.handle_event_bookmarks,
'CON_TYPE': self.handle_event_con_type,
'FILE_REQUEST': self.handle_event_file_request,
'FILE_REQUEST_ERROR': self.handle_event_file_request_error,
'FILE_SEND_ERROR': self.handle_event_file_send_error,
'STANZA_ARRIVED': self.handle_event_stanza_arrived,
'STANZA_SENT': self.handle_event_stanza_sent,
'HTTP_AUTH': self.handle_event_http_auth,
'VCARD_PUBLISHED': self.handle_event_vcard_published,
'VCARD_NOT_PUBLISHED': self.handle_event_vcard_not_published,
'ASK_NEW_NICK': self.handle_event_ask_new_nick,
}
def exec_event(self, account):
ev = gajim.events_for_ui[account].pop(0)
self.handlers[ev[0]](account, ev[1])
def process_connections(self):
try:
# We copy the list of connections because one can disappear while we
# process()
accounts = []
for account in gajim.connections:
accounts.append(account)
for account in accounts:
if gajim.connections[account].connected:
gajim.connections[account].process(0.01)
if gajim.socks5queue.connected:
2005-09-09 00:12:14 +02:00
gajim.socks5queue.process(0)
2005-08-10 13:52:37 +02:00
for account in gajim.events_for_ui: #when we create a new account we don't have gajim.connection
while len(gajim.events_for_ui[account]):
gajim.mutex_events_for_ui.lock(self.exec_event, account)
gajim.mutex_events_for_ui.unlock()
2005-07-23 13:52:53 +02:00
time.sleep(0.01) # so threads in connection.py have time to run
return True # renew timeout (loop for ever)
except KeyboardInterrupt:
sys.exit()
return False
def save_config(self):
err_code = parser.write()
if err_code is not None:
2005-08-23 11:32:44 +02:00
strerr = os.strerror(err_code)
print strerr
# it is good to notify the user
# in case he cannot see the output of the console
dialogs.ErrorDialog(_('Cannot save your preferences'),
strerr).get_response()
sys.exit(1)
2005-07-21 10:05:10 +02:00
def enable_dbus(self):
2005-07-18 10:18:30 +02:00
if 'remote_control' not in globals():
2005-07-18 01:03:40 +02:00
import remote_control
if not hasattr(self, 'remote') or not self.remote:
try:
self.remote = remote_control.Remote()
except remote_control.DbusNotSupported:
self.remote = None
return False
except remote_control.SessionBusNotPresent:
self.remote = None
return False
else:
# enable the previously disabled object
self.remote.set_enabled(True)
return True
def disable_dbus(self):
2005-07-18 10:37:43 +02:00
if hasattr(self, 'remote') and self.remote is not None:
# just tell the remote object to skip remote messages
self.remote.set_enabled(False)
else:
self.remote = None
def __init__(self):
helpers.check_paths()
gajim.interface = self
self.default_values = {
'inmsgcolor': gajim.config.get('inmsgcolor'),
'outmsgcolor': gajim.config.get('outmsgcolor'),
'statusmsgcolor': gajim.config.get('statusmsgcolor'),
}
parser.read()
2005-06-13 18:53:23 +02:00
# Do not set gajim.verbose to False if -v option was given
if gajim.config.get('verbose'):
gajim.verbose = True
2005-06-14 00:11:09 +02:00
#add default emoticons if there is not in the config file
if len(gajim.config.get_per('emoticons')) == 0:
for emot in gajim.config.emoticons_default:
gajim.config.add_per('emoticons', emot)
gajim.config.set_per('emoticons', emot, 'path', gajim.config.emoticons_default[emot])
2005-06-14 00:11:09 +02:00
#add default status messages if there is not in the config file
if len(gajim.config.get_per('statusmsg')) == 0:
for msg in gajim.config.statusmsg_default:
gajim.config.add_per('statusmsg', msg)
gajim.config.set_per('statusmsg', msg, 'message', gajim.config.statusmsg_default[msg])
2005-06-14 00:11:09 +02:00
#add default themes if there is not in the config file
theme = gajim.config.get('roster_theme')
if not theme in gajim.config.get_per('themes'):
gajim.config.set('roster_theme', 'green')
2005-06-14 00:11:09 +02:00
if len(gajim.config.get_per('themes')) == 0:
d = ['accounttextcolor', 'accountbgcolor', 'accountfont', 'accountfontattrs',
'grouptextcolor', 'groupbgcolor', 'groupfont', 'groupfontattrs',
'contacttextcolor', 'contactbgcolor', 'contactfont', 'contactfontattrs',
'bannertextcolor', 'bannerbgcolor']
font_str = gtkgui_helpers.get_default_font()
if font_str is None:
font_str = 'Sans 10'
2005-06-14 00:11:09 +02:00
default = gajim.config.themes_default
for theme_name in default:
gajim.config.add_per('themes', theme_name)
theme = default[theme_name]
2005-06-14 00:11:09 +02:00
for o in d:
gajim.config.set_per('themes', theme_name, o,
theme[d.index(o)])
if gajim.config.get('autodetect_browser_mailer'):
2005-08-05 01:11:55 +02:00
gtkgui_helpers.autodetect_browser_mailer()
if gajim.verbose:
2005-05-18 11:17:41 +02:00
gajim.log.setLevel(gajim.logging.DEBUG)
else:
gajim.log.setLevel(None)
gajim.socks5queue = socks5.SocksQueue(
self.handle_event_file_rcv_completed,
self.handle_event_file_progress)
for account in gajim.config.get_per('accounts'):
gajim.connections[account] = common.connection.Connection(account)
2005-09-11 15:56:38 +02:00
gtk.about_dialog_set_email_hook(self.on_launch_browser_mailer, 'mail')
gtk.about_dialog_set_url_hook(self.on_launch_browser_mailer, 'url')
self.windows = {'logs': {}}
for a in gajim.connections:
self.windows[a] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
gajim.contacts[a] = {}
gajim.groups[a] = {}
gajim.gc_contacts[a] = {}
gajim.gc_connected[a] = {}
gajim.newly_added[a] = []
gajim.to_be_removed[a] = []
gajim.awaiting_events[a] = {}
gajim.nicks[a] = gajim.config.get_per('accounts', a, 'name')
gajim.allow_notifications[a] = False
gajim.sleeper_state[a] = 0
gajim.encrypted_chats[a] = []
gajim.last_message_time[a] = {}
gajim.status_before_autoaway[a] = ''
gajim.events_for_ui[a] = []
2005-04-12 17:30:09 +02:00
self.roster = roster_window.RosterWindow()
if gajim.config.get('use_dbus'):
2005-07-21 10:05:10 +02:00
self.enable_dbus()
else:
self.disable_dbus()
2005-07-21 10:05:10 +02:00
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps/gajim.png')
pix = gtk.gdk.pixbuf_new_from_file(path_to_file)
gtk.window_set_default_icon(pix) # set the icon to all newly opened windows
self.roster.window.set_icon_from_file(path_to_file) # and to roster window
self.sleeper = common.sleepy.Sleepy(
gajim.config.get('autoawaytime') * 60, # make minutes to seconds
gajim.config.get('autoxatime') * 60)
2005-03-28 03:20:47 +02:00
self.systray_enabled = False
self.systray_capabilities = False
if os.name == 'nt':
try:
import systraywin32
except: # user doesn't have trayicon capabilities
pass
else:
self.systray_capabilities = True
self.systray = systraywin32.SystrayWin32()
else:
try:
import egg.trayicon # use gnomepythonextras trayicon
except:
try:
import trayicon # use the one we distribute
except: # user doesn't have trayicon capabilities
pass
else:
self.systray_capabilities = True
self.systray = systray.Systray()
2005-03-14 18:39:18 +01:00
else:
self.systray_capabilities = True
self.systray = systray.Systray()
if self.systray_capabilities and gajim.config.get('trayicon'):
self.show_systray()
if gajim.config.get('check_for_new_version'):
check_for_new_version.Check_for_new_version_dialog()
2005-04-17 01:15:03 +02:00
self.init_regexp()
2005-03-26 22:09:49 +01:00
# get instances for windows/dialogs that will show_all()/hide()
self.windows['file_transfers'] = dialogs.FileTransfersWindow()
self.windows['preferences'] = config.PreferencesWindow()
self.windows['add_remove_emoticons'] = \
config.ManageEmoticonsWindow()
self.windows['roster'] = self.roster
for account in gajim.connections:
self.windows[account]['xml_console'] = \
dialogs.XMLConsoleWindow(account)
self.register_handlers(gajim.connections[account])
gobject.timeout_add(100, self.autoconnect)
gobject.timeout_add(200, self.process_connections)
gobject.timeout_add(500, self.read_sleepy)
2003-11-30 23:40:24 +01:00
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
try: # Import Psyco if available
import psyco
psyco.full()
except ImportError:
pass
2005-10-10 15:12:28 +02:00
if os.name != 'nt':
2005-10-10 15:15:32 +02:00
# Session Management support
2005-10-10 15:12:28 +02:00
try:
import gnome.ui
except ImportError:
print >> sys.stderr, _('Session Management support not available (missing gnome.ui module)')
else:
def die_cb(cli):
gtk.main_quit()
gnome.program_init('gajim', gajim.version)
cli = gnome.ui.master_client()
cli.connect('die', die_cb)
path_to_gajim_script = gtkgui_helpers.get_abspath_for_script('gajim')
if path_to_gajim_script:
2005-10-10 15:12:28 +02:00
argv = [path_to_gajim_script]
# FIXME: remove this typeerror catch when gnome python is old and
# not bad patched by distro men [2.12.0 + should not need all that
# NORMALLY]
try:
cli.set_restart_command(argv)
except TypeError:
cli.set_restart_command(len(argv), argv)
2005-10-10 15:15:32 +02:00
# register (by default only the first time) xmmpi: to Gajim
2005-10-10 15:12:28 +02:00
try:
import gconf
# in try because daemon may not be there
client = gconf.client_get_default()
2005-10-10 15:12:28 +02:00
we_set = False
if gajim.config.get('set_xmpp://_handler_everytime'):
we_set = True
elif client.get_string('/desktop/gnome/url-handlers/xmpp/command') is None:
we_set = True
if we_set:
path_to_gajim_script, type = gtkgui_helpers.get_abspath_for_script(
'gajim-remote', True)
if path_to_gajim_script:
if type == 'svn':
command = path_to_gajim_script + ' open_chat %s'
else: # 'installed'
command = 'gajim-remote open_chat %s'
client.set_bool('/desktop/gnome/url-handlers/xmpp/enabled', True)
client.set_string('/desktop/gnome/url-handlers/xmpp/command', command)
client.set_bool('/desktop/gnome/url-handlers/xmpp/needs_terminal', False)
except:
pass
Interface()
gtk.main()