Logo Search packages:      
Sourcecode: gajim version File versions  Download package

connection.py

##    common/connection.py
##
## Contributors for this file:
##    - Yann Le Boulanger <asterix@lagaule.org>
##    - Nikos Kouremenos <nkour@jabber.org>
##    - Dimitur Kirov <dkirov@gmail.com>
##    - Travis Shirk <travis@pobox.com>
##
## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
##                         Vincent Hanquez <tab@snarc.org>
## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
##                    Vincent Hanquez <tab@snarc.org>
##                    Nikos Kouremenos <nkour@jabber.org>
##                    Dimitur Kirov <dkirov@gmail.com>
##                    Travis Shirk <travis@pobox.com>
##                    Norman Rasmussen <norman@rasmussen.co.za>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##


import os
import random
random.seed()

import signal
if os.name != 'nt':
      signal.signal(signal.SIGPIPE, signal.SIG_DFL)

import common.xmpp
from common import helpers
from common import gajim
from common import GnuPG

from connection_handlers import *
USE_GPG = GnuPG.USE_GPG

from common import i18n
_ = i18n._

00048 class Connection(ConnectionHandlers):
      '''Connection class'''
      def __init__(self, name):
            ConnectionHandlers.__init__(self)
            self.name = name
            self.connected = 0 # offline
            self.connection = None # xmpppy ClientCommon instance
            # this property is used to prevent double connections
            self.last_connection = None # last ClientCommon instance
            self.gpg = None
            self.status = ''
            self.old_show = ''
            # increase/decrease default timeout for server responses
            self.try_connecting_for_foo_secs = 45
            # holds the actual hostname to which we are connected
            self.connected_hostname = None
            self.time_to_reconnect = None
            self.new_account_info = None
            self.bookmarks = []
            self.on_purpose = False
            self.last_io = gajim.idlequeue.current_time()
            self.last_sent = []
            self.last_history_line = {}
            self.password = gajim.config.get_per('accounts', name, 'password')
            self.server_resource = gajim.config.get_per('accounts', name, 'resource')
            if gajim.config.get_per('accounts', self.name, 'keep_alives_enabled'):
                  self.keepalives = gajim.config.get_per('accounts', self.name,'keep_alive_every_foo_secs')
            else:
                  self.keepalives = 0
            self.privacy_rules_supported = False
            # Do we continue connection when we get roster (send presence,get vcard...)
            self.continue_connect_info = None
            if USE_GPG:
                  self.gpg = GnuPG.GnuPG()
                  gajim.config.set('usegpg', True)
            else:
                  gajim.config.set('usegpg', False)
            
            self.on_connect_success = None
            self.on_connect_failure = None
            self.retrycount = 0
            self.jids_for_auto_auth = [] # list of jid to auto-authorize
            
      # END __init__
      def put_event(self, ev):
            if gajim.handlers.has_key(ev[0]):
                  gajim.handlers[ev[0]](self.name, ev[1])

00096       def dispatch(self, event, data):
            '''always passes account name as first param'''
            self.put_event((event, data))


      def _reconnect(self):
            # Do not try to reco while we are already trying
            self.time_to_reconnect = None
            if self.connected < 2: #connection failed
                  gajim.log.debug('reconnect')
                  self.retrycount += 1
                  signed = self.get_signed_msg(self.status)
                  self.on_connect_auth = self._init_roster
                  self.connect_and_init(self.old_show, self.status, signed)
            else:
                  # reconnect succeeded
                  self.time_to_reconnect = None
                  self.retrycount = 0
      
      # We are doing disconnect at so many places, better use one function in all
      def disconnect(self, on_purpose = False):
            self.on_purpose = on_purpose
            self.connected = 0
            self.time_to_reconnect = None
            if self.connection:
                  # make sure previous connection is completely closed
                  gajim.proxy65_manager.disconnect(self.connection)
                  self.connection.disconnect()
                  self.connection = None
      
