Beispiel #1
0
    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        if options.version:
            print "Current Emesene Version: " + Info.EMESENE_VERSION
            print "Last Stable Version: " + Info.EMESENE_LAST_STABLE
            print "\n" + Info.EMESENE_WEBSITE
            sys.exit(0)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    extension.get_and_instantiate('quit')
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True
Beispiel #2
0
    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        if options.version:
            print "Current Emesene Version: " + Info.EMESENE_VERSION
            print "Last Stable Version: " + Info.EMESENE_LAST_STABLE
            print "\n" + Info.EMESENE_WEBSITE
            sys.exit(0)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    extension.get_and_instantiate('quit')
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True
Beispiel #3
0
    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    sys.exit(0)
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True
Beispiel #4
0
class Controller(object):
    '''class that handle the transition between states of the windows'''

    def __init__(self):
        '''class constructor'''
        self.window = None
        self.tray_icon = None
        self.conversations = []
        self.minimize = False
        self.single_instance = None
        self.config = e3.common.Config()
        self.config_dir = e3.common.ConfigDir()
        self.config_path = self.config_dir.join('config')
        self.config.load(self.config_path)

        if self.config.d_accounts is None:
            self.config.d_accounts = {}
        if self.config.d_remembers is None:
            self.config.d_remembers = {}

        self.session = None
        self.logged_in = False
        self.cur_service = None
        self.notification = None
        self.conv_manager_available = False
        self.last_session_account = None
        self.last_session_service = None

        lang = self.config.get_or_set("language_config", None)
        language_management.install_desired_translation(lang)

        self._parse_commandline()
        self._setup()

        if hasattr(signal, 'SIGINT'):
            signal.signal(signal.SIGINT,
                lambda * args: glib.idle_add(self.kill))
        if hasattr(signal, 'SIGTERM'):
            signal.signal(signal.SIGTERM,
                lambda * args: glib.idle_add(self.kill))
        if hasattr(signal, 'SIGHUP'):
            signal.signal(signal.SIGHUP,
                lambda * args: glib.idle_add(self.kill))

    def _setup(self):
        '''register core extensions'''
        extension.category_register('session', dummy.Session,
                single_instance=True)
        if xmpp is not None:
            extension.register('session', xmpp.Session)
        extension.register('session', dummy.Session)

        if papylib is not None:
            extension.register('session', papylib.Session)
            extension.set_default('session', papylib.Session)
        else:
            extension.set_default('session', dummy.Session)

        #external API stuff
        self.dbus_ext = extension.get_and_instantiate('external api')
        self.network_checker = extension.get_and_instantiate(
            'network checker')

        self.unity_launcher = extension.get_and_instantiate('unity launcher')

        extension.category_register('sound', e3.common.Sounds.SoundPlayer,
                None, True)
        extension.category_register('notification',
                e3.common.notification.Notification)
        extension.category_register('history exporter',
                e3.Logger.save_logs_as_txt)
        extension.register('history exporter',
                e3.Logger.save_logs_as_xml)

        if self.config.session is None:
            default_id = extension.get_category('session').default_id
            self.config.session = default_id
        else:
            default_id = self.config.session

        extension.set_default_by_id('session', default_id)

    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        if options.version:
            print "Current Emesene Version: " + Info.EMESENE_VERSION
            print "Last Stable Version: " + Info.EMESENE_LAST_STABLE
            print "\n" + Info.EMESENE_WEBSITE
            sys.exit(0)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    extension.get_and_instantiate('quit')
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True

    def start(self, account=None):
        '''the entry point to the class'''
        windowcls = extension.get_default('window frame')
        self.window = windowcls(self.close_session) # main window
        self._set_location(self.window)

        self._draw_tray_icon() # default tray icon

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)
        use_ipv6 = self.config.get_or_set('b_use_ipv6', False)

        #cancel autologin if another emesene instance is running
        self.go_login(proxy, use_http, use_ipv6, no_autologin=self.emesene_is_running)

        if self.minimize:
            self.window.iconify()
        self.window.show()

    def go_login(self, proxy=None, use_http=None, use_ipv6=None,
                 cancel_clicked=False, no_autologin=False):
        '''shows the login GUI'''
        if proxy is None:
            proxy = self._get_proxy_settings()
        if use_http is None:
            use_http = self.config.get_or_set('b_use_http', False)
        if use_ipv6 is None:
            use_ipv6 = self.config.get_or_set('b_use_ipv6', False)

        self._save_login_dimensions()
        self._set_location(self.window)

        self.window.go_login(self.on_login_connect,
                             self.on_preferences_changed, self.config,
                             self.config_dir, self.config_path, proxy,
                             use_http, use_ipv6, self.config.session,
                             cancel_clicked, no_autologin)
        self.tray_icon.set_login()

    def _new_session(self, account=None):
        '''create a new session object'''

        if self.session is not None:
            self.session.quit()

        self.session = extension.get_and_instantiate('session')

        # if you add a signal here, add it on _remove_subscriptions
        signals = self.session.signals
        signals.close.subscribe(self.on_close)
        signals.login_succeed.subscribe(self.on_login_succeed)
        signals.login_failed.subscribe(self.on_login_failed)
        signals.contact_list_ready.subscribe(self.on_contact_list_ready)
        signals.conv_first_action.subscribe(self.on_new_conversation)
        signals.disconnected.subscribe(self.on_disconnected)
        signals.picture_change_succeed.subscribe(self.on_picture_change_succeed)

        #let's start dbus and unity launcher
        self.dbus_ext.set_new_session(self.session, self.window)
        if self.unity_launcher is not None:
            self.unity_launcher.set_session(self.session)

    def _restore_session(self):
        account = self.session.account
        if self.conv_manager_available:
            self.session.conversation_managers = []
            if account and self.last_session_account == account.account and \
               self.last_session_service == account.service:
                self.conv_manager_available = False
                self.session.conversations = {}
                for conv_manager in self.conversations:
                    conv_manager.renew_session(self.session)
                    self.session.conversation_managers.append(conv_manager)
            else:
                for conv_manager in self.conversations:
                    conv_manager.close_all()
                    self.conversations.remove(conv_manager)

        self.last_session_account = account.account
        self.last_session_service = account.service

    def kill(self):
        '''method that tries to kill emesene in a friendly way'''
        try:
            self.close_session()
        except:
            log.exception("Error while shutting down")
            sys.exit(1)

    def close_session(self, do_exit=True, server_disconnected=False):
        '''close session'''
        # prevent preference window from staying open and breaking things
        pref = extension.get_instance('preferences')
        if pref:
            pref.hide()

        # close all dialogs that are open
        extension.get_default('dialog').close_all()

        self._remove_subscriptions()

        if server_disconnected:
            for conv_manager in self.conversations:
                conv_manager.close_session()
            self.conv_manager_available = True # update with new session
        else:
            for conv_manager in self.conversations:
                conv_manager.close_all()

        if self.session:
            self.session.stop_mail_client()
            self.session.quit()

        if self.session is not None:
            self._save_application_language()
            self.session.save_extensions_config()

        self._save_login_dimensions()

        if self.session and self.logged_in:
            self.session.save_config()
            self.session = None
            self.logged_in = False

        self.config.save(self.config_path)

        #http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks
        #http://mg.pov.lt/objgraph/
        # install python-objgraph
        # also you can run emesene in pdb: pdb ./emesene.py
        # then 'r' and CTRL+C when you need the shell.
        #import objgraph
        ##objgraph.show_most_common_types()
        #objgraph.show_growth()

        if do_exit:
            extension.get_and_instantiate('quit')
            if os.name == "nt":
                os._exit(0)

    def _remove_subscriptions(self):
        '''remove the subscriptions to signals'''
        if self.session is not None:
            signals = self.session.signals
            signals.close.unsubscribe(self.on_close)
            signals.login_succeed.unsubscribe(self.on_login_succeed)
            signals.login_failed.unsubscribe(self.on_login_failed)
            signals.contact_list_ready.unsubscribe(self.on_contact_list_ready)
            signals.conv_first_action.unsubscribe(self.on_new_conversation)
            signals.disconnected.unsubscribe(self.on_disconnected)
            signals.picture_change_succeed.unsubscribe(
                    self.on_picture_change_succeed)
            if self.unity_launcher is not None:
                self.unity_launcher.remove_session()
            # unsubscribe notifications signals
            if self.notification:
                self.notification.remove_subscriptions()
                self.notification = None
            if self.tray_icon:
                self.tray_icon.unsubscribe()
            self.window.on_disconnect(self.close_session)
            self.dbus_ext.stop()
            extension.unsubscribe(self._on_tray_icon_changed, 'tray icon')

    def _save_application_language(self):
        '''save global settings to application config
           obtained from session settings.
        '''
        if self.config is None:
            return
        self.config.language_config = self.session.config.language_config

    def _get_proxy_settings(self):
        '''return the values of the proxy settings as a e3.Proxy object
        initialize the values on config if not exist'''

        use_proxy = self.config.get_or_set('b_use_proxy', False)
        use_proxy_auth = self.config.get_or_set('b_use_proxy_auth', False)
        host = self.config.get_or_set('proxy_host', '')
        port = self.config.get_or_set('proxy_port', '')
        user = self.config.get_or_set('proxy_user', '')
        passwd = self.config.get_or_set('proxy_passwd', '')

        self.config.get_or_set('b_use_http', False)

        return e3.Proxy(use_proxy, host, port, use_proxy_auth, user,
            passwd)

    def _save_proxy_settings(self, proxy):
        '''save the values of the proxy settings to config'''
        self.config.b_use_proxy = proxy.use_proxy
        self.config.b_use_proxy_auth = proxy.use_auth
        self.config.proxy_host = proxy.host
        self.config.proxy_port = proxy.port
        self.config.proxy_user = proxy.user
        self.config.proxy_passwd = proxy.passwd

    def _save_login_dimensions(self):
        '''save the dimensions of the login window
        '''
        width, height, posx, posy = self.window.get_dimensions()

        if not self.window.is_maximized():
            self.config.i_login_posx = posx
            self.config.i_login_posy = posy
            self.config.i_login_width = width
            self.config.i_login_height = height
            self.config.b_login_maximized = False
        else:
            self.config.b_login_maximized = True

    def draw_main_screen(self):
        '''create and populate the main screen
        '''
        last_avatar_path = self.session.config_dir.get_path("last_avatar")
        self.session.load_config()

        image_name = self.session.config.get_or_set('image_theme', 'default')
        emote_name = self.session.config.get_or_set('emote_theme', 'default')
        sound_name = self.session.config.get_or_set('sound_theme', 'default')
        conv_name = self.session.config.get_or_set('adium_theme',
                'renkoo.AdiumMessagesStyle')
        conv_name_variant = self.session.config.get_or_set('adium_theme_variant',
                '')
        gui.theme.set_theme(image_name, emote_name, sound_name, conv_name, conv_name_variant)

        self.session.config.get_or_set('last_avatar', last_avatar_path)

        self.config.save(self.config_path)
        self.session.set_default_extensions_from_config()

        self._draw_tray_icon() # user-specific tray icon
        self.tray_icon.set_main(self.session)

        self.window.go_main(self.session, self.on_new_conversation,
                            self.tray_icon.quit_on_close)

    def _draw_tray_icon(self):
        '''draws the tray icon'''
        trayiconcls = extension.get_default('tray icon')

        if self.tray_icon is not None:
            if trayiconcls == self.tray_icon.__class__:
                return
            self.tray_icon.unsubscribe()

        handler = gui.base.TrayIconHandler(self.session, gui.theme, self.close_session)
        self.tray_icon = trayiconcls(handler, self.window)
        extension.subscribe(self._on_tray_icon_changed, 'tray icon')

    def _on_tray_icon_changed(self, new_extension):
        self._draw_tray_icon()
        self.tray_icon.set_main(self.session)

    def _sync_emesene1(self):
        syn = extension.get_default('synch tool')
        # Check if a synch tool is present. Synch tool is only in the gtk gui.
        # Remove the following 'if' when it will be in the qt4 gui too.
        if syn:
            user = self.session.account.account
            current_service = self.session.config.service
            syn = syn(self.session, current_service)
            syn.show()

    def _set_location(self, window, is_conv=False, single_window=False):
        '''get and set the location of the window'''
        if is_conv:
            posx = self.session.config.get_or_set('i_conv_posx', 100)
            posy = self.session.config.get_or_set('i_conv_posy', 100)
            width = self.session.config.get_or_set('i_conv_width', 600)
            height = self.session.config.get_or_set('i_conv_height', 400)
            maximized = self.session.config.get_or_set('b_conv_maximized',
                    False)
        else:
            posx = self.config.get_or_set('i_login_posx', 100)
            posy = self.config.get_or_set('i_login_posy', 100)
            width = self.config.get_or_set('i_login_width', 250)
            height = self.config.get_or_set('i_login_height', 410)
            maximized = self.config.get_or_set('b_login_maximized', False)

        if maximized:
            window.maximize()

        window.set_location(width, height, posx, posy, single_window and is_conv)

    def on_preferences_changed(self, use_http, use_ipv6, proxy, session_id, service):
        '''called when the preferences on login change'''
        self.config.session = session_id
        extension.set_default_by_id('session', session_id)
        self.config.b_use_http = use_http
        self.config.b_use_ipv6 = use_ipv6
        self.config.service = service
        self._save_proxy_settings(proxy)

    def on_login_failed(self, reason):
        '''callback called when login fails'''
        self._save_login_dimensions()
        self._remove_subscriptions()
        self._new_session()
        self.go_login(cancel_clicked=True)
        self.window.content_main.clear_all()
        self.window.content_main.show_error(reason, login_failed=True)

    def _setup_plugins(self):
        plugin_manager = get_pluginmanager()
        plugin_manager.scan_directory('plugins')
        plugin_dir = self.config_dir.join('plugins')
        if not os.path.exists(plugin_dir):
            os.makedirs(plugin_dir)
        plugin_manager.scan_directory(plugin_dir)

        self.session.config.get_or_set('l_active_plugins', [])

        for plugin in self.session.config.l_active_plugins:
            plugin_manager.plugin_start(plugin, self.session)
        self.session.set_default_extensions_from_config()

    def on_login_succeed(self):
        '''callback called on login succeed'''
        self._save_login_dimensions()
        self.config.save(self.config_path)

        self.draw_main_screen()
        self._setup_plugins()

        self._restore_session()

        self._sync_emesene1()

        self.session.start_mail_client()
        self.logged_in = True
        self.network_checker.set_new_session(self.session)


    def on_login_connect(self, account, session_id, proxy,
                         use_http, use_ipv6, 
                         host=None, port=None, on_reconnect=False):
        '''called when the user press the connect button'''
        self._save_login_dimensions()
        self._set_location(self.window)
        self.cur_service = [host, port]
        if not on_reconnect:
            self.on_preferences_changed(use_http, use_ipv6,
                    proxy, session_id, self.config.service)
            self.avatar_path = self.config_dir.join(host, account.account,
                    'avatars', 'last')
            self.window.go_connect(self.on_cancel_login, self.avatar_path,
                    self.config)
            self.window.show()
        else:
            self.window.content_main.clear_connect()

        self._new_session(account)

        # set default values if not already set
        self.session.config.get_or_set('b_conv_minimized', True)
        self.session.config.get_or_set('b_conv_maximized', False)
        self.session.config.get_or_set('b_mute_sounds', False)
        self.session.config.get_or_set('b_play_send', False)
        self.session.config.get_or_set('b_play_nudge', True)
        self.session.config.get_or_set('b_play_first_send', True)
        self.session.config.get_or_set('b_play_type', True)
        self.session.config.get_or_set('b_mute_sounds_when_focussed', True)
        self.session.config.get_or_set('b_play_contact_online', True)
        self.session.config.get_or_set('b_play_contact_offline', True)
        self.session.config.get_or_set('b_notify_contact_online', True)
        self.session.config.get_or_set('b_notify_contact_offline', True)
        self.session.config.get_or_set('b_notify_receive_message', True)
        self.session.config.get_or_set('b_notify_only_when_available', True)
        self.session.config.get_or_set('b_show_userpanel', True)
        self.session.config.get_or_set('b_show_mail_inbox', True)
        self.session.config.get_or_set('b_show_emoticons', True)
        self.session.config.get_or_set('b_show_header', True)
        self.session.config.get_or_set('b_show_info', True)
        self.session.config.get_or_set('b_show_toolbar', True)
        self.session.config.get_or_set('b_allow_auto_scroll', True)
        self.session.config.get_or_set('adium_theme', 'renkoo.AdiumMessageStyle')
        self.session.config.get_or_set('b_enable_spell_check', False)
        self.session.config.get_or_set('b_download_folder_per_account', False)
        self.session.config.get_or_set('b_override_text_color', False)
        self.session.config.get_or_set('override_text_color', '#000000')
        self.session.config.get_or_set('b_conversation_tabs', True)
        self.session.config.get_or_set('b_single_window', True)
        self.session.config.get_or_set('b_open_mail_in_desktop', False)

        # set account uuid for session
        self.session.account_uuid = account.uuid

        self.session.login(account.account, account.password, account.status,
            proxy, host, port, use_http, use_ipv6)

    def on_cancel_login(self):
        '''
        method called when user select cancel login
        '''
        if self.session is not None:
            self.session.quit()
        self.go_login(cancel_clicked=True, no_autologin=True)

    def on_contact_list_ready(self):
        '''callback called when the contact list is ready to be used'''
        notificationcls = extension.get_default('notification')
        self.notification = notificationcls(self.session)
        self.soundPlayer = extension.get_and_instantiate('sound', self.session)

    def on_new_conversation(self, cid, members, other_started=True):
        '''callback called when the other user does an action that justify
        opening a conversation'''
        conv_tabs = self.session.config.b_conversation_tabs
        sing_wind = self.session.config.b_single_window

        conv_manager = None

        # check to see if there is a conversation with the same member
        for convman in self.conversations:
            if convman.has_similar_conversation(cid, members):
                conv_manager = convman
                break

        if conv_manager is None:
            if not self.conversations or not conv_tabs:
                if sing_wind and conv_tabs:
                    window = self.window
                else:
                    windowcls = extension.get_default('window frame')
                    window = windowcls(self._on_conversation_window_close)

                window.go_conversation(self.session, self._on_conversation_window_close)
                self._set_location(window, True, sing_wind)
                conv_manager = window.content_conv
                self.conversations.append(conv_manager)
                self.session.conversation_managers.append(conv_manager)

                if not (sing_wind and conv_tabs):
                    if self.session.config.b_conv_minimized and other_started:
                        window.iconify()
                        window.show()
                        window.iconify()
                    else:
                        window.show()
            else:
                conv_manager = self.conversations[0]

        conversation = conv_manager.new_conversation(cid, members)

        # raises the container and grabs the focus
        # handles cases where window is minimized and ctrl+tab focus stealing
        if not other_started:
            conv_manager.present(conversation, sing_wind and conv_tabs)

        if self.session.config.b_play_first_send and not \
           self.session.config.b_play_type:
            self.soundPlayer.play(gui.theme.sound_theme.sound_type)

    def _on_conversation_window_close(self, conv_manager):
        '''method called when the conversation window is closed'''
        if self.session:
            width, height, posx, posy = conv_manager.get_dimensions()

            if not conv_manager.is_maximized():
                self.session.config.i_conv_width = width
                self.session.config.i_conv_height = height
                self.session.config.i_conv_posx = posx
                self.session.config.i_conv_posy = posy
                self.session.config.b_conv_maximized = False
            else:
                self.session.config.b_conv_maximized = True
                self.session.config.i_conv_width = width #needed for single window
            self.session.conversation_managers.remove(conv_manager)

        self.conversations.remove(conv_manager)

    def on_close(self, close=False):
        '''called when the session is closed by the user'''
        self.close_session(close)
        if not close:
            self.go_login(cancel_clicked=True, no_autologin=True)

    def on_disconnected(self, reason, reconnect=0):
        '''called when the server disconnect us'''
        account = self.session.account
        self.close_session(False, True)
        if reconnect:
            self.on_reconnect(account)
        else:
            self.go_login(cancel_clicked=True, no_autologin=True)
            if reason is not None:
                self.window.content_main.clear_all()
                self.window.content_main.show_error(reason)

    def on_reconnect(self, account):
        '''makes the reconnect after 30 seconds'''
        self.window.go_connect(self.on_cancel_login, self.avatar_path,
                self.config)

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)
        use_ipv6 = self.config.get_or_set('b_use_ipv6', False)
        self.window.content_main.on_reconnect(self.on_login_connect, account, \
                                         self.config.session, proxy, use_http, \
                                         use_ipv6, self.cur_service)

        self.tray_icon.set_login()

    def on_picture_change_succeed(self, account, path):
        '''save the avatar change as the last avatar'''
        if account == self.session.account.account:
            last_avatar_path = self.session.config_dir.get_path("last_avatar")
            if path:
                shutil.copy(path, last_avatar_path)
            else:
                try:
                    os.remove(last_avatar_path)
                except OSError, e:
                    log.warning("Cannot remove file: %s" % e)
