Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(202)

Side by Side Diff: third_party/twisted_8_1/twisted/words/protocols/oscar.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.words.test -*-
2 # Copyright (c) 2001-2005 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """
7 An implementation of the OSCAR protocol, which AIM and ICQ use to communcate.
8
9 Maintainer: U{Paul Swartz<mailto:z3p@twistedmatrix.com>}
10 """
11
12 from __future__ import nested_scopes
13
14 from twisted.internet import reactor, defer, protocol
15 from twisted.python import log
16
17 import struct
18 import md5
19 import string
20 import socket
21 import random
22 import time
23 import types
24 import re
25
26 def logPacketData(data):
27 lines = len(data)/16
28 if lines*16 != len(data): lines=lines+1
29 for i in range(lines):
30 d = tuple(data[16*i:16*i+16])
31 hex = map(lambda x: "%02X"%ord(x),d)
32 text = map(lambda x: (len(repr(x))>3 and '.') or x, d)
33 log.msg(' '.join(hex)+ ' '*3*(16-len(d)) +''.join(text))
34 log.msg('')
35
36 def SNAC(fam,sub,id,data,flags=[0,0]):
37 header="!HHBBL"
38 head=struct.pack(header,fam,sub,
39 flags[0],flags[1],
40 id)
41 return head+str(data)
42
43 def readSNAC(data):
44 header="!HHBBL"
45 head=list(struct.unpack(header,data[:10]))
46 return head+[data[10:]]
47
48 def TLV(type,value):
49 header="!HH"
50 head=struct.pack(header,type,len(value))
51 return head+str(value)
52
53 def readTLVs(data,count=None):
54 header="!HH"
55 dict={}
56 while data and len(dict)!=count:
57 head=struct.unpack(header,data[:4])
58 dict[head[0]]=data[4:4+head[1]]
59 data=data[4+head[1]:]
60 if not count:
61 return dict
62 return dict,data
63
64 def encryptPasswordMD5(password,key):
65 m=md5.new()
66 m.update(key)
67 m.update(md5.new(password).digest())
68 m.update("AOL Instant Messenger (SM)")
69 return m.digest()
70
71 def encryptPasswordICQ(password):
72 key=[0xF3,0x26,0x81,0xC4,0x39,0x86,0xDB,0x92,0x71,0xA3,0xB9,0xE6,0x53,0x7A,0 x95,0x7C]
73 bytes=map(ord,password)
74 r=""
75 for i in range(len(bytes)):
76 r=r+chr(bytes[i]^key[i%len(key)])
77 return r
78
79 def dehtml(text):
80 text=string.replace(text,"<br>","\n")
81 text=string.replace(text,"<BR>","\n")
82 text=string.replace(text,"<Br>","\n") # XXX make this a regexp
83 text=string.replace(text,"<bR>","\n")
84 text=re.sub('<.*?>','',text)
85 text=string.replace(text,'&gt;','>')
86 text=string.replace(text,'&lt;','<')
87 text=string.replace(text,'&nbsp;',' ')
88 text=string.replace(text,'&#34;','"')
89 text=string.replace(text,'&amp;','&')
90 return text
91
92 def html(text):
93 text=string.replace(text,'"','&#34;')
94 text=string.replace(text,'&','&amp;')
95 text=string.replace(text,'<','&lt;')
96 text=string.replace(text,'>','&gt;')
97 text=string.replace(text,"\n","<br>")
98 return '<html><body bgcolor="white"><font color="black">%s</font></body></ht ml>'%text
99
100 class OSCARUser:
101 def __init__(self, name, warn, tlvs):
102 self.name = name
103 self.warning = warn
104 self.flags = []
105 self.caps = []
106 for k,v in tlvs.items():
107 if k == 1: # user flags
108 v=struct.unpack('!H',v)[0]
109 for o, f in [(1,'trial'),
110 (2,'unknown bit 2'),
111 (4,'aol'),
112 (8,'unknown bit 4'),
113 (16,'aim'),
114 (32,'away'),
115 (1024,'activebuddy')]:
116 if v&o: self.flags.append(f)
117 elif k == 2: # member since date
118 self.memberSince = struct.unpack('!L',v)[0]
119 elif k == 3: # on-since
120 self.onSince = struct.unpack('!L',v)[0]
121 elif k == 4: # idle time
122 self.idleTime = struct.unpack('!H',v)[0]
123 elif k == 5: # unknown
124 pass
125 elif k == 6: # icq online status
126 if v[2] == '\x00':
127 self.icqStatus = 'online'
128 elif v[2] == '\x01':
129 self.icqStatus = 'away'
130 elif v[2] == '\x02':
131 self.icqStatus = 'dnd'
132 elif v[2] == '\x04':
133 self.icqStatus = 'out'
134 elif v[2] == '\x10':
135 self.icqStatus = 'busy'
136 else:
137 self.icqStatus = 'unknown'
138 elif k == 10: # icq ip address
139 self.icqIPaddy = socket.inet_ntoa(v)
140 elif k == 12: # icq random stuff
141 self.icqRandom = v
142 elif k == 13: # capabilities
143 caps=[]
144 while v:
145 c=v[:16]
146 if c==CAP_ICON: caps.append("icon")
147 elif c==CAP_IMAGE: caps.append("image")
148 elif c==CAP_VOICE: caps.append("voice")
149 elif c==CAP_CHAT: caps.append("chat")
150 elif c==CAP_GET_FILE: caps.append("getfile")
151 elif c==CAP_SEND_FILE: caps.append("sendfile")
152 elif c==CAP_SEND_LIST: caps.append("sendlist")
153 elif c==CAP_GAMES: caps.append("games")
154 else: caps.append(("unknown",c))
155 v=v[16:]
156 caps.sort()
157 self.caps=caps
158 elif k == 14: pass
159 elif k == 15: # session length (aim)
160 self.sessionLength = struct.unpack('!L',v)[0]
161 elif k == 16: # session length (aol)
162 self.sessionLength = struct.unpack('!L',v)[0]
163 elif k == 30: # no idea
164 pass
165 else:
166 log.msg("unknown tlv for user %s\nt: %s\nv: %s"%(self.name,k,rep r(v)))
167
168 def __str__(self):
169 s = '<OSCARUser %s' % self.name
170 o = []
171 if self.warning!=0: o.append('warning level %s'%self.warning)
172 if hasattr(self, 'flags'): o.append('flags %s'%self.flags)
173 if hasattr(self, 'sessionLength'): o.append('online for %i minutes' % (s elf.sessionLength/60,))
174 if hasattr(self, 'idleTime'): o.append('idle for %i minutes' % self.idle Time)
175 if self.caps: o.append('caps %s'%self.caps)
176 if o:
177 s=s+', '+', '.join(o)
178 s=s+'>'
179 return s
180
181
182 class SSIGroup:
183 def __init__(self, name, tlvs = {}):
184 self.name = name
185 #self.tlvs = []
186 #self.userIDs = []
187 self.usersToID = {}
188 self.users = []
189 #if not tlvs.has_key(0xC8): return
190 #buddyIDs = tlvs[0xC8]
191 #while buddyIDs:
192 # bid = struct.unpack('!H',buddyIDs[:2])[0]
193 # buddyIDs = buddyIDs[2:]
194 # self.users.append(bid)
195
196 def findIDFor(self, user):
197 return self.usersToID[user]
198
199 def addUser(self, buddyID, user):
200 self.usersToID[user] = buddyID
201 self.users.append(user)
202 user.group = self
203
204 def oscarRep(self, groupID, buddyID):
205 tlvData = TLV(0xc8, reduce(lambda x,y:x+y, [struct.pack('!H',self.usersT oID[x]) for x in self.users]))
206 return struct.pack('!H', len(self.name)) + self.name + \
207 struct.pack('!HH', groupID, buddyID) + '\000\001' + tlvData
208
209
210 class SSIBuddy:
211 def __init__(self, name, tlvs = {}):
212 self.name = name
213 self.tlvs = tlvs
214 for k,v in tlvs.items():
215 if k == 0x013c: # buddy comment
216 self.buddyComment = v
217 elif k == 0x013d: # buddy alerts
218 actionFlag = ord(v[0])
219 whenFlag = ord(v[1])
220 self.alertActions = []
221 self.alertWhen = []
222 if actionFlag&1:
223 self.alertActions.append('popup')
224 if actionFlag&2:
225 self.alertActions.append('sound')
226 if whenFlag&1:
227 self.alertWhen.append('online')
228 if whenFlag&2:
229 self.alertWhen.append('unidle')
230 if whenFlag&4:
231 self.alertWhen.append('unaway')
232 elif k == 0x013e:
233 self.alertSound = v
234
235 def oscarRep(self, groupID, buddyID):
236 tlvData = reduce(lambda x,y: x+y, map(lambda (k,v):TLV(k,v), self.tlvs.i tems()), '\000\000')
237 return struct.pack('!H', len(self.name)) + self.name + \
238 struct.pack('!HH', groupID, buddyID) + '\000\000' + tlvData
239
240
241 class OscarConnection(protocol.Protocol):
242 def connectionMade(self):
243 self.state=""
244 self.seqnum=0
245 self.buf=''
246 self.stopKeepAliveID = None
247 self.setKeepAlive(4*60) # 4 minutes
248
249 def connectionLost(self, reason):
250 log.msg("Connection Lost! %s" % self)
251 self.stopKeepAlive()
252
253 # def connectionFailed(self):
254 # log.msg("Connection Failed! %s" % self)
255 # self.stopKeepAlive()
256
257 def sendFLAP(self,data,channel = 0x02):
258 header="!cBHH"
259 self.seqnum=(self.seqnum+1)%0xFFFF
260 seqnum=self.seqnum
261 head=struct.pack(header,'*', channel,
262 seqnum, len(data))
263 self.transport.write(head+str(data))
264 # if isinstance(self, ChatService):
265 # logPacketData(head+str(data))
266
267 def readFlap(self):
268 header="!cBHH"
269 if len(self.buf)<6: return
270 flap=struct.unpack(header,self.buf[:6])
271 if len(self.buf)<6+flap[3]: return
272 data,self.buf=self.buf[6:6+flap[3]],self.buf[6+flap[3]:]
273 return [flap[1],data]
274
275 def dataReceived(self,data):
276 # if isinstance(self, ChatService):
277 # logPacketData(data)
278 self.buf=self.buf+data
279 flap=self.readFlap()
280 while flap:
281 func=getattr(self,"oscar_%s"%self.state,None)
282 if not func:
283 log.msg("no func for state: %s" % self.state)
284 state=func(flap)
285 if state:
286 self.state=state
287 flap=self.readFlap()
288
289 def setKeepAlive(self,t):
290 self.keepAliveDelay=t
291 self.stopKeepAlive()
292 self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive)
293
294 def sendKeepAlive(self):
295 self.sendFLAP("",0x05)
296 self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendK eepAlive)
297
298 def stopKeepAlive(self):
299 if self.stopKeepAliveID:
300 self.stopKeepAliveID.cancel()
301 self.stopKeepAliveID = None
302
303 def disconnect(self):
304 """
305 send the disconnect flap, and sever the connection
306 """
307 self.sendFLAP('', 0x04)
308 def f(reason): pass
309 self.connectionLost = f
310 self.transport.loseConnection()
311
312
313 class SNACBased(OscarConnection):
314 snacFamilies = {
315 # family : (version, toolID, toolVersion)
316 }
317 def __init__(self,cookie):
318 self.cookie=cookie
319 self.lastID=0
320 self.supportedFamilies = ()
321 self.requestCallbacks={} # request id:Deferred
322
323 def sendSNAC(self,fam,sub,data,flags=[0,0]):
324 """
325 send a snac and wait for the response by returning a Deferred.
326 """
327 reqid=self.lastID
328 self.lastID=reqid+1
329 d = defer.Deferred()
330 d.reqid = reqid
331
332 #d.addErrback(self._ebDeferredError,fam,sub,data) # XXX for testing
333
334 self.requestCallbacks[reqid] = d
335 self.sendFLAP(SNAC(fam,sub,reqid,data))
336 return d
337
338 def _ebDeferredError(self, error, fam, sub, data):
339 log.msg('ERROR IN DEFERRED %s' % error)
340 log.msg('on sending of message, family 0x%02x, subtype 0x%02x' % (fam, s ub))
341 log.msg('data: %s' % repr(data))
342
343 def sendSNACnr(self,fam,sub,data,flags=[0,0]):
344 """
345 send a snac, but don't bother adding a deferred, we don't care.
346 """
347 self.sendFLAP(SNAC(fam,sub,0x10000*fam+sub,data))
348
349 def oscar_(self,data):
350 self.sendFLAP("\000\000\000\001"+TLV(6,self.cookie), 0x01)
351 return "Data"
352
353 def oscar_Data(self,data):
354 snac=readSNAC(data[1])
355 if self.requestCallbacks.has_key(snac[4]):
356 d = self.requestCallbacks[snac[4]]
357 del self.requestCallbacks[snac[4]]
358 if snac[1]!=1:
359 d.callback(snac)
360 else:
361 d.errback(snac)
362 return
363 func=getattr(self,'oscar_%02X_%02X'%(snac[0],snac[1]),None)
364 if not func:
365 self.oscar_unknown(snac)
366 else:
367 func(snac[2:])
368 return "Data"
369
370 def oscar_unknown(self,snac):
371 log.msg("unknown for %s" % self)
372 log.msg(snac)
373
374
375 def oscar_01_03(self, snac):
376 numFamilies = len(snac[3])/2
377 self.supportedFamilies = struct.unpack("!"+str(numFamilies)+'H', snac[3] )
378 d = ''
379 for fam in self.supportedFamilies:
380 if self.snacFamilies.has_key(fam):
381 d=d+struct.pack('!2H',fam,self.snacFamilies[fam][0])
382 self.sendSNACnr(0x01,0x17, d)
383
384 def oscar_01_0A(self,snac):
385 """
386 change of rate information.
387 """
388 # this can be parsed, maybe we can even work it in
389 pass
390
391 def oscar_01_18(self,snac):
392 """
393 host versions, in the same format as we sent
394 """
395 self.sendSNACnr(0x01,0x06,"") #pass
396
397 def clientReady(self):
398 """
399 called when the client is ready to be online
400 """
401 d = ''
402 for fam in self.supportedFamilies:
403 if self.snacFamilies.has_key(fam):
404 version, toolID, toolVersion = self.snacFamilies[fam]
405 d = d + struct.pack('!4H',fam,version,toolID,toolVersion)
406 self.sendSNACnr(0x01,0x02,d)
407
408 class BOSConnection(SNACBased):
409 snacFamilies = {
410 0x01:(3, 0x0110, 0x059b),
411 0x13:(3, 0x0110, 0x059b),
412 0x02:(1, 0x0110, 0x059b),
413 0x03:(1, 0x0110, 0x059b),
414 0x04:(1, 0x0110, 0x059b),
415 0x06:(1, 0x0110, 0x059b),
416 0x08:(1, 0x0104, 0x0001),
417 0x09:(1, 0x0110, 0x059b),
418 0x0a:(1, 0x0110, 0x059b),
419 0x0b:(1, 0x0104, 0x0001),
420 0x0c:(1, 0x0104, 0x0001)
421 }
422
423 capabilities = None
424
425 def __init__(self,username,cookie):
426 SNACBased.__init__(self,cookie)
427 self.username=username
428 self.profile = None
429 self.awayMessage = None
430 self.services = {}
431
432 if not self.capabilities:
433 self.capabilities = [CAP_CHAT]
434
435 def parseUser(self,data,count=None):
436 l=ord(data[0])
437 name=data[1:1+l]
438 warn,foo=struct.unpack("!HH",data[1+l:5+l])
439 warn=int(warn/10)
440 tlvs=data[5+l:]
441 if count:
442 tlvs,rest = readTLVs(tlvs,foo)
443 else:
444 tlvs,rest = readTLVs(tlvs), None
445 u = OSCARUser(name, warn, tlvs)
446 if rest == None:
447 return u
448 else:
449 return u, rest
450
451 def oscar_01_05(self, snac, d = None):
452 """
453 data for a new service connection
454 d might be a deferred to be called back when the service is ready
455 """
456 tlvs = readTLVs(snac[3][2:])
457 service = struct.unpack('!H',tlvs[0x0d])[0]
458 ip = tlvs[5]
459 cookie = tlvs[6]
460 #c = serviceClasses[service](self, cookie, d)
461 c = protocol.ClientCreator(reactor, serviceClasses[service], self, cooki e, d)
462 def addService(x):
463 self.services[service] = x
464 c.connectTCP(ip, 5190).addCallback(addService)
465 #self.services[service] = c
466
467 def oscar_01_07(self,snac):
468 """
469 rate paramaters
470 """
471 self.sendSNACnr(0x01,0x08,"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05") # ack
472 self.initDone()
473 self.sendSNACnr(0x13,0x02,'') # SSI rights info
474 self.sendSNACnr(0x02,0x02,'') # location rights info
475 self.sendSNACnr(0x03,0x02,'') # buddy list rights
476 self.sendSNACnr(0x04,0x04,'') # ICBM parms
477 self.sendSNACnr(0x09,0x02,'') # BOS rights
478
479 def oscar_01_10(self,snac):
480 """
481 we've been warned
482 """
483 skip = struct.unpack('!H',snac[3][:2])[0]
484 newLevel = struct.unpack('!H',snac[3][2+skip:4+skip])[0]/10
485 if len(snac[3])>4+skip:
486 by = self.parseUser(snac[3][4+skip:])
487 else:
488 by = None
489 self.receiveWarning(newLevel, by)
490
491 def oscar_01_13(self,snac):
492 """
493 MOTD
494 """
495 pass # we don't care for now
496
497 def oscar_02_03(self, snac):
498 """
499 location rights response
500 """
501 tlvs = readTLVs(snac[3])
502 self.maxProfileLength = tlvs[1]
503
504 def oscar_03_03(self, snac):
505 """
506 buddy list rights response
507 """
508 tlvs = readTLVs(snac[3])
509 self.maxBuddies = tlvs[1]
510 self.maxWatchers = tlvs[2]
511
512 def oscar_03_0B(self, snac):
513 """
514 buddy update
515 """
516 self.updateBuddy(self.parseUser(snac[3]))
517
518 def oscar_03_0C(self, snac):
519 """
520 buddy offline
521 """
522 self.offlineBuddy(self.parseUser(snac[3]))
523
524 # def oscar_04_03(self, snac):
525
526 def oscar_04_05(self, snac):
527 """
528 ICBM parms response
529 """
530 self.sendSNACnr(0x04,0x02,'\x00\x00\x00\x00\x00\x0b\x1f@\x03\xe7\x03\xe7 \x00\x00\x00\x00') # IM rights
531
532 def oscar_04_07(self, snac):
533 """
534 ICBM message (instant message)
535 """
536 data = snac[3]
537 cookie, data = data[:8], data[8:]
538 channel = struct.unpack('!H',data[:2])[0]
539 data = data[2:]
540 user, data = self.parseUser(data, 1)
541 tlvs = readTLVs(data)
542 if channel == 1: # message
543 flags = []
544 multiparts = []
545 for k, v in tlvs.items():
546 if k == 2:
547 while v:
548 v = v[2:] # skip bad data
549 messageLength, charSet, charSubSet = struct.unpack('!3H' , v[:6])
550 messageLength -= 4
551 message = [v[6:6+messageLength]]
552 if charSet == 0:
553 pass # don't add anything special
554 elif charSet == 2:
555 message.append('unicode')
556 elif charSet == 3:
557 message.append('iso-8859-1')
558 elif charSet == 0xffff:
559 message.append('none')
560 if charSubSet == 0xb:
561 message.append('macintosh')
562 if messageLength > 0: multiparts.append(tuple(message))
563 v = v[6+messageLength:]
564 elif k == 3:
565 flags.append('acknowledge')
566 elif k == 4:
567 flags.append('auto')
568 elif k == 6:
569 flags.append('offline')
570 elif k == 8:
571 iconLength, foo, iconSum, iconStamp = struct.unpack('!LHHL', v)
572 if iconLength:
573 flags.append('icon')
574 flags.append((iconLength, iconSum, iconStamp))
575 elif k == 9:
576 flags.append('buddyrequest')
577 elif k == 0xb: # unknown
578 pass
579 elif k == 0x17:
580 flags.append('extradata')
581 flags.append(v)
582 else:
583 log.msg('unknown TLV for incoming IM, %04x, %s' % (k,repr(v) ))
584
585 # unknown tlv for user SNewdorf
586 # t: 29
587 # v: '\x00\x00\x00\x05\x02\x01\xd2\x04r\x00\x01\x01\x10/\x8c\x8b\x8a\x1e\x94*\x bc\x80}\x8d\xc4;\x1dEM'
588 # XXX what is this?
589 self.receiveMessage(user, multiparts, flags)
590 elif channel == 2: # rondevouz
591 status = struct.unpack('!H',tlvs[5][:2])[0]
592 requestClass = tlvs[5][10:26]
593 moreTLVs = readTLVs(tlvs[5][26:])
594 if requestClass == CAP_CHAT: # a chat request
595 exchange = struct.unpack('!H',moreTLVs[10001][:2])[0]
596 name = moreTLVs[10001][3:-2]
597 instance = struct.unpack('!H',moreTLVs[10001][-2:])[0]
598 if not self.services.has_key(SERVICE_CHATNAV):
599 self.connectService(SERVICE_CHATNAV,1).addCallback(lambda x: self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, instance).\
600 addCallback(self._cbGetChatInfoForInvite, user, moreTLVs [12]))
601 else:
602 self.services[SERVICE_CHATNAV].getChatInfo(exchange, name, i nstance).\
603 addCallback(self._cbGetChatInfoForInvite, user, moreTLVs [12])
604 elif requestClass == CAP_SEND_FILE:
605 if moreTLVs.has_key(11): # cancel
606 log.msg('cancelled file request')
607 log.msg(status)
608 return # handle this later
609 name = moreTLVs[10001][9:-7]
610 desc = moreTLVs[12]
611 log.msg('file request from %s, %s, %s' % (user, name, desc))
612 self.receiveSendFileRequest(user, name, desc, cookie)
613 else:
614 log.msg('unsupported rondevouz: %s' % requestClass)
615 log.msg(repr(moreTLVs))
616 else:
617 log.msg('unknown channel %02x' % channel)
618 log.msg(tlvs)
619
620 def _cbGetChatInfoForInvite(self, info, user, message):
621 apply(self.receiveChatInvite, (user,message)+info)
622
623 def oscar_09_03(self, snac):
624 """
625 BOS rights response
626 """
627 tlvs = readTLVs(snac[3])
628 self.maxPermitList = tlvs[1]
629 self.maxDenyList = tlvs[2]
630
631 def oscar_0B_02(self, snac):
632 """
633 stats reporting interval
634 """
635 self.reportingInterval = struct.unpack('!H',snac[3][:2])[0]
636
637 def oscar_13_03(self, snac):
638 """
639 SSI rights response
640 """
641 #tlvs = readTLVs(snac[3])
642 pass # we don't know how to parse this
643
644 # methods to be called by the client, and their support methods
645 def requestSelfInfo(self):
646 """
647 ask for the OSCARUser for ourselves
648 """
649 d = defer.Deferred()
650 self.sendSNAC(0x01, 0x0E, '').addCallback(self._cbRequestSelfInfo, d)
651 return d
652
653 def _cbRequestSelfInfo(self, snac, d):
654 d.callback(self.parseUser(snac[5]))
655
656 def initSSI(self):
657 """
658 this sends the rate request for family 0x13 (Server Side Information)
659 so we can then use it
660 """
661 return self.sendSNAC(0x13, 0x02, '').addCallback(self._cbInitSSI)
662
663 def _cbInitSSI(self, snac, d):
664 return {} # don't even bother parsing this
665
666 def requestSSI(self, timestamp = 0, revision = 0):
667 """
668 request the server side information
669 if the deferred gets None, it means the SSI is the same
670 """
671 return self.sendSNAC(0x13, 0x05,
672 struct.pack('!LH',timestamp,revision)).addCallback(self._cbRequestSS I)
673
674 def _cbRequestSSI(self, snac, args = ()):
675 if snac[1] == 0x0f: # same SSI as we have
676 return
677 itemdata = snac[5][3:]
678 if args:
679 revision, groups, permit, deny, permitMode, visibility = args
680 else:
681 version, revision = struct.unpack('!BH', snac[5][:3])
682 groups = {}
683 permit = []
684 deny = []
685 permitMode = None
686 visibility = None
687 while len(itemdata)>4:
688 nameLength = struct.unpack('!H', itemdata[:2])[0]
689 name = itemdata[2:2+nameLength]
690 groupID, buddyID, itemType, restLength = \
691 struct.unpack('!4H', itemdata[2+nameLength:10+nameLength])
692 tlvs = readTLVs(itemdata[10+nameLength:10+nameLength+restLength])
693 itemdata = itemdata[10+nameLength+restLength:]
694 if itemType == 0: # buddies
695 groups[groupID].addUser(buddyID, SSIBuddy(name, tlvs))
696 elif itemType == 1: # group
697 g = SSIGroup(name, tlvs)
698 if groups.has_key(0): groups[0].addUser(groupID, g)
699 groups[groupID] = g
700 elif itemType == 2: # permit
701 permit.append(name)
702 elif itemType == 3: # deny
703 deny.append(name)
704 elif itemType == 4: # permit deny info
705 if not tlvs.has_key(0xcb):
706 continue # this happens with ICQ
707 permitMode = {1:'permitall',2:'denyall',3:'permitsome',4:'denyso me',5:'permitbuddies'}[ord(tlvs[0xca])]
708 visibility = {'\xff\xff\xff\xff':'all','\x00\x00\x00\x04':'notai m'}[tlvs[0xcb]]
709 elif itemType == 5: # unknown (perhaps idle data)?
710 pass
711 else:
712 log.msg('%s %s %s %s %s' % (name, groupID, buddyID, itemType, tl vs))
713 timestamp = struct.unpack('!L',itemdata)[0]
714 if not timestamp: # we've got more packets coming
715 # which means add some deferred stuff
716 d = defer.Deferred()
717 self.requestCallbacks[snac[4]] = d
718 d.addCallback(self._cbRequestSSI, (revision, groups, permit, deny, p ermitMode, visibility))
719 return d
720 return (groups[0].users,permit,deny,permitMode,visibility,timestamp,revi sion)
721
722 def activateSSI(self):
723 """
724 active the data stored on the server (use buddy list, permit deny settin gs, etc.)
725 """
726 self.sendSNACnr(0x13,0x07,'')
727
728 def startModifySSI(self):
729 """
730 tell the OSCAR server to be on the lookout for SSI modifications
731 """
732 self.sendSNACnr(0x13,0x11,'')
733
734 def addItemSSI(self, item, groupID = None, buddyID = None):
735 """
736 add an item to the SSI server. if buddyID == 0, then this should be a g roup.
737 this gets a callback when it's finished, but you can probably ignore it.
738 """
739 if groupID is None:
740 if isinstance(item, SSIGroup):
741 groupID = 0
742 else:
743 groupID = item.group.group.findIDFor(item.group)
744 if buddyID is None:
745 buddyID = item.group.findIDFor(item)
746 return self.sendSNAC(0x13,0x08, item.oscarRep(groupID, buddyID))
747
748 def modifyItemSSI(self, item, groupID = None, buddyID = None):
749 if groupID is None:
750 if isinstance(item, SSIGroup):
751 groupID = 0
752 else:
753 groupID = item.group.group.findIDFor(item.group)
754 if buddyID is None:
755 buddyID = item.group.findIDFor(item)
756 return self.sendSNAC(0x13,0x09, item.oscarRep(groupID, buddyID))
757
758 def delItemSSI(self, item, groupID = None, buddyID = None):
759 if groupID is None:
760 if isinstance(item, SSIGroup):
761 groupID = 0
762 else:
763 groupID = item.group.group.findIDFor(item.group)
764 if buddyID is None:
765 buddyID = item.group.findIDFor(item)
766 return self.sendSNAC(0x13,0x0A, item.oscarRep(groupID, buddyID))
767
768 def endModifySSI(self):
769 self.sendSNACnr(0x13,0x12,'')
770
771 def setProfile(self, profile):
772 """
773 set the profile.
774 send None to not set a profile (different from '' for a blank one)
775 """
776 self.profile = profile
777 tlvs = ''
778 if self.profile is not None:
779 tlvs = TLV(1,'text/aolrtf; charset="us-ascii"') + \
780 TLV(2,self.profile)
781
782 tlvs = tlvs + TLV(5, ''.join(self.capabilities))
783 self.sendSNACnr(0x02, 0x04, tlvs)
784
785 def setAway(self, away = None):
786 """
787 set the away message, or return (if away == None)
788 """
789 self.awayMessage = away
790 tlvs = TLV(3,'text/aolrtf; charset="us-ascii"') + \
791 TLV(4,away or '')
792 self.sendSNACnr(0x02, 0x04, tlvs)
793
794 def setIdleTime(self, idleTime):
795 """
796 set our idle time. don't call more than once with a non-0 idle time.
797 """
798 self.sendSNACnr(0x01, 0x11, struct.pack('!L',idleTime))
799
800 def sendMessage(self, user, message, wantAck = 0, autoResponse = 0, offline = 0 ): \
801 #haveIcon = 0, ):
802 """
803 send a message to user (not an OSCARUseR).
804 message can be a string, or a multipart tuple.
805 if wantAck, we return a Deferred that gets a callback when the message i s sent.
806 if autoResponse, this message is an autoResponse, as if from an away mes sage.
807 if offline, this is an offline message (ICQ only, I think)
808 """
809 data = ''.join([chr(random.randrange(0, 127)) for i in range(8)]) # cook ie
810 data = data + '\x00\x01' + chr(len(user)) + user
811 if not type(message) in (types.TupleType, types.ListType):
812 message = [[message,]]
813 if type(message[0][0]) == types.UnicodeType:
814 message[0].append('unicode')
815 messageData = ''
816 for part in message:
817 charSet = 0
818 if 'unicode' in part[1:]:
819 charSet = 2
820 part[0] = part[0].encode('utf-8')
821 elif 'iso-8859-1' in part[1:]:
822 charSet = 3
823 part[0] = part[0].encode('iso-8859-1')
824 elif 'none' in part[1:]:
825 charSet = 0xffff
826 if 'macintosh' in part[1:]:
827 charSubSet = 0xb
828 else:
829 charSubSet = 0
830 messageData = messageData + '\x01\x01' + \
831 struct.pack('!3H',len(part[0])+4,charSet,charSubSet)
832 messageData = messageData + part[0]
833 data = data + TLV(2, '\x05\x01\x00\x03\x01\x01\x02'+messageData)
834 if wantAck:
835 data = data + TLV(3,'')
836 if autoResponse:
837 data = data + TLV(4,'')
838 if offline:
839 data = data + TLV(6,'')
840 if wantAck:
841 return self.sendSNAC(0x04, 0x06, data).addCallback(self._cbSendMessa geAck, user, message)
842 self.sendSNACnr(0x04, 0x06, data)
843
844 def _cbSendMessageAck(self, snac, user, message):
845 return user, message
846
847 def connectService(self, service, wantCallback = 0, extraData = ''):
848 """
849 connect to another service
850 if wantCallback, we return a Deferred that gets called back when the ser vice is online.
851 if extraData, append that to our request.
852 """
853 if wantCallback:
854 d = defer.Deferred()
855 self.sendSNAC(0x01,0x04,struct.pack('!H',service) + extraData).addCa llback(self._cbConnectService, d)
856 return d
857 else:
858 self.sendSNACnr(0x01,0x04,struct.pack('!H',service))
859
860 def _cbConnectService(self, snac, d):
861 self.oscar_01_05(snac[2:], d)
862
863 def createChat(self, shortName):
864 """
865 create a chat room
866 """
867 if self.services.has_key(SERVICE_CHATNAV):
868 return self.services[SERVICE_CHATNAV].createChat(shortName)
869 else:
870 return self.connectService(SERVICE_CHATNAV,1).addCallback(lambda s: s.createChat(shortName))
871
872
873 def joinChat(self, exchange, fullName, instance):
874 """
875 join a chat room
876 """
877 #d = defer.Deferred()
878 return self.connectService(0x0e, 1, TLV(0x01, struct.pack('!HB',exchange , len(fullName)) + fullName +
879 struct.pack('!H', instance))).addCallback(self._cbJoin Chat) #, d)
880 #return d
881
882 def _cbJoinChat(self, chat):
883 del self.services[SERVICE_CHAT]
884 return chat
885
886 def warnUser(self, user, anon = 0):
887 return self.sendSNAC(0x04, 0x08, '\x00'+chr(anon)+chr(len(user))+user).a ddCallback(self._cbWarnUser)
888
889 def _cbWarnUser(self, snac):
890 oldLevel, newLevel = struct.unpack('!2H', snac[5])
891 return oldLevel, newLevel
892
893 def getInfo(self, user):
894 #if user.
895 return self.sendSNAC(0x02, 0x05, '\x00\x01'+chr(len(user))+user).addCall back(self._cbGetInfo)
896
897 def _cbGetInfo(self, snac):
898 user, rest = self.parseUser(snac[5],1)
899 tlvs = readTLVs(rest)
900 return tlvs.get(0x02,None)
901
902 def getAway(self, user):
903 return self.sendSNAC(0x02, 0x05, '\x00\x03'+chr(len(user))+user).addCall back(self._cbGetAway)
904
905 def _cbGetAway(self, snac):
906 user, rest = self.parseUser(snac[5],1)
907 tlvs = readTLVs(rest)
908 return tlvs.get(0x04,None) # return None if there is no away message
909
910 #def acceptSendFileRequest(self,
911
912 # methods to be overriden by the client
913 def initDone(self):
914 """
915 called when we get the rate information, which means we should do other init. stuff.
916 """
917 log.msg('%s initDone' % self)
918 pass
919
920 def updateBuddy(self, user):
921 """
922 called when a buddy changes status, with the OSCARUser for that buddy.
923 """
924 log.msg('%s updateBuddy %s' % (self, user))
925 pass
926
927 def offlineBuddy(self, user):
928 """
929 called when a buddy goes offline
930 """
931 log.msg('%s offlineBuddy %s' % (self, user))
932 pass
933
934 def receiveMessage(self, user, multiparts, flags):
935 """
936 called when someone sends us a message
937 """
938 pass
939
940 def receiveWarning(self, newLevel, user):
941 """
942 called when someone warns us.
943 user is either None (if it was anonymous) or an OSCARUser
944 """
945 pass
946
947 def receiveChatInvite(self, user, message, exchange, fullName, instance, sho rtName, inviteTime):
948 """
949 called when someone invites us to a chat room
950 """
951 pass
952
953 def chatReceiveMessage(self, chat, user, message):
954 """
955 called when someone in a chatroom sends us a message in the chat
956 """
957 pass
958
959 def chatMemberJoined(self, chat, member):
960 """
961 called when a member joins the chat
962 """
963 pass
964
965 def chatMemberLeft(self, chat, member):
966 """
967 called when a member leaves the chat
968 """
969 pass
970
971 def receiveSendFileRequest(self, user, file, description, cookie):
972 """
973 called when someone tries to send a file to us
974 """
975 pass
976
977 class OSCARService(SNACBased):
978 def __init__(self, bos, cookie, d = None):
979 SNACBased.__init__(self, cookie)
980 self.bos = bos
981 self.d = d
982
983 def connectionLost(self, reason):
984 for k,v in self.bos.services.items():
985 if v == self:
986 del self.bos.services[k]
987 return
988
989 def clientReady(self):
990 SNACBased.clientReady(self)
991 if self.d:
992 self.d.callback(self)
993 self.d = None
994
995 class ChatNavService(OSCARService):
996 snacFamilies = {
997 0x01:(3, 0x0010, 0x059b),
998 0x0d:(1, 0x0010, 0x059b)
999 }
1000 def oscar_01_07(self, snac):
1001 # rate info
1002 self.sendSNACnr(0x01, 0x08, '\000\001\000\002\000\003\000\004\000\005')
1003 self.sendSNACnr(0x0d, 0x02, '')
1004
1005 def oscar_0D_09(self, snac):
1006 self.clientReady()
1007
1008 def getChatInfo(self, exchange, name, instance):
1009 d = defer.Deferred()
1010 self.sendSNAC(0x0d,0x04,struct.pack('!HB',exchange,len(name)) + \
1011 name + struct.pack('!HB',instance,2)). \
1012 addCallback(self._cbGetChatInfo, d)
1013 return d
1014
1015 def _cbGetChatInfo(self, snac, d):
1016 data = snac[5][4:]
1017 exchange, length = struct.unpack('!HB',data[:3])
1018 fullName = data[3:3+length]
1019 instance = struct.unpack('!H',data[3+length:5+length])[0]
1020 tlvs = readTLVs(data[8+length:])
1021 shortName = tlvs[0x6a]
1022 inviteTime = struct.unpack('!L',tlvs[0xca])[0]
1023 info = (exchange,fullName,instance,shortName,inviteTime)
1024 d.callback(info)
1025
1026 def createChat(self, shortName):
1027 #d = defer.Deferred()
1028 data = '\x00\x04\x06create\xff\xff\x01\x00\x03'
1029 data = data + TLV(0xd7, 'en')
1030 data = data + TLV(0xd6, 'us-ascii')
1031 data = data + TLV(0xd3, shortName)
1032 return self.sendSNAC(0x0d, 0x08, data).addCallback(self._cbCreateChat)
1033 #return d
1034
1035 def _cbCreateChat(self, snac): #d):
1036 exchange, length = struct.unpack('!HB',snac[5][4:7])
1037 fullName = snac[5][7:7+length]
1038 instance = struct.unpack('!H',snac[5][7+length:9+length])[0]
1039 #d.callback((exchange, fullName, instance))
1040 return exchange, fullName, instance
1041
1042 class ChatService(OSCARService):
1043 snacFamilies = {
1044 0x01:(3, 0x0010, 0x059b),
1045 0x0E:(1, 0x0010, 0x059b)
1046 }
1047 def __init__(self,bos,cookie, d = None):
1048 OSCARService.__init__(self,bos,cookie,d)
1049 self.exchange = None
1050 self.fullName = None
1051 self.instance = None
1052 self.name = None
1053 self.members = None
1054
1055 clientReady = SNACBased.clientReady # we'll do our own callback
1056
1057 def oscar_01_07(self,snac):
1058 self.sendSNAC(0x01,0x08,"\000\001\000\002\000\003\000\004\000\005")
1059 self.clientReady()
1060
1061 def oscar_0E_02(self, snac):
1062 # try: # this is EVIL
1063 # data = snac[3][4:]
1064 # self.exchange, length = struct.unpack('!HB',data[:3])
1065 # self.fullName = data[3:3+length]
1066 # self.instance = struct.unpack('!H',data[3+length:5+length])[0]
1067 # tlvs = readTLVs(data[8+length:])
1068 # self.name = tlvs[0xd3]
1069 # self.d.callback(self)
1070 # except KeyError:
1071 data = snac[3]
1072 self.exchange, length = struct.unpack('!HB',data[:3])
1073 self.fullName = data[3:3+length]
1074 self.instance = struct.unpack('!H',data[3+length:5+length])[0]
1075 tlvs = readTLVs(data[8+length:])
1076 self.name = tlvs[0xd3]
1077 self.d.callback(self)
1078
1079 def oscar_0E_03(self,snac):
1080 users=[]
1081 rest=snac[3]
1082 while rest:
1083 user, rest = self.bos.parseUser(rest, 1)
1084 users.append(user)
1085 if not self.fullName:
1086 self.members = users
1087 else:
1088 self.members.append(users[0])
1089 self.bos.chatMemberJoined(self,users[0])
1090
1091 def oscar_0E_04(self,snac):
1092 user=self.bos.parseUser(snac[3])
1093 for u in self.members:
1094 if u.name == user.name: # same person!
1095 self.members.remove(u)
1096 self.bos.chatMemberLeft(self,user)
1097
1098 def oscar_0E_06(self,snac):
1099 data = snac[3]
1100 user,rest=self.bos.parseUser(snac[3][14:],1)
1101 tlvs = readTLVs(rest[8:])
1102 message=tlvs[1]
1103 self.bos.chatReceiveMessage(self,user,message)
1104
1105 def sendMessage(self,message):
1106 tlvs=TLV(0x02,"us-ascii")+TLV(0x03,"en")+TLV(0x01,message)
1107 self.sendSNAC(0x0e,0x05,
1108 "\x46\x30\x38\x30\x44\x00\x63\x00\x00\x03\x00\x01\x00\x00\ x00\x06\x00\x00\x00\x05"+
1109 struct.pack("!H",len(tlvs))+
1110 tlvs)
1111
1112 def leaveChat(self):
1113 self.disconnect()
1114
1115 class OscarAuthenticator(OscarConnection):
1116 BOSClass = BOSConnection
1117 def __init__(self,username,password,deferred=None,icq=0):
1118 self.username=username
1119 self.password=password
1120 self.deferred=deferred
1121 self.icq=icq # icq mode is disabled
1122 #if icq and self.BOSClass==BOSConnection:
1123 # self.BOSClass=ICQConnection
1124
1125 def oscar_(self,flap):
1126 if not self.icq:
1127 self.sendFLAP("\000\000\000\001", 0x01)
1128 self.sendFLAP(SNAC(0x17,0x06,0,
1129 TLV(TLV_USERNAME,self.username)+
1130 TLV(0x004B,'')))
1131 self.state="Key"
1132 else:
1133 encpass=encryptPasswordICQ(self.password)
1134 self.sendFLAP('\000\000\000\001'+
1135 TLV(0x01,self.username)+
1136 TLV(0x02,encpass)+
1137 TLV(0x03,'ICQ Inc. - Product of ICQ (TM).2001b.5.18.1. 3659.85')+
1138 TLV(0x16,"\x01\x0a")+
1139 TLV(0x17,"\x00\x05")+
1140 TLV(0x18,"\x00\x12")+
1141 TLV(0x19,"\000\001")+
1142 TLV(0x1a,"\x0eK")+
1143 TLV(0x14,"\x00\x00\x00U")+
1144 TLV(0x0f,"en")+
1145 TLV(0x0e,"us"),0x01)
1146 self.state="Cookie"
1147
1148 def oscar_Key(self,data):
1149 snac=readSNAC(data[1])
1150 key=snac[5][2:]
1151 encpass=encryptPasswordMD5(self.password,key)
1152 self.sendFLAP(SNAC(0x17,0x02,0,
1153 TLV(TLV_USERNAME,self.username)+
1154 TLV(TLV_PASSWORD,encpass)+
1155 TLV(0x004C, '')+ # unknown
1156 TLV(TLV_CLIENTNAME,"AOL Instant Messenger (SM), versi on 4.8.2790/WIN32")+
1157 TLV(0x0016,"\x01\x09")+
1158 TLV(TLV_CLIENTMAJOR,"\000\004")+
1159 TLV(TLV_CLIENTMINOR,"\000\010")+
1160 TLV(0x0019,"\000\000")+
1161 TLV(TLV_CLIENTSUB,"\x0A\xE6")+
1162 TLV(0x0014,"\x00\x00\x00\xBB")+
1163 TLV(TLV_LANG,"en")+
1164 TLV(TLV_COUNTRY,"us")+
1165 TLV(TLV_USESSI,"\001")))
1166 return "Cookie"
1167
1168 def oscar_Cookie(self,data):
1169 snac=readSNAC(data[1])
1170 if self.icq:
1171 i=snac[5].find("\000")
1172 snac[5]=snac[5][i:]
1173 tlvs=readTLVs(snac[5])
1174 if tlvs.has_key(6):
1175 self.cookie=tlvs[6]
1176 server,port=string.split(tlvs[5],":")
1177 d = self.connectToBOS(server, int(port))
1178 d.addErrback(lambda x: log.msg("Connection Failed! Reason: %s" % x))
1179 if self.deferred:
1180 d.chainDeferred(self.deferred)
1181 self.disconnect()
1182 elif tlvs.has_key(8):
1183 errorcode=tlvs[8]
1184 errorurl=tlvs[4]
1185 if errorcode=='\000\030':
1186 error="You are attempting to sign on again too soon. Please try again later."
1187 elif errorcode=='\000\005':
1188 error="Invalid Username or Password."
1189 else: error=repr(errorcode)
1190 self.error(error,errorurl)
1191 else:
1192 log.msg('hmm, weird tlvs for %s cookie packet' % str(self))
1193 log.msg(tlvs)
1194 log.msg('snac')
1195 log.msg(str(snac))
1196 return "None"
1197
1198 def oscar_None(self,data): pass
1199
1200 def connectToBOS(self, server, port):
1201 c = protocol.ClientCreator(reactor, self.BOSClass, self.username, self.c ookie)
1202 return c.connectTCP(server, int(port))
1203
1204 def error(self,error,url):
1205 log.msg("ERROR! %s %s" % (error,url))
1206 if self.deferred: self.deferred.errback((error,url))
1207 self.transport.loseConnection()
1208
1209 FLAP_CHANNEL_NEW_CONNECTION = 0x01
1210 FLAP_CHANNEL_DATA = 0x02
1211 FLAP_CHANNEL_ERROR = 0x03
1212 FLAP_CHANNEL_CLOSE_CONNECTION = 0x04
1213
1214 SERVICE_CHATNAV = 0x0d
1215 SERVICE_CHAT = 0x0e
1216 serviceClasses = {
1217 SERVICE_CHATNAV:ChatNavService,
1218 SERVICE_CHAT:ChatService
1219 }
1220 TLV_USERNAME = 0x0001
1221 TLV_CLIENTNAME = 0x0003
1222 TLV_COUNTRY = 0x000E
1223 TLV_LANG = 0x000F
1224 TLV_CLIENTMAJOR = 0x0017
1225 TLV_CLIENTMINOR = 0x0018
1226 TLV_CLIENTSUB = 0x001A
1227 TLV_PASSWORD = 0x0025
1228 TLV_USESSI = 0x004A
1229
1230 CAP_ICON = '\011F\023FL\177\021\321\202"DEST\000\000'
1231 CAP_VOICE = '\011F\023AL\177\021\321\202"DEST\000\000'
1232 CAP_IMAGE = '\011F\023EL\177\021\321\202"DEST\000\000'
1233 CAP_CHAT = 't\217$ b\207\021\321\202"DEST\000\000'
1234 CAP_GET_FILE = '\011F\023HL\177\021\321\202"DEST\000\000'
1235 CAP_SEND_FILE = '\011F\023CL\177\021\321\202"DEST\000\000'
1236 CAP_GAMES = '\011F\023GL\177\021\321\202"DEST\000\000'
1237 CAP_SEND_LIST = '\011F\023KL\177\021\321\202"DEST\000\000'
1238 CAP_SERV_REL = '\011F\023IL\177\021\321\202"DEST\000\000'
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/words/protocols/msn.py ('k') | third_party/twisted_8_1/twisted/words/protocols/toc.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698