00126       def _disconnectedReconnCB(self):
            '''Called when we are disconnected'''
            gajim.log.debug('disconnectedReconnCB')
            if self.connected > 1:
                  # we cannot change our status to offline or connectiong
                  # after we auth to server
                  self.old_show = STATUS_LIST[self.connected]
            self.connected = 0
            self.dispatch('STATUS', 'offline')
            if not self.on_purpose:
                  self.disconnect()
                  if gajim.config.get_per('accounts', self.name, 'autoreconnect') \
                        and self.retrycount <= 10:
                        self.connected = 1
                        self.dispatch('STATUS', 'connecting')
                        self.time_to_reconnect = 10
                        # this check has moved from _reconnect method
                        if self.retrycount > 5:
                              self.time_to_reconnect = 20
                        else:
                              self.time_to_reconnect = 10
                        gajim.idlequeue.set_alarm(self._reconnect_alarm, 
                                                            self.time_to_reconnect)
                  elif self.on_connect_failure:
                        self.on_connect_failure()
                        self.on_connect_failure = None
                  else:
                              # show error dialog
                        self._connection_lost()
            else:
                  self.disconnect()
            self.on_purpose = False
      # END disconenctedReconnCB
      
      def _connection_lost(self):
            self.dispatch('ERROR',
            (_('Connection with account "%s" has been lost') % self.name,
            _('To continue sending and receiving messages, you will need to reconnect.')))

      def _event_dispatcher(self, realm, event, data):
            if realm == common.xmpp.NS_REGISTER:
                  if event == common.xmpp.features_nb.REGISTER_DATA_RECEIVED:
                        # data is (agent, DataFrom, is_form)
                        if self.new_account_info and\
                        self.new_account_info['hostname'] == data[0]:
                              #it's a new account
                              if not data[1]: # wrong answer
                                    print self.connection.lastErr
                                    self.dispatch('ACC_NOT_OK', (
                                          _('Transport %s answered wrongly to register request.') % \
                                          data[0]))
                                    return
                              req = data[1].asDict()
                              req['username'] = self.new_account_info['name']
                              req['password'] = self.new_account_info['password']
                              def _on_register_result(result):
                                    if not common.xmpp.isResultNode(result):
                                          self.dispatch('ACC_NOT_OK', (result.getError()))
                                          return
                                    self.connected = 0
                                    self.password = self.new_account_info['password']
                                    if USE_GPG:
                                          self.gpg = GnuPG.GnuPG()
                                          gajim.config.set('usegpg', True)
                                    else:
                                          gajim.config.set('usegpg', False)
                                    gajim.connections[self.name] = self
                                    self.dispatch('ACC_OK', (self.new_account_info))
                                    self.new_account_info = None
                                    self.connection = None
                              common.xmpp.features_nb.register(self.connection, data[0],
                                    req, _on_register_result)
                              return
                        if not data[1]: # wrong answer
                              self.dispatch('ERROR', (_('Invalid answer'),
                                    _('Transport %s answered wrongly to register request.') % \
                                    data[0]))
                              return
                        is_form = data[2]
                        if is_form:
                              conf = self.parse_data_form(data[1])
                        else:
                              conf = data[1].asDict()
                        self.dispatch('REGISTER_AGENT_INFO', (data[0], conf, is_form))
            elif realm == '':
                  if event == common.xmpp.transports.DATA_RECEIVED:
                        self.dispatch('STANZA_ARRIVED', unicode(data, errors = 'ignore'))
                  elif event == common.xmpp.transports.DATA_SENT:
                        self.dispatch('STANZA_SENT', unicode(data))

      def select_next_host(self, hosts):
            hosts_best_prio = []
            best_prio = 65535
            sum_weight = 0
            for h in hosts:
                  if h['prio'] < best_prio:
                        hosts_best_prio = [h]
                        best_prio = h['prio']
                        sum_weight = h['weight']
                  elif h['prio'] == best_prio:
                        hosts_best_prio.append(h)
                        sum_weight += h['weight']
            if len(hosts_best_prio) == 1:
                  return hosts_best_prio[0]
            r = random.randint(0, sum_weight)
            min_w = sum_weight
            # We return the one for which has the minimum weight and weight >= r
            for h in hosts_best_prio:
                  if h['weight'] >= r:
                        if h['weight'] <= min_w:
                              min_w = h['weight']
            return h

