Exemplo n.º 1
0
    def _create_client(self):
        self._client = Client(log_context='TEST')
        self._client.set_domain(self.address.domain)
        self._client.set_username(self.address.localpart)
        self._client.set_resource('test')

        proxy_ip = self._builder.proxy_ip.get_text()
        if proxy_ip:
            proxy_port = int(self._builder.proxy_port.get_text())
            proxy_host = '%s:%s' % (proxy_ip, proxy_port)
            proxy = ProxyData(
                self._builder.proxy_type.get_active_text().lower(), proxy_host,
                self._builder.proxy_username.get_text() or None,
                self._builder.proxy_password.get_text() or None)
            self._client.set_proxy(proxy)

        self._client.set_connection_types(self._get_connection_types())
        self._client.set_protocols(self._get_connection_protocols())

        self._client.set_password(self.password)

        self._client.subscribe('resume-failed', self._on_signal)
        self._client.subscribe('resume-successful', self._on_signal)
        self._client.subscribe('disconnected', self._on_signal)
        self._client.subscribe('connection-lost', self._on_signal)
        self._client.subscribe('connection-failed', self._on_signal)
        self._client.subscribe('connected', self._on_connected)

        self._client.subscribe('stanza-sent', self._on_stanza_sent)
        self._client.subscribe('stanza-received', self._on_stanza_received)

        self._client.register_handler(
            StanzaHandler('message', self._on_message))
Exemplo n.º 2
0
 def createClient(self, xmpp_hosntame, username, password):
     self.client = Client()
     self.client.set_domain(xmpp_hosntame)
     self.client.set_username(username)
     self.client.set_password(password)
     self.client.set_resource(self.AUCTION_RESOURCE)
     self.client.set_ignore_tls_errors(True)
     self.client.subscribe('connection-failed', self._on_signal)
Exemplo n.º 3
0
 def createClient(self):
     self.client = Client()
     self.client.set_domain(self.XMPP_HOSTNAME)
     self.client.set_username(self.ITEM_ID_AS_LOGIN.format(self.itemId))
     self.client.set_password(self.AUCTION_PASSWORD)
     self.client.set_resource(self.AUCTION_RESOURCE)
     self.client.set_ignore_tls_errors(True)
     self.client.subscribe('resume-failed', self._on_signal)
     self.client.subscribe('resume-successful', self._on_signal)
     self.client.subscribe('disconnected', self._on_signal)
     self.client.subscribe('connection-lost', self._on_signal)
     self.client.subscribe('connection-failed', self._on_signal)
     self.client.subscribe('connected', self._on_connected)
     self.client.register_handler(StanzaHandler('message',
                                                self._on_message))
Exemplo n.º 4
0
    def _create_client(self):
        if self._destroyed:
            # If we disable an account cleanup() is called and all
            # modules are unregistered. Because disable_account() does not wait
            # for the client to properly disconnect, handlers of the
            # nbxmpp.Client() are emitted after we called cleanup().
            # After nbxmpp.Client() disconnects and is destroyed we create a
            # new instance with this method but modules.get_handlers() fails
            # because modules are already unregistered.
            # TODO: Make this nicer
            return
        log.info('Create new nbxmpp client')
        self._client = NBXMPPClient(log_context=self._account)
        self.connection = self._client
        self._client.set_domain(self._hostname)
        self._client.set_username(self._user)
        self._client.set_resource(get_resource(self._account))

        pass_saved = app.settings.get_account_setting(self._account,
                                                      'savepass')
        if pass_saved:
            # Request password from keyring only if the user chose to save
            # his password
            self.password = passwords.get_password(self._account)

        self._client.set_password(self.password)
        self._client.set_accepted_certificates(
            app.cert_store.get_certificates())

        self._client.subscribe('resume-failed', self._on_resume_failed)
        self._client.subscribe('resume-successful', self._on_resume_successful)
        self._client.subscribe('disconnected', self._on_disconnected)
        self._client.subscribe('connection-failed', self._on_connection_failed)
        self._client.subscribe('connected', self._on_connected)

        self._client.subscribe('stanza-sent', self._on_stanza_sent)
        self._client.subscribe('stanza-received', self._on_stanza_received)

        for handler in modules.get_handlers(self):
            self._client.register_handler(handler)
