Newer
Older
## Copyright (C) 2003-2013 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005 Alex Podaras <bigpod AT gmail.com>
## Norman Rasmussen <norman AT rasmussen.co.za>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
## Alex Mauer <hawke AT hawkesnest.net>
## Copyright (C) 2005-2007 Travis Shirk <travis AT pobox.com>
## Nikos Kouremenos <kourem AT gmail.com>
## Stefan Bethge <stefan AT lanpartei.de>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## James Newton <redshodan AT gmail.com>
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
## Julien Pivotto <roidelapluie AT gmail.com>
## Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## This file is part of Gajim.
##
## Gajim 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 3 only.
## Gajim 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.
##
## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import warnings
if os.name == 'nt':
log_path = os.path.join(os.environ['APPDATA'], 'Gajim')
if not os.path.exists(log_path):
os.mkdir(log_path, 0700)
log_file = os.path.join(log_path, 'gajim.log')
fout = open(log_file, 'a')
sys.stdout = fout
sys.stderr = fout
warnings.filterwarnings(action='ignore')
if os.path.isdir('gtk'):
# Used to create windows installer with GTK included
paths = os.environ['PATH']
list_ = paths.split(';')
new_list = []
for p in list_:
if p.find('gtk') < 0 and p.find('GTK') < 0:
new_list.append(p)
new_list.insert(0, os.path.join(os.getcwd(), 'gtk', 'lib'))
new_list.insert(0, os.path.join(os.getcwd(), 'gtk', 'bin'))
os.environ['PATH'] = ';'.join(new_list)
try:
import nbxmpp
except ImportError:
print 'Gajim needs python-nbxmpp to run. Quiting...'
sys.exit()
from common import demandimport
demandimport.enable()
demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
'logging.NullHandler', 'dbus.service', 'OpenSSL.SSL', 'OpenSSL.crypto',
'common.sleepy', 'DLFCN', 'dl', 'xml.sax', 'xml.sax.handler', 'ic',

Yann Leboulanger
committed
'Crypto.PublicKey', 'IPython', 'contextlib', 'imp', 'gst.interfaces',
'monotonic', 'gtkexcepthook']
if os.name == 'nt':
import locale
import gettext
APP = 'gajim'
DIR = '../po'
lang, enc = locale.getdefaultlocale()
os.environ['LANG'] = lang
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)
gettext.install(APP, DIR, unicode=True)
locale.setlocale(locale.LC_ALL, '')
import ctypes
import ctypes.util
libintl_path = ctypes.util.find_library('intl')
if libintl_path == None:
if os.path.exists(local_intl):
libintl_path = local_intl
if libintl_path == None:
raise ImportError('intl.dll library not found')
libintl = ctypes.cdll.LoadLibrary(libintl_path)
libintl.bind_textdomain_codeset(APP, 'UTF-8')

Yann Leboulanger
committed
if os.name == 'nt':
# needed for docutils
sys.path.append('.')

Yann Leboulanger
committed
from common import logging_helpers
logging_helpers.init('TERM' in os.environ)
import logging
# gajim.gui or gajim.gtk more appropriate ?
log = logging.getLogger('gajim.gajim')
import getopt
def parseOpts():
profile_ = ''
config_path_ = None
try:
shortargs = 'hqvl:p:c:'
# add gtk/gnome session option as gtk_get_option_group is not wrapped
longargs = 'help quiet verbose loglevel= profile= config-path='
longargs += ' class= name= screen= gtk-module= sync g-fatal-warnings'
longargs += ' sm-client-id= sm-client-state-file= sm-disable'
opts = getopt.getopt(sys.argv[1:], shortargs, longargs.split())[0]
except getopt.error, msg1:
print msg1
print 'for help use --help'
sys.exit(2)
for o, a in opts:
if o in ('-h', '--help'):
print _('Usage:') + \
'\n gajim [options] filename\n\n' + \
_('Options:') + \
'\n -h, --help ' + \
_('Show this help message and exit') + \
'\n -q, --quiet ' + \
_('Show only critical errors') + \
'\n -v, --verbose ' + \
_('Print xml stanzas and other debug information') + \
'\n -p, --profile ' + \
_('Use config.name in configuration directory') + \
'\n -c, --config-path ' + \
_('Set configuration directory') + \
'\n -l, --loglevel ' + \
_('Configure logging system')
sys.exit()
elif o in ('-q', '--quiet'):
logging_helpers.set_quiet()
elif o in ('-v', '--verbose'):
logging_helpers.set_verbose()
elif o in ('-p', '--profile'): # gajim --profile name
elif o in ('-l', '--loglevel'):
logging_helpers.set_loglevels(a)
elif o in ('-c', '--config-path'):
config_path_ = a
return profile_, config_path_