00239       def connect(self, data = None):
            ''' Start a connection to the Jabber server.
            Returns connection, and connection type ('tls', 'ssl', 'tcp', '')
            data MUST contain name, hostname, resource, usessl, proxy,
            use_custom_host, custom_host (if use_custom_host), custom_port (if
            use_custom_host), '''
            if self.connection:
                  return self.connection, ''

            if data:
                  name = data['name']
                  hostname = data['hostname']
                  resource = data['resource']
                  usessl = data['usessl']
                  self.try_connecting_for_foo_secs = 45
                  p = data['proxy']
                  use_srv = True
                  use_custom = data['use_custom_host']
                  if use_custom:
                        custom_h = data['custom_host']
                        custom_p = data['custom_port']
            else:
                  name = gajim.config.get_per('accounts', self.name, 'name')
                  hostname = gajim.config.get_per('accounts', self.name, 'hostname')
                  resource = gajim.config.get_per('accounts', self.name, 'resource')
                  usessl = gajim.config.get_per('accounts', self.name, 'usessl')
                  self.try_connecting_for_foo_secs = gajim.config.get_per('accounts',
                        self.name, 'try_connecting_for_foo_secs')
                  p = gajim.config.get_per('accounts', self.name, 'proxy')
                  use_srv = gajim.config.get_per('accounts', self.name, 'use_srv')
                  use_custom = gajim.config.get_per('accounts', self.name,
                        'use_custom_host')
                  custom_h = gajim.config.get_per('accounts', self.name, 'custom_host')
                  custom_p = gajim.config.get_per('accounts', self.name, 'custom_port')

            #create connection if it doesn't already exist
            self.connected = 1
            if p and p in gajim.config.get_per('proxies'):
                  proxy = {'host': gajim.config.get_per('proxies', p, 'host')}
                  proxy['port'] = gajim.config.get_per('proxies', p, 'port')
                  proxy['user'] = gajim.config.get_per('proxies', p, 'user')
                  proxy['password'] = gajim.config.get_per('proxies', p, 'pass')
            else:
                  proxy = None

            h = hostname
            p = 5222
            # autodetect [for SSL in 5223/443 and for TLS if broadcasted]
            secur = None
            if usessl:
                  p = 5223
                  secur = 1 # 1 means force SSL no matter what the port will be
                  use_srv = False # wants ssl? disable srv lookup
            if use_custom:
                  h = custom_h
                  p = custom_p
                  use_srv = False

            hosts = []
            # SRV resolver
            self._proxy = proxy
            self._secure = secur
            self._hosts = [ {'host': h, 'port': p, 'prio': 10, 'weight': 10} ]
            self._hostname = hostname
            if use_srv:
                  # add request for srv query to the resolve, on result '_on_resolve' will be called
                  gajim.resolver.resolve('_xmpp-client._tcp.' + h.encode('utf-8'), self._on_resolve)
            else:
                  self._on_resolve('', [])

      def _on_resolve(self, host, result_array):
            # SRV query returned at least one valid result, we put it in hosts dict
            if len(result_array) != 0:
                  self._hosts = [i for i in result_array]
            self.connect_to_next_host()

      def connect_to_next_host(self, retry = False):
            if len(self._hosts):
                  if self.last_connection:
                        self.last_connection.socket.disconnect()
                        self.last_connection = None
                        self.connection = None
                  if gajim.verbose:
                        con = common.xmpp.NonBlockingClient(self._hostname, caller = self,
                              on_connect = self.on_connect_success,
                              on_connect_failure = self.connect_to_next_host)
                  else:
                        con = common.xmpp.NonBlockingClient(self._hostname, debug = [], caller = self,
                              on_connect = self.on_connect_success,
                              on_connect_failure = self.connect_to_next_host)
                  self.last_connection = con
                  # increase default timeout for server responses
                  common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs
                  con.set_idlequeue(gajim.idlequeue)
                  host = self.select_next_host(self._hosts)
                  self._current_host = host
                  self._hosts.remove(host)
                  con.connect((host['host'], host['port']), proxy = self._proxy,
                        secure = self._secure)
                  return
            else:
                  if not retry or self.retrycount > 10:
                        self.retrycount = 0
                        self.time_to_reconnect = None
                        if self.on_connect_failure:
                              self.on_connect_failure()
                              self.on_connect_failure = None
                        else:
                              # shown error dialog
                              self._connection_lost()
                  else:
                        # try reconnect if connection has failed before auth to server
                        self._disconnectedReconnCB()

      def _connect_failure(self, con_type = None):
            if not con_type:
                  # we are not retrying, and not conecting
                  if not self.retrycount and self.connected != 0:
                        self.disconnect(on_purpose = True)
                        self.dispatch('STATUS', 'offline')
                        self.dispatch('ERROR', (_('Could not connect to "%s"') % self._hostname,
                              _('Check your connection or try again later.')))

      def _connect_success(self, con, con_type):
            if not self.connected: # We went offline during connecting process
                  # FIXME - not possible, maybe it was when we used threads
                  return
            self.hosts = []
            if not con_type:
                  gajim.log.debug('Could not connect to %s:%s' % (self._current_host['host'],
                        self._current_host['port']))
            self.connected_hostname = self._current_host['host']
            self.on_connect_failure = None
            con.RegisterDisconnectHandler(self._disconnectedReconnCB)
            gajim.log.debug(_('Connected to server %s:%s with %s') % (self._current_host['host'],
                  self._current_host['port'], con_type))
            # Ask metacontacts before roster
            self.get_metacontacts()
            self._register_handlers(con, con_type)
            return True

      def _register_handlers(self, con, con_type):
            self.peerhost = con.get_peerhost()
            # notify the gui about con_type
            self.dispatch('CON_TYPE', con_type)
            ConnectionHandlers._register_handlers(self, con, con_type)
            name = gajim.config.get_per('accounts', self.name, 'name')
            hostname = gajim.config.get_per('accounts', self.name, 'hostname')
            resource = gajim.config.get_per('accounts', self.name, 'resource')
            self.connection = con
            con.auth(name, self.password, resource, 1, self.__on_auth)

      def __on_auth(self, con, auth):
            if not con:
                  self.disconnect(on_purpose = True)
                  self.dispatch('STATUS', 'offline')
                  self.dispatch('ERROR', (_('Could not connect to "%s"') % self._hostname,
                        _('Check your connection or try again later')))
                  if self.on_connect_auth:
                        self.on_connect_auth(None)
                        self.on_connect_auth = None
                        return
            if not self.connected: # We went offline during connecting process
                  if self.on_connect_auth:
                        self.on_connect_auth(None)
                        self.on_connect_auth = None
                        return
            if hasattr(con, 'Resource'):
                  self.server_resource = con.Resource
            if auth:
                  self.last_io = gajim.idlequeue.current_time()
                  self.connected = 2
                  if self.on_connect_auth:
                        self.on_connect_auth(con)
                        self.on_connect_auth = None
            else:
                  # Forget password if needed
                  if not gajim.config.get_per('accounts', self.name, 'savepass'):
                        self.password = None
                  gajim.log.debug("Couldn't authenticate to %s" % self._hostname)
                  self.disconnect(on_purpose = True)
                  self.dispatch('STATUS', 'offline')
                  self.dispatch('ERROR', (_('Authentication failed with "%s"') % self._hostname,
                        _('Please check your login and password for correctness.')))
                  if self.on_connect_auth:
                        self.on_connect_auth(None)
                        self.on_connect_auth = None
      # END connect

      def quit(self, kill_core):
            if kill_core and self.connected > 1:
                  self.disconnect(on_purpose = True)
      