Exemplo n.º 5
0
class Main:
    STATUS_JOINING = 'joining'
    AUCTION_RESOURCE = 'Auction'
    ITEM_ID_AS_LOGIN = '******'
    AUCTION_ID_FORMAT = ITEM_ID_AS_LOGIN + '@{}'

    def __init__(self):
        self.client = None
        self.chatManager = None
        self.chat = None

    def main(self, xmpp_hostname, sniper_id, sniper_password, item_id):
        self.connectTo(xmpp_hostname, sniper_id, sniper_password, item_id)
        main_window = MainWindow()
        return main_window

    def connectTo(self, xmpp_hostname, username, password, item_id):
        self.createClient(xmpp_hostname, username, password)
        #self.client.connect()
        #self.client.send(nbxmpp.Presence())
        self.chatManager = ChatManager(self.client)
        self.chat = self.chatManager.create_chat(
            self.auctionId(item_id, xmpp_hostname))

    def auctionId(self, itemId, xmpp_hostname):
        return self.AUCTION_ID_FORMAT.format(itemId, xmpp_hostname)

    def createClient(self, xmpp_hosntame, username, password):
        self.client = Client()
        self.client.set_domain(xmpp_hosntame)
        self.client.set_username(username)
        self.client.set_password(password)
        self.client.set_resource(self.AUCTION_RESOURCE)
        self.client.set_ignore_tls_errors(True)
        self.client.subscribe('connection-failed', self._on_signal)

    def _on_signal(self, _client, signal_name, *args, **kwargs):
        print('%s, Error: %s', signal_name, self.client.get_error())
Exemplo n.º 6
0
class FakeAuctionServer:
    ITEM_ID_AS_LOGIN = "******"
    AUCTION_RESOURCE = "Auction"
    XMPP_HOSTNAME = "localhost"
    AUCTION_PASSWORD = "******"

    def __init__(self, itemId):
        self.itemId = itemId
        self.client: Client = None
        self.messageListener = SingleMessageListener()

    def startSellingItem(self):
        if self.client is None:
            self.createClient()

        print("connecting")
        self.client.connect()
        while True:
            print(self.client.state)

    def hasReceivedJoinRequestFromSniper(self):
        self.messageListener.receivesAMessage()

    def stop(self):
        pass

    def getItemId(self):
        return self.itemId

    def createClient(self):
        self.client = Client()
        self.client.set_domain(self.XMPP_HOSTNAME)
        self.client.set_username(self.ITEM_ID_AS_LOGIN.format(self.itemId))
        self.client.set_password(self.AUCTION_PASSWORD)
        self.client.set_resource(self.AUCTION_RESOURCE)
        self.client.set_ignore_tls_errors(True)
        self.client.subscribe('resume-failed', self._on_signal)
        self.client.subscribe('resume-successful', self._on_signal)
        self.client.subscribe('disconnected', self._on_signal)
        self.client.subscribe('connection-lost', self._on_signal)
        self.client.subscribe('connection-failed', self._on_signal)
        self.client.subscribe('connected', self._on_connected)
        self.client.register_handler(StanzaHandler('message',
                                                   self._on_message))

    def _on_signal(self, _client, _signal_name):
        print("signal")

    def _on_connected(self, _client, _signal_name):
        print("connected")
        self.client.send(nbxmpp.Presence())

    def _on_message(self, _stream, stanza, _properties):
        print('Message received')
        print(stanza.getBody())
        self.messageListener.processMessage(stanza)