Yann Leboulanger
committed
import locale
profile, config_path = parseOpts()
if config_path:
config_path = unicode(config_path, locale.getpreferredencoding())
profile = unicode(profile, locale.getpreferredencoding())
import common.configpaths
common.configpaths.gajimpaths.init(config_path)
del config_path
common.configpaths.gajimpaths.init_profile(profile)
del profile

Yann Leboulanger
committed
if os.name == 'nt':

Yann Leboulanger
committed
plugins_locale_dir = os.path.join(common.configpaths.gajimpaths[
'PLUGINS_USER'], 'locale').encode(locale.getpreferredencoding())
libintl.bindtextdomain('gajim_plugins', plugins_locale_dir)
libintl.bind_textdomain_codeset('gajim_plugins', 'UTF-8')
class MyStderr(object):
_file = None
_error = None
def write(self, text):
fname = os.path.join(common.configpaths.gajimpaths.cache_root,
os.path.split(sys.executable)[1]+'.log')
if self._file is None and self._error is None:
try:
self._file = open(fname, 'a')
except Exception, details:
self._error = details
if self._file is not None:
self._file.write(text)
self._file.flush()
def flush(self):
if self._file is not None:
self._file.flush()
sys.stderr = MyStderr()

Yann Leboulanger
committed
# PyGTK2.10+ only throws a warning
warnings.filterwarnings('error', module='gtk')
try:
gobject.set_prgname('gajim')
except Warning, msg2:
if str(msg2) == 'could not open display':
print >> sys.stderr, _('Gajim needs X server to run. Quiting...')
else:
print >> sys.stderr, _('importing PyGTK failed: %s') % str(msg2)
warnings.filterwarnings(action='ignore')
if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
i18n.direction_mark = u'\u200F'
pritext = ''
from common import exceptions
from common import gajim
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to repair it (see '
'http://trac.gajim.org/wiki/DatabaseBackup) or remove it (all history '
'will be lost).') % common.logger.LOG_DB_PATH
else:
from common import dbus_support
if dbus_support.supported:
from music_track_listener import MusicTrackListener
from ctypes import CDLL
from ctypes.util import find_library
import platform
sysname = platform.system()
if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
libc = CDLL(find_library('c'))
# The constant defined in <linux/prctl.h> which is used to set the name
# of the process.
PR_SET_NAME = 15
if sysname == 'Linux':
libc.prctl(PR_SET_NAME, 'gajim')
elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
libc.setproctitle('gajim')
if gtk.pygtk_version < (2, 22, 0):
pritext = _('Gajim needs PyGTK 2.22 or above')
sectext = _('Gajim needs PyGTK 2.22 or above to run. Quiting...')
elif gtk.gtk_version < (2, 22, 0):
pritext = _('Gajim needs GTK 2.22 or above')
sectext = _('Gajim needs GTK 2.22 or above to run. Quiting...')
if os.name == 'nt':
try:
import winsound # windows-only built-in module for playing wav
import win32api # do NOT remove. we req this module
except Exception:
pritext = _('Gajim needs pywin32 to run')
sectext = _('Please make sure that Pywin32 is installed on your '
'system. You can get it at %s') % \
'http://sourceforge.net/project/showfiles.php?group_id=78018'
if pritext:
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()
import gtkgui_helpers
gajimpaths = common.configpaths.gajimpaths
pid_filename = gajimpaths['PID_FILE']
config_filename = gajimpaths['CONFIG_FILE']

Yann Leboulanger
committed
def pid_alive():
try:
pf = open(pid_filename)
except IOError:
# probably file not found
return False
try:
pid = int(pf.read().strip())
pf.close()
except Exception:
traceback.print_exc()
# PID file exists, but something happened trying to read PID
# Could be 0.10 style empty PID file, so assume Gajim is running
return True
if os.name == 'nt':
try:
from ctypes import (windll, c_ulong, c_int, Structure, c_char)
from ctypes import (POINTER, pointer, sizeof)
except Exception:
return True
class PROCESSENTRY32(Structure):
_fields_ = [
('dwSize', c_ulong, ),
('cntUsage', c_ulong, ),
('th32ProcessID', c_ulong, ),
('th32DefaultHeapID', c_ulong, ),
('th32ModuleID', c_ulong, ),
('cntThreads', c_ulong, ),
('th32ParentProcessID', c_ulong, ),
('pcPriClassBase', c_ulong, ),
('dwFlags', c_ulong, ),
('szExeFile', c_char*512, ),
]
kernel = windll.kernel32
kernel.CreateToolhelp32Snapshot.argtypes = c_ulong, c_ulong,
kernel.CreateToolhelp32Snapshot.restype = c_int
kernel.Process32First.argtypes = c_int, POINTER(PROCESSENTRY32),
kernel.Process32First.restype = c_int
kernel.Process32Next.argtypes = c_int, POINTER(PROCESSENTRY32),
kernel.Process32Next.restype = c_int
TH32CS_SNAPPROCESS = 2
CreateToolhelp32Snapshot = kernel.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
assert CreateToolhelp32Snapshot > 0, 'CreateToolhelp32Snapshot failed'
pe32 = PROCESSENTRY32()
pe32.dwSize = sizeof( PROCESSENTRY32 )
f3 = kernel.Process32First(CreateToolhelp32Snapshot, pointer(pe32))
if pe32.th32ProcessID == pid_:
return pe32.szExeFile
f3 = kernel.Process32Next(CreateToolhelp32Snapshot, pointer(pe32))
if get_p(pid) in ('python.exe', 'gajim.exe'):
return True
return False
try:
if not os.path.exists('/proc'):
return True # no /proc, assume Gajim is running
try:
f1 = open('/proc/%d/cmdline'% pid)
except IOError, e1:
if e1.errno == errno.ENOENT:
return False # file/pid does not exist
raise
n = f1.read().lower()
f1.close()
if n.find('gajim') < 0:
return False
return True # Running Gajim found at pid
except Exception:
traceback.print_exc()
# If we are here, pidfile exists, but some unexpected error occured.
# Assume Gajim is running.
return True