00432       def build_privacy_rule(self, name, action):
            '''Build a Privacy rule stanza for invisibility'''
            iq = common.xmpp.Iq('set', common.xmpp.NS_PRIVACY, xmlns = '')
            l = iq.getTag('query').setTag('list', {'name': name})
            i = l.setTag('item', {'action': action, 'order': '1'})
            i.setTag('presence-out')
            return iq

00440       def activate_privacy_rule(self, name):
            '''activate a privacy rule'''
            iq = common.xmpp.Iq('set', common.xmpp.NS_PRIVACY, xmlns = '')
            iq.getTag('query').setTag('active', {'name': name})
            self.connection.send(iq)

      def send_invisible_presence(self, msg, signed, initial = False):
            # try to set the privacy rule
            iq = self.build_privacy_rule('invisible', 'deny')
            self.connection.SendAndCallForResponse(iq, self._continue_invisible,
                  {'msg': msg, 'signed': signed, 'initial': initial})

      def _continue_invisible(self, con, iq_obj, msg, signed, initial):
            ptype = ''
            show = ''
            # FIXME: JEP 126 need some modifications (see http://lists.jabber.ru/pipermail/ejabberd/2005-July/001252.html). So I disable it for the moment
            if 1 or iq_obj.getType() == 'error': #server doesn't support privacy lists
                  # We use the old way which is not xmpp complient
                  ptype = 'invisible'
                  show = 'invisible'
            else:
                  # active the privacy rule
                  self.privacy_rules_supported = True
                  self.activate_privacy_rule('invisible')
            prio = unicode(gajim.config.get_per('accounts', self.name, 'priority'))
            p = common.xmpp.Presence(typ = ptype, priority = prio, show = show)
            p = self.add_sha(p, ptype != 'unavailable')
            if msg:
                  p.setStatus(msg)
            if signed:
                  p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed)
            self.connection.send(p)
            self.dispatch('STATUS', 'invisible')
            if initial:
                  #ask our VCard
                  self.request_vcard(None)

                  #Get bookmarks from private namespace
                  self.get_bookmarks()

                  #Inform GUI we just signed in
                  self.dispatch('SIGNED_IN', ())

      def test_gpg_passphrase(self, password):
            self.gpg.passphrase = password
            keyID = gajim.config.get_per('accounts', self.name, 'keyid')
            signed = self.gpg.sign('test', keyID)
            self.gpg.password = None
            return signed != 'BAD_PASSPHRASE'

      def get_signed_msg(self, msg):
            signed = ''
            keyID = gajim.config.get_per('accounts', self.name, 'keyid')
            if keyID and USE_GPG:
                  use_gpg_agent = gajim.config.get('use_gpg_agent')
                  if self.connected < 2 and self.gpg.passphrase is None and \
                        not use_gpg_agent:
                        # We didn't set a passphrase
                        self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
                              #%s is the account name here
                              _('You will be connected to %s without OpenPGP.') % self.name))
                  elif self.gpg.passphrase is not None or use_gpg_agent:
                        signed = self.gpg.sign(msg, keyID)
                        if signed == 'BAD_PASSPHRASE':
                              signed = ''
                              if self.connected < 2:
                                    self.dispatch('BAD_PASSPHRASE', ())
            return signed

      def connect_and_auth(self):
            self.on_connect_success = self._connect_success
            self.on_connect_failure = self._connect_failure
            self.connect()

      def connect_and_init(self, show, msg, signed):
            self.continue_connect_info = [show, msg, signed]
            self.on_connect_auth = self._init_roster
            self.connect_and_auth()

      def _init_roster(self, con):
            self.connection = con
            if self.connection:
                  con.set_send_timeout(self.keepalives, self.send_keepalive)
                  self.connection.onreceive(None)
                  # Ask metacontacts before roster
                  self.get_metacontacts()

      def change_status(self, show, msg, sync = False, auto = False):
            if not show in STATUS_LIST:
                  return -1
            sshow = helpers.get_xmpp_show(show)
            if not msg:
                  msg = ''
            keyID = gajim.config.get_per('accounts', self.name, 'keyid')
            if keyID and USE_GPG and not msg:
                  lowered_uf_status_msg = helpers.get_uf_show(show).lower()
                  # do not show I'm invisible!
                  if lowered_uf_status_msg == _('invisible'):
                        lowered_uf_status_msg = _('offline')
                  msg = _("I'm %s") % lowered_uf_status_msg
            signed = ''
            if not auto and not show == 'offline':
                  signed = self.get_signed_msg(msg)
            self.status = msg
            if show != 'offline' and not self.connected:
                  # set old_show to requested 'show' in case we need to
                  # recconect before we auth to server
                  self.old_show = show
                  self.on_purpose = False 
                  self.connect_and_init(show, msg, signed)

            elif show == 'offline' and self.connected:
                  self.connected = 0
                  if self.connection:
                        self.on_purpose = True
                        p = common.xmpp.Presence(typ = 'unavailable')
                        p = self.add_sha(p, False)
                        if msg:
                              p.setStatus(msg)
                        self.remove_all_transfers()
                        self.time_to_reconnect = None
                        self.connection.start_disconnect(p, self._on_disconnected)
                  else:
                        self.time_to_reconnect = None
                        self._on_disconnected()

            elif show != 'offline' and self.connected:
                  # dont'try to connect, when we are in state 'connecting'
                  if self.connected == 1:
                        return
                  was_invisible = self.connected == STATUS_LIST.index('invisible')
                  self.connected = STATUS_LIST.index(show)
                  if show == 'invisible':
                        self.send_invisible_presence(msg, signed)
                        return
                  if was_invisible and self.privacy_rules_supported:
                        iq = self.build_privacy_rule('visible', 'allow')
                        self.connection.send(iq)
                        self.activate_privacy_rule('visible')
                  prio = unicode(gajim.config.get_per('accounts', self.name,
                        'priority'))
                  p = common.xmpp.Presence(typ = None, priority = prio, show = sshow)
                  p = self.add_sha(p)
                  if msg:
                        p.setStatus(msg)
                  if signed:
                        p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed)
                  if self.connection:
                        self.connection.send(p)
                  self.dispatch('STATUS', show)