Beispiel #5
0
class Controller(object):
    '''class that handle the transition between states of the windows'''
    def __init__(self):
        '''class constructor'''
        self.window = None
        self.tray_icon = None
        self.conversations = []
        self.minimize = False
        self.single_instance = None
        self.config = e3.common.Config()
        self.config_dir = e3.common.ConfigDir()
        self.config_path = self.config_dir.join('config')
        self.config.load(self.config_path)

        if self.config.d_accounts is None:
            self.config.d_accounts = {}
        if self.config.d_remembers is None:
            self.config.d_remembers = {}

        self.session = None
        self.logged_in = False
        self.cur_service = None
        self.notification = None
        self.conv_manager_available = False
        self.last_session_account = None
        self.last_session_service = None

        lang = self.config.get_or_set("language_config", None)
        language_management.install_desired_translation(lang)

        self._parse_commandline()
        self._setup()

        if hasattr(signal, 'SIGINT'):
            signal.signal(signal.SIGINT,
                          lambda *args: glib.idle_add(self.kill))
        if hasattr(signal, 'SIGTERM'):
            signal.signal(signal.SIGTERM,
                          lambda *args: glib.idle_add(self.kill))
        if hasattr(signal, 'SIGHUP'):
            signal.signal(signal.SIGHUP,
                          lambda *args: glib.idle_add(self.kill))

    def _setup(self):
        '''register core extensions'''
        extension.category_register('session',
                                    dummy.Session,
                                    single_instance=True)
        if Info.EMESENE_VERSION.endswith("dev"):
            extension.register('session', dummy.Session)

        if webqq is not None:
            extension.register('session', webqq.Session)
            extension.set_default('session', webqq.Session)

        if xmpp is not None:
            extension.register('session', xmpp.Session)
            extension.set_default('session', xmpp.Session)

        if papylib is not None:
            extension.register('session', papylib.Session)
            extension.set_default('session', papylib.Session)

        #external API stuff
        self.dbus_ext = extension.get_and_instantiate('external api')
        self.network_checker = extension.get_and_instantiate('network checker')

        handler = gui.base.TrayIconHandler(self.session, gui.theme,
                                           self.close_session)
        unitylaunchercls = extension.get_default('unity launcher')
        self.unity_launcher = unitylaunchercls(handler)

        extension.category_register('sound', e3.common.Sounds.SoundPlayer,
                                    None, True)
        extension.category_register('notification',
                                    e3.common.notification.Notification)
        extension.category_register('history exporter', e3.Logger.ExporterTxt)
        extension.register('history exporter', e3.Logger.ExporterXml)
        extension.register('history exporter', e3.Logger.ExporterHtml)
        extension.register('history exporter', e3.Logger.ExporterCsv)
        extension.register('history exporter', e3.Logger.ExporterJSON)

        # ui callbacks for plugins
        extension.category_register('send message callback handler',
                                    e3.common.PriorityList,
                                    single_instance=True)
        extension.category_register('receive message callback handler',
                                    e3.common.PriorityList,
                                    single_instance=True)

        if self.config.session is None:
            default_id = extension.get_category('session').default_id
            self.config.session = default_id
        else:
            default_id = self.config.session

        extension.set_default_by_id('session', default_id)

    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        if options.version:
            print "Current Emesene Version: " + Info.EMESENE_VERSION
            print "Last Stable Version: " + Info.EMESENE_LAST_STABLE
            print "\n" + Info.EMESENE_WEBSITE
            sys.exit(0)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    extension.get_and_instantiate('quit')
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True

    def start(self, account=None):
        '''the entry point to the class'''
        windowcls = extension.get_default('window frame')
        self.window = windowcls(self.close_session)  # main window
        self._set_location(self.window)

        self._draw_tray_icon()  # default tray icon

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)
        use_ipv6 = self.config.get_or_set('b_use_ipv6', False)

        #cancel autologin if another emesene instance is running
        self.go_login(proxy,
                      use_http,
                      use_ipv6,
                      no_autologin=self.emesene_is_running)

        if self.minimize:
            self.window.iconify()
        self.window.show()

    def go_login(self,
                 proxy=None,
                 use_http=None,
                 use_ipv6=None,
                 cancel_clicked=False,
                 no_autologin=False):
        '''shows the login GUI'''
        if proxy is None:
            proxy = self._get_proxy_settings()
        if use_http is None:
            use_http = self.config.get_or_set('b_use_http', False)
        if use_ipv6 is None:
            use_ipv6 = self.config.get_or_set('b_use_ipv6', False)

        self._save_login_dimensions()
        self._set_location(self.window)

        self.window.go_login(self.on_login_connect,
                             self.on_preferences_changed, self.config,
                             self.config_dir, self.config_path, proxy,
                             use_http, use_ipv6, self.config.session,
                             cancel_clicked, no_autologin)
        self.tray_icon.set_login()

    def _new_session(self, account=None):
        '''create a new session object'''

        if self.session:
            self.close_session(False)

        self.session = extension.get_and_instantiate('session')

        self.session.cb_gui_send_message = extension.get_and_instantiate(
            'send message callback handler')
        self.session.cb_gui_recv_message = extension.get_and_instantiate(
            'receive message callback handler')

        # if you add a signal here, add it on _remove_subscriptions
        signals = self.session.signals
        signals.close.subscribe(self.on_close)
        signals.login_succeed.subscribe(self.on_login_succeed)
        signals.login_failed.subscribe(self.on_login_failed)
        signals.contact_list_ready.subscribe(self.on_contact_list_ready)
        signals.conv_first_action.subscribe(self.on_new_conversation)
        signals.disconnected.subscribe(self.on_disconnected)
        signals.picture_change_succeed.subscribe(
            self.on_picture_change_succeed)

        #let's start dbus and unity launcher
        self.dbus_ext.set_new_session(self.session, self.window)
        if self.unity_launcher is not None:
            self.unity_launcher.set_main(self.session)

    def _restore_session(self):
        account = self.session.account
        if self.conv_manager_available:
            self.session.conversation_managers = []
            if account and self.last_session_account == account.account and \
               self.last_session_service == account.service:
                self.conv_manager_available = False
                self.session.conversations = {}
                for conv_manager in self.conversations:
                    conv_manager.renew_session(self.session)
                    self.session.conversation_managers.append(conv_manager)
            else:
                for conv_manager in self.conversations:
                    conv_manager.close_all()
                    self.conversations.remove(conv_manager)

        self.last_session_account = account.account
        self.last_session_service = account.service

    def kill(self):
        '''method that tries to kill emesene in a friendly way'''
        try:
            self.close_session()
        except:
            log.exception("Error while shutting down")
            sys.exit(1)

    def close_session(self, do_exit=True, server_disconnected=False):
        '''close session'''
        # prevent preference window from staying open and breaking things
        pref = extension.get_instance('preferences')
        if pref:
            pref.hide()

        # close all dialogs that are open
        extension.get_default('dialog').close_all()

        self._remove_subscriptions()

        if server_disconnected:
            for conv_manager in self.conversations:
                conv_manager.close_session()
            self.conv_manager_available = True  # update with new session
        else:
            for conv_manager in self.conversations:
                conv_manager.close_all()

        if self.session:
            self.session.stop_mail_client()
            self.session.quit()
            self._save_application_language()
            self.session.save_extensions_config()

        self._save_login_dimensions()

        if self.session and self.logged_in:
            self.session.save_config()
            self.logged_in = False

        self.session = None

        self.config.save(self.config_path)

        #http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks
        #http://mg.pov.lt/objgraph/
        # install python-objgraph
        # also you can run emesene in pdb: pdb ./emesene.py
        # then 'r' and CTRL+C when you need the shell.
        #import objgraph
        ##objgraph.show_most_common_types()
        #objgraph.show_growth(limit=None)

        if do_exit:
            extension.get_and_instantiate('quit')
            if os.name == "nt":
                os._exit(0)

    def _remove_subscriptions(self):
        '''remove the subscriptions to signals'''
        if self.session is not None:
            signals = self.session.signals
            signals.close.unsubscribe(self.on_close)
            signals.login_succeed.unsubscribe(self.on_login_succeed)
            signals.login_failed.unsubscribe(self.on_login_failed)
            signals.contact_list_ready.unsubscribe(self.on_contact_list_ready)
            signals.conv_first_action.unsubscribe(self.on_new_conversation)
            signals.disconnected.unsubscribe(self.on_disconnected)
            signals.picture_change_succeed.unsubscribe(
                self.on_picture_change_succeed)
            if self.unity_launcher is not None:
                self.unity_launcher.unsubscribe()
            # unsubscribe notifications signals
            if self.notification:
                self.notification.remove_subscriptions()
                self.notification = None
            if self.tray_icon:
                self.tray_icon.unsubscribe()
            self.window.on_disconnect(self.close_session)
            self.dbus_ext.stop()

    def _save_application_language(self):
        '''save global settings to application config
           obtained from session settings.
        '''
        if self.config is None:
            return
        self.config.language_config = self.session.config.language_config

    def _get_proxy_settings(self):
        '''return the values of the proxy settings as a e3.Proxy object
        initialize the values on config if not exist'''

        use_proxy = self.config.get_or_set('b_use_proxy', False)
        use_proxy_auth = self.config.get_or_set('b_use_proxy_auth', False)
        host = self.config.get_or_set('proxy_host', '')
        port = self.config.get_or_set('proxy_port', '')
        user = self.config.get_or_set('proxy_user', '')
        passwd = self.config.get_or_set('proxy_passwd', '')

        self.config.get_or_set('b_use_http', False)

        return e3.Proxy(use_proxy, host, port, use_proxy_auth, user, passwd)

    def _save_proxy_settings(self, proxy):
        '''save the values of the proxy settings to config'''
        self.config.b_use_proxy = proxy.use_proxy
        self.config.b_use_proxy_auth = proxy.use_auth
        self.config.proxy_host = proxy.host
        self.config.proxy_port = proxy.port
        self.config.proxy_user = proxy.user
        self.config.proxy_passwd = proxy.passwd

    def _save_login_dimensions(self):
        '''save the dimensions of the login window
        '''
        width, height, posx, posy = self.window.get_dimensions()

        if not self.window.is_maximized():
            self.config.i_login_posx = posx
            self.config.i_login_posy = posy
            self.config.i_login_width = width
            self.config.i_login_height = height
            self.config.b_login_maximized = False
        else:
            self.config.b_login_maximized = True

    def draw_main_screen(self):
        '''create and populate the main screen
        '''
        last_avatar_path = self.session.config_dir.get_path("last_avatar")
        self.session.load_config()

        image_name = self.session.config.get_or_set('image_theme', 'default')
        emote_name = self.session.config.get_or_set('emote_theme', 'default')
        sound_name = self.session.config.get_or_set('sound_theme', 'default')
        conv_name = self.session.config.get_or_set(
            'adium_theme', 'renkoo.AdiumMessagesStyle')
        conv_name_variant = self.session.config.get_or_set(
            'adium_theme_variant', '')
        gui.theme.set_theme(image_name, emote_name, sound_name, conv_name,
                            conv_name_variant)

        self.session.config.get_or_set('last_avatar', last_avatar_path)

        self.config.save(self.config_path)
        self.session.set_default_extensions_from_config()

        self._draw_tray_icon()  # user-specific tray icon
        self.tray_icon.set_main(self.session)

        self.window.go_main(self.session, self.on_new_conversation,
                            self.tray_icon.quit_on_close)

    def _draw_tray_icon(self):
        '''draws the tray icon'''
        trayiconcls = extension.get_default('tray icon')

        if self.tray_icon is not None:
            if trayiconcls == self.tray_icon.__class__:
                return
            self.tray_icon.hide()
        else:
            extension.subscribe(self._on_tray_icon_changed, 'tray icon')

        handler = gui.base.TrayIconHandler(self.session, gui.theme,
                                           self.close_session)
        self.tray_icon = trayiconcls(handler, self.window)

    def _on_tray_icon_changed(self, new_extension):
        self._draw_tray_icon()
        self.tray_icon.set_main(self.session)

    def _sync_emesene1(self):
        syn = extension.get_default('synch tool')
        # Check if a synch tool is present. Synch tool is only in the gtk gui.
        # Remove the following 'if' when it will be in the qt4 gui too.
        if syn:
            user = self.session.account.account
            current_service = self.session.config.service
            syn = syn(self.session, current_service)
            syn.show()

    def _set_location(self, window, is_conv=False, single_window=False):
        '''get and set the location of the window'''
        if is_conv:
            posx = self.session.config.get_or_set('i_conv_posx', 100)
            posy = self.session.config.get_or_set('i_conv_posy', 100)
            width = self.session.config.get_or_set('i_conv_width', 600)
            height = self.session.config.get_or_set('i_conv_height', 400)
            maximized = self.session.config.get_or_set('b_conv_maximized',
                                                       False)
        else:
            posx = self.config.get_or_set('i_login_posx', 100)
            posy = self.config.get_or_set('i_login_posy', 100)
            width = self.config.get_or_set('i_login_width', 250)
            height = self.config.get_or_set('i_login_height', 410)
            maximized = self.config.get_or_set('b_login_maximized', False)

        if maximized:
            window.maximize()

        window.set_location(width, height, posx, posy, single_window
                            and is_conv)

    def on_preferences_changed(self, use_http, use_ipv6, proxy, session_id,
                               service):
        '''called when the preferences on login change'''
        self.config.session = session_id
        extension.set_default_by_id('session', session_id)
        self.config.b_use_http = use_http
        self.config.b_use_ipv6 = use_ipv6
        self.config.service = service
        self._save_proxy_settings(proxy)

    def on_login_failed(self, reason):
        '''callback called when login fails'''
        self._save_login_dimensions()
        self._remove_subscriptions()
        self._new_session()
        self.go_login(cancel_clicked=True)
        self.window.content_main.clear_all()
        self.window.content_main.show_error(reason, login_failed=True)

    def _setup_plugins(self):
        plugin_manager = get_pluginmanager()
        plugin_manager.scan_directory('plugins')
        plugin_dir = self.config_dir.join('plugins')
        if not os.path.exists(plugin_dir):
            os.makedirs(plugin_dir)
        plugin_manager.scan_directory(plugin_dir)

        self.session.config.get_or_set('l_active_plugins', [])

        for plugin in self.session.config.l_active_plugins:
            plugin_manager.plugin_start(plugin, self.session)
        self.session.set_default_extensions_from_config()

    def on_login_succeed(self):
        '''callback called on login succeed'''
        self._save_login_dimensions()
        self.config.save(self.config_path)

        self.draw_main_screen()
        self._setup_plugins()

        self._restore_session()

        self._sync_emesene1()

        self.check_for_updates()

        self.session.start_mail_client()
        self.logged_in = True
        self.network_checker.set_new_session(self.session)

    def on_login_connect(self,
                         account,
                         session_id,
                         proxy,
                         use_http,
                         use_ipv6,
                         host=None,
                         port=None,
                         on_reconnect=False):
        '''called when the user press the connect button'''
        self._save_login_dimensions()
        self._set_location(self.window)
        self.cur_service = [host, port]
        if not on_reconnect:
            self.on_preferences_changed(use_http, use_ipv6, proxy, session_id,
                                        self.config.service)
            self.avatar_path = self.config_dir.join(host, account.account,
                                                    'avatars', 'last')
            self.window.go_connect(self.on_cancel_login, self.avatar_path,
                                   self.config)
            self.window.show()
        else:
            self.window.content_main.clear_connect()

        self._new_session(account)

        # set default values if not already set
        self.session.config.get_or_set('b_conv_minimized', True)
        self.session.config.get_or_set('b_conv_maximized', False)

        self.session.config.get_or_set('b_mute_sounds', False)
        self.session.config.get_or_set('b_play_send', False)
        self.session.config.get_or_set('b_play_nudge', True)
        self.session.config.get_or_set('b_play_first_send', True)
        self.session.config.get_or_set('b_play_type', True)
        self.session.config.get_or_set('b_mute_sounds_when_focussed', True)
        self.session.config.get_or_set('b_play_contact_online', True)
        self.session.config.get_or_set('b_play_contact_offline', True)

        self.session.config.get_or_set('b_mute_notification', False)
        self.session.config.get_or_set('b_notify_endpoint_added', True)
        self.session.config.get_or_set('b_notify_endpoint_updated', False)
        self.session.config.get_or_set('b_notify_contact_online', True)
        self.session.config.get_or_set('b_notify_contact_offline', True)
        self.session.config.get_or_set('b_notify_receive_message', True)
        self.session.config.get_or_set('b_notify_typing', False)
        self.session.config.get_or_set('b_notify_when_focussed', False)
        self.session.config.get_or_set('b_notify_only_when_available', True)

        self.session.config.get_or_set('b_show_userpanel', True)
        self.session.config.get_or_set('b_show_mail_inbox', True)
        self.session.config.get_or_set('b_show_emoticons', True)
        self.session.config.get_or_set('b_show_header', True)
        self.session.config.get_or_set('b_show_info', True)
        self.session.config.get_or_set('b_show_toolbar', True)
        self.session.config.get_or_set('b_allow_auto_scroll', True)
        self.session.config.get_or_set('adium_theme',
                                       'renkoo.AdiumMessageStyle')
        self.session.config.get_or_set('b_enable_spell_check', False)
        self.session.config.get_or_set('b_download_folder_per_account', False)
        self.session.config.get_or_set('b_override_text_color', False)
        self.session.config.get_or_set('override_text_color', '#000000')
        self.session.config.get_or_set('b_conversation_tabs', True)
        self.session.config.get_or_set('b_single_window', True)
        self.session.config.get_or_set('b_open_mail_in_desktop', False)

        # set account uuid for session
        self.session.account_uuid = account.uuid

        self.session.login(account.account, account.password, account.status,
                           proxy, host, port, use_http, use_ipv6)

    def on_cancel_login(self):
        '''
        method called when user select cancel login
        '''
        self.close_session(False)
        self.go_login(cancel_clicked=True, no_autologin=True)

    def on_contact_list_ready(self):
        '''callback called when the contact list is ready to be used'''
        notificationcls = extension.get_default('notification')
        self.notification = notificationcls(self.session)
        self.soundPlayer = extension.get_and_instantiate('sound', self.session)

    def on_new_conversation(self, cid, members, other_started=True):
        '''callback called when the other user does an action that justify
        opening a conversation'''
        conv_tabs = self.session.config.b_conversation_tabs
        sing_wind = self.session.config.b_single_window

        conv_manager = None

        # check to see if there is a conversation with the same member
        for convman in self.conversations:
            if convman.has_similar_conversation(cid, members):
                conv_manager = convman
                break

        if conv_manager is None:
            if not self.conversations or not conv_tabs:
                if sing_wind and conv_tabs:
                    window = self.window
                else:
                    windowcls = extension.get_default('window frame')
                    window = windowcls(self._on_conversation_window_close)

                window.go_conversation(self.session,
                                       self._on_conversation_window_close)
                self._set_location(window, True, sing_wind)
                conv_manager = window.content_conv
                self.conversations.append(conv_manager)
                self.session.conversation_managers.append(conv_manager)

                if not (sing_wind and conv_tabs):
                    if self.session.config.b_conv_minimized and other_started:
                        window.iconify()
                        window.show()
                        window.iconify()
                    else:
                        window.show()
            else:
                conv_manager = self.conversations[0]

        conversation = conv_manager.new_conversation(cid, members)

        # raises the container and grabs the focus
        # handles cases where window is minimized and ctrl+tab focus stealing
        if not other_started:
            conv_manager.present(conversation, sing_wind and conv_tabs)

        if self.session.config.b_play_first_send and not \
           self.session.config.b_play_type:
            self.soundPlayer.play(gui.theme.sound_theme.sound_type)

    def _on_conversation_window_close(self, conv_manager):
        '''method called when the conversation window is closed'''
        if self.session:
            width, height, posx, posy = conv_manager.get_dimensions()

            if not conv_manager.is_maximized():
                self.session.config.i_conv_width = width
                self.session.config.i_conv_height = height
                self.session.config.i_conv_posx = posx
                self.session.config.i_conv_posy = posy
                self.session.config.b_conv_maximized = False
            else:
                self.session.config.b_conv_maximized = True
                self.session.config.i_conv_width = width  #needed for single window
            self.session.conversation_managers.remove(conv_manager)

        self.conversations.remove(conv_manager)

    def on_close(self, close=False):
        '''called when the session is closed by the user'''
        self.close_session(close)
        if not close:
            self.go_login(cancel_clicked=True, no_autologin=True)

    def on_disconnected(self, reason, reconnect=0):
        '''called when the server disconnect us'''
        account = self.session.account
        self.close_session(False, True)
        if reconnect:
            self.on_reconnect(account)
        else:
            self.go_login(cancel_clicked=True, no_autologin=True)
            if reason is not None:
                self.window.content_main.clear_all()
                self.window.content_main.show_error(reason)

    def on_reconnect(self, account):
        '''makes the reconnect after 30 seconds'''
        self.window.go_connect(self.on_cancel_login, self.avatar_path,
                               self.config)

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)
        use_ipv6 = self.config.get_or_set('b_use_ipv6', False)
        self.window.content_main.on_reconnect(self.on_login_connect, account, \
                                         self.config.session, proxy, use_http, \
                                         use_ipv6, self.cur_service)

        self.tray_icon.set_login()

    def on_picture_change_succeed(self, account, path):
        '''save the avatar change as the last avatar'''
        if account == self.session.account.account:
            last_avatar_path = self.session.config_dir.get_path("last_avatar")
            if path:
                shutil.copy(path, last_avatar_path)
            else:
                try:
                    os.remove(last_avatar_path)
                except OSError, e:
                    log.warning("Cannot remove file: %s" % e)
