connection.py 7.67 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# -*- coding:utf-8 -*-
#
# Copyright 2010 Le Coz Florent <louizatakk@fedoraproject.org>
#
# This file is part of Poezio.
#
# Poezio is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Poezio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Poezio.  If not, see <http://www.gnu.org/licenses/>.

19 20 21 22
"""
Defines the Connection class
"""

23 24 25
from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset,
                     gettext as _)

26
import sys
27
import threading
28 29 30

import xmpp
from config import config
31
from logging import logger
32
from handler import Handler
33
from common import jid_get_node, jid_get_domain, is_jid_the_same
34

35
class Connection(threading.Thread):
36
    """
37 38
    Receives everything from Jabber and emits the
    appropriate signals
39 40
    """
    def __init__(self, server, resource):
41
        threading.Thread.__init__(self)
42
        self.handler = Handler()
43
        self.daemon = True      # exit the program when this thread exits
44 45 46 47
        if config.get('jid', '') == '':
            self.server = server
        else:
            self.server = jid_get_domain(config.get('jid', ''))
48 49 50
        self.resource = resource
        self.online = 0         # 1:connected, 2:auth confirmed
        self.jid = ''           # we don't know our jid yet (anon account)
51
        self.port = config.get('port', 5222)
52
        self.client = xmpp.Client(self.server, debug=[])
53 54 55

    def run(self):
        """
56
        run in a thread
57 58 59
        connect to server
        """
        if not self.connect_to_server(self.server, self.port):
60
            self.handler.emit('error', msg='Could not connect to server')
61
            sys.exit(-1)
62
        if not self.authenticate(config.get('jid', '') == ''):
63
            self.handler.emit('error', msg='Could not authenticate to server')
64
            sys.exit(-1)
65
        # TODO, become invisible before sendInitPresence
66
        self.client.sendInitPresence(requestRoster=0)
67
        self.register_handlers()
68 69

        self.online = 1      # 2 when confirmation of our auth is received
70 71
        while 1:
            self.process()
72 73

    def connect_to_server(self, server, port):
74 75 76
        """
        Connect to the server
        """
77 78 79 80 81
        if config.get('use_proxy','false') == 'true':
            return self.client.connect((server, port),
                                       {'host': config.get("proxy_server", ""),
                                        'port': config.get("proxy_port", 1080),
                                        'user': config.get("proxy_user", ""),
82 83
                                        'password': config.get("proxy_password",
                                                               "")
84 85 86
                                        })
        else:
            return self.client.connect((server, port))
87 88

    def authenticate(self, anon=True):
89 90 91
        """
        Authenticate to the server
        """
92
        if anon:
93 94 95 96
            try:
                self.client.auth(None, "", self.resource)
                return True
            except TypeError:
97
                self.handler.emit('error', msg=_('Error: Could not authenticate. Please make sure the server you chose (%s) supports anonymous authentication' % (config.get('server', ''))))
98
                return False
99
        else:
100 101 102
            password = config.get('password', '')
            jid = config.get('jid', '')
            auth = self.client.auth(jid_get_node(jid), password, "salut")
103
            return True
104 105

    def register_handlers(self):
106
        """
107
        registers handlers from xmpppy signals
108
        """
109 110
        self.client.RegisterHandler('iq', self.on_get_time, typ='get',
                                    ns="urn:xmpp:time")
111
        self.client.RegisterHandler('iq', self.on_get_vcard)
112 113
        self.client.RegisterHandler('iq', self.on_get_version, typ='get',
                                    ns=xmpp.NS_VERSION)
114 115
        self.client.RegisterHandler('presence', self.handler_presence)
        self.client.RegisterHandler('message', self.handler_message)
116 117

    def error_message(self, stanza):
118 119 120
        """
        handles the error messages
        """
121 122 123 124 125
        from_ = stanza.getFrom()
        if not from_:
            room_name = ''
        else:
            room_name = from_.getStripped()
126 127 128
        self.handler.emit('error-message', room=room_name,
                          error=stanza.getTag('error'),
                          msg=stanza.getError())
129
        raise xmpp.protocol.NodeProcessed
130 131

    def handler_presence(self, connection, presence):
132
        """
133 134
        check if it's a normal or a muc presence
        """
135 136 137 138 139 140
        is_muc = False
        tags = presence.getTags('x')
        for tag in tags:
            if tag.getAttr('xmlns') == 'http://jabber.org/protocol/muc#user':
                is_muc = True
        if is_muc:
141 142 143 144 145 146
            self.handler_muc_presence(connection, presence)
        else:
            self.handler_normal_presence(connection, presence)

    def handler_normal_presence(self, connection, presence):
        """
147
        handles the non-MUC presences
148
        """
149
        fro = presence.getFrom()
150
        toj = presence.getAttr('to')
151 152 153
        if presence.getType() == 'error':
            self.error_message(presence)
            return
154
        if not toj or fro == toj:           # own presence
155
            self.online = 2
156
            self.jid = toj
157
            self.handler.emit('on-connected', jid=fro)
158 159 160 161 162 163 164

    def handler_muc_presence(self, connection, presence):
        """
        handles the presence messages
        """
        if not connection:
            return
165
        self.handler.emit('room-presence', stanza=presence)
166
        raise xmpp.protocol.NodeProcessed
167

168
    def handler_delayed_message(self, connection, message):
169 170 171 172 173 174 175
        """
        handles the delayed messages
        These are received when we join a muc and we are sent the
        recent history
        """
        if not connection:
            return
176 177
        self.handler.emit('room-delayed-message', stanza=message)
        raise xmpp.protocol.NodeProcessed
178

179
    def handler_message(self, connection, message):
180 181 182 183 184
        """
        handles the common messages
        """
        if not connection:
            return
185 186 187
        if message.getType() == 'error':
            self.error_message(message)
            return
188 189 190 191
        if message.getType() == 'groupchat':
            self.handler.emit('room-message', stanza=message)
        else:
            self.handler.emit('private-message', stanza=message)
192

193
        raise xmpp.protocol.NodeProcessed
194

195
    def process(self, timeout=10):
196 197 198 199 200
        """
        Main connection loop
        It just waits for something to process (something is received
        or something has to be sent)
        """
201
        if self.online:
202
            self.client.Process(timeout)
203
        else:
204
            logger.warning('disconnecting...')
205
            sys.exit()
206 207

    def on_get_version(self, connection, iq):
208 209 210 211 212
        """
        Handles the iq requesting our software version
        """
        if not connection:
            return
213 214 215
        self.handler.emit('send-version', iq_obj=iq)

    def on_get_time(self, connection, iq):
216 217 218 219 220
        """
        handles the iq requesting our  time
        """
        if not connection:
            return
221
        self.handler.emit('send-time', iq_obj=iq)
222 223 224 225 226 227 228

    def on_get_vcard(self, connection, iq):
        """
        we received a vcard
        """
        from common import debug
        debug('\n====\n%s\n\n' % iq)