Exemplo n.º 7
0
class Client(ConnectionHandlers):
    def __init__(self, account):
        self._client = None
        self._account = account
        self.name = account
        self._hostname = app.settings.get_account_setting(
            self._account, 'hostname')
        self._user = app.settings.get_account_setting(self._account, 'name')
        self.password = None

        self._priority = 0
        self._connect_machine_calls = 0
        self.addressing_supported = False

        self.is_zeroconf = False
        self.pep = {}
        self.roster_supported = True

        self._state = ClientState.DISCONNECTED
        self._status_sync_on_resume = False
        self._status = 'online'
        self._status_message = ''
        self._idle_status = 'online'
        self._idle_status_enabled = True
        self._idle_status_message = ''

        self._reconnect = True
        self._reconnect_timer_source = None
        self._destroy_client = False
        self._remove_account = False

        self._destroyed = False

        self.available_transports = {}

        modules.register_modules(self)

        self._create_client()

        if Monitor.is_available():
            self._idle_handler_id = Monitor.connect('state-changed',
                                                    self._idle_state_changed)
            self._screensaver_handler_id = app.app.connect(
                'notify::screensaver-active', self._screensaver_state_changed)

        ConnectionHandlers.__init__(self)

    def _set_state(self, state):
        log.info('State: %s', state)
        self._state = state

    @property
    def state(self):
        return self._state

    @property
    def account(self):
        return self._account

    @property
    def status(self):
        return self._status

    @property
    def status_message(self):
        if self._idle_status_active():
            return self._idle_status_message
        return self._status_message

    @property
    def priority(self):
        return self._priority

    @property
    def certificate(self):
        return self._client.peer_certificate[0]

    @property
    def features(self):
        return self._client.features

    @property
    def local_address(self):
        address = self._client.local_address
        if address is not None:
            return address.to_string().split(':')[0]
        return None

    def set_remove_account(self, value):
        # Used by the RemoveAccount Assistant to make the Client
        # not react to any stream errors that happen while the
        # account is removed by the server and the connection is killed
        self._remove_account = value

    def _create_client(self):
        if self._destroyed:
            # If we disable an account cleanup() is called and all
            # modules are unregistered. Because disable_account() does not wait
            # for the client to properly disconnect, handlers of the
            # nbxmpp.Client() are emitted after we called cleanup().
            # After nbxmpp.Client() disconnects and is destroyed we create a
            # new instance with this method but modules.get_handlers() fails
            # because modules are already unregistered.
            # TODO: Make this nicer
            return
        log.info('Create new nbxmpp client')
        self._client = NBXMPPClient(log_context=self._account)
        self.connection = self._client
        self._client.set_domain(self._hostname)
        self._client.set_username(self._user)
        self._client.set_resource(get_resource(self._account))

        pass_saved = app.settings.get_account_setting(self._account,
                                                      'savepass')
        if pass_saved:
            # Request password from keyring only if the user chose to save
            # his password
            self.password = passwords.get_password(self._account)

        self._client.set_password(self.password)
        self._client.set_accepted_certificates(
            app.cert_store.get_certificates())

        self._client.subscribe('resume-failed', self._on_resume_failed)
        self._client.subscribe('resume-successful', self._on_resume_successful)
        self._client.subscribe('disconnected', self._on_disconnected)
        self._client.subscribe('connection-failed', self._on_connection_failed)
        self._client.subscribe('connected', self._on_connected)

        self._client.subscribe('stanza-sent', self._on_stanza_sent)
        self._client.subscribe('stanza-received', self._on_stanza_received)

        for handler in modules.get_handlers(self):
            self._client.register_handler(handler)

    def _on_resume_failed(self, _client, _signal_name):
        log.info('Resume failed')
        app.nec.push_incoming_event(
            NetworkEvent('our-show', account=self._account, show='offline'))
        self.get_module('Chatstate').enabled = False

    def _on_resume_successful(self, _client, _signal_name):
        self._set_state(ClientState.CONNECTED)
        self._set_client_available()

        if self._status_sync_on_resume:
            self._status_sync_on_resume = False
            self.update_presence()
        else:
            # Normally show is updated when we receive a presence reflection.
            # On resume, if show has not changed while offline, we don’t send
            # a new presence so we have to trigger the event here.
            app.nec.push_incoming_event(
                NetworkEvent('our-show',
                             account=self._account,
                             show=self._status))

    def _set_client_available(self):
        self._set_state(ClientState.AVAILABLE)
        app.nec.push_incoming_event(
            NetworkEvent('account-connected', account=self._account))

    def disconnect(self, gracefully, reconnect, destroy_client=False):
        if self._state.is_disconnecting:
            log.warning('Disconnect already in progress')
            return

        self._set_state(ClientState.DISCONNECTING)
        self._reconnect = reconnect
        self._destroy_client = destroy_client

        log.info('Starting to disconnect %s', self._account)
        self._client.disconnect(immediate=not gracefully)

    def _on_disconnected(self, _client, _signal_name):
        log.info('Disconnect %s', self._account)
        self._set_state(ClientState.DISCONNECTED)

        domain, error, text = self._client.get_error()

        if self._remove_account:
            # Account was removed via RemoveAccount Assistant.
            self._reconnect = False

        elif domain == StreamError.BAD_CERTIFICATE:
            self._reconnect = False
            self._destroy_client = True

            cert, errors = self._client.peer_certificate

            open_window('SSLErrorDialog',
                        account=self._account,
                        client=self,
                        cert=cert,
                        error=errors.pop())

        elif domain in (StreamError.STREAM, StreamError.BIND):
            if error == 'conflict':
                # Reset resource
                app.settings.set_account_setting(self._account, 'resource',
                                                 'gajim.$rand')

        elif domain == StreamError.SASL:
            self._reconnect = False
            self._destroy_client = True

            if error in ('not-authorized', 'no-password'):

                def _on_password(password):
                    self.password = password
                    self._client.set_password(password)
                    self._prepare_for_connect()

                app.nec.push_incoming_event(
                    NetworkEvent('password-required',
                                 conn=self,
                                 on_password=_on_password))

            app.nec.push_incoming_event(
                NetworkEvent('simple-notification',
                             account=self._account,
                             type_='connection-failed',
                             title=_('Authentication failed'),
                             text=text or error))

        if self._reconnect:
            self._after_disconnect()
            self._schedule_reconnect()
            app.nec.push_incoming_event(
                NetworkEvent('our-show', account=self._account, show='error'))

        else:
            self.get_module('Chatstate').enabled = False
            app.nec.push_incoming_event(
                NetworkEvent('our-show', account=self._account,
                             show='offline'))
            self._after_disconnect()

    def _after_disconnect(self):
        self._disable_reconnect_timer()

        self.get_module('VCardAvatars').avatar_advertised = False

        app.proxy65_manager.disconnect(self._client)
        self.terminate_sessions()
        self.get_module('Bytestream').remove_all_transfers()

        if self._destroy_client:
            self._client.destroy()
            self._client = None
            self._destroy_client = False
            self._create_client()

        app.nec.push_incoming_event(
            NetworkEvent('account-disconnected', account=self._account))

    def _on_connection_failed(self, _client, _signal_name):
        self._schedule_reconnect()

    def _on_connected(self, _client, _signal_name):
        self._set_state(ClientState.CONNECTED)
        self.get_module('MUC').get_manager().reset_state()
        self.get_module('Discovery').discover_server_info()
        self.get_module('Discovery').discover_account_info()
        self.get_module('Discovery').discover_server_items()
        self.get_module('Chatstate').enabled = True
        self.get_module('MAM').reset_state()

    def _on_stanza_sent(self, _client, _signal_name, stanza):
        app.nec.push_incoming_event(
            NetworkEvent('stanza-sent', account=self._account, stanza=stanza))

    def _on_stanza_received(self, _client, _signal_name, stanza):
        app.nec.push_incoming_event(
            NetworkEvent('stanza-received',
                         account=self._account,
                         stanza=stanza))

    def get_own_jid(self):
        """
        Return the last full JID we received on a bind event.
        In case we were never connected it returns the bare JID from config.
        """
        if self._client is not None:
            jid = self._client.get_bound_jid()
            if jid is not None:
                return jid

        # This returns the bare jid
        return nbxmpp.JID.from_string(app.get_jid_from_account(self._account))

    def change_status(self, show, message):
        if not message:
            message = ''

        self._idle_status_enabled = show == 'online'
        self._status_message = message

        if show != 'offline':
            self._status = show

        if self._state.is_disconnecting:
            log.warning('Can\'t change status while '
                        'disconnect is in progress')
            return

        if self._state.is_disconnected:
            if show == 'offline':
                return

            self._prepare_for_connect()
            return

        if self._state.is_connecting:
            if show == 'offline':
                self.disconnect(gracefully=False,
                                reconnect=False,
                                destroy_client=True)
            return

        if self._state.is_reconnect_scheduled:
            if show == 'offline':
                self._destroy_client = True
                self._abort_reconnect()
            else:
                self._prepare_for_connect()
            return

        # We are connected
        if show == 'offline':
            self.set_user_activity(None)
            self.set_user_mood(None)
            self.set_user_tune(None)
            self.set_user_location(None)
            presence = self.get_module('Presence').get_presence(
                typ='unavailable', status=message, caps=False)

            self.send_stanza(presence)
            self.disconnect(gracefully=True,
                            reconnect=False,
                            destroy_client=True)
            return

        self.update_presence()

    def update_presence(self, include_muc=True):
        status, message, idle = self.get_presence_state()
        self._priority = app.get_priority(self._account, status)
        self.get_module('Presence').send_presence(priority=self._priority,
                                                  show=status,
                                                  status=message,
                                                  idle_time=idle)

        if include_muc:
            self.get_module('MUC').update_presence()

    def set_user_activity(self, activity):
        self.get_module('UserActivity').set_activity(activity)

    def set_user_mood(self, mood):
        self.get_module('UserMood').set_mood(mood)

    def set_user_tune(self, tune):
        self.get_module('UserTune').set_tune(tune)

    def set_user_location(self, location):
        self.get_module('UserLocation').set_location(location)

    def get_module(self, name):
        return modules.get(self._account, name)

    @helpers.call_counter
    def connect_machine(self):
        log.info('Connect machine state: %s', self._connect_machine_calls)
        if self._connect_machine_calls == 1:
            self.get_module('MetaContacts').get_metacontacts()
        elif self._connect_machine_calls == 2:
            self.get_module('Delimiter').get_roster_delimiter()
        elif self._connect_machine_calls == 3:
            self.get_module('Roster').request_roster()
        elif self._connect_machine_calls == 4:
            self._finish_connect()

    def _finish_connect(self):
        self._status_sync_on_resume = False
        self._set_client_available()

        # We did not resume the stream, so we are not joined any MUCs
        self.update_presence(include_muc=False)

        self.get_module('Bookmarks').request_bookmarks()
        self.get_module('SoftwareVersion').set_enabled(True)
        self.get_module('LastActivity').set_enabled(True)
        self.get_module('Annotations').request_annotations()
        self.get_module('Blocking').get_blocking_list()

        # Inform GUI we just signed in
        app.nec.push_incoming_event(
            NetworkEvent('signed-in', account=self._account, conn=self))
        modules.send_stored_publish(self._account)

    def send_stanza(self, stanza):
        """
        Send a stanza untouched
        """
        return self._client.send_stanza(stanza)

    def send_message(self, message):
        if not self._state.is_available:
            log.warning('Trying to send message while offline')
            return

        stanza = self.get_module('Message').build_message_stanza(message)
        message.stanza = stanza

        if message.contact is None:
            # Only Single Message should have no contact
            self._send_message(message)
            return

        method = message.contact.settings.get('encryption')
        if not method:
            self._send_message(message)
            return

        # TODO: Make extension point return encrypted message
        extension = 'encrypt'
        if message.is_groupchat:
            extension = 'gc_encrypt'
        app.plugin_manager.extension_point(extension + method, self, message,
                                           self._send_message)

    def _send_message(self, message):
        message.set_sent_timestamp()
        message.message_id = self.send_stanza(message.stanza)

        app.nec.push_incoming_event(
            MessageSentEvent(None, jid=message.jid, **vars(message)))

        if message.is_groupchat:
            return

        self.get_module('Message').log_message(message)

    def send_messages(self, jids, message):
        if not self._state.is_available:
            log.warning('Trying to send message while offline')
            return

        for jid in jids:
            message = message.copy()
            message.contact = app.contacts.create_contact(jid, message.account)
            stanza = self.get_module('Message').build_message_stanza(message)
            message.stanza = stanza
            self._send_message(message)

    def _prepare_for_connect(self):
        custom_host = get_custom_host(self._account)
        if custom_host is not None:
            self._client.set_custom_host(*custom_host)

        gssapi = app.settings.get_account_setting(self._account,
                                                  'enable_gssapi')
        if gssapi:
            self._client.set_mechs(['GSSAPI'])

        anonymous = app.settings.get_account_setting(self._account,
                                                     'anonymous_auth')
        if anonymous:
            self._client.set_mechs(['ANONYMOUS'])

        if app.settings.get_account_setting(self._account,
                                            'use_plain_connection'):
            self._client.set_connection_types([ConnectionType.PLAIN])

        proxy = get_user_proxy(self._account)
        if proxy is not None:
            self._client.set_proxy(proxy)

        self.connect()

    def connect(self, ignored_tls_errors=None):
        if self._state not in (ClientState.DISCONNECTED,
                               ClientState.RECONNECT_SCHEDULED):
            # Do not try to reco while we are already trying
            return

        log.info('Connect')

        self._client.set_ignored_tls_errors(ignored_tls_errors)
        self._reconnect = True
        self._disable_reconnect_timer()
        self._set_state(ClientState.CONNECTING)

        if warn_about_plain_connection(self._account,
                                       self._client.connection_types):
            app.nec.push_incoming_event(
                NetworkEvent('plain-connection',
                             account=self._account,
                             connect=self._client.connect,
                             abort=self._abort_reconnect))
            return

        self._client.connect()

    def _schedule_reconnect(self):
        self._set_state(ClientState.RECONNECT_SCHEDULED)
        log.info("Reconnect to %s in 3s", self._account)
        self._reconnect_timer_source = GLib.timeout_add_seconds(
            3, self._prepare_for_connect)

    def _abort_reconnect(self):
        self._set_state(ClientState.DISCONNECTED)
        self._disable_reconnect_timer()
        app.nec.push_incoming_event(
            NetworkEvent('our-show', account=self._account, show='offline'))

        if self._destroy_client:
            self._client.destroy()
            self._client = None
            self._destroy_client = False
            self._create_client()

    def _disable_reconnect_timer(self):
        if self._reconnect_timer_source is not None:
            GLib.source_remove(self._reconnect_timer_source)
            self._reconnect_timer_source = None

    def _idle_state_changed(self, monitor):
        state = monitor.state.value

        if monitor.is_awake():
            self._idle_status = state
            self._idle_status_message = ''
            self._update_status()
            return

        if not app.settings.get(f'auto{state}'):
            return

        if (state in ('away', 'xa') and self._status == 'online'
                or state == 'xa' and self._idle_status == 'away'):

            self._idle_status = state
            self._idle_status_message = get_idle_status_message(
                state, self._status_message)
            self._update_status()

    def _update_status(self):
        if not self._idle_status_enabled:
            return

        self._status = self._idle_status
        if self._state.is_available:
            self.update_presence()
        else:
            self._status_sync_on_resume = True

    def _idle_status_active(self):
        if not Monitor.is_available():
            return False

        if not self._idle_status_enabled:
            return False

        return self._idle_status != 'online'

    def get_presence_state(self):
        if self._idle_status_active():
            return self._idle_status, self._idle_status_message, True
        return self._status, self._status_message, False

    @staticmethod
    def _screensaver_state_changed(application, _param):
        active = application.get_property('screensaver-active')
        Monitor.set_extended_away(active)

    def cleanup(self):
        self._destroyed = True
        if Monitor.is_available():
            Monitor.disconnect(self._idle_handler_id)
            app.app.disconnect(self._screensaver_handler_id)
        if self._client is not None:
            # cleanup() is called before nbmxpp.Client has disconnected,
            # when we disable the account. So we need to unregister
            # handlers here.
            # TODO: cleanup() should not be called before disconnect is finished
            for handler in modules.get_handlers(self):
                self._client.unregister_handler(handler)
        modules.unregister_modules(self)

    def quit(self, kill_core):
        if kill_core and self._state in (ClientState.CONNECTING,
                                         ClientState.CONNECTED,
                                         ClientState.AVAILABLE):
            self.disconnect(gracefully=True, reconnect=False)
