connection.py 7.58 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
        room_name = stanza.getFrom().getStripped()
122 123 124
        self.handler.emit('error-message', room=room_name,
                          error=stanza.getTag('error'),
                          msg=stanza.getError())
125
        raise xmpp.protocol.NodeProcessed
126 127

    def handler_presence(self, connection, presence):
128
        """
129 130
        check if it's a normal or a muc presence
        """
131 132 133 134 135 136
        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:
137 138 139 140 141 142
            self.handler_muc_presence(connection, presence)
        else:
            self.handler_normal_presence(connection, presence)

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

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

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

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

189
        raise xmpp.protocol.NodeProcessed
190

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

    def on_get_version(self, connection, iq):
204 205 206 207 208
        """
        Handles the iq requesting our software version
        """
        if not connection:
            return
209 210 211
        self.handler.emit('send-version', iq_obj=iq)

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

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