00591       def _on_disconnected(self):
            ''' called when a disconnect request has completed successfully'''
            self.dispatch('STATUS', 'offline')
            self.disconnect()

      def get_status(self):
            return STATUS_LIST[self.connected]

      def send_motd(self, jid, subject = '', msg = ''):
            if not self.connection:
                  return
            msg_iq = common.xmpp.Message(to = jid, body = msg, subject = subject)
            self.connection.send(msg_iq)

      def send_message(self, jid, msg, keyID, type = 'chat', subject='',
      chatstate = None, msg_id = None, composing_jep = None, resource = None):
            if not self.connection:
                  return
            if not msg and chatstate is None:
                  return
            fjid = jid
            if resource:
                  fjid += '/' + resource
            msgtxt = msg
            msgenc = ''
            if keyID and USE_GPG:
                  #encrypt
                  msgenc = self.gpg.encrypt(msg, [keyID])
                  if msgenc:
                        msgtxt = '[This message is encrypted]'
                        lang = os.getenv('LANG')
                        if lang is not None or lang != 'en': # we're not english
                              msgtxt = _('[This message is encrypted]') +\
                                    ' ([This message is encrypted])' # one  in locale and one en
            if type == 'chat':
                  msg_iq = common.xmpp.Message(to = fjid, body = msgtxt, typ = type)
            else:
                  if subject:
                        msg_iq = common.xmpp.Message(to = fjid, body = msgtxt,
                              typ = 'normal', subject = subject)
                  else:
                        msg_iq = common.xmpp.Message(to = fjid, body = msgtxt,
                              typ = 'normal')
            if msgenc:
                  msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc)

            # chatstates - if peer supports jep85 or jep22, send chatstates
            # please note that the only valid tag inside a message containing a <body>
            # tag is the active event
            if chatstate is not None:
                  if composing_jep == 'JEP-0085' or not composing_jep:
                        # JEP-0085
                        msg_iq.setTag(chatstate, namespace = common.xmpp.NS_CHATSTATES)
                  if composing_jep == 'JEP-0022' or not composing_jep:
                        # JEP-0022
                        chatstate_node = msg_iq.setTag('x', namespace = common.xmpp.NS_EVENT)
                        if not msgtxt: # when no <body>, add <id>
                              if not msg_id: # avoid putting 'None' in <id> tag
                                    msg_id = ''
                              chatstate_node.setTagData('id', msg_id)
                        # when msgtxt, requests JEP-0022 composing notification
                        if chatstate is 'composing' or msgtxt: 
                              chatstate_node.addChild(name = 'composing') 

            self.connection.send(msg_iq)
            no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')
            ji = gajim.get_jid_without_resource(jid)
            if self.name not in no_log_for and ji not in no_log_for:
                  log_msg = msg
                  if subject:
                        log_msg = _('Subject: %s\n%s') % (subject, msg)
                  if log_msg:
                        if type == 'chat':
                              kind = 'chat_msg_sent'
                        else:
                              kind = 'single_msg_sent'
                        gajim.logger.write(kind, jid, log_msg)
            self.dispatch('MSGSENT', (jid, msg, keyID))
      