Exemplo n.º 8
0
    def _get_base_client(self,
                         domain,
                         username,
                         mode,
                         advanced,
                         ignore_all_errors):

        client = Client(log_context='Account Wizard')
        client.set_domain(domain)
        client.set_username(username)
        client.set_mode(mode)
        client.set_ignore_tls_errors(ignore_all_errors)
        client.set_accepted_certificates(
            app.cert_store.get_certificates())

        if advanced:
            custom_host = self.get_page('advanced').get_custom_host()
            if custom_host is not None:
                client.set_custom_host(*custom_host)

            proxy_name = self.get_page('advanced').get_proxy()
            proxy_data = get_proxy(proxy_name)
            if proxy_data is not None:
                client.set_proxy(proxy_data)

        client.subscribe('disconnected', self._on_disconnected)
        client.subscribe('connection-failed', self._on_connection_failed)
        client.subscribe('stanza-sent', self._on_stanza_sent)
        client.subscribe('stanza-received', self._on_stanza_received)
        return client
Exemplo n.º 9
0
class TestClient(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='Test Client')
        self.set_default_size(500, 500)

        self._builder = Builder('client.ui')
        self._builder.connect_signals(self)

        self.add(self._builder.grid)

        self._client = None
        self._scroll_timeout = None
        self._create_paths()
        self._load_config()

    def _create_client(self):
        self._client = Client(log_context='TEST')
        self._client.set_domain(self.address.domain)
        self._client.set_username(self.address.localpart)
        self._client.set_resource('test')

        proxy_ip = self._builder.proxy_ip.get_text()
        if proxy_ip:
            proxy_port = int(self._builder.proxy_port.get_text())
            proxy_host = '%s:%s' % (proxy_ip, proxy_port)
            proxy = ProxyData(
                self._builder.proxy_type.get_active_text().lower(), proxy_host,
                self._builder.proxy_username.get_text() or None,
                self._builder.proxy_password.get_text() or None)
            self._client.set_proxy(proxy)

        self._client.set_connection_types(self._get_connection_types())
        self._client.set_protocols(self._get_connection_protocols())

        self._client.set_password(self.password)

        self._client.subscribe('resume-failed', self._on_signal)
        self._client.subscribe('resume-successful', self._on_signal)
        self._client.subscribe('disconnected', self._on_signal)
        self._client.subscribe('connection-lost', self._on_signal)
        self._client.subscribe('connection-failed', self._on_signal)
        self._client.subscribe('connected', self._on_connected)

        self._client.subscribe('stanza-sent', self._on_stanza_sent)
        self._client.subscribe('stanza-received', self._on_stanza_received)

        self._client.register_handler(
            StanzaHandler('message', self._on_message))

    @property
    def password(self):
        return self._builder.password.get_text()

    @property
    def address(self):
        return JID.from_string(self._builder.address.get_text())

    @property
    def xml_box(self):
        return self._builder.xml_box

    def scroll_to_end(self):
        adj_v = self._builder.scrolledwin.get_vadjustment()
        if adj_v is None:
            # This can happen when the Widget is already destroyed when called
            # from GLib.idle_add
            self._scroll_timeout = None
            return
        max_scroll_pos = adj_v.get_upper() - adj_v.get_page_size()
        adj_v.set_value(max_scroll_pos)

        adj_h = self._builder.scrolledwin.get_hadjustment()
        adj_h.set_value(0)
        self._scroll_timeout = None

    def _on_signal(self, _client, signal_name, *args, **kwargs):
        log.info('%s, Error: %s', signal_name, self._client.get_error())
        if signal_name == 'disconnected':
            if self._client.get_error() is None:
                return
            domain, error, text = self._client.get_error()
            if domain == StreamError.BAD_CERTIFICATE:
                self._client.set_ignore_tls_errors(True)
                self._client.connect()

    def _on_connected(self, _client, _signal_name):
        self.send_presence()

    def _on_message(self, _stream, stanza, _properties):
        log.info('Message received')
        log.info(stanza.getBody())

    def _on_stanza_sent(self, _stream, _signal_name, data):
        self.xml_box.add(StanzaRow(data, False))
        self._add_scroll_timeout()

    def _on_stanza_received(self, _stream, _signal_name, data):
        self.xml_box.add(StanzaRow(data, True))
        self._add_scroll_timeout()

    def _add_scroll_timeout(self):
        if self._scroll_timeout is not None:
            return
        self._scroll_timeout = GLib.timeout_add(50, self.scroll_to_end)

    def _connect_clicked(self, *args):
        if self._client is None:
            self._create_client()

        self._client.connect()

    def _disconnect_clicked(self, *args):
        if self._client is not None:
            self._client.disconnect()

    def _clear_clicked(self, *args):
        self.xml_box.foreach(self._remove)

    def _on_reconnect_clicked(self, *args):
        if self._client is not None:
            self._client.reconnect()

    def _get_connection_types(self):
        types = []
        if self._builder.directtls.get_active():
            types.append(ConnectionType.DIRECT_TLS)
        if self._builder.starttls.get_active():
            types.append(ConnectionType.START_TLS)
        if self._builder.plain.get_active():
            types.append(ConnectionType.PLAIN)
        return types

    def _get_connection_protocols(self):
        protocols = []
        if self._builder.tcp.get_active():
            protocols.append(ConnectionProtocol.TCP)
        if self._builder.websocket.get_active():
            protocols.append(ConnectionProtocol.WEBSOCKET)
        return protocols

    def _on_save_clicked(self, *args):
        data = {}
        data['jid'] = self._builder.address.get_text()
        data['password'] = self._builder.password.get_text()
        data['proxy_type'] = self._builder.proxy_type.get_active_text()
        data['proxy_ip'] = self._builder.proxy_ip.get_text()
        data['proxy_port'] = self._builder.proxy_port.get_text()
        data['proxy_username'] = self._builder.proxy_username.get_text()
        data['proxy_password'] = self._builder.proxy_password.get_text()

        data['directtls'] = self._builder.directtls.get_active()
        data['starttls'] = self._builder.starttls.get_active()
        data['plain'] = self._builder.plain.get_active()
        data['tcp'] = self._builder.tcp.get_active()
        data['websocket'] = self._builder.websocket.get_active()

        path = self._get_config_dir() / 'config'
        with path.open('w') as fp:
            json.dump(data, fp)

    def _load_config(self):
        path = self._get_config_dir() / 'config'
        if not path.exists():
            return

        with path.open('r') as fp:
            data = json.load(fp)

        self._builder.address.set_text(data.get('jid', ''))
        self._builder.password.set_text(data.get('password', ''))
        self._builder.proxy_type.set_active_id(data.get('proxy_type', 'HTTP'))
        self._builder.proxy_ip.set_text(data.get('proxy_ip', ''))
        self._builder.proxy_port.set_text(data.get('proxy_port', ''))
        self._builder.proxy_username.set_text(data.get('proxy_username', ''))
        self._builder.proxy_password.set_text(data.get('proxy_password', ''))

        self._builder.directtls.set_active(data.get('directtls', False))
        self._builder.starttls.set_active(data.get('starttls', False))
        self._builder.plain.set_active(data.get('plain', False))
        self._builder.tcp.set_active(data.get('tcp', False))
        self._builder.websocket.set_active(data.get('websocket', False))

    @staticmethod
    def _get_config_dir():
        if os.name == 'nt':
            return Path(os.path.join(os.environ['appdata'], 'nbxmpp'))

        expand = os.path.expanduser
        base = os.getenv('XDG_CONFIG_HOME')
        if base is None or base[0] != '/':
            base = expand('~/.config')
        return Path(os.path.join(base, 'nbxmpp'))

    def _create_paths(self):
        path_ = self._get_config_dir()
        if not path_.exists():
            for parent_path in reversed(path_.parents):
                # Create all parent folders
                # don't use mkdir(parent=True), as it ignores `mode`
                # when creating the parents
                if not parent_path.exists():
                    print('creating %s directory' % parent_path)
                    parent_path.mkdir(mode=0o700)
            print('creating %s directory' % path_)
            path_.mkdir(mode=0o700)

    def _remove(self, item):
        self.xml_box.remove(item)
        item.destroy()

    def send_presence(self):
        presence = nbxmpp.Presence()
        self._client.send_stanza(presence)