Yann Leboulanger
committed

Yann Leboulanger
committed
def show_remote_gajim_roster():
try:
import dbus
OBJ_PATH = '/org/gajim/dbus/RemoteObject'
INTERFACE = 'org.gajim.dbus.RemoteInterface'
SERVICE = 'org.gajim.dbus'
# Attempt to call show_roster
dbus.Interface(dbus.SessionBus().get_object(SERVICE, OBJ_PATH), INTERFACE).__getattr__("show_roster")()
return True
except Exception:
return False

Yann Leboulanger
committed
if pid_alive():

Yann Leboulanger
committed
if (show_remote_gajim_roster()):
print("Gajim is already running, bringing the roster to front...")
sys.exit(0)
pixs = []
for size in (16, 32, 48, 64, 128):
pix = gtkgui_helpers.get_icon_pixmap('gajim', size)
if pix:
pixs.append(pix)
if pixs:
# set the icon to all windows
gtk.window_set_default_icon_list(*pixs)
pritext = _('Gajim is already running')
sectext = _('Another instance of Gajim seems to be running\nRun anyway?')
dialog = dialogs.YesNoDialog(pritext, sectext)
dialog.popup()
if dialog.run() != gtk.RESPONSE_YES:
sys.exit(3)
dialog.destroy()
# run anyway, delete pid and useless global vars
if os.path.exists(pid_filename):
os.remove(pid_filename)
del pix
del pritext
del sectext
dialog.destroy()

Yann Leboulanger
committed
# Create .gajim dir
pid_dir = os.path.dirname(pid_filename)
if not os.path.exists(pid_dir):
check_paths.create_path(pid_dir)
f2 = open(pid_filename, 'w')
f2.write(str(os.getpid()))
f2.close()
except IOError, e2:
dlg = dialogs.ErrorDialog(_('Disk Write Error'), str(e2))
dlg.run()
dlg.destroy()
sys.exit()

Yann Leboulanger
committed
def on_exit():
# delete pid file on normal exit
if os.path.exists(pid_filename):
os.remove(pid_filename)
# Shutdown GUI and save config
if hasattr(gajim.interface, 'roster') and gajim.interface.roster:
gajim.interface.roster.prepare_quit()

Yann Leboulanger
committed
import atexit
atexit.register(on_exit)
from gui_interface import Interface
def sigint_cb(num, stack):
sys.exit(5)
# ^C exits the application normally to delete pid file
signal.signal(signal.SIGINT, sigint_cb)
signal.signal(signal.SIGTERM, sigint_cb)
log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(), \
sys.getfilesystemencoding(), locale.getpreferredencoding())
if os.name != 'nt':
# Session Management support
try:
import gnome.ui
except ImportError:
pass
else:
def die_cb(dummy):
gajim.interface.roster.quit_gtkgui_interface()
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(
if path_to_gajim_script:
argv = [path_to_gajim_script]
try:
cli.set_restart_command(argv)
except TypeError:
# Fedora systems have a broken gnome-python wrapper for this
# function.
cli.set_restart_command(len(argv), argv)
check_paths.check_and_possibly_create_paths()
interface = Interface()
interface.run()
try:
if os.name != 'nt':
# This makes Gajim unusable under windows, and threads are used only
# for GPG, so not under windows
gtk.gdk.threads_init()
if os.name != 'nt':
gtk.gdk.threads_leave()
except KeyboardInterrupt:
print >> sys.stderr, 'KeyboardInterrupt'