00670       def send_stanza(self, stanza):
            ''' send a stanza untouched '''
            if not self.connection:
                  return
            self.connection.send(stanza)
      
      def ack_subscribed(self, jid):
            if not self.connection:
                  return
            gajim.log.debug('ack\'ing subscription complete for %s' % jid)
            p = common.xmpp.Presence(jid, 'subscribe')
            self.connection.send(p)

      def ack_unsubscribed(self, jid):
            if not self.connection:
                  return
            gajim.log.debug('ack\'ing unsubscription complete for %s' % jid)
            p = common.xmpp.Presence(jid, 'unsubscribe')
            self.connection.send(p)

      def request_subscription(self, jid, msg = '', name = '', groups = [],
      auto_auth = False):
            if not self.connection:
                  return
            gajim.log.debug('subscription request for %s' % jid)
            if auto_auth:
                  self.jids_for_auto_auth.append(jid)
            # RFC 3921 section 8.2
            infos = {'jid': jid}
            if name:
                  infos['name'] = name
            iq = common.xmpp.Iq('set', common.xmpp.NS_ROSTER)
            q = iq.getTag('query')
            item = q.addChild('item', attrs = infos)
            for g in groups:
                  item.addChild('group').setData(g)
            self.connection.send(iq)

            p = common.xmpp.Presence(jid, 'subscribe')
            p = self.add_sha(p)
            if not msg:
                  msg = _('I would like to add you to my roster.')
            p.setStatus(msg)
            self.connection.send(p)

      def send_authorization(self, jid):
            if not self.connection:
                  return
            p = common.xmpp.Presence(jid, 'subscribed')
            p = self.add_sha(p)
            self.connection.send(p)

      def refuse_authorization(self, jid):
            if not self.connection:
                  return
            p = common.xmpp.Presence(jid, 'unsubscribed')
            p = self.add_sha(p)
            self.connection.send(p)

      def unsubscribe(self, jid, remove_auth = True):
            if not self.connection:
                  return
            if remove_auth:
                  self.connection.getRoster().delItem(jid)
                  jid_list = gajim.config.get_per('contacts')
                  for j in jid_list:
                        if j.startswith(jid):
                              gajim.config.del_per('contacts', j)
            else:
                  self.connection.getRoster().Unsubscribe(jid)
                  self.update_contact(jid, '', [])

      def unsubscribe_agent(self, agent):
            if not self.connection:
                  return
            iq = common.xmpp.Iq('set', common.xmpp.NS_REGISTER, to = agent)
            iq.getTag('query').setTag('remove')
            id = self.connection.getAnID()
            iq.setID(id)
            self.awaiting_answers[id] = (AGENT_REMOVED, agent)
            self.connection.send(iq)
            self.connection.getRoster().delItem(agent)

00753       def update_contact(self, jid, name, groups):
            '''update roster item on jabber server'''
            if self.connection:
                  self.connection.getRoster().setItem(jid = jid, name = name,
                        groups = groups)
      
      def new_account(self, name, config, sync = False):
            # If a connection already exist we cannot create a new account
            if self.connection:
                  return
            self._hostname = config['hostname']
            self.new_account_info = config
            self.name = name
            self.on_connect_success = self._on_new_account
            self.on_connect_failure = self._on_new_account
            self.connect(config)

      def _on_new_account(self, con = None, con_type = None):
            if not con_type:
                  self.dispatch('ACC_NOT_OK',
                        (_('Could not connect to "%s"') % self._hostname))
                  return
            self.on_connect_failure = None
            self.connection = con
            common.xmpp.features_nb.getRegInfo(con, self._hostname)

      def account_changed(self, new_name):
            self.name = new_name

      def request_last_status_time(self, jid, resource):
            if not self.connection:
                  return
            to_whom_jid = jid
            if resource:
                  to_whom_jid += '/' + resource
            iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\
                  common.xmpp.NS_LAST)
            self.connection.send(iq)

      def request_os_info(self, jid, resource):
            if not self.connection:
                  return
            to_whom_jid = jid
            if resource:
                  to_whom_jid += '/' + resource
            iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\
                  common.xmpp.NS_VERSION)
            self.connection.send(iq)

