4 ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
5 ## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
6 ## Copyright (C) 2005 Alex Podaras <bigpod AT gmail.com>
7 ## Norman Rasmussen <norman AT rasmussen.co.za>
8 ## Stéphan Kochen <stephan AT kochen.nl>
9 ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
10 ## Alex Mauer <hawke AT hawkesnest.net>
11 ## Copyright (C) 2005-2007 Travis Shirk <travis AT pobox.com>
12 ## Nikos Kouremenos <kourem AT gmail.com>
13 ## Copyright (C) 2006 Junglecow J <junglecow AT gmail.com>
14 ## Stefan Bethge <stefan AT lanpartei.de>
15 ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
16 ## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
17 ## James Newton <redshodan AT gmail.com>
18 ## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
19 ## Julien Pivotto <roidelapluie AT gmail.com>
20 ## Stephan Erb <steve-e AT h3c.de>
21 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
23 ## This file is part of Gajim.
25 ## Gajim is free software; you can redistribute it and/or modify
26 ## it under the terms of the GNU General Public License as published
27 ## by the Free Software Foundation; version 3 only.
29 ## Gajim is distributed in the hope that it will be useful,
30 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
31 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 ## GNU General Public License for more details.
34 ## You should have received a copy of the GNU General Public License
35 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
38 from common
import demandimport
40 demandimport
.ignore
+= ['gobject._gobject', 'libasyncns', 'i18n',
41 'logging.NullHandler', 'dbus.glib', 'dbus.service',
42 'command_system.implementation.standard', 'OpenSSL.SSL', 'OpenSSL.crypto',
43 'common.sleepy', 'DLFCN', 'dl', 'xml.sax', 'xml.sax.handler', 'ic']
53 lang
, enc
= locale
.getdefaultlocale()
54 os
.environ
['LANG'] = lang
55 gettext
.bindtextdomain(APP
, DIR
)
56 gettext
.textdomain(APP
)
57 gettext
.install(APP
, DIR
, unicode=True)
59 locale
.setlocale(locale
.LC_ALL
, '')
62 libintl_path
= ctypes
.util
.find_library('intl')
63 if libintl_path
== None:
64 local_intl
= os
.path
.join('gtk', 'bin', 'intl.dll')
65 if os
.path
.exists(local_intl
):
66 libintl_path
= local_intl
67 if libintl_path
== None:
68 raise ImportError('intl.dll library not found')
69 libintl
= ctypes
.cdll
.LoadLibrary(libintl_path
)
70 libintl
.bindtextdomain(APP
, DIR
)
71 libintl
.bind_textdomain_codeset(APP
, 'UTF-8')
76 log_path
= os
.path
.join(os
.environ
['APPDATA'], 'Gajim')
77 if not os
.path
.exists(log_path
):
78 os
.mkdir(log_path
, 0700)
79 log_file
= os
.path
.join(log_path
, 'gajim.log')
80 fout
= open(log_file
, 'a')
84 warnings
.filterwarnings(action
='ignore')
86 if os
.path
.isdir('gtk'):
87 # Used to create windows installer with GTK included
88 paths
= os
.environ
['PATH']
89 list_
= paths
.split(';')
92 if p
.find('gtk') < 0 and p
.find('GTK') < 0:
94 new_list
.insert(0, 'gtk/lib')
95 new_list
.insert(0, 'gtk/bin')
96 os
.environ
['PATH'] = ';'.join(new_list
)
97 os
.environ
['GTK_BASEPATH'] = 'gtk'
100 # needed for docutils
103 from common
import logging_helpers
104 logging_helpers
.init('TERM' in os
.environ
)
107 # gajim.gui or gajim.gtk more appropriate ?
108 log
= logging
.getLogger('gajim.gajim')
111 from common
import i18n
118 shortargs
= 'hqvl:p:c:'
119 longargs
= 'help quiet verbose loglevel= profile= config_path='
120 opts
= getopt
.getopt(sys
.argv
[1:], shortargs
, longargs
.split())[0]
121 except getopt
.error
, msg1
:
123 print 'for help use --help'
126 if o
in ('-h', '--help'):
127 print 'gajim [--help] [--quiet] [--verbose] ' + \
128 '[--loglevel subsystem=level[,subsystem=level[...]]] ' + \
129 '[--profile name] [--config-path]'
131 elif o
in ('-q', '--quiet'):
132 logging_helpers
.set_quiet()
133 elif o
in ('-v', '--verbose'):
134 logging_helpers
.set_verbose()
135 elif o
in ('-p', '--profile'): # gajim --profile name
137 elif o
in ('-l', '--loglevel'):
138 logging_helpers
.set_loglevels(a
)
139 elif o
in ('-c', '--config-path'):
141 return profile_
, config_path_
143 profile
, config_path
= parseOpts()
147 profile
= unicode(profile
, locale
.getpreferredencoding())
149 import common
.configpaths
150 common
.configpaths
.gajimpaths
.init(config_path
)
152 common
.configpaths
.gajimpaths
.init_profile(profile
)
156 class MyStderr(object):
159 def write(self
, text
):
160 fname
= os
.path
.join(common
.configpaths
.gajimpaths
.cache_root
,
161 os
.path
.split(sys
.executable
)[1]+'.log')
162 if self
._file
is None and self
._error
is None:
164 self
._file
= open(fname
, 'a')
165 except Exception, details
:
166 self
._error
= details
167 if self
._file
is not None:
168 self
._file
.write(text
)
171 if self
._file
is not None:
174 sys
.stderr
= MyStderr()
176 # PyGTK2.10+ only throws a warning
177 warnings
.filterwarnings('error', module
='gtk')
181 except Warning, msg2
:
182 if str(msg2
) == 'could not open display':
183 print >> sys
.stderr
, _('Gajim needs X server to run. Quiting...')
185 print >> sys
.stderr
, _('importing PyGTK failed: %s') % str(msg2
)
187 warnings
.resetwarnings()
189 gobject
.set_prgname('gajim')
192 warnings
.filterwarnings(action
='ignore')
196 from common
import exceptions
198 from common
import gajim
199 except exceptions
.DatabaseMalformed
:
200 pritext
= _('Database Error')
201 sectext
= _('The database file (%s) cannot be read. Try to repair it (see '
202 'http://trac.gajim.org/wiki/DatabaseBackup) or remove it (all history '
203 'will be lost).') % common
.logger
.LOG_DB_PATH
205 from common
import dbus_support
206 if dbus_support
.supported
:
207 from music_track_listener
import MusicTrackListener
209 from ctypes
import CDLL
210 from ctypes
.util
import find_library
213 sysname
= platform
.system()
214 if sysname
in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
215 libc
= CDLL(find_library('c'))
217 # The constant defined in <linux/prctl.h> which is used to set the name
221 if sysname
== 'Linux':
222 libc
.prctl(PR_SET_NAME
, 'gajim')
223 elif sysname
in ('FreeBSD', 'OpenBSD', 'NetBSD'):
224 libc
.setproctitle('gajim')
226 if gtk
.pygtk_version
< (2, 16, 0):
227 pritext
= _('Gajim needs PyGTK 2.16 or above')
228 sectext
= _('Gajim needs PyGTK 2.16 or above to run. Quiting...')
229 elif gtk
.gtk_version
< (2, 16, 0):
230 pritext
= _('Gajim needs GTK 2.16 or above')
231 sectext
= _('Gajim needs GTK 2.16 or above to run. Quiting...')
233 from common
import check_paths
237 import winsound
# windows-only built-in module for playing wav
238 import win32api
# do NOT remove. we req this module
240 pritext
= _('Gajim needs pywin32 to run')
241 sectext
= _('Please make sure that Pywin32 is installed on your '
242 'system. You can get it at %s') % \
243 'http://sourceforge.net/project/showfiles.php?group_id=78018'
246 dlg
= gtk
.MessageDialog(None,
247 gtk
.DIALOG_DESTROY_WITH_PARENT | gtk
.DIALOG_MODAL
,
248 gtk
.MESSAGE_ERROR
, gtk
.BUTTONS_OK
, message_format
= pritext
)
250 dlg
.format_secondary_text(sectext
)
260 import gtkgui_helpers
262 gajimpaths
= common
.configpaths
.gajimpaths
264 pid_filename
= gajimpaths
['PID_FILE']
265 config_filename
= gajimpaths
['CONFIG_FILE']
273 pf
= open(pid_filename
)
275 # probably file not found
279 pid
= int(pf
.read().strip())
282 traceback
.print_exc()
283 # PID file exists, but something happened trying to read PID
284 # Could be 0.10 style empty PID file, so assume Gajim is running
289 from ctypes
import (windll
, c_ulong
, c_int
, Structure
, c_char
)
290 from ctypes
import (POINTER
, pointer
, sizeof
)
294 class PROCESSENTRY32(Structure
):
296 ('dwSize', c_ulong
, ),
297 ('cntUsage', c_ulong
, ),
298 ('th32ProcessID', c_ulong
, ),
299 ('th32DefaultHeapID', c_ulong
, ),
300 ('th32ModuleID', c_ulong
, ),
301 ('cntThreads', c_ulong
, ),
302 ('th32ParentProcessID', c_ulong
, ),
303 ('pcPriClassBase', c_ulong
, ),
304 ('dwFlags', c_ulong
, ),
305 ('szExeFile', c_char
*512, ),
308 kernel
= windll
.kernel32
309 kernel
.CreateToolhelp32Snapshot
.argtypes
= c_ulong
, c_ulong
,
310 kernel
.CreateToolhelp32Snapshot
.restype
= c_int
311 kernel
.Process32First
.argtypes
= c_int
, POINTER(PROCESSENTRY32
),
312 kernel
.Process32First
.restype
= c_int
313 kernel
.Process32Next
.argtypes
= c_int
, POINTER(PROCESSENTRY32
),
314 kernel
.Process32Next
.restype
= c_int
317 TH32CS_SNAPPROCESS
= 2
318 CreateToolhelp32Snapshot
= kernel
.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0)
319 assert CreateToolhelp32Snapshot
> 0, 'CreateToolhelp32Snapshot failed'
320 pe32
= PROCESSENTRY32()
321 pe32
.dwSize
= sizeof( PROCESSENTRY32
)
322 f3
= kernel
.Process32First(CreateToolhelp32Snapshot
, pointer(pe32
))
324 if pe32
.th32ProcessID
== pid_
:
325 return pe32
.szExeFile
326 f3
= kernel
.Process32Next(CreateToolhelp32Snapshot
, pointer(pe32
))
328 if get_p(pid
) in ('python.exe', 'gajim.exe'):
332 if not os
.path
.exists('/proc'):
333 return True # no /proc, assume Gajim is running
336 f1
= open('/proc/%d/cmdline'% pid
)
338 if e1
.errno
== errno
.ENOENT
:
339 return False # file/pid does not exist
342 n
= f1
.read().lower()
344 if n
.find('gajim') < 0:
346 return True # Running Gajim found at pid
348 traceback
.print_exc()
350 # If we are here, pidfile exists, but some unexpected error occured.
351 # Assume Gajim is running.
355 pix
= gtkgui_helpers
.get_icon_pixmap('gajim', 48)
356 gtk
.window_set_default_icon(pix
) # set the icon to all newly opened wind
357 pritext
= _('Gajim is already running')
358 sectext
= _('Another instance of Gajim seems to be running\nRun anyway?')
359 dialog
= dialogs
.YesNoDialog(pritext
, sectext
)
361 if dialog
.run() != gtk
.RESPONSE_YES
:
364 # run anyway, delete pid and useless global vars
365 if os
.path
.exists(pid_filename
):
366 os
.remove(pid_filename
)
373 pid_dir
= os
.path
.dirname(pid_filename
)
374 if not os
.path
.exists(pid_dir
):
375 check_paths
.create_path(pid_dir
)
378 f2
= open(pid_filename
, 'w')
379 f2
.write(str(os
.getpid()))
382 dlg
= dialogs
.ErrorDialog(_('Disk Write Error'), str(e2
))
389 # delete pid file on normal exit
390 if os
.path
.exists(pid_filename
):
391 os
.remove(pid_filename
)
392 # Shutdown GUI and save config
393 if hasattr(gajim
.interface
, 'roster') and gajim
.interface
.roster
:
394 gajim
.interface
.roster
.prepare_quit()
397 atexit
.register(on_exit
)
399 from gui_interface
import Interface
401 if __name__
== '__main__':
402 def sigint_cb(num
, stack
):
404 # ^C exits the application normally to delete pid file
405 signal
.signal(signal
.SIGINT
, sigint_cb
)
407 log
.info("Encodings: d:%s, fs:%s, p:%s", sys
.getdefaultencoding(), \
408 sys
.getfilesystemencoding(), locale
.getpreferredencoding())
411 # Session Management support
419 gajim
.interface
.roster
.quit_gtkgui_interface()
420 gnome
.program_init('gajim', gajim
.version
)
421 cli
= gnome
.ui
.master_client()
422 cli
.connect('die', die_cb
)
424 path_to_gajim_script
= gtkgui_helpers
.get_abspath_for_script(
427 if path_to_gajim_script
:
428 argv
= [path_to_gajim_script
]
430 cli
.set_restart_command(argv
)
432 # Fedora systems have a broken gnome-python wrapper for this
434 cli
.set_restart_command(len(argv
), argv
)
436 check_paths
.check_and_possibly_create_paths()
438 interface
= Interface()
443 # This makes Gajim unusable under windows, and threads are used only
444 # for GPG, so not under windows
445 gtk
.gdk
.threads_init()
447 except KeyboardInterrupt:
448 print >> sys
.stderr
, 'KeyboardInterrupt'