root/branches/gajim_0.7/src/gajim.py

Revision 1569, 27.1 kB (checked in by asterix, 4 years ago)

translate status messages too

  • Property executable set to 1
  • Property svn:executable set to *
  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
Line 
1#!/bin/sh
2''':'
3exec python -OOt "$0" ${1+"$@"}
4' '''
5##      gajim.py
6##
7## Gajim Team:
8## - Yann Le Boulanger <asterix@lagaule.org>
9## - Vincent Hanquez <tab@snarc.org>
10## - Nikos Kouremenos <kourem@gmail.com>
11##
12##      Copyright (C) 2003-2005 Gajim Team
13##
14## This program is free software; you can redistribute it and/or modify
15## it under the terms of the GNU General Public License as published
16## by the Free Software Foundation; version 2 only.
17##
18## This program is distributed in the hope that it will be useful,
19## but WITHOUT ANY WARRANTY; without even the implied warranty of
20## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21## GNU General Public License for more details.
22##
23               
24import pygtk
25pygtk.require('2.0')
26import gtk
27import gtk.glade
28import pango
29import gobject
30import os
31import sre
32import signal
33import sys
34import getopt
35
36from common import i18n
37i18n.init()
38_ = i18n._
39APP = i18n.APP
40gtk.glade.bindtextdomain(APP, i18n.DIR)
41gtk.glade.textdomain(APP)
42
43import common.sleepy
44import check_for_new_version
45from common import gajim
46from common import connection
47
48from common import optparser
49
50profile = ''
51try:
52       opts, args = getopt.getopt(sys.argv[1:], 'hp:', [ 'help', 'profile=' ])
53except getopt.error, msg:
54       print msg
55       print 'for help use --help'
56       sys.exit(2)
57for o, a in opts:
58       if o in ('-h', '--help'):
59               print 'gajim [--help] [--profile name]'
60               sys.exit(0)
61       elif o in ('-p', '--profile'): # gajim --profile name
62               profile = a
63
64
65config_filename = os.path.expanduser('~/.gajim/config')
66if os.name == 'nt':
67        try:
68                # Documents and Settings\[User Name]\Application Data\Gajim\logs
69                config_filename = os.environ['appdata'] + '/Gajim/config'
70        except KeyError:
71                # win9x so ./config
72                config_filename = 'config'
73
74if profile:
75       config_filename += '.%s' % profile
76
77parser = optparser.OptionsParser(config_filename)
78
79try:
80        import winsound # windows-only built-in module for playing wav
81except ImportError:
82        pass
83
84class User:
85        '''Information concerning each users'''
86        def __init__(self, *args):
87                if len(args) == 0:
88                        self.jid = ''
89                        self.name = ''
90                        self.groups = []
91                        self.show = ''
92                        self.status = ''
93                        self.sub = ''
94                        self.ask = ''
95                        self.resource = ''
96                        self.priority = 1
97                        self.keyID = ''
98                elif len(args) == 10:
99                        self.jid = args[0]
100                        self.name = args[1]
101                        self.groups = args[2]
102                        self.show = args[3]
103                        self.status = args[4]
104                        self.sub = args[5]
105                        self.ask = args[6]
106                        self.resource = args[7]
107                        self.priority = args[8]
108                        self.keyID = args[9]
109                else: raise TypeError, _('bad arguments')
110
111import roster_window
112import systray
113import dialogs
114import config
115
116GTKGUI_GLADE = 'gtkgui.glade'
117
118
119class Interface:
120        def launch_browser_mailer(self, kind, url):
121                #kind = 'url' or 'mail'
122                if os.name == 'nt':
123                        try:
124                                os.startfile(url) # if pywin32 is installed we open
125                        except:
126                                pass
127                        return
128                if gajim.config.get('openwith') == 'gnome-open':
129                        app = 'gnome-open'
130                        args = ['gnome-open']
131                        args.append(url)
132                elif gajim.config.get('openwith') == 'kfmclient exec':
133                        app = 'kfmclient'
134                        args = ['kfmclient', 'exec']
135                elif gajim.config.get('openwith') == 'custom':
136                        if kind == 'url':
137                                conf = gajim.config.get('custombrowser')
138                        if kind == 'mail':
139                                conf = gajim.config.get('custommailapp')
140                        if conf == '': # if no app is configured
141                                return
142                        args = conf.split()
143                        app = args[0]
144                args.append(url)
145                try:
146                        if os.name == 'posix':
147                                os.spawnvp(os.P_NOWAIT, app, args)
148                        else:
149                                os.spawnv(os.P_NOWAIT, app, args)
150                except:
151                        pass
152
153        def play_timeout(self, pid):
154                pidp, r = os.waitpid(pid, os.WNOHANG)
155                return False
156
157        def play_sound(self, event):
158                if not gajim.config.get('sounds_on'):
159                        return
160                path_to_soundfile = gajim.config.get_per('soundevents', event, 'path')
161                if not os.path.exists(path_to_soundfile):
162                        return
163                if os.name  == 'nt':
164                        try:
165                                winsound.PlaySound(path_to_soundfile, \
166                                                                        winsound.SND_FILENAME|winsound.SND_ASYNC)
167                        except:
168                                pass
169                elif os.name == 'posix':
170                        if gajim.config.get('soundplayer') == '':
171                                return
172                        argv = gajim.config.get('soundplayer').split()
173                        argv.append(path_to_soundfile)
174                        pid = os.spawnvp(os.P_NOWAIT, argv[0], argv)
175                        pidp, r = os.waitpid(pid, os.WNOHANG)
176                        if pidp == 0:
177                                gobject.timeout_add(10000, self.play_timeout, pid)
178
179        def handle_event_roster(self, account, data):
180                #('ROSTER', account, array)
181                self.roster.mklists(data, account)
182                self.roster.draw_roster()
183       
184        def handle_event_warning(self, unused, msg):
185                dialogs.Warning_dialog(msg)
186       
187        def handle_event_error(self, unused, msg):
188                dialogs.Error_dialog(msg)
189       
190        def handle_event_error_answer(self, account, array):
191                #('ERROR_ANSWER', account, (jid_from. errmsg, errcode))
192                jid_from = array[0]
193                if jid_from in self.windows[account]['gc']:
194                        self.windows[account]['gc'][jid_from].print_conversation(
195                                'Error %s: %s' % (array[2], array[1]), jid_from)
196
197        def allow_notif(self, account):
198                self.allow_notifications[account] = True
199
200        def handle_event_status(self, account, status): # OUR status
201                #('STATUS', account, status)
202                if status != 'offline':
203                        gobject.timeout_add(30000, self.allow_notif, account)
204                else:
205                        self.allow_notifications[account] = False
206                self.roster.on_status_changed(account, status)
207       
208        def handle_event_notify(self, account, array):
209                #('NOTIFY', account, (jid, status, message, resource, priority, keyID,
210                # role, affiliation, real_jid, reason, actor, statusCode))
211                statuss = ['offline', 'error', 'online', 'chat', 'away', 'xa', 'dnd', 'invisible']
212                old_show = 0
213                new_show = statuss.index(array[1])
214                jid = array[0].split('/')[0]
215                keyID = array[5]
216                resource = array[3]
217                if not resource:
218                        resource = ''
219                priority = array[4]
220                if jid.find('@') <= 0:
221                        #It must be an agent
222                        ji = jid.replace('@', '')
223                else:
224                        ji = jid
225                #Update user
226                if self.roster.contacts[account].has_key(ji):
227                        luser = self.roster.contacts[account][ji]
228                        user1 = None
229                        resources = []
230                        for u in luser:
231                                resources.append(u.resource)
232                                if u.resource == resource:
233                                        user1 = u
234                                        break
235                        if user1:
236                                if user1.show in statuss:
237                                        old_show = statuss.index(user1.show)
238                        else:
239                                user1 = self.roster.contacts[account][ji][0]
240                                if user1.show in statuss:
241                                        old_show = statuss.index(user1.show)
242                                if (resources != [''] and (len(luser) != 1 or 
243                                        luser[0].show != 'offline')) and not jid.find('@') <= 0:
244                                        old_show = 0
245                                        user1 = User(user1.jid, user1.name, user1.groups, user1.show, \
246                                        user1.status, user1.sub, user1.ask, user1.resource, \
247                                                user1.priority, user1.keyID)
248                                        luser.append(user1)
249                                user1.resource = resource
250                        if user1.jid.find('@') > 0 and len(luser) == 1: # It's not an agent
251                                if old_show == 0 and new_show > 1:
252                                        if not user1.jid in self.roster.newly_added[account]:
253                                                self.roster.newly_added[account].append(user1.jid)
254                                        if user1.jid in self.roster.to_be_removed[account]:
255                                                self.roster.to_be_removed[account].remove(user1.jid)
256                                        gobject.timeout_add(5000, self.roster.remove_newly_added, \
257                                                user1.jid, account)
258                                if old_show > 1 and new_show == 0 and gajim.connections[account].\
259                                        connected > 1:
260                                        if not user1.jid in self.roster.to_be_removed[account]:
261                                                self.roster.to_be_removed[account].append(user1.jid)
262                                        if user1.jid in self.roster.newly_added[account]:
263                                                self.roster.newly_added[account].remove(user1.jid)
264                                        self.roster.draw_contact(user1.jid, account)
265                                        if not self.queues[account].has_key(jid):
266                                                gobject.timeout_add(5000, self.roster.really_remove_user, \
267                                                        user1, account)
268                        user1.show = array[1]
269                        user1.status = array[2]
270                        user1.priority = priority
271                        user1.keyID = keyID
272                if jid.find('@') <= 0:
273                        #It must be an agent
274                        if self.roster.contacts[account].has_key(ji):
275                                #Update existing iter
276                                self.roster.draw_contact(ji, account)
277                elif self.roster.contacts[account].has_key(ji):
278                        #It isn't an agent
279                        self.roster.chg_user_status(user1, array[1], array[2], account)
280                        #play sound
281                        if old_show < 2 and new_show > 1:
282                                if gajim.config.get_per('soundevents', 'contact_connected',
283                                                                                                'enabled'):
284                                        self.play_sound('contact_connected')
285                                if not self.windows[account]['chats'].has_key(jid) and \
286                                        not self.queues[account].has_key(jid) and \
287                                        gajim.config.get('notify_on_signin') and \
288                                        self.allow_notifications[account]:
289                                        show_notification = False
290                                        # check OUR status and if we allow notifications for that status
291                                        if gajim.config.get('autopopupaway'): # always notify
292                                                show_notification = True
293                                        elif gajim.connections[account].connected in (2, 3): # we're online or chat
294                                                show_notification = True
295                                        if show_notification:
296                                                instance = dialogs.Popup_notification_window(self,
297                                                                                                                'Contact signed in', jid, account)
298                                                self.roster.popup_notification_windows.append(instance)
299                                               
300                        elif old_show > 1 and new_show < 2:
301                                if gajim.config.get_per('soundevents', 'contact_disconnected',
302                                                                                                'enabled'):
303                                        self.play_sound('contact_disconnected')
304                                if not self.windows[account]['chats'].has_key(jid) and \
305                                        not self.queues[account].has_key(jid) and \
306                                        gajim.config.get('notify_on_signout'):
307                                        show_notification = False
308                                        # check OUR status and if we allow notifications for that status
309                                        if gajim.config.get('autopopupaway'): # always notify
310                                                show_notification = True
311                                        elif gajim.connections[account].connected in (2, 3): # we're online or chat
312                                                show_notification = True
313                                        if show_notification:
314                                                instance = dialogs.Popup_notification_window(self,
315                                                                                                        'Contact signed out', jid, account)
316                                                self.roster.popup_notification_windows.append(instance)
317                               
318                elif self.windows[account]['gc'].has_key(ji):
319                        #it is a groupchat presence
320                        self.windows[account]['gc'][ji].chg_user_status(ji, resource, \
321                                array[1], array[2], array[6], array[7], array[8], array[9], \
322                                array[10], array[11], account)
323
324        def handle_event_msg(self, account, array):
325                #('MSG', account, (user, msg, time))
326                jid = array[0].split('/')[0]
327                if jid.find('@') <= 0:
328                        jid = jid.replace('@', '')
329                if gajim.config.get('ignore_unknown_contacts') and \
330                        not self.roster.contacts[account].has_key(jid):
331                        return
332
333                first = False
334                if not self.windows[account]['chats'].has_key(jid) and \
335                                                not self.queues[account].has_key(jid):
336                        first = True
337                        if gajim.config.get('notify_on_new_message'):
338                                show_notification = False
339                                # check OUR status and if we allow notifications for that status
340                                if gajim.config.get('autopopupaway'): # always show notification
341                                        show_notification = True
342                                elif gajim.connections[account].connected in (2, 3): # we're online or chat
343                                        show_notification = True
344                                if show_notification:
345                                        instance = dialogs.Popup_notification_window(self,
346                                                                                                                                        'New Message', jid, account)
347                                        self.roster.popup_notification_windows.append(instance)
348                self.roster.on_message(jid, array[1], array[2], account)
349                if gajim.config.get_per('soundevents', 'first_message_received', \
350                        'enabled') and first:
351                        self.play_sound('first_message_received')
352                if gajim.config.get_per('soundevents', 'next_message_received', \
353                        'enabled') and not first:
354                        self.play_sound('next_message_received')
355               
356        def handle_event_msgerror(self, account, array):
357                #('MSGERROR', account, (jid, error_code, error_msg, msg, time))
358                jid = array[0].split('/')[0]
359                if jid in self.windows[account]['gc']:
360                        self.windows[account]['gc'][jid].print_conversation('Error %s: %s' % \
361                                (array[1], array[2]), jid)
362                        if self.windows[account]['gc'][jid].get_active_jid() == jid:
363                                self.windows[account]['gc'][jid].set_subject(jid, \
364                                        self.windows[account]['gc'][jid].subjects[jid])
365                        return
366                if jid.find('@') <= 0:
367                        jid = jid.replace('@', '')
368                self.roster.on_message(jid, _('error while sending') + \
369                        ' \"%s\" ( %s )' % (array[3], array[2]), array[4], account)
370               
371        def handle_event_msgsent(self, account, array):
372                #('MSG', account, (jid, msg, keyID))
373                if gajim.config.get_per('soundevents', 'message_sent', 'enabled'):
374                        self.play_sound('message_sent')
375               
376        def handle_event_subscribe(self, account, array):
377                #('SUBSCRIBE', account, (jid, text))
378                dialogs.Subscription_request_window(self, array[0], array[1], account)
379
380        def handle_event_subscribed(self, account, array):
381                #('SUBSCRIBED', account, (jid, resource))
382                jid = array[0]
383                if self.roster.contacts[account].has_key(jid):
384                        u = self.roster.contacts[account][jid][0]
385                        u.resource = array[1]
386                        self.roster.remove_user(u, account)
387                        if 'not in the roster' in u.groups:
388                                u.groups.remove('not in the roster')
389                        if len(u.groups) == 0:
390                                u.groups = ['General']
391                        self.roster.add_user_to_roster(u.jid, account)
392                        gajim.connections[account].update_user(u.jid, u.name, u.groups)
393                else:
394                        user1 = User(jid, jid, ['General'], 'online', \
395                                'online', 'to', '', array[1], 0, '')
396                        self.roster.contacts[account][jid] = [user1]
397                        self.roster.add_user_to_roster(jid, account)
398                dialogs.Information_dialog(_('You are now authorized by %s') % jid)
399
400        def handle_event_unsubscribed(self, account, jid):
401                dialogs.Information_dialog(_('You are now unsubscribed by %s') % jid)
402
403        def handle_event_agent_info(self, account, array):
404                #('AGENT_INFO', account, (agent, identities, features, items))
405                if self.windows[account].has_key('disco'):
406                        self.windows[account]['disco'].agent_info(array[0], array[1], \
407                                array[2], array[3])
408
409        def handle_event_register_agent_info(self, account, array):
410                #('AGENT_INFO', account, (agent, infos))
411                if array[1].has_key('instructions'):
412                        config.Service_registration_window(array[0], array[1], self, account)
413                else:
414                        dialogs.Error_dialog(_('error contacting %s') % array[0])
415
416        def handle_event_agent_info_items(self, account, array):
417                #('AGENT_INFO_ITEMS', account, (agent, node, items))
418                if self.windows[account].has_key('disco'):
419                        self.windows[account]['disco'].agent_info_items(array[0], array[1], 
420                                array[2])
421
422        def handle_event_agent_info_info(self, account, array):
423                #('AGENT_INFO_INFO', account, (agent, node, identities, features))
424                if self.windows[account].has_key('disco'):
425                        self.windows[account]['disco'].agent_info_info(array[0], array[1], \
426                                array[2], array[3])
427
428        def handle_event_acc_ok(self, account, array):
429                #('ACC_OK', account, (name, config))
430                name = array[0]
431                gajim.config.add_per('accounts', name)
432                for opt in array[1]:
433                        gajim.config.set_per('accounts', name, opt, array[1][opt])
434                if self.windows.has_key('account_modification'):
435                        self.windows['account_modification'].account_is_ok(array[0])
436                self.windows[name] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}}
437                self.queues[name] = {}
438                gajim.connections[name].connected = 0
439                self.nicks[name] = array[1]['name']
440                self.allow_notifications[name] = False
441                self.roster.groups[name] = {}
442                self.roster.contacts[name] = {}
443                self.roster.newly_added[name] = []
444                self.roster.to_be_removed[name] = []
445                self.sleeper_state[name] = 0
446                if self.windows.has_key('accounts'):
447                        self.windows['accounts'].init_accounts()
448                self.roster.draw_roster()
449
450        def handle_event_quit(self, p1, p2):
451                self.roster.quit_gtkgui_plugin()
452
453        def handle_event_myvcard(self, account, array):
454                nick = ''
455                if array.has_key('NICKNAME'):
456                        nick = array['NICKNAME']
457                if nick == '':
458                        nick = gajim.config.get_per('accounts', account, 'name')
459                self.nicks[account] = nick
460
461        def handle_event_vcard(self, account, array):
462                if self.windows[account]['infos'].has_key(array['jid']):
463                        self.windows[account]['infos'][array['jid']].set_values(array)
464
465        def handle_event_os_info(self, account, array):
466                if self.windows[account]['infos'].has_key(array[0]):
467                        self.windows[account]['infos'][array[0]].set_os_info(array[1], \
468                                array[2], array[3])
469
470        def handle_event_gc_msg(self, account, array):
471                #('GC_MSG', account, (jid, msg, time))
472                jids = array[0].split('/')
473                jid = jids[0]
474                if not self.windows[account]['gc'].has_key(jid):
475                        return
476                if len(jids) == 1:
477                        #message from server
478                        self.windows[account]['gc'][jid].print_conversation(array[1], jid, \
479                                tim = array[2])
480                else:
481                        #message from someone
482                        self.windows[account]['gc'][jid].print_conversation(array[1], jid, \
483                                jids[1], array[2])
484
485        def handle_event_gc_subject(self, account, array):
486                #('GC_SUBJECT', account, (jid, subject))
487                jids = array[0].split('/')
488                jid = jids[0]
489                if not self.windows[account]['gc'].has_key(jid):
490                        return
491                self.windows[account]['gc'][jid].set_subject(jid, array[1])
492                if len(jids) > 1:
493                        self.windows[account]['gc'][jid].print_conversation(\
494                                '%s has set the subject to %s' % (jids[1], array[1]), jid)
495
496        def handle_event_gc_config(self, account, array):
497                #('GC_CONFIG', account, (jid, config))  config is a dict
498                jid = array[0].split('/')[0]
499                if not self.windows[account]['gc_config'].has_key(jid):
500                        self.windows[account]['gc_config'][jid] = \
501                        config.Groupchat_config_window(self, account, jid, array[1])
502
503        def handle_event_bad_passphrase(self, account, array):
504                dialogs.Warning_dialog(_('Your GPG passphrase is wrong, so you are connected without your GPG key'))
505
506        def handle_event_roster_info(self, account, array):
507                #('ROSTER_INFO', account, (jid, name, sub, ask, groups))
508                jid = array[0]
509                if not self.roster.contacts[account].has_key(jid):
510                        return
511                users = self.roster.contacts[account][jid]
512                if not (array[2] or array[3]):
513                        self.roster.remove_user(users[0], account)
514                        del self.roster.contacts[account][jid]
515                        #TODO if it was the only one in its group, remove the group
516                        return
517                for user in users:
518                        name = array[1]
519                        if name:
520                                user.name = name
521                        user.sub = array[2]
522                        user.ask = array[3]
523                        if array[4]:
524                                user.groups = array[4]
525                self