00802       def get_settings(self):
            ''' Get Gajim settings as described in JEP 0049 '''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ='get')
            iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
            iq3 = iq2.addChild(name='gajim', namespace='gajim:prefs')
            self.connection.send(iq)

00811       def get_bookmarks(self):
            '''Get Bookmarks from storage as described in JEP 0048'''
            self.bookmarks = [] #avoid multiple bookmarks when re-connecting
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ='get')
            iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
            iq2.addChild(name='storage', namespace='storage:bookmarks')
            self.connection.send(iq)

00821       def store_bookmarks(self):
            ''' Send bookmarks to the storage namespace '''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ='set')
            iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
            iq3 = iq2.addChild(name='storage', namespace='storage:bookmarks')
            for bm in self.bookmarks:
                  iq4 = iq3.addChild(name = "conference")
                  iq4.setAttr('jid', bm['jid'])
                  iq4.setAttr('autojoin', bm['autojoin'])
                  iq4.setAttr('name', bm['name'])
                  # Only add optional elements if not empty
                  # Note: need to handle both None and '' as empty
                  #   thus shouldn't use "is not None"
                  if bm['nick']:
                        iq5 = iq4.setTagData('nick', bm['nick'])
                  if bm['password']:
                        iq5 = iq4.setTagData('password', bm['password'])
            self.connection.send(iq)

00842       def get_metacontacts(self):
            '''Get metacontacts list from storage as described in JEP 0049'''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ='get')
            iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
            iq2.addChild(name='storage', namespace='storage:metacontacts')
            self.connection.send(iq)

00851       def store_metacontacts(self, tags_list):
            ''' Send meta contacts to the storage namespace '''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ='set')
            iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
            iq3 = iq2.addChild(name='storage', namespace='storage:metacontacts')
            for tag in tags_list:
                  for data in tags_list[tag]:
                        jid = data['jid']
                        dict_ = {'jid': jid, 'tag': tag}
                        if data.has_key('order'):
                              dict_['order'] = data['order']
                        iq3.addChild(name = 'meta', attrs = dict_)
            self.connection.send(iq)

      def send_agent_status(self, agent, ptype):
            if not self.connection:
                  return
            p = common.xmpp.Presence(to = agent, typ = ptype)
            p = self.add_sha(p, ptype != 'unavailable')
            self.connection.send(p)

      def join_gc(self, nick, room, server, password):
            if not self.connection:
                  return
            show = helpers.get_xmpp_show(STATUS_LIST[self.connected])
            if show == 'invisible':
                  # Never join a room when invisible
                  return
            p = common.xmpp.Presence(to = '%s@%s/%s' % (room, server, nick),
                  show = show, status = self.status)
            if gajim.config.get('send_sha_in_gc_presence'):
                  p = self.add_sha(p)
            t = p.setTag(common.xmpp.NS_MUC + ' x')
            if password:
                  t.setTagData('password', password)
            self.connection.send(p)
            #last date/time in history to avoid duplicate
            # FIXME: This JID needs to be normalized; see #1364
            jid='%s@%s' % (room, server)
            last_log = gajim.logger.get_last_date_that_has_logs(jid, is_room = True)
            if last_log is None:
                  last_log = 0
            self.last_history_line[jid]= last_log

      def send_gc_message(self, jid, msg):
            if not self.connection:
                  return
            msg_iq = common.xmpp.Message(jid, msg, typ = 'groupchat')
            self.connection.send(msg_iq)
            self.dispatch('MSGSENT', (jid, msg))

      def send_gc_subject(self, jid, subject):
            if not self.connection:
                  return
            msg_iq = common.xmpp.Message(jid,typ = 'groupchat', subject = subject)
            self.connection.send(msg_iq)

      def request_gc_config(self, room_jid):
            iq = common.xmpp.Iq(typ = 'get', queryNS = common.xmpp.NS_MUC_OWNER,
                  to = room_jid)
            self.connection.send(iq)

      def change_gc_nick(self, room_jid, nick):
            if not self.connection:
                  return
            p = common.xmpp.Presence(to = '%s/%s' % (room_jid, nick))
            p = self.add_sha(p)
            self.connection.send(p)

      def send_gc_status(self, nick, jid, show, status):
            if not self.connection:
                  return
            if show == 'invisible':
                  show = 'offline'
            ptype = None
            if show == 'offline':
                  ptype = 'unavailable'
            show = helpers.get_xmpp_show(show)
            p = common.xmpp.Presence(to = '%s/%s' % (jid, nick), typ = ptype,
                  show = show, status = status)
            if gajim.config.get('send_sha_in_gc_presence'):
                  p = self.add_sha(p, ptype != 'unavailable')
            # send instantly so when we go offline, status is sent to gc before we
            # disconnect from jabber server
            self.connection.send(p)