Beispiel #6
0
class Controller(object):
    '''class that handle the transition between states of the windows'''

    def __init__(self):
        '''class constructor'''
        self.window = None
        self.tray_icon = None
        self.conversations = []
        self.minimize = False
        self.single_instance = None
        self.config = e3.common.Config()
        self.config_dir = e3.common.ConfigDir('emesene2')
        self.config_path = self.config_dir.join('config')
        self.config.load(self.config_path)

        if self.config.d_accounts is None:
            self.config.d_accounts = {}
        if self.config.d_remembers is None:
            self.config.d_remembers = {}

        self.session = None
        self.logged_in = False
        self.timeout_id = None
        self.cur_service = None
        self.notification = None
        self.conv_manager_available = False
        self.last_session_account = None
        self.last_session_service = None
      
        lang = self.config.get_or_set("language_config", None)
        
        language_management.install_desired_translation(lang)

        self._parse_commandline()
        self._setup()

        if hasattr(signal, 'SIGINT'):
            signal.signal(signal.SIGINT,
                lambda * args: glib.idle_add(self.close_session))
        if hasattr(signal, 'SIGTERM'):
            signal.signal(signal.SIGTERM,
                lambda * args: glib.idle_add(self.close_session))
        if hasattr(signal, 'SIGHUP'):
            signal.signal(signal.SIGHUP,
                lambda * args: glib.idle_add(self.close_session))

    def _setup(self):
        '''register core extensions'''
        extension.category_register('session', dummy.Session,
                single_instance=True)
        #extension.category_register('session', msn.Session,
        #        single_instance=True)
        if jabber is not None:
            extension.register('session', jabber.Session)
        extension.register('session', dummy.Session)
        #extension.register('session', msn.Session)

        if papylib is not None:
            extension.register('session', papylib.Session)
            extension.set_default('session', papylib.Session)
        else:
            extension.set_default('session', dummy.Session)

        #DBus extension stuffs
        if DBusController is not None:
            extension.category_register('external api', DBusController)
            extension.set_default('external api', DBusController)
            self.dbus_ext = extension.get_and_instantiate('external api')
        else:
            self.dbus_ext = None

        if NetworkChecker is not None:
            extension.category_register('network checker', NetworkChecker)
            extension.set_default('network checker', NetworkChecker)
            self.network_checker = extension.get_and_instantiate(
                    'network checker')
        else:
            self.network_checker = None

        self.unity_launcher = extension.get_and_instantiate('unity launcher')

        extension.category_register('sound', e3.common.Sounds.SoundPlayer,
                None, True)
        extension.category_register('notification',
                e3.common.notification.Notification)
        extension.category_register('history exporter',
                e3.Logger.save_logs_as_txt)
        extension.register('history exporter',
                e3.Logger.save_logs_as_xml)

        if self.config.session is None:
            default_id = extension.get_category('session').default_id
            self.config.session = default_id
        else:
            default_id = self.config.session

        extension.set_default_by_id('session', default_id)

    def _parse_commandline(self):
        '''parse command line options'''
        options = optionprovider.PluggableOptionParser.get_parsing()[0]

        debugger.init(debuglevel=options.debuglevel)

        #needed to check for autologin
        self.emesene_is_running = False
        try:
            if os.name == 'posix':
                from SingleInstance import SingleInstancePosix as SingleInstance
            else:
                from SingleInstance import SingleInstanceWin32 as SingleInstance

            self.single_instance = SingleInstance()
            if self.single_instance.emesene_is_running():
                self.emesene_is_running = True
                # try to show the instance that's already running
                if options.single_instance:
                    print "Another instance of emesene is already running."
                    self.single_instance.show()
                    sys.exit(0)
        except ImportError:
            pass

        if options.minimized:
            self.minimize = True

    def start(self, account=None):
        '''the entry point to the class'''
        windowcls = extension.get_default('window frame')
        self.window = windowcls(self.close_session) # main window
        self._set_location(self.window)

        self._draw_tray_icon()

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)

        #cancel autologin if another emesene instance is running
        self.go_login(proxy, use_http, no_autologin=self.emesene_is_running)

        if self.minimize:
            self.window.iconify()
        self.window.show()

    def go_login(self, proxy=None, use_http=None, 
                 cancel_clicked=False, no_autologin=False):
        '''shows the login GUI'''
        if proxy is None:
            proxy = self._get_proxy_settings()
        if use_http is None:
            use_http = self.config.get_or_set('b_use_http', False)

        if self.window.content_type != 'empty':
            self.window.clear()

        self._save_login_dimensions()
        self._set_location(self.window)

        self.window.go_login(self.on_login_connect,
                             self.on_preferences_changed, self.config,
                             self.config_dir, self.config_path, proxy,
                             use_http, self.config.session, 
                             cancel_clicked, no_autologin)
        self.tray_icon.set_login()

    def _new_session(self, account=None):
        '''create a new session object'''

        if self.session is not None:
            self.session.quit()

        self.session = extension.get_and_instantiate('session')

        # if you add a signal here, add it on _remove_subscriptions
        signals = self.session.signals
        signals.close.subscribe(self.on_close)
        signals.login_succeed.subscribe(self.on_login_succeed)
        signals.login_failed.subscribe(self.on_login_failed)
        signals.contact_list_ready.subscribe(self.on_contact_list_ready)
        signals.conv_first_action.subscribe(self.on_new_conversation)
        signals.disconnected.subscribe(self.on_disconnected)
        signals.picture_change_succeed.subscribe(self.on_picture_change_succeed)
        signals.contact_added_you.subscribe(self.on_pending_contacts)

        #let's start dbus and unity launcher
        if self.dbus_ext is not None:
            self.dbus_ext.set_new_session(self.session, self.window)
        if self.unity_launcher is not None:
            self.unity_launcher.set_session(self.session)

    def _restore_session(self):
        account = self.session.account
        if self.conv_manager_available:
            self.session.conversation_managers = []
            if account and self.last_session_account == account.account and \
               self.last_session_service == account.service:
                self.conv_manager_available = False
                self.session.conversations = {}
                for conv_manager in self.conversations:
                    conv_manager.renew_session(self.session)
                    self.session.conversation_managers.append(conv_manager)
            else:
                for conv_manager in self.conversations:
                    conv_manager.hide_all()
                    # _on_conversation_window_close, without saving settings
                    conv_manager.close_all()
                    self.conversations.remove(conv_manager)

        self.last_session_account = account.account
        self.last_session_service = account.service

    def close_session(self, do_exit=True, server_disconnected=False):
        '''close session'''
        # prevent preference window from staying open and breaking things
        pref = extension.get_instance('preferences')
        if pref:
            pref.hide()

        self._remove_subscriptions()

        if server_disconnected:
            for conv_manager in self.conversations:
                conv_manager.close_session()
            self.conv_manager_available = True # update with new session
        else:
            for conv_manager in self.conversations:
                conv_manager.hide_all()
                self._on_conversation_window_close(conv_manager)

        if self.timeout_id:
            glib.source_remove(self.timeout_id)
            self.timeout_id = None

        if self.session is not None:
            self.session.stop_mail_client()
            self.session.quit()

        self.window.on_disconnect(self.close_session)

        self._save_application_language()
        self.save_extensions_config()
        self._save_login_dimensions()

        if self.session is not None and self.logged_in:
            self.session.save_config()
            self.session = None
            self.logged_in = False

        self.config.save(self.config_path)

        if do_exit:
            if self.tray_icon is not None:
                self.tray_icon.set_visible(False)
            self.window.hide()
            self.window = None

            sys.exit(0)

    def _remove_subscriptions(self):
        '''remove the subscriptions to signals'''
        if self.session is not None:
            signals = self.session.signals
            signals.close.unsubscribe(self.on_close)
            signals.login_succeed.unsubscribe(self.on_login_succeed)
            signals.login_failed.unsubscribe(self.on_login_failed)
            signals.contact_list_ready.unsubscribe(self.on_contact_list_ready)
            signals.conv_first_action.unsubscribe(self.on_new_conversation)
            signals.disconnected.unsubscribe(self.on_disconnected)
            signals.picture_change_succeed.unsubscribe(
                    self.on_picture_change_succeed)
            signals.contact_added_you.unsubscribe(self.on_pending_contacts)
            if self.unity_launcher is not None:
                self.unity_launcher.remove_session()
            # unsubscribe notifications signals
            if self.notification:
                self.notification.remove_subscriptions()
                self.notification = None

    def _save_application_language(self):
        '''save global settings to application config
           obtained from session settings.
        '''
        if self.session is None:
            return
            
        if self.config is None:
            return
        
        self.config.language_config = self.session.config.language_config


    def save_extensions_config(self):
        '''save the state of the extensions to the config'''
        if self.session is None:
            return

        if self.session.config.d_extensions is None:
            self.session.config.d_extensions = {}

        for name, category in extension.get_categories().iteritems():
            self.session.config.d_extensions[name] = \
                category.default_id

    def set_default_extensions_from_config(self):
        '''get the ids of the default extensions stored on config
        and set them as default on the extensions module'''

        if self.session.config.d_extensions is not None:
            for cat_name, ext_id in self.session.config\
                    .d_extensions.iteritems():
                extension.set_default_by_id(cat_name, ext_id)

    def _get_proxy_settings(self):
        '''return the values of the proxy settings as a e3.Proxy object
        initialize the values on config if not exist'''

        use_proxy = self.config.get_or_set('b_use_proxy', False)
        use_proxy_auth = self.config.get_or_set('b_use_proxy_auth', False)
        host = self.config.get_or_set('proxy_host', '')
        port = self.config.get_or_set('proxy_port', '')
        user = self.config.get_or_set('proxy_user', '')
        passwd = self.config.get_or_set('proxy_passwd', '')

        self.config.get_or_set('b_use_http', False)

        return e3.Proxy(use_proxy, host, port, use_proxy_auth, user,
            passwd)

    def _save_proxy_settings(self, proxy):
        '''save the values of the proxy settings to config'''
        self.config.b_use_proxy = proxy.use_proxy
        self.config.b_use_proxy_auth = proxy.use_auth
        self.config.proxy_host = proxy.host
        self.config.proxy_port = proxy.port
        self.config.proxy_user = proxy.user
        self.config.proxy_passwd = proxy.passwd

    def _save_login_dimensions(self):
        '''save the dimensions of the login window
        '''
        width, height, posx, posy = self.window.get_dimensions()

        # when login window is minimized, posx and posy are -32000 on Windows
        if os.name == "nt":
            # make sure that the saved dimensions are visible
            if posx < (-width):
                posx = 0
            if posy < (-height):
                posy = 0

        if not self.window.is_maximized():
            self.config.i_login_posx = posx
            self.config.i_login_posy = posy
            self.config.i_login_width = width
            self.config.i_login_height = height
            self.config.b_login_maximized = False
        else:
            self.config.b_login_maximized = True

    def draw_main_screen(self):
        '''create and populate the main screen
        '''
        self.window.clear()

        last_avatar_path = self.session.config_dir.get_path("last_avatar")
        self.session.load_config()
        
        if 'msn' in self.session.SERVICES:
            # keepalive conversations...or not
            b_keepalive = self.session.config.get_or_set("b_papylib_keepalive", False)
            self.session.get_worker().keepalive_conversations = b_keepalive

        image_name = self.session.config.get_or_set('image_theme', 'default')
        emote_name = self.session.config.get_or_set('emote_theme', 'default')
        sound_name = self.session.config.get_or_set('sound_theme', 'default')
        conv_name = self.session.config.get_or_set('adium_theme',
                'renkoo.AdiumMessagesStyle')
        conv_name_variant = self.session.config.get_or_set('adium_theme_variant',
                '')
        gui.theme.set_theme(image_name, emote_name, sound_name, conv_name, conv_name_variant)

        self.session.config.get_or_set('last_avatar', last_avatar_path)

        self.config.save(self.config_path)
        self.set_default_extensions_from_config()

        self._draw_tray_icon()
        self.tray_icon.set_main(self.session)

        self.window.go_main(self.session, self.on_new_conversation,
                            self.tray_icon.quit_on_close)

    def _draw_tray_icon(self):
        '''draws the tray icon'''
        trayiconcls = extension.get_default('tray icon')

        if self.tray_icon is not None:
            if trayiconcls == self.tray_icon.__class__:
                return
            self.tray_icon.set_visible(False)

        handler = gui.base.TrayIconHandler(self.session, gui.theme, self.close_session)
        self.tray_icon = trayiconcls(handler, self.window)

    def _sync_emesene1(self):
        syn = extension.get_default('synch tool')
        # Check if a synch tool is present. Synch tool is only in the gtk gui.
        # Remove the following 'if' when it will be in the qt4 gui too.
        if syn:
            user = self.session.account.account
            current_service = self.session.config.service
            syn = syn(self.session, current_service)
            syn.show()

    def _set_location(self, window, is_conv=False):
        '''get and set the location of the window'''
        if is_conv:
            posx = self.session.config.get_or_set('i_conv_posx', 100)
            posy = self.session.config.get_or_set('i_conv_posy', 100)
            width = self.session.config.get_or_set('i_conv_width', 600)
            height = self.session.config.get_or_set('i_conv_height', 400)
            maximized = self.session.config.get_or_set('b_conv_maximized',
                    False)
        else:
            posx = self.config.get_or_set('i_login_posx', 100)
            posy = self.config.get_or_set('i_login_posy', 100)
            width = self.config.get_or_set('i_login_width', 250)
            height = self.config.get_or_set('i_login_height', 410)
            maximized = self.config.get_or_set('b_login_maximized', False)

        screen = window.get_screen()
        pwidth, pheight = screen.get_width(), screen.get_height()
        if posx > pwidth:
            posx = (pwidth - width) // 2
        if posy > pheight:
            posy = (pheight - height) // 2
        if maximized:
            window.maximize()

        window.set_location(width, height, posx, posy)

    def on_preferences_changed(self, use_http, proxy, session_id, service):
        '''called when the preferences on login change'''
        self.config.session = session_id
        extension.set_default_by_id('session', session_id)
        self.config.b_use_http = use_http
        self.config.service = service
        self._save_proxy_settings(proxy)

    def on_login_failed(self, reason):
        '''callback called when login fails'''
        self._save_login_dimensions()
        self._remove_subscriptions()
        self._new_session()
        self.go_login(cancel_clicked=True)
        self.window.content.clear_all()
        self.window.content.show_error(reason)

    def _setup_plugins(self):
        plugin_manager = get_pluginmanager()
        plugin_manager.scan_directory('plugins')
        plugin_dir = self.config_dir.join('plugins')
        if not os.path.exists(plugin_dir):
            os.makedirs(plugin_dir)
        plugin_manager.scan_directory(plugin_dir)

        self.session.config.get_or_set('l_active_plugins', [])

        for plugin in self.session.config.l_active_plugins:
            plugin_manager.plugin_start(plugin, self.session)
        self.set_default_extensions_from_config()
        self.window.content.replace_extensions()

    def on_login_succeed(self):
        '''callback called on login succeed'''
        self._save_login_dimensions()
        self.config.save(self.config_path)

        self.draw_main_screen()
        self._setup_plugins()

        self._restore_session()

        self._sync_emesene1()

        self.session.start_mail_client()
        self.logged_in = True

        if self.network_checker is not None:
            self.network_checker.set_new_session(self.session)

    def on_login_connect(self, account, session_id, proxy,
                         use_http, host=None, port=None, on_reconnect=False):
        '''called when the user press the connect button'''
        self._save_login_dimensions()
        self._set_location(self.window)
        self.cur_service = [host, port]
        if not on_reconnect:
            self.on_preferences_changed(use_http, proxy, session_id,
                    self.config.service)
            self.window.clear()
            self.avatar_path = self.config_dir.join(host, account.account,
                    'avatars', 'last')
            self.window.go_connect(self.on_cancel_login, self.avatar_path,
                    self.config)
            self.window.show()
        else:
            self.window.content.clear_connect()

        self._new_session(account)
        
        # set default values if not already set
        self.session.config.get_or_set('b_conv_minimized', True)
        self.session.config.get_or_set('b_conv_maximized', False)
        self.session.config.get_or_set('b_mute_sounds', False)
        self.session.config.get_or_set('b_play_send', False)
        self.session.config.get_or_set('b_play_nudge', True)
        self.session.config.get_or_set('b_play_first_send', True)
        self.session.config.get_or_set('b_play_type', True)
        self.session.config.get_or_set('b_mute_sounds_when_focussed', True)
        self.session.config.get_or_set('b_play_contact_online', True)
        self.session.config.get_or_set('b_play_contact_offline', True)
        self.session.config.get_or_set('b_notify_contact_online', True)
        self.session.config.get_or_set('b_notify_contact_offline', True)
        self.session.config.get_or_set('b_notify_receive_message', True)
        self.session.config.get_or_set('b_notify_only_when_available', True)
        self.session.config.get_or_set('b_show_userpanel', True)
        self.session.config.get_or_set('b_show_mail_inbox', True)
        self.session.config.get_or_set('b_show_emoticons', True)
        self.session.config.get_or_set('b_show_header', True)
        self.session.config.get_or_set('b_show_info', True)
        self.session.config.get_or_set('b_show_toolbar', True)
        self.session.config.get_or_set('b_allow_auto_scroll', True)
        self.session.config.get_or_set('adium_theme',
                'renkoo.AdiumMessageStyle')
        self.session.config.get_or_set('b_enable_spell_check', False)
        self.session.config.get_or_set('b_download_folder_per_account', False)
        self.session.config.get_or_set('b_override_text_color', False)
        self.session.config.get_or_set('override_text_color', '#000000')
       
        self.timeout_id = glib.timeout_add(500,
                self.session.signals._handle_events)
        self.session.login(account.account, account.password, account.status,
            proxy, host, port, use_http)

    def on_cancel_login(self):
        '''
        method called when user select cancel login
        '''
        if self.session is not None:
            self.session.quit()
        self.go_login(cancel_clicked=True, no_autologin=True)

    def on_pending_contacts(self):
        '''callback called when some contact is pending'''
        def on_contact_added_you(responses):
            '''
            callback called when the dialog is closed
            '''
            for account in responses['accepted']:
                self.session.add_contact(account)

            for account in responses['rejected']:
                self.session.reject_contact(account)

        if self.session.contacts.pending:
            accounts = []
            for contact in self.session.contacts.pending.values():
                accounts.append((contact.account, contact.display_name))

            dialog = extension.get_default('dialog')
            dialog.contact_added_you(accounts, on_contact_added_you)

    def on_contact_list_ready(self):
        '''callback called when the contact list is ready to be used'''
        self.window.content.contact_list.fill()

        self.on_pending_contacts()

        glib.timeout_add(500, self.session.logger.check)

        notificationcls = extension.get_default('notification')
        self.notification = notificationcls(self.session)
        self.soundPlayer = extension.get_and_instantiate('sound', self.session)

    def on_new_conversation(self, cid, members, other_started=True):
        '''callback called when the other user does an action that justify
        opening a conversation'''
        conversation_tabs = self.session.config.get_or_set(
                'b_conversation_tabs', True)

        conv_manager = None

        # check to see if there is a conversation with the same member
        for convman in self.conversations:
            if convman.has_similar_conversation(cid, members):
                conv_manager = convman
                break

        if conv_manager is None:
            if not self.conversations or not conversation_tabs:

                windowcls = extension.get_default('window frame')
                window = windowcls(self._on_conversation_window_close)

                window.go_conversation(self.session)
                self._set_location(window, True)
                conv_manager = window.content
                self.conversations.append(conv_manager)
                self.session.conversation_managers.append(conv_manager)

                if self.session.config.b_conv_minimized and other_started:
                    window.iconify()
                    window.show()
                    window.iconify()
                else:
                    window.show()

            else:
                conv_manager = self.conversations[0]

        conversation = conv_manager.new_conversation(cid, members)

        conversation.update_data()
        conversation.show(other_started) # puts widget visible

        # raises the container and grabs the focus
        # handles cases where window is minimized and ctrl+tab focus stealing
        if not other_started:
            conv_manager.present(conversation)


        if self.session.config.b_play_first_send and not \
           self.session.config.b_play_type:
            self.soundPlayer.play(gui.theme.sound_theme.sound_type)

    def _on_conversation_window_close(self, conv_manager):
        '''method called when the conversation window is closed'''
        if self.session:
            width, height, posx, posy = \
                    conv_manager.get_dimensions()

            # when window is minimized, posx and posy are -32000 on Windows
            if os.name == "nt":
                # make sure that the saved dimensions are visible
                if posx < (-width):
                    posx = 0
                if posy < (-height):
                    posy = 0

            if not conv_manager.is_maximized():
                self.session.config.i_conv_width = width
                self.session.config.i_conv_height = height
                self.session.config.i_conv_posx = posx
                self.session.config.i_conv_posy = posy
                self.session.config.b_conv_maximized = False
            else:
                self.session.config.b_conv_maximized = True
            self.session.conversation_managers.remove(conv_manager)

        conv_manager.close_all()
        self.conversations.remove(conv_manager)

    def on_close(self, close=False):
        '''called when the session is closed by the user'''
        self.close_session(close)
        if not close:
            self.go_login(cancel_clicked=True, no_autologin=True)

    def on_disconnected(self, reason, reconnect=0):
        '''called when the server disconnect us'''
        account = self.session.account
        self.close_session(False, True)
        if reconnect:
            self.on_reconnect(account)
        else:
            self.go_login(cancel_clicked=True, no_autologin=True)
            if reason is not None:
                self.window.content.clear_all()
                self.window.content.show_error(reason)

    def on_reconnect(self, account):
        '''makes the reconnect after 30 seconds'''
        self.window.clear()
        self.window.go_connect(self.on_cancel_login, self.avatar_path,
                self.config)

        proxy = self._get_proxy_settings()
        use_http = self.config.get_or_set('b_use_http', False)
        self.window.content.on_reconnect(self.on_login_connect, account, \
                                         self.config.session, proxy, use_http, \
                                         self.cur_service)

    def on_picture_change_succeed(self, account, path):
        '''save the avatar change as the last avatar'''
        if account == self.session.account.account:
            last_avatar_path = self.session.config_dir.get_path("last_avatar")
            if path:
                shutil.copy(path, last_avatar_path)
            else:
                try:
                    os.remove(last_avatar_path)
                except OSError, e:
                    log.warning("Cannot remove file: %s" % e)