File: connection.py

package info (click to toggle)
pythoncard 0.8.1-8.1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, lenny
  • size: 5,352 kB
  • ctags: 4,594
  • sloc: python: 42,401; makefile: 55; sh: 22
file content (269 lines) | stat: -rw-r--r-- 10,244 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

"""
__version__ = "$Revision: 1.9 $"
__date__ = "$Date: 2004/04/14 02:38:48 $"
"""

import wx
import os, sys
import jabber

DEBUG_LEVEL = 1

class JabberConnection:
    def __init__(self, parent, account):
        self.keepRunning = 1
        self._parent = parent
        self.con = None

        self.server = account['server']
        self.username = account['username']
        self.password = account['password']
        self.resource = account['resource']

        self.createNewConnection()

    def createNewConnection(self):
        # should make debug level settable in configuration
        con = jabber.Client(host=self.server, debug=DEBUG_LEVEL, log=sys.stderr)
        
        self.con = con
        
        con.setMessageHandler(self.messageCB)
        con.setPresenceHandler(self.presenceCB)
        con.setIqHandler(self.iqCB)
        con.setDisconnectHandler(self.disconnectedCB)

        try:
            con.connect()
        except IOError, e:
            print "Couldn't connect: %s" % e
            ##sys.exit(0)
            return
        else:
            print "Connected"

        if con.auth(self.username, self.password, self.resource):
            print "Logged in as %s to server %s" % (self.username, self.server)
        else:
            print "eek -> ", con.lastErr, con.lastErrCode

        print "Requesting Roster Info"
        con.requestRoster()
        con.sendInitPresence()

        JID = self.username + '@' + self.server + '/' + self.resource
        print "JID", JID
        self.JID = JID
        self.shortJID = str(self.JID.split('/')[0])

        self.updateRoster()
        self.updateRosterDisplay()

        # track which groupchat rooms we've joined
        # for special presence handling
        self.groupchatJIDS = {}

    def updateRoster(self):
        _roster = self.con.getRoster()
        print "\n"
        self.roster = {}
        for jid in _roster.getJIDs():
            # 2002-11-30
            # don't show gateways in the roster
            # what is the proper handling of gateways?!
            if '@' not in str(jid):
                continue
            print "%s :: %s (%s/%s)" % \
                (jid, _roster.getOnline(jid), _roster.getStatus(jid), _roster.getShow(jid))
            self.roster[str(jid)] = [_roster.getOnline(jid), _roster.getStatus(jid), _roster.getShow(jid)]
        print "\n"

    def updateRosterDisplay(self):
        roster = self.roster
        items = {}
        for key in roster:
            jid = str(key)
            status = roster[key][0].lower()
            show = roster[key][1]
            if show is None:
                show = ""
            else:
                # I noticed that some clients might let in a CR/LF on the end
                # so might as well get rid of leading and trailing whitespace
                show = show.strip()
            items[jid] = (status, show)
            self._parent.rosterQueue.put((None, items))
            wx.WakeUpIdle()

        """
        Exception in thread Thread-1:
        Traceback (most recent call last):
          File "C:\Python22\lib\threading.py", line 408, in __bootstrap
            self.run()
          File "C:\Python22\lib\threading.py", line 396, in run
            apply(self.__target, self.__args, self.__kwargs)
          File "C:\python\jabberChat\connection.py", line 92, in spinMyWheels
            self.con.process(1)
          File "C:\python\xmlstream.py", line 450, in process
            if not len(self.read()): # length of 0 means disconnect
          File "C:\python\xmlstream.py", line 379, in read
            data_in = data_in + \
          File "<string>", line 1, in recv
        error: (10054, 'Connection reset by peer')
        """

    def spinMyWheels(self):
        while self.keepRunning and self.con is not None:
            #print "spinning..."
            try:
                self.con.process(1)
            except:
                # sometimes I get the connection error above
                # so this is an attempt to workaround losing
                # the connection by creating a new one
                self.createNewConnection()
                print "***** CONNECTION PROBLEM *****"

    def sendMessage(self, to, txt, messageType='chat'):
        print "\n"
        msg = jabber.Message(to, txt.strip())
        msg.setType(messageType)
        print "<%s> %s" % (self.JID, msg.getBody())
        self.con.send(msg)
        print "\n"

    def sendChatMessage(self, to, txt):
        self.sendMessage(to, txt, 'chat')

    def sendGroupChatMessage(self, to, txt):
        self.sendMessage(to, txt, 'groupchat')

    def joinGroupChat(self, to, nickname=None):
        if to not in self.groupchatJIDS:
            self.groupchatJIDS[to] = {}
            if nickname is None:
                nickname = self.username
            print "****** JOINING ROOM ******", to, "as", nickname
            self.sendPresence(to=to + '/' + nickname)
            # we could get an error joining, but I'm not sure 
            # where to process that yet
            
    def messageCB(self, con, msg):
        """Called when a message is recieved"""
        if msg.getBody(): ## Dont show blank messages ##
            print '<' + str(msg.getFrom()) + '>' + ' ' + msg.getBody()
            txt = msg.getBody()
            self._parent.msgQueue.put((msg.getFrom(), txt))
            wx.WakeUpIdle()
    
    def presenceCB(self, con, prs):
        """Called when a presence is recieved"""
        who = str(prs.getFrom())
        type = prs.getType()
        if type is None:
            type = 'available'
        txt = None
    
        # subscription request: 
        # - accept their subscription
        # - send request for subscription to their presence
        if type == 'subscribe':
            print "subscribe request from %s" % (who)
            con.send(jabber.Presence(to=who, type='subscribed'))
            con.send(jabber.Presence(to=who, type='subscribe'))
            txt = "subscribe request from %s" % (who)
    
        # unsubscription request: 
        # - accept their unsubscription
        # - send request for unsubscription to their presence
        elif type == 'unsubscribe':
            print "unsubscribe request from %s" % (who)
            con.send(jabber.Presence(to=who, type='unsubscribed'))
            con.send(jabber.Presence(to=who, type='unsubscribe'))
            txt = "unsubscribe request from %s" % (who)
        elif type == 'subscribed':
            print "we are now subscribed to %s" % (who)
            txt = "we are now subscribed to %s" % (who)
        elif type == 'unsubscribed':
            print "we are now unsubscribed to %s"  % (who)
            txt = "we are now unsubscribed to %s"  % (who)
        elif type == 'available':
            print "%s is available (%s / %s)" % (who, prs.getShow(), prs.getStatus())
            txt = "%s is available (%s / %s)" % (who, prs.getShow(), prs.getStatus())
            # who is of the form 'username@domain/resource'
            jid = str(who.split('/')[0])
            # KEA 2002-11-30
            # should presences for the same jid such as altis@jabber.org/Exodus
            # and altis@jabber.org/default be treated separately?
            # for now, skip duplicate jids for both
            # available and unavailable
            #
            # I'm not showing gateways either
            # and still need to figure out the proper handling
            # of them
            if '@' in jid and jid != self.shortJID:
                if jid in self.groupchatJIDS:
                    nickname = str(who.split('/')[1])
                    print "*******GROUPCHAT", jid, who, prs.getStatus(), prs.getShow()
                    self.groupchatJIDS[jid][nickname] = (prs.getStatus(), prs.getShow())
                    self._parent.rosterQueue.put((jid, self.groupchatJIDS[jid]))
                    wx.WakeUpIdle()
                else:
                    self.roster[jid] = ['online', prs.getStatus(), prs.getShow()]
                    self.updateRosterDisplay()
        elif type == 'unavailable':
            print "%s is unavailable (%s / %s)" % (who, prs.getShow(), prs.getStatus())
            txt = "%s is unavailable (%s / %s)" % (who, prs.getShow(), prs.getStatus())
            # who is of the form 'username@domain/resource'
            jid = str(who.split('/')[0])
            if '@' in jid and jid != self.shortJID:
                if jid in self.groupchatJIDS:
                    nickname = str(who.split('/')[1])
                    print "*******GROUPCHAT", jid, who, prs.getStatus(), prs.getShow()
                    try:
                        del self.groupchatJIDS[jid][nickname]
                        self._parent.rosterQueue.put((jid, self.groupchatJIDS[jid]))
                        wx.WakeUpIdle()
                    except:
                        pass
                else:
                    self.roster[jid] = ['offline', prs.getStatus(), prs.getShow()]
                    self.updateRosterDisplay()

        if txt is not None:
            # need to decide whether we want a separate queue for
            # status messages, for now just let the messages be
            # printed to the console
            #self._parent.msgQueue.put(txt)
            #wx.WakeUpIdle()
            pass
    
    def iqCB(self, con,iq):
        """Called when an iq is recieved, we just let the library handle it at the moment"""
        pass

    # see p. 145 of the Programming Jabber
    # and
    # http://www.jabber.org/protocol/coredata.html#presence
    def sendPresence(self, status="Available", to=None):
        #presence = jabber.Presence(type='available')
        presence = jabber.Presence(to)
        presence.setStatus(status)
        if status == "Available":
            # apparently "normal" is the default
            #presence.setShow("normal")
            pass
        elif status == "Do Not Disturb":
            presence.setShow("dnd")
        else:
            presence.setShow("away")
        self.con.send(presence)

    def disconnectedCB(self, con):
        print "Ouch, network error"
        #sys.exit(1)

    def disconnect(self):
        self.con.disconnect()
        print "Bye!"