00939       def gc_set_role(self, room_jid, nick, role, reason = ''):
            '''role is for all the life of the room so it's based on nick'''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS =\
                  common.xmpp.NS_MUC_ADMIN)
            item = iq.getTag('query').setTag('item')
            item.setAttr('nick', nick)
            item.setAttr('role', role)
            if reason:
                  item.addChild(name = 'reason', payload = reason)
            self.connection.send(iq)

00952       def gc_set_affiliation(self, room_jid, jid, affiliation, reason = ''):
            '''affiliation is for all the life of the room so it's based on jid'''
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS =\
                  common.xmpp.NS_MUC_ADMIN)
            item = iq.getTag('query').setTag('item')
            item.setAttr('jid', jid)
            item.setAttr('affiliation', affiliation)
            if reason:
                  item.addChild(name = 'reason', payload = reason)
            self.connection.send(iq)

      def send_gc_affiliation_list(self, room_jid, list):
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS = \
                  common.xmpp.NS_MUC_ADMIN)
            item = iq.getTag('query')
            for jid in list:
                  item_tag = item.addChild('item', {'jid': jid,
                        'affiliation': list[jid]['affiliation']})
                  if list[jid].has_key('reason') and list[jid]['reason']:
                        item_tag.setTagData('reason', list[jid]['reason'])
            self.connection.send(iq)

      def get_affiliation_list(self, room_jid, affiliation):
            if not self.connection:
                  return
            iq = common.xmpp.Iq(typ = 'get', to = room_jid, queryNS = \
                  common.xmpp.NS_MUC_ADMIN)
            item = iq.getTag('query').setTag('item')
            item.setAttr('affiliation', affiliation)
            self.connection.send(iq)

      def send_gc_config(self, room_jid, config):
            iq = common.xmpp.Iq(typ = 'set', to = room_jid, queryNS =\
                  common.xmpp.NS_MUC_OWNER)
            query = iq.getTag('query')
            self.build_data_from_dict(query, config)
            self.connection.send(iq)

      def gpg_passphrase(self, passphrase):
            if USE_GPG:
                  use_gpg_agent = gajim.config.get('use_gpg_agent')
                  if use_gpg_agent:
                        self.gpg.passphrase = None
                  else:
                        self.gpg.passphrase = passphrase

      def ask_gpg_keys(self):
            if USE_GPG:
                  keys = self.gpg.get_keys()
                  return keys
            return None

      def ask_gpg_secrete_keys(self):
            if USE_GPG:
                  keys = self.gpg.get_secret_keys()
                  return keys
            return None

      def change_password(self, password):
            if not self.connection:
                  return
            hostname = gajim.config.get_per('accounts', self.name, 'hostname')
            username = gajim.config.get_per('accounts', self.name, 'name')
            iq = common.xmpp.Iq(typ = 'set', to = hostname)
            q = iq.setTag(common.xmpp.NS_REGISTER + ' query')
            q.setTagData('username',username)
            q.setTagData('password',password)
            self.connection.send(iq)

      def unregister_account(self, on_remove_success):
            # no need to write this as a class method and keep the value of on_remove_success
            # as a class property as pass it as an argument
            def _on_unregister_account_connect(con):
                  self.on_connect_auth = None
                  if self.connected > 1:
                        hostname = gajim.config.get_per('accounts', self.name, 'hostname')
                        iq = common.xmpp.Iq(typ = 'set', to = hostname)
                        q = iq.setTag(common.xmpp.NS_REGISTER + ' query').setTag('remove')
                        con.send(iq)
                        on_remove_success(True)
                        return
                  on_remove_success(False)
            if self.connected == 0:
                  self.on_connect_auth = _on_unregister_account_connect
                  self.connect_and_auth()
            else:
                  _on_unregister_account_connect(self.connection)

01044       def send_invite(self, room, to, reason=''):
            '''sends invitation'''
            message=common.xmpp.Message(to = room)
            c = message.addChild(name = 'x', namespace = common.xmpp.NS_MUC_USER)
            c = c.addChild(name = 'invite', attrs={'to' : to})
            if reason != '':
                  c.setTagData('reason', reason)
            self.connection.send(message)

      def send_keepalive(self):
            # nothing received for the last foo seconds (60 secs by default)
            if self.connection:
                  self.connection.send(' ')

      def _reconnect_alarm(self):
            if self.time_to_reconnect:
                  if self.connected < 2:
                        self._reconnect()
                  else:
                        self.time_to_reconnect = None

# END Connection

Generated by  Doxygen 1.6.0   Back to index