| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
""" |
|---|
| 6 |
Implements a AOL Instant Messenger TOC server and client, using the Twisted |
|---|
| 7 |
framework. |
|---|
| 8 |
|
|---|
| 9 |
TODO: |
|---|
| 10 |
info,dir: see how gaim connects for this...it may never work if it tries to |
|---|
| 11 |
connect to the aim server automatically |
|---|
| 12 |
|
|---|
| 13 |
This module is deprecated. |
|---|
| 14 |
|
|---|
| 15 |
Maintainer: Paul Swartz |
|---|
| 16 |
""" |
|---|
| 17 |
|
|---|
| 18 |
import warnings |
|---|
| 19 |
warnings.warn( |
|---|
| 20 |
"twisted.words.protocols.toc is deprecated since Twisted 9.0. " |
|---|
| 21 |
"Use twisted.words.protocols.oscar instead.", |
|---|
| 22 |
category=DeprecationWarning, |
|---|
| 23 |
stacklevel=2) |
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
from twisted.internet import reactor, protocol |
|---|
| 28 |
from twisted.python import log |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
import struct |
|---|
| 32 |
import string |
|---|
| 33 |
import time |
|---|
| 34 |
import base64 |
|---|
| 35 |
import os |
|---|
| 36 |
import StringIO |
|---|
| 37 |
|
|---|
| 38 |
SIGNON,DATA,ERROR,SIGNOFF,KEEP_ALIVE=range(1,6) |
|---|
| 39 |
PERMITALL,DENYALL,PERMITSOME,DENYSOME=range(1,5) |
|---|
| 40 |
|
|---|
| 41 |
DUMMY_CHECKSUM = -559038737 |
|---|
| 42 |
|
|---|
| 43 |
def quote(s): |
|---|
| 44 |
rep=['\\','$','{','}','[',']','(',')','"'] |
|---|
| 45 |
for r in rep: |
|---|
| 46 |
s=string.replace(s,r,"\\"+r) |
|---|
| 47 |
return "\""+s+"\"" |
|---|
| 48 |
|
|---|
| 49 |
def unquote(s): |
|---|
| 50 |
if s=="": return "" |
|---|
| 51 |
if s[0]!='"': return s |
|---|
| 52 |
r=string.replace |
|---|
| 53 |
s=s[1:-1] |
|---|
| 54 |
s=r(s,"\\\\","\\") |
|---|
| 55 |
s=r(s,"\\$","$") |
|---|
| 56 |
s=r(s,"\\{","{") |
|---|
| 57 |
s=r(s,"\\}","}") |
|---|
| 58 |
s=r(s,"\\[","[") |
|---|
| 59 |
s=r(s,"\\]","]") |
|---|
| 60 |
s=r(s,"\\(","(") |
|---|
| 61 |
s=r(s,"\\)",")") |
|---|
| 62 |
s=r(s,"\\\"","\"") |
|---|
| 63 |
return s |
|---|
| 64 |
|
|---|
| 65 |
def unquotebeg(s): |
|---|
| 66 |
for i in range(1,len(s)): |
|---|
| 67 |
if s[i]=='"' and s[i-1]!='\\': |
|---|
| 68 |
q=unquote(s[:i+1]) |
|---|
| 69 |
return [q,s[i+2:]] |
|---|
| 70 |
|
|---|
| 71 |
def unroast(pw): |
|---|
| 72 |
roaststring="Tic/Toc" |
|---|
| 73 |
pw=string.lower(pw[2:]) |
|---|
| 74 |
r="" |
|---|
| 75 |
count=0 |
|---|
| 76 |
hex=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] |
|---|
| 77 |
while pw: |
|---|
| 78 |
st,pw=pw[:2],pw[2:] |
|---|
| 79 |
value=(16*hex.index(st[0]))+hex.index(st[1]) |
|---|
| 80 |
xor=ord(roaststring[count]) |
|---|
| 81 |
count=(count+1)%len(roaststring) |
|---|
| 82 |
r=r+chr(value^xor) |
|---|
| 83 |
return r |
|---|
| 84 |
|
|---|
| 85 |
def roast(pw): |
|---|
| 86 |
|
|---|
| 87 |
key="Tic/Toc" |
|---|
| 88 |
ro="0x" |
|---|
| 89 |
i=0 |
|---|
| 90 |
ascii=map(ord,pw) |
|---|
| 91 |
for c in ascii: |
|---|
| 92 |
ro=ro+'%02x'%(c^ord(key[i%len(key)])) |
|---|
| 93 |
i=i+1 |
|---|
| 94 |
return string.lower(ro) |
|---|
| 95 |
|
|---|
| 96 |
def checksum(b): |
|---|
| 97 |
return DUMMY_CHECKSUM |
|---|
| 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 |
def checksum_file(f): |
|---|
| 128 |
return DUMMY_CHECKSUM |
|---|
| 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 |
def normalize(s): |
|---|
| 163 |
s=string.lower(s) |
|---|
| 164 |
s=string.replace(s," ","") |
|---|
| 165 |
return s |
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
class TOCParseError(ValueError): |
|---|
| 169 |
pass |
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 |
class TOC(protocol.Protocol): |
|---|
| 173 |
users={} |
|---|
| 174 |
|
|---|
| 175 |
def connectionMade(self): |
|---|
| 176 |
|
|---|
| 177 |
self._buf="" |
|---|
| 178 |
self._ourseqnum=0L |
|---|
| 179 |
self._theirseqnum=0L |
|---|
| 180 |
self._mode="Flapon" |
|---|
| 181 |
self._onlyflaps=0 |
|---|
| 182 |
self._laststatus={} |
|---|
| 183 |
self.username=None |
|---|
| 184 |
self.permitmode=PERMITALL |
|---|
| 185 |
self.permitlist=[] |
|---|
| 186 |
self.denylist=[] |
|---|
| 187 |
self.buddylist=[] |
|---|
| 188 |
self.signontime=0 |
|---|
| 189 |
self.idletime=0 |
|---|
| 190 |
self.userinfo="<br>" |
|---|
| 191 |
self.userclass=" O" |
|---|
| 192 |
self.away="" |
|---|
| 193 |
self.saved=None |
|---|
| 194 |
|
|---|
| 195 |
def _debug(self,data): |
|---|
| 196 |
log.msg(data) |
|---|
| 197 |
|
|---|
| 198 |
def connectionLost(self, reason): |
|---|
| 199 |
self._debug("dropped connection from %s" % self.username) |
|---|
| 200 |
try: |
|---|
| 201 |
del self.factory.users[self.username] |
|---|
| 202 |
except: |
|---|
| 203 |
pass |
|---|
| 204 |
for k in self.factory.chatroom.keys(): |
|---|
| 205 |
try: |
|---|
| 206 |
self.factory.chatroom[k].leave(self) |
|---|
| 207 |
except TOCParseError: |
|---|
| 208 |
pass |
|---|
| 209 |
if self.saved: |
|---|
| 210 |
self.factory.savedusers[self.username]=self.saved |
|---|
| 211 |
self.updateUsers() |
|---|
| 212 |
|
|---|
| 213 |
def sendFlap(self,type,data): |
|---|
| 214 |
""" |
|---|
| 215 |
send a FLAP to the client |
|---|
| 216 |
""" |
|---|
| 217 |
send="*" |
|---|
| 218 |
self._debug(data) |
|---|
| 219 |
if type==DATA: |
|---|
| 220 |
data=data+"\000" |
|---|
| 221 |
length=len(data) |
|---|
| 222 |
send=send+struct.pack("!BHH",type,self._ourseqnum,length) |
|---|
| 223 |
send=send+data |
|---|
| 224 |
self._ourseqnum=self._ourseqnum+1 |
|---|
| 225 |
if self._ourseqnum>(256L**4): |
|---|
| 226 |
self._ourseqnum=0 |
|---|
| 227 |
self.transport.write(send) |
|---|
| 228 |
|
|---|
| 229 |
def dataReceived(self,data): |
|---|
| 230 |
self._buf=self._buf+data |
|---|
| 231 |
try: |
|---|
| 232 |
func=getattr(self,"mode%s"%self._mode) |
|---|
| 233 |
except: |
|---|
| 234 |
return |
|---|
| 235 |
self._mode=func() |
|---|
| 236 |
if self._onlyflaps and self.isFlap(): self.dataReceived("") |
|---|
| 237 |
|
|---|
| 238 |
def isFlap(self): |
|---|
| 239 |
""" |
|---|
| 240 |
tests to see if a flap is actually on the buffer |
|---|
| 241 |
""" |
|---|
| 242 |
if self._buf=='': return 0 |
|---|
| 243 |
if self._buf[0]!="*": return 0 |
|---|
| 244 |
if len(self._buf)<6: return 0 |
|---|
| 245 |
foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) |
|---|
| 246 |
if type not in range(1,6): return 0 |
|---|
| 247 |
if len(self._buf)<6+length: return 0 |
|---|
| 248 |
return 1 |
|---|
| 249 |
|
|---|
| 250 |
def readFlap(self): |
|---|
| 251 |
""" |
|---|
| 252 |
read the first FLAP off self._buf, raising errors if it isn't in the right form. |
|---|
| 253 |
the FLAP is the basic TOC message format, and is logically equivilant to a packet in TCP |
|---|
| 254 |
""" |
|---|
| 255 |
if self._buf=='': return None |
|---|
| 256 |
if self._buf[0]!="*": |
|---|
| 257 |
raise TOCParseError |
|---|
| 258 |
if len(self._buf)<6: return None |
|---|
| 259 |
foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) |
|---|
| 260 |
if len(self._buf)<6+length: return None |
|---|
| 261 |
data=self._buf[6:6+length] |
|---|
| 262 |
self._buf=self._buf[6+length:] |
|---|
| 263 |
if data and data[-1]=="\000": |
|---|
| 264 |
data=data[:-1] |
|---|
| 265 |
self._debug([type,data]) |
|---|
| 266 |
return [type,data] |
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 |
|
|---|
| 270 |
|
|---|
| 271 |
|
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 |
|
|---|
| 275 |
|
|---|
| 276 |
|
|---|
| 277 |
|
|---|
| 278 |
|
|---|
| 279 |
|
|---|
| 280 |
|
|---|
| 281 |
|
|---|
| 282 |
|
|---|
| 283 |
|
|---|
| 284 |
def modeFlapon(self): |
|---|
| 285 |
|
|---|
| 286 |
if len(self._buf)<10: return "Flapon" |
|---|
| 287 |
flapon,self._buf=self._buf[:10],self._buf[10:] |
|---|
| 288 |
if flapon!="FLAPON\r\n\r\n": |
|---|
| 289 |
raise TOCParseError |
|---|
| 290 |
self.sendFlap(SIGNON,"\000\000\000\001") |
|---|
| 291 |
self._onlyflaps=1 |
|---|
| 292 |
return "Signon" |
|---|
| 293 |
|
|---|
| 294 |
def modeSignon(self): |
|---|
| 295 |
flap=self.readFlap() |
|---|
| 296 |
if flap==None: |
|---|
| 297 |
return "Signon" |
|---|
| 298 |
if flap[0]!=SIGNON: raise TOCParseError |
|---|
| 299 |
version,tlv,unlength=struct.unpack("!LHH",flap[1][:8]) |
|---|
| 300 |
if version!=1 or tlv!=1 or unlength+8!=len(flap[1]): |
|---|
| 301 |
raise TOCParseError |
|---|
| 302 |
self.username=normalize(flap[1][8:]) |
|---|
| 303 |
if self.username in self.factory.savedusers.keys(): |
|---|
| 304 |
self.saved=self.factory.savedusers[self.username] |
|---|
| 305 |
else: |
|---|
| 306 |
self.saved=SavedUser() |
|---|
| 307 |
self.saved.nick=self.username |
|---|
| 308 |
return "TocSignon" |
|---|
| 309 |
|
|---|
| 310 |
def modeTocSignon(self): |
|---|
| 311 |
flap=self.readFlap() |
|---|
| 312 |
if flap==None: |
|---|
| 313 |
return "TocSignon" |
|---|
| 314 |
if flap[0]!=DATA: raise TOCParseError |
|---|
| 315 |
data=string.split(flap[1]," ") |
|---|
| 316 |
if data[0]!="toc_signon": raise TOCParseError |
|---|
| 317 |
for i in data: |
|---|
| 318 |
if not i:data.remove(i) |
|---|
| 319 |
password=unroast(data[4]) |
|---|
| 320 |
if not(self.authorize(data[1],int(data[2]),data[3],password)): |
|---|
| 321 |
self.sendError(BAD_NICKNAME) |
|---|
| 322 |
self.transport.loseConnection() |
|---|
| 323 |
return |
|---|
| 324 |
self.sendFlap(DATA,"SIGN_ON:TOC1.0") |
|---|
| 325 |
self.sendFlap(DATA,"NICK:%s"%self.saved.nick) |
|---|
| 326 |
self.sendFlap(DATA,"CONFIG:%s"%self.saved.config) |
|---|
| 327 |
|
|---|
| 328 |
return "Connected" |
|---|
| 329 |
|
|---|
| 330 |
def authorize(self,server,port,username,password): |
|---|
| 331 |
if self.saved.password=="": |
|---|
| 332 |
self.saved.password=password |
|---|
| 333 |
return 1 |
|---|
| 334 |
else: |
|---|
| 335 |
return self.saved.password==password |
|---|
| 336 |
|
|---|
| 337 |
def modeConnected(self): |
|---|
| 338 |
flap=self.readFlap() |
|---|
| 339 |
while flap!=None: |
|---|
| 340 |
if flap[0] not in [DATA,KEEP_ALIVE]: raise TOCParseError |
|---|
| 341 |
flapdata=string.split(flap[1]," ",1) |
|---|
| 342 |
tocname=flapdata[0][4:] |
|---|
| 343 |
if len(flapdata)==2: |
|---|
| 344 |
data=flapdata[1] |
|---|
| 345 |
else: |
|---|
| 346 |
data="" |
|---|
| 347 |
func=getattr(self,"toc_"+tocname,None) |
|---|
| 348 |
if func!=None: |
|---|
| 349 |
func(data) |
|---|
| 350 |
else: |
|---|
| 351 |
self.toc_unknown(tocname,data) |
|---|
| 352 |
flap=self.readFlap() |
|---|
| 353 |
return "Connected" |
|---|
| 354 |
|
|---|
| 355 |
def toc_unknown(self,tocname,data): |
|---|
| 356 |
self._debug("unknown! %s %s" % (tocname,data)) |
|---|
| 357 |
|
|---|
| 358 |
def toc_init_done(self,data): |
|---|
| 359 |
""" |
|---|
| 360 |
called when all the setup is done. |
|---|
| 361 |
|
|---|
| 362 |
toc_init_done |
|---|
| 363 |
""" |
|---|
| 364 |
self.signontime=int(time.time()) |
|---|
| 365 |
self.factory.users[self.username]=self |
|---|
| 366 |
self.updateUsers() |
|---|
| 367 |
|
|---|
| 368 |
def toc_add_permit(self,data): |
|---|
| 369 |
""" |
|---|
| 370 |
adds users to the permit list. if the list is null, then set the mode to DENYALL |
|---|
| 371 |
""" |
|---|
| 372 |
if data=="": |
|---|
| 373 |
self.permitmode=DENYALL |
|---|
| 374 |
self.permitlist=[] |
|---|
| 375 |
self.denylist=[] |
|---|
| 376 |
else: |
|---|
| 377 |
self.permitmode=PERMITSOME |
|---|
| 378 |
self.denylist=[] |
|---|
| 379 |
users=string.split(data," ") |
|---|
| 380 |
map(self.permitlist.append,users) |
|---|
| 381 |
self.updateUsers() |
|---|
| 382 |
|
|---|
| 383 |
def toc_add_deny(self,data): |
|---|
| 384 |
""" |
|---|
| 385 |
adds users to the deny list. if the list is null, then set the mode to PERMITALL |
|---|
| 386 |
""" |
|---|
| 387 |
if data=="": |
|---|
| 388 |
self.permitmode=PERMITALL |
|---|
| 389 |
self.permitlist=[] |
|---|
| 390 |
self.denylist=[] |
|---|
| 391 |
else: |
|---|
| 392 |
self.permitmode=DENYSOME |
|---|
| 393 |
self.permitlist=[] |
|---|
| 394 |
users=string.split(data," ") |
|---|
| 395 |
map(self.denylist.append,users) |
|---|
| 396 |
self.updateUsers() |
|---|
| 397 |
|
|---|
| 398 |
def toc_evil(self,data): |
|---|
| 399 |
""" |
|---|
| 400 |
warns a user. |
|---|
| 401 |
|
|---|
| 402 |
toc_evil <username> <anon|norm> |
|---|
| 403 |
""" |
|---|
| 404 |
username,nora=string.split(data," ") |
|---|
| 405 |
if nora=="anon": |
|---|
| 406 |
user="" |
|---|
| 407 |
else: |
|---|
| 408 |
user=self.saved.nick |
|---|
| 409 |
if not(self.factory.users.has_key(username)): |
|---|
| 410 |
self.sendError(CANT_WARN,username) |
|---|
| 411 |
return |
|---|
| 412 |
if self.factory.users[username].saved.evilness>=100: |
|---|
| 413 |
self.sendError(CANT_WARN,username) |
|---|
| 414 |
return |
|---|
| 415 |
self.factory.users[username].evilFrom(user) |
|---|
| 416 |
|
|---|
| 417 |
def toc_add_buddy(self,data): |
|---|
| 418 |
""" |
|---|
| 419 |
adds users to the buddy list |
|---|
| 420 |
|
|---|
| 421 |
toc_add_buddy <buddyname1> [<buddyname2>] [<buddyname3>]... |
|---|
| 422 |
""" |
|---|
| 423 |
buddies=map(normalize,string.split(data," ")) |
|---|
| 424 |
for b in buddies: |
|---|
| 425 |
if b not in self.buddylist: |
|---|
| 426 |
self.buddylist.append(b) |
|---|
| 427 |
for buddy in buddies: |
|---|
| 428 |
try: |
|---|
| 429 |
buddy=self.factory.users[buddy] |
|---|
| 430 |
except: |
|---|
| 431 |
pass |
|---|
| 432 |
else: |
|---|
| 433 |
self.buddyUpdate(buddy) |
|---|
| 434 |
|
|---|
| 435 |
def toc_remove_buddy(self,data): |
|---|
| 436 |
""" |
|---|
| 437 |
removes users from the buddy list |
|---|
| 438 |
|
|---|
| 439 |
toc_remove_buddy <buddyname1> [<buddyname2>] [<buddyname3>]... |
|---|
| 440 |
""" |
|---|
| 441 |
buddies=string.split(data," ") |
|---|
| 442 |
for buddy in buddies: |
|---|
| 443 |
try: |
|---|
| 444 |
self.buddylist.remove(normalize(buddy)) |
|---|
| 445 |
except: pass |
|---|
| 446 |
|
|---|
| 447 |
def toc_send_im(self,data): |
|---|
| 448 |
""" |
|---|
| 449 |
incoming instant message |
|---|
| 450 |
|
|---|
| 451 |
toc_send_im <screenname> <quoted message> [auto] |
|---|
| 452 |
""" |
|---|
| 453 |
username,data=string.split(data," ",1) |
|---|
| 454 |
auto=0 |
|---|
| 455 |
if data[-4:]=="auto": |
|---|
| 456 |
auto=1 |
|---|
| 457 |
data=data[:-5] |
|---|
| 458 |
data=unquote(data) |
|---|
| 459 |
if not(self.factory.users.has_key(username)): |
|---|
| 460 |
self.sendError(NOT_AVAILABLE,username) |
|---|
| 461 |
return |
|---|
| 462 |
user=self.factory.users[username] |
|---|
| 463 |
if not(self.canContact(user)): |
|---|
| 464 |
self.sendError(NOT_AVAILABLE,username) |
|---|
| 465 |
return |
|---|
| 466 |
user.hearWhisper(self,data,auto) |
|---|
| 467 |
|
|---|
| 468 |
def toc_set_info(self,data): |
|---|
| 469 |
""" |
|---|
| 470 |
set the users information, retrivable with toc_get_info |
|---|
| 471 |
|
|---|
| 472 |
toc_set_info <user info (quoted)> |
|---|
| 473 |
""" |
|---|
| 474 |
info=unquote(data) |
|---|
| 475 |
self._userinfo=info |
|---|
| 476 |
|
|---|
| 477 |
def toc_set_idle(self,data): |
|---|
| 478 |
""" |
|---|
| 479 |
set/unset idle |
|---|
| 480 |
|
|---|
| 481 |
toc_set_idle <seconds> |
|---|
| 482 |
""" |
|---|
| 483 |
seconds=int(data) |
|---|
| 484 |
self.idletime=time.time()-seconds |
|---|
| 485 |
self.updateUsers() |
|---|
| 486 |
|
|---|
| 487 |
def toc_set_away(self,data): |
|---|
| 488 |
""" |
|---|
| 489 |
set/unset away message |
|---|
| 490 |
|
|---|
| 491 |
toc_set_away [<away message>] |
|---|
| 492 |
""" |
|---|
| 493 |
away=unquote(data) |
|---|
| 494 |
if not self.away and away: |
|---|
| 495 |
self.away=away |
|---|
| 496 |
self.userclass=self.userclass+'U' |
|---|
| 497 |
self.updateUsers() |
|---|
| 498 |
elif self.away and not away: |
|---|
| 499 |
self.away="" |
|---|
| 500 |
self.userclass=self.userclass[:2] |
|---|
| 501 |
self.updateUsers() |
|---|
| 502 |
else: |
|---|
| 503 |
raise TOCParseError |
|---|
| 504 |
|
|---|
| 505 |
def toc_chat_join(self,data): |
|---|
| 506 |
""" |
|---|
| 507 |
joins the chat room. |
|---|
| 508 |
|
|---|
| 509 |
toc_chat_join <exchange> <room name> |
|---|
| 510 |
""" |
|---|
| 511 |
exchange,name=string.split(data," ",1) |
|---|
| 512 |
self.factory.getChatroom(int(exchange),unquote(name)).join(self) |
|---|
| 513 |
|
|---|
| 514 |
def toc_chat_invite(self,data): |
|---|
| 515 |
""" |
|---|
| 516 |
invite others to the room. |
|---|
| 517 |
|
|---|
| 518 |
toc_chat_invite <room id> <invite message> <buddy 1> [<buddy2>]... |
|---|
| 519 |
""" |
|---|
| 520 |
id,data=string.split(data," ",1) |
|---|
| 521 |
id=int(id) |
|---|
| 522 |
message,data=unquotebeg(data) |
|---|
| 523 |
buddies=string.split(data," ") |
|---|
| 524 |
for b in buddies: |
|---|
| 525 |
room=self.factory.chatroom[id] |
|---|
| 526 |
bud=self.factory.users[b] |
|---|
| 527 |
bud.chatInvite(room,self,message) |
|---|
| 528 |
|
|---|
| 529 |
def toc_chat_accept(self,data): |
|---|
| 530 |
""" |
|---|
| 531 |
accept an invitation. |
|---|
| 532 |
|
|---|
| 533 |
toc_chat_accept <room id> |
|---|
| 534 |
""" |
|---|
| 535 |
id=int(data) |
|---|
| 536 |
self.factory.chatroom[id].join(self) |
|---|
| 537 |
|
|---|
| 538 |
def toc_chat_send(self,data): |
|---|
| 539 |
""" |
|---|
| 540 |
send a message to the chat room. |
|---|
| 541 |
|
|---|
| 542 |
toc_chat_send <room id> <message> |
|---|
| 543 |
""" |
|---|
| 544 |
id,message=string.split(data," ",1) |
|---|
| 545 |
id=int(id) |
|---|
| 546 |
message=unquote(message) |
|---|
| 547 |
self.factory.chatroom[id].say(self,message) |
|---|
| 548 |
|
|---|
| 549 |
def toc_chat_whisper(self,data): |
|---|
| 550 |
id,user,message=string.split(data," ",2) |
|---|
| 551 |
id=int(id) |
|---|
| 552 |
room=self.factory.chatroom[id] |
|---|
| 553 |
message=unquote(message) |
|---|
| 554 |
self.factory.users[user].chatWhisper(room,self,message) |
|---|
| 555 |
|
|---|
| 556 |
def toc_chat_leave(self,data): |
|---|
| 557 |
""" |
|---|
| 558 |
leave the room. |
|---|
| 559 |
|
|---|
| 560 |
toc_chat_leave <room id> |
|---|
| 561 |
""" |
|---|
| 562 |
id=int(data) |
|---|
| 563 |
self.factory.chatroom[id].leave(self) |
|---|
| 564 |
|
|---|
| 565 |
def toc_set_config(self,data): |
|---|
| 566 |
""" |
|---|
| 567 |
set the saved config. this gets send when you log in. |
|---|
| 568 |
|
|---|
| 569 |
toc_set_config <config> |
|---|
| 570 |
""" |
|---|
| 571 |
self.saved.config=unquote(data) |
|---|
| 572 |
|
|---|
| 573 |
def toc_get_info(self,data): |
|---|
| 574 |
""" |
|---|
| 575 |
get the user info for a user |
|---|
| 576 |
|
|---|
| 577 |
toc_get_info <username> |
|---|
| 578 |
""" |
|---|
| 579 |
if not self.factory.users.has_key(data): |
|---|
| 580 |
self.sendError(901,data) |
|---|
| 581 |
return |
|---|
| 582 |
self.sendFlap(2,"GOTO_URL:TIC:info/%s"%data) |
|---|
| 583 |
|
|---|
| 584 |
def toc_format_nickname(self,data): |
|---|
| 585 |
""" |
|---|
| 586 |
change the format of your nickname. |
|---|
| 587 |
|
|---|
| 588 |
toc_format_nickname <new format> |
|---|
| 589 |
""" |
|---|
| 590 |
|
|---|
| 591 |
nick=unquote(data) |
|---|
| 592 |
if normalize(nick)==self.username: |
|---|
| 593 |
self.saved.nick=nick |
|---|
| 594 |
self.sendFlap(2,"ADMIN_NICK_STATUS:0") |
|---|
| 595 |
else: |
|---|
| 596 |
self.sendError(BAD_INPUT) |
|---|
| 597 |
|
|---|
| 598 |
def toc_change_passwd(self,data): |
|---|
| 599 |
orig,data=unquotebeg(data) |
|---|
| 600 |
new=unquote(data) |
|---|
| 601 |
if orig==self.saved.password: |
|---|
| 602 |
self.saved.password=new |
|---|
| 603 |
self.sendFlap(2,"ADMIN_PASSWD_STATUS:0") |
|---|
| 604 |
else: |
|---|
| 605 |
self.sendError(BAD_INPUT) |
|---|
| 606 |
|
|---|
| 607 |
def sendError(self,code,*varargs): |
|---|
| 608 |
""" |
|---|
| 609 |
send an error to the user. listing of error messages is below. |
|---|
| 610 |
""" |
|---|
| 611 |
send="ERROR:%s"%code |
|---|
| 612 |
for v in varargs: |
|---|
| 613 |
send=send+":"+v |
|---|
| 614 |
self.sendFlap(DATA,send) |
|---|
| 615 |
|
|---|
| 616 |
def updateUsers(self): |
|---|
| 617 |
""" |
|---|
| 618 |
Update the users who have us on their buddylist. |
|---|
| 619 |
Called when the user changes anything (idle,away) so people can get updates. |
|---|
| 620 |
""" |
|---|
| 621 |
for user in self.factory.users.values(): |
|---|
| 622 |
if self.username in user.buddylist and self.canContact(user): |
|---|
| 623 |
user.buddyUpdate(self) |
|---|
| 624 |
|
|---|
| 625 |
def getStatus(self,user): |
|---|
| 626 |
if self.canContact(user): |
|---|
| 627 |
if self in self.factory.users.values():ol='T' |
|---|
| 628 |
else: ol='F' |
|---|
| 629 |
idle=0 |
|---|
| 630 |
if self.idletime: |
|---|
| 631 |
idle=int((time.time()-self.idletime)/60) |
|---|
| 632 |
return (self.saved.nick,ol,self.saved.evilness,self.signontime,idle,self.userclass) |
|---|
| 633 |
else: |
|---|
| 634 |
return (self.saved.nick,'F',0,0,0,self.userclass) |
|---|
| 635 |
|
|---|
| 636 |
def canContact(self,user): |
|---|
| 637 |
if self.permitmode==PERMITALL: return 1 |
|---|
| 638 |
elif self.permitmode==DENYALL: return 0 |
|---|
| 639 |
elif self.permitmode==PERMITSOME: |
|---|
| 640 |
if user.username in self.permitlist: return 1 |
|---|
| 641 |
else: return 0 |
|---|
| 642 |
elif self.permitmode==DENYSOME: |
|---|
| 643 |
if user.username in self.denylist: return 0 |
|---|
| 644 |
else: return 1 |
|---|
| 645 |
else: |
|---|
| 646 |
assert 0,"bad permitmode %s" % self.permitmode |
|---|
| 647 |
|
|---|
| 648 |
def buddyUpdate(self,user): |
|---|
| 649 |
""" |
|---|
| 650 |
Update the buddy. Called from updateUsers() |
|---|
| 651 |
""" |
|---|
| 652 |
if not self.canContact(user): return |
|---|
| 653 |
status=user.getStatus(self) |
|---|
| 654 |
if not self._laststatus.has_key(user): |
|---|
| 655 |
self._laststatus[user]=() |
|---|
| 656 |
if self._laststatus[user]!=status: |
|---|
| 657 |
send="UPDATE_BUDDY:%s:%s:%s:%s:%s:%s"%status |
|---|
| 658 |
self.sendFlap(DATA,send) |
|---|
| 659 |
self._laststatus[user]=status |
|---|
| 660 |
|
|---|
| 661 |
def hearWhisper(self,user,data,auto=0): |
|---|
| 662 |
""" |
|---|
| 663 |
Called when you get an IM. If auto=1, it's an autoreply from an away message. |
|---|
| 664 |
""" |
|---|
| 665 |
if not self.canContact(user): return |
|---|
| 666 |
if auto: auto='T' |
|---|
| 667 |
else: auto='F' |
|---|
| 668 |
send="IM_IN:%s:%s:%s"%(user.saved.nick,auto,data) |
|---|
| 669 |
self.sendFlap(DATA,send) |
|---|
| 670 |
|
|---|
| 671 |
def evilFrom(self,user): |
|---|
| 672 |
if user=="": |
|---|
| 673 |
percent=0.03 |
|---|
| 674 |
else: |
|---|
| 675 |
percent=0.1 |
|---|
| 676 |
self.saved.evilness=self.saved.evilness+int((100-self.saved.evilness)*percent) |
|---|
| 677 |
self.sendFlap(2,"EVILED:%s:%s"%(self.saved.evilness,user)) |
|---|
| 678 |
self.updateUsers() |
|---|
| 679 |
|
|---|
| 680 |
def chatJoin(self,room): |
|---|
| 681 |
self.sendFlap(2,"CHAT_JOIN:%s:%s"%(room.id,room.name)) |
|---|
| 682 |
f="CHAT_UPDATE_BUDDY:%s:T"%room.id |
|---|
| 683 |
for u in room.users: |
|---|
| 684 |
if u!=self: |
|---|
| 685 |
u.chatUserUpdate(room,self) |
|---|
| 686 |
f=f+":"+u.saved.nick |
|---|
| 687 |
self.sendFlap(2,f) |
|---|
| 688 |
|
|---|
| 689 |
def chatInvite(self,room,user,message): |
|---|
| 690 |
if not self.canContact(user): return |
|---|
| 691 |
self.sendFlap(2,"CHAT_INVITE:%s:%s:%s:%s"%(room.name,room.id,user.saved.nick,message)) |
|---|
| 692 |
|
|---|
| 693 |
def chatUserUpdate(self,room,user): |
|---|
| 694 |
if user in room.users: |
|---|
| 695 |
inroom='T' |
|---|
| 696 |
else: |
|---|
| 697 |
inroom='F' |
|---|
| 698 |
self.sendFlap(2,"CHAT_UPDATE_BUDDY:%s:%s:%s"%(room.id,inroom,user.saved.nick)) |
|---|
| 699 |
|
|---|
| 700 |
def chatMessage(self,room,user,message): |
|---|
| 701 |
if not self.canContact(user): return |
|---|
| 702 |
self.sendFlap(2,"CHAT_IN:%s:%s:F:%s"%(room.id,user.saved.nick,message)) |
|---|
| 703 |
|
|---|
| 704 |
def chatWhisper(self,room,user,message): |
|---|
| 705 |
if not self.canContact(user): return |
|---|
| 706 |
self.sendFlap(2,"CHAT_IN:%s:%s:T:%s"%(room.id,user.saved.nick,message)) |
|---|
| 707 |
|
|---|
| 708 |
def chatLeave(self,room): |
|---|
| 709 |
self.sendFlap(2,"CHAT_LEFT:%s"%(room.id)) |
|---|
| 710 |
|
|---|
| 711 |
|
|---|
| 712 |
class Chatroom: |
|---|
| 713 |
def __init__(self,fac,exchange,name,id): |
|---|
| 714 |
self.exchange=exchange |
|---|
| 715 |
self.name=name |
|---|
| 716 |
self.id=id |
|---|
| 717 |
self.factory=fac |
|---|
| 718 |
self.users=[] |
|---|
| 719 |
|
|---|
| 720 |
def join(self,user): |
|---|
| 721 |
if user in self.users: |
|---|
| 722 |
return |
|---|
| 723 |
self.users.append(user) |
|---|
| 724 |
user.chatJoin(self) |
|---|
| 725 |
|
|---|
| 726 |
def leave(self,user): |
|---|
| 727 |
if user not in self.users: |
|---|
| 728 |
raise TOCParseError |
|---|
| 729 |
self.users.remove(user) |
|---|
| 730 |
user.chatLeave(self) |
|---|
| 731 |
for u in self.users: |
|---|
| 732 |
u.chatUserUpdate(self,user) |
|---|
| 733 |
if len(self.users)==0: |
|---|
| 734 |
self.factory.remChatroom(self) |
|---|
| 735 |
|
|---|
| 736 |
def say(self,user,message): |
|---|
| 737 |
for u in self.users: |
|---|
| 738 |
u.chatMessage(self,user,message) |
|---|
| 739 |
|
|---|
| 740 |
|
|---|
| 741 |
class SavedUser: |
|---|
| 742 |
def __init__(self): |
|---|
| 743 |
self.config="" |
|---|
| 744 |
self.nick="" |
|---|
| 745 |
self.password="" |
|---|
| 746 |
self.evilness=0 |
|---|
| 747 |
|
|---|
| 748 |
|
|---|
| 749 |
class TOCFactory(protocol.Factory): |
|---|
| 750 |
def __init__(self): |
|---|
| 751 |
self.users={} |
|---|
| 752 |
self.savedusers={} |
|---|
| 753 |
self.chatroom={} |
|---|
| 754 |
self.chatroomid=0 |
|---|
| 755 |
|
|---|
| 756 |
def buildProtocol(self,addr): |
|---|
| 757 |
p=TOC() |
|---|
| 758 |
p.factory=self |
|---|
| 759 |
return p |
|---|
| 760 |
|
|---|
| 761 |
def getChatroom(self,exchange,name): |
|---|
| 762 |
for i in self.chatroom.values(): |
|---|
| 763 |
if normalize(i.name)==normalize(name): |
|---|
| 764 |
return i |
|---|
| 765 |
self.chatroom[self.chatroomid]=Chatroom(self,exchange,name,self.chatroomid) |
|---|
| 766 |
self.chatroomid=self.chatroomid+1 |
|---|
| 767 |
return self.chatroom[self.chatroomid-1] |
|---|
| 768 |
|
|---|
| 769 |
def remChatroom(self,room): |
|---|
| 770 |
id=room.id |
|---|
| 771 |
del self.chatroom[id] |
|---|
| 772 |
|
|---|
| 773 |
MAXARGS={} |
|---|
| 774 |
MAXARGS["CONFIG"]=0 |
|---|
| 775 |
MAXARGS["NICK"]=0 |
|---|
| 776 |
MAXARGS["IM_IN"]=2 |
|---|
| 777 |
MAXARGS["UPDATE_BUDDY"]=5 |
|---|
| 778 |
MAXARGS["ERROR"]=-1 |
|---|
| 779 |
MAXARGS["EVILED"]=1 |
|---|
| 780 |
MAXARGS["CHAT_JOIN"]=1 |
|---|
| 781 |
MAXARGS["CHAT_IN"]=3 |
|---|
| 782 |
MAXARGS["CHAT_UPDATE_BUDDY"]=-1 |
|---|
| 783 |
MAXARGS["CHAT_INVITE"]=3 |
|---|
| 784 |
MAXARGS["CHAT_LEFT"]=0 |
|---|
| 785 |
MAXARGS["ADMIN_NICK_STATUS"]=0 |
|---|
| 786 |
MAXARGS["ADMIN_PASSWD_STATUS"]=0 |
|---|
| 787 |
|
|---|
| 788 |
|
|---|
| 789 |
class TOCClient(protocol.Protocol): |
|---|
| 790 |
def __init__(self,username,password,authhost="login.oscar.aol.com",authport=5190): |
|---|
| 791 |
|
|---|
| 792 |
self.username=normalize(username) |
|---|
| 793 |
self._password=password |
|---|
| 794 |
self._mode="SendNick" |
|---|
| 795 |
self._ourseqnum=19071 |
|---|
| 796 |
self._authhost=authhost |
|---|
| 797 |
self._authport=authport |
|---|
| 798 |
self._online=0 |
|---|
| 799 |
self._buddies=[] |
|---|
| 800 |
self._privacymode=PERMITALL |
|---|
| 801 |
self._permitlist=[] |
|---|
| 802 |
self._roomnames={} |
|---|
| 803 |
self._receivedchatmembers={} |
|---|
| 804 |
self._denylist=[] |
|---|
| 805 |
self._cookies={} |
|---|
| 806 |
self._buf='' |
|---|
| 807 |
self._awaymessage='' |
|---|
| 808 |
|
|---|
| 809 |
def _debug(self,data): |
|---|
| 810 |
log.msg(data) |
|---|
| 811 |
|
|---|
| 812 |
def sendFlap(self,type,data): |
|---|
| 813 |
if type==DATA: |
|---|
| 814 |
data=data+"\000" |
|---|
| 815 |
length=len(data) |
|---|
| 816 |
s="*" |
|---|
| 817 |
s=s+struct.pack("!BHH",type,self._ourseqnum,length) |
|---|
| 818 |
s=s+data |
|---|
| 819 |
self._ourseqnum=self._ourseqnum+1 |
|---|
| 820 |
if self._ourseqnum>(256*256+256): |
|---|
| 821 |
self._ourseqnum=0 |
|---|
| 822 |
self._debug(data) |
|---|
| 823 |
self.transport.write(s) |
|---|
| 824 |
|
|---|
| 825 |
def isFlap(self): |
|---|
| 826 |
""" |
|---|
| 827 |
tests to see if a flap is actually on the buffer |
|---|
| 828 |
""" |
|---|
| 829 |
if self._buf=='': return 0 |
|---|
| 830 |
if self._buf[0]!="*": return 0 |
|---|
| 831 |
if len(self._buf)<6: return 0 |
|---|
| 832 |
foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) |
|---|
| 833 |
if type not in range(1,6): return 0 |
|---|
| 834 |
if len(self._buf)<6+length: return 0 |
|---|
| 835 |
return 1 |
|---|
| 836 |
|
|---|
| 837 |
def readFlap(self): |
|---|
| 838 |
if self._buf=='': return None |
|---|
| 839 |
if self._buf[0]!="*": |
|---|
| 840 |
raise TOCParseError |
|---|
| 841 |
if len(self._buf)<6: return None |
|---|
| 842 |
foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) |
|---|
| 843 |
if len(self._buf)<6+length: return None |
|---|
| 844 |
data=self._buf[6:6+length] |
|---|
| 845 |
self._buf=self._buf[6+length:] |
|---|
| 846 |
if data and data[-1]=="\000": |
|---|
| 847 |
data=data[:-1] |
|---|
| 848 |
return [type,data] |
|---|
| 849 |
|
|---|
| 850 |
def connectionMade(self): |
|---|
| 851 |
self._debug("connection made! %s" % self.transport) |
|---|
| 852 |
self.transport.write("FLAPON\r\n\r\n") |
|---|
| 853 |
|
|---|
| 854 |
def connectionLost(self, reason): |
|---|
| 855 |
self._debug("connection lost!") |
|---|
| 856 |
self._online=0 |
|---|
| 857 |
|
|---|
| 858 |
def dataReceived(self,data): |
|---|
| 859 |
self._buf=self._buf+data |
|---|
| 860 |
while self.isFlap(): |
|---|
| 861 |
flap=self.readFlap() |
|---|
| 862 |
func=getattr(self,"mode%s"%self._mode) |
|---|
| 863 |
func(flap) |
|---|
| 864 |
|
|---|
| 865 |
def modeSendNick(self,flap): |
|---|
| 866 |
if flap!=[1,"\000\000\000\001"]: raise TOCParseError |
|---|
| 867 |
s="\000\000\000\001\000\001"+struct.pack("!H",len(self.username))+self.username |
|---|
| 868 |
self.sendFlap(1,s) |
|---|
| 869 |
s="toc_signon %s %s %s %s english \"penguin\""%(self._authhost,\ |
|---|
| 870 |
self._authport,self.username,roast(self._password)) |
|---|
| 871 |
self.sendFlap(2,s) |
|---|
| 872 |
self._mode="Data" |
|---|
| 873 |
|
|---|
| 874 |
def modeData(self,flap): |
|---|
| 875 |
if not flap[1]: |
|---|
| 876 |
return |
|---|
| 877 |
if not ':' in flap[1]: |
|---|
| 878 |
self._debug("bad SNAC:%s"%(flap[1])) |
|---|
| 879 |
return |
|---|
| 880 |
command,rest=string.split(flap[1],":",1) |
|---|
| 881 |
if MAXARGS.has_key(command): |
|---|
| 882 |
maxsplit=MAXARGS[command] |
|---|
| 883 |
else: |
|---|
| 884 |
maxsplit=-1 |
|---|
| 885 |
if maxsplit==-1: |
|---|
| 886 |
l=tuple(string.split(rest,":")) |
|---|
| 887 |
elif maxsplit==0: |
|---|
| 888 |
l=(rest,) |
|---|
| 889 |
else: |
|---|
| 890 |
l=tuple(string.split(rest,":",maxsplit)) |
|---|
| 891 |
self._debug("%s %s"%(command,l)) |
|---|
| 892 |
try: |
|---|
| 893 |
func=getattr(self,"toc%s"%command) |
|---|
| 894 |
self._debug("calling %s"%func) |
|---|
| 895 |
except: |
|---|
| 896 |
self._debug("calling %s"%self.tocUNKNOWN) |
|---|
| 897 |
self.tocUNKNOWN(command,l) |
|---|
| 898 |
return |
|---|
| 899 |
func(l) |
|---|
| 900 |
|
|---|
| 901 |
def tocUNKNOWN(self,command,data): |
|---|
| 902 |
pass |
|---|
| 903 |
|
|---|
| 904 |
def tocSIGN_ON(self,data): |
|---|
| 905 |
if data!=("TOC1.0",): raise TOCParseError |
|---|
| 906 |
self._debug("Whee, signed on!") |
|---|
| 907 |
if self._buddies: self.add_buddy(self._buddies) |
|---|
| 908 |
self._online=1 |
|---|
| 909 |
self.onLine() |
|---|
| 910 |
|
|---|
| 911 |
def tocNICK(self,data): |
|---|
| 912 |
""" |
|---|
| 913 |
Handle a message that looks like:: |
|---|
| 914 |
|
|---|
| 915 |
NICK:<format of nickname> |
|---|
| 916 |
""" |
|---|
| 917 |
self.username=data[0] |
|---|
| 918 |
|
|---|
| 919 |
def tocCONFIG(self,data): |
|---|
| 920 |
""" |
|---|
| 921 |
Handle a message that looks like:: |
|---|
| 922 |
|
|---|
| 923 |
CONFIG:<config> |
|---|
| 924 |
|
|---|
| 925 |
Format of config data: |
|---|
| 926 |
|
|---|
| 927 |
- g: group. all users until next g or end of config are in this group |
|---|
| 928 |
- b: buddy |
|---|
| 929 |
- p: person on the permit list |
|---|
| 930 |
- d: person on the deny list |
|---|
| 931 |
- m: permit/deny mode (1: permit all, 2: deny all, 3: permit some, 4: deny some) |
|---|
| 932 |
""" |
|---|
| 933 |
data=data[0] |
|---|
| 934 |
if data and data[0]=="{":data=data[1:-1] |
|---|
| 935 |
lines=string.split(data,"\n") |
|---|
| 936 |
buddylist={} |
|---|
| 937 |
currentgroup="" |
|---|
| 938 |
permit=[] |
|---|
| 939 |
deny=[] |
|---|
| 940 |
mode=1 |
|---|
| 941 |
for l in lines: |
|---|
| 942 |
if l: |
|---|
| 943 |
code,data=l[0],l[2:] |
|---|
| 944 |
if code=='g': |
|---|
| 945 |
currentgroup=data |
|---|
| 946 |
buddylist[currentgroup]=[] |
|---|
| 947 |
elif code=='b': |
|---|
| 948 |
buddylist[currentgroup].append(data) |
|---|
| 949 |
elif code=='p': |
|---|
| 950 |
permit.append(data) |
|---|
| 951 |
elif code=='d': |
|---|
| 952 |
deny.append(data) |
|---|
| 953 |
elif code=='m': |
|---|
| 954 |
mode=int(data) |
|---|
| 955 |
self.gotConfig(mode,buddylist,permit,deny) |
|---|
| 956 |
|
|---|
| 957 |
def tocIM_IN(self,data): |
|---|
| 958 |
""" |
|---|
| 959 |
Handle a message that looks like:: |
|---|
| 960 |
|
|---|
| 961 |
IM_IN:<user>:<autoreply T|F>:message |
|---|
| 962 |
""" |
|---|
| 963 |
user=data[0] |
|---|
| 964 |
autoreply=(data[1]=='T') |
|---|
| 965 |
message=data[2] |
|---|
| 966 |
self.hearMessage(user,message,autoreply) |
|---|
| 967 |
|
|---|
| 968 |
def tocUPDATE_BUDDY(self,data): |
|---|
| 969 |
""" |
|---|
| 970 |
Handle a message that looks like:: |
|---|
| 971 |
|
|---|
| 972 |
UPDATE_BUDDY:<username>:<online T|F>:<warning level>:<signon time>:<idle time (minutes)>:<user class> |
|---|
| 973 |
""" |
|---|
| 974 |
data=list(data) |
|---|
| 975 |
online=(data[1]=='T') |
|---|
| 976 |
if len(data[5])==2: |
|---|
| 977 |
data[5]=data[5]+" " |
|---|
| 978 |
away=(data[5][-1]=='U') |
|---|
| 979 |
if data[5][-1]=='U': |
|---|
| 980 |
data[5]=data[5][:-1] |
|---|
| 981 |
self.updateBuddy(data[0],online,int(data[2]),int(data[3]),int(data[4]),data[5],away) |
|---|
| 982 |
|
|---|
| 983 |
def tocERROR(self,data): |
|---|
| 984 |
""" |
|---|
| 985 |
Handle a message that looks like:: |
|---|
| 986 |
|
|---|
| 987 |
ERROR:<error code>:<misc. data> |
|---|
| 988 |
""" |
|---|
| 989 |
code,args=data[0],data[1:] |
|---|
| 990 |
self.hearError(int(code),args) |
|---|
| 991 |
|
|---|
| 992 |
def tocEVILED(self,data): |
|---|
| 993 |
""" |
|---|
| 994 |
Handle a message that looks like:: |
|---|
| 995 |
|
|---|
| 996 |
EVILED:<current warning level>:<user who warned us> |
|---|
| 997 |
""" |
|---|
| 998 |
self.hearWarning(data[0],data[1]) |
|---|
| 999 |
|
|---|
| 1000 |
def tocCHAT_JOIN(self,data): |
|---|
| 1001 |
""" |
|---|
| 1002 |
Handle a message that looks like:: |
|---|
| 1003 |
|
|---|
| 1004 |
CHAT_JOIN:<room id>:<room name> |
|---|
| 1005 |
""" |
|---|
| 1006 |
|
|---|
| 1007 |
self._roomnames[int(data[0])]=data[1] |
|---|
| 1008 |
self._receivedchatmembers[int(data[0])]=0 |
|---|
| 1009 |
|
|---|
| 1010 |
def tocCHAT_UPDATE_BUDDY(self,data): |
|---|
| 1011 |
""" |
|---|
| 1012 |
Handle a message that looks like:: |
|---|
| 1013 |
|
|---|
| 1014 |
CHAT_UPDATE_BUDDY:<room id>:<in room? T/F>:<user 1>:<user 2>... |
|---|
| 1015 |
""" |
|---|
| 1016 |
roomid=int(data[0]) |
|---|
| 1017 |
inroom=(data[1]=='T') |
|---|
| 1018 |
if self._receivedchatmembers[roomid]: |
|---|
| 1019 |
for u in data[2:]: |
|---|
| 1020 |
self.chatUpdate(roomid,u,inroom) |
|---|
| 1021 |
else: |
|---|
| 1022 |
self._receivedchatmembers[roomid]=1 |
|---|
| 1023 |
self.chatJoined(roomid,self._roomnames[roomid],list(data[2:])) |
|---|
| 1024 |
|
|---|
| 1025 |
def tocCHAT_IN(self,data): |
|---|
| 1026 |
""" |
|---|
| 1027 |
Handle a message that looks like:: |
|---|
| 1028 |
|
|---|
| 1029 |
CHAT_IN:<room id>:<username>:<whisper T/F>:<message> |
|---|
| 1030 |
|
|---|
| 1031 |
whisper isn't used |
|---|
| 1032 |
""" |
|---|
| 1033 |
whisper=(data[2]=='T') |
|---|
| 1034 |
if whisper: |
|---|
| 1035 |
self.chatHearWhisper(int(data[0]),data[1],data[3]) |
|---|
| 1036 |
else: |
|---|
| 1037 |
self.chatHearMessage(int(data[0]),data[1],data[3]) |
|---|
| 1038 |
|
|---|
| 1039 |
def tocCHAT_INVITE(self,data): |
|---|
| 1040 |
""" |
|---|
| 1041 |
Handle a message that looks like:: |
|---|
| 1042 |
|
|---|
| 1043 |
CHAT_INVITE:<room name>:<room id>:<username>:<message> |
|---|
| 1044 |
""" |
|---|
| 1045 |
self.chatInvited(int(data[1]),data[0],data[2],data[3]) |
|---|
| 1046 |
|
|---|
| 1047 |
def tocCHAT_LEFT(self,data): |
|---|
| 1048 |
""" |
|---|
| 1049 |
Handle a message that looks like:: |
|---|
| 1050 |
|
|---|
| 1051 |
CHAT_LEFT:<room id> |
|---|
| 1052 |
""" |
|---|
| 1053 |
self.chatLeft(int(data[0])) |
|---|
| 1054 |
del self._receivedchatmembers[int(data[0])] |
|---|
| 1055 |
del self._roomnames[int(data[0])] |
|---|
| 1056 |
|
|---|
| 1057 |
def tocRVOUS_PROPOSE(self,data): |
|---|
| 1058 |
""" |
|---|
| 1059 |
Handle a message that looks like:: |
|---|
| 1060 |
|
|---|
| 1061 |
RVOUS_PROPOSE:<user>:<uuid>:<cookie>:<seq>:<rip>:<pip>:<vip>:<port> |
|---|
| 1062 |
[:tlv tag1:tlv value1[:tlv tag2:tlv value2[:...]]] |
|---|
| 1063 |
""" |
|---|
| 1064 |
user,uid,cookie,seq,rip,pip,vip,port=data[:8] |
|---|
| 1065 |
cookie=base64.decodestring(cookie) |
|---|
| 1066 |
port=int(port) |
|---|
| 1067 |
tlvs={} |
|---|
| 1068 |
for i in range(8,len(data),2): |
|---|
| 1069 |
key=data[i] |
|---|
| 1070 |
value=base64.decodestring(data[i+1]) |
|---|
| 1071 |
tlvs[key]=value |
|---|
| 1072 |
name=UUIDS[uid] |
|---|
| 1073 |
try: |
|---|
| 1074 |
func=getattr(self,"toc%s"%name) |
|---|
| 1075 |
except: |
|---|
| 1076 |
self._debug("no function for UID %s" % uid) |
|---|
| 1077 |
return |
|---|
| 1078 |
func(user,cookie,seq,pip,vip,port,tlvs) |
|---|
| 1079 |
|
|---|
| 1080 |
def tocSEND_FILE(self,user,cookie,seq,pip,vip,port,tlvs): |
|---|
| 1081 |
if tlvs.has_key('12'): |
|---|
| 1082 |
description=tlvs['12'] |
|---|
| 1083 |
else: |
|---|
| 1084 |
description="" |
|---|
| 1085 |
subtype,numfiles,size=struct.unpack("!HHI",tlvs['10001'][:8]) |
|---|
| 1086 |
name=tlvs['10001'][8:-4] |
|---|
| 1087 |
while name[-1]=='\000': |
|---|
| 1088 |
name=name[:-1] |
|---|
| 1089 |
self._cookies[cookie]=[user,SEND_FILE_UID,pip,port,{'name':name}] |
|---|
| 1090 |
self.rvousProposal("send",cookie,user,vip,port,description=description, |
|---|
| 1091 |
name=name,files=numfiles,size=size) |
|---|
| 1092 |
|
|---|
| 1093 |
def tocGET_FILE(self,user,cookie,seq,pip,vip,port,tlvs): |
|---|
| 1094 |
return |
|---|
| 1095 |
|
|---|
| 1096 |
|
|---|
| 1097 |
|
|---|
| 1098 |
|
|---|
| 1099 |
def onLine(self): |
|---|
| 1100 |
""" |
|---|
| 1101 |
called when we are first online |
|---|
| 1102 |
""" |
|---|
| 1103 |
pass |
|---|
| 1104 |
|
|---|
| 1105 |
def gotConfig(self,mode,buddylist,permit,deny): |
|---|
| 1106 |
""" |
|---|
| 1107 |
called when we get a configuration from the server |
|---|
| 1108 |
mode := permit/deny mode |
|---|
| 1109 |
buddylist := current buddylist |
|---|
| 1110 |
permit := permit list |
|---|
| 1111 |
deny := deny list |
|---|
| 1112 |
""" |
|---|
| 1113 |
pass |
|---|
| 1114 |
|
|---|
| 1115 |
def hearError(self,code,args): |
|---|
| 1116 |
""" |
|---|
| 1117 |
called when an error is received |
|---|
| 1118 |
code := error code |
|---|
| 1119 |
args := misc. arguments (username, etc.) |
|---|
| 1120 |
""" |
|---|
| 1121 |
pass |
|---|
| 1122 |
|
|---|
| 1123 |
def hearWarning(self,newamount,username): |
|---|
| 1124 |
""" |
|---|
| 1125 |
called when we get warned |
|---|
| 1126 |
newamount := the current warning level |
|---|
| 1127 |
username := the user who warned us, or '' if it's anonymous |
|---|
| 1128 |
""" |
|---|
| 1129 |
pass |
|---|
| 1130 |
|
|---|
| 1131 |
def hearMessage(self,username,message,autoreply): |
|---|
| 1132 |
""" |
|---|
| 1133 |
called when you receive an IM |
|---|
| 1134 |
username := the user who the IM is from |
|---|
| 1135 |
message := the message |
|---|
| 1136 |
autoreply := true if the message is an autoreply from an away message |
|---|
| 1137 |
""" |
|---|
| 1138 |
pass |
|---|
| 1139 |
|
|---|
| 1140 |
def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): |
|---|
| 1141 |
""" |
|---|
| 1142 |
called when a buddy changes state |
|---|
| 1143 |
username := the user whos state changed |
|---|
| 1144 |
online := true if the user is online |
|---|
| 1145 |
evilness := the users current warning level |
|---|
| 1146 |
signontime := the time the user signed on (UNIX epoch) |
|---|
| 1147 |
idletime := the time the user has been idle (minutes) |
|---|
| 1148 |
away := true if the user is away |
|---|
| 1149 |
userclass := the class of the user (generally " O") |
|---|
| 1150 |
""" |
|---|
| 1151 |
pass |
|---|
| 1152 |
|
|---|
| 1153 |
def chatJoined(self,roomid,roomname,users): |
|---|
| 1154 |
""" |
|---|
| 1155 |
we just joined a chat room |
|---|
| 1156 |
roomid := the AIM id for the room |
|---|
| 1157 |
roomname := the name for the room |
|---|
| 1158 |
users := a list of the users already in the room |
|---|
| 1159 |
""" |
|---|
| 1160 |
pass |
|---|
| 1161 |
|
|---|
| 1162 |
def chatUpdate(self,roomid,username,inroom): |
|---|
| 1163 |
""" |
|---|
| 1164 |
a user has joined the room |
|---|
| 1165 |
roomid := the AIM id for the room |
|---|
| 1166 |
username := the username |
|---|
| 1167 |
inroom := true if the user is in the room |
|---|
| 1168 |
""" |
|---|
| 1169 |
pass |
|---|
| 1170 |
|
|---|
| 1171 |
def chatHearMessage(self,roomid,username,message): |
|---|
| 1172 |
""" |
|---|
| 1173 |
a message was sent to the room |
|---|
| 1174 |
roomid := the AIM id for the room |
|---|
| 1175 |
username := the user who sent the message |
|---|
| 1176 |
message := the message |
|---|
| 1177 |
""" |
|---|
| 1178 |
pass |
|---|
| 1179 |
|
|---|
| 1180 |
def chatHearWhisper(self,roomid,username,message): |
|---|
| 1181 |
""" |
|---|
| 1182 |
someone whispered to us in a chatroom |
|---|
| 1183 |
roomid := the AIM for the room |
|---|
| 1184 |
username := the user who whispered to us |
|---|
| 1185 |
message := the message |
|---|
| 1186 |
""" |
|---|
| 1187 |
pass |
|---|
| 1188 |
|
|---|
| 1189 |
def chatInvited(self,roomid,roomname,username,message): |
|---|
| 1190 |
""" |
|---|
| 1191 |
we were invited to a chat room |
|---|
| 1192 |
roomid := the AIM id for the room |
|---|
| 1193 |
roomname := the name of the room |
|---|
| 1194 |
username := the user who invited us |
|---|
| 1195 |
message := the invite message |
|---|
| 1196 |
""" |
|---|
| 1197 |
pass |
|---|
| 1198 |
|
|---|
| 1199 |
def chatLeft(self,roomid): |
|---|
| 1200 |
""" |
|---|
| 1201 |
we left the room |
|---|
| 1202 |
roomid := the AIM id for the room |
|---|
| 1203 |
""" |
|---|
| 1204 |
pass |
|---|
| 1205 |
|
|---|
| 1206 |
def rvousProposal(self,type,cookie,user,vip,port,**kw): |
|---|
| 1207 |
""" |
|---|
| 1208 |
we were asked for a rondevouz |
|---|
| 1209 |
type := the type of rondevous. currently, one of ["send"] |
|---|
| 1210 |
cookie := the cookie. pass this to rvous_accept() |
|---|
| 1211 |
user := the user who asked us |
|---|
| 1212 |
vip := their verified_ip |
|---|
| 1213 |
port := the port they want us to conenct to |
|---|
| 1214 |
kw := misc. args |
|---|
| 1215 |
""" |
|---|
| 1216 |
pass |
|---|
| 1217 |
|
|---|
| 1218 |
def receiveBytes(self,user,file,chunk,sofar,total): |
|---|
| 1219 |
""" |
|---|
| 1220 |
we received part of a file from a file transfer |
|---|
| 1221 |
file := the name of the file |
|---|
| 1222 |
chunk := the chunk of data |
|---|
| 1223 |
sofar := how much data we've gotten so far |
|---|
| 1224 |
total := the total amount of data |
|---|
| 1225 |
""" |
|---|
| 1226 |
pass |
|---|
| 1227 |
|
|---|
| 1228 |
def isaway(self): |
|---|
| 1229 |
""" |
|---|
| 1230 |
return our away status |
|---|
| 1231 |
""" |
|---|
| 1232 |
return len(self._awaymessage)>0 |
|---|
| 1233 |
|
|---|
| 1234 |
def set_config(self,mode,buddylist,permit,deny): |
|---|
| 1235 |
""" |
|---|
| 1236 |
set the server configuration |
|---|
| 1237 |
mode := permit mode |
|---|
| 1238 |
buddylist := buddy list |
|---|
| 1239 |
permit := permit list |
|---|
| 1240 |
deny := deny list |
|---|
| 1241 |
""" |
|---|
| 1242 |
s="m %s\n"%mode |
|---|
| 1243 |
for g in buddylist.keys(): |
|---|
| 1244 |
s=s+"g %s\n"%g |
|---|
| 1245 |
for u in buddylist[g]: |
|---|
| 1246 |
s=s+"b %s\n"%u |
|---|
| 1247 |
for p in permit: |
|---|
| 1248 |
s=s+"p %s\n"%p |
|---|
| 1249 |
for d in deny: |
|---|
| 1250 |
s=s+"d %s\n"%d |
|---|
| 1251 |
|
|---|
| 1252 |
self.sendFlap(2,"toc_set_config %s"%quote(s)) |
|---|
| 1253 |
|
|---|
| 1254 |
def add_buddy(self,buddies): |
|---|
| 1255 |
s="" |
|---|
| 1256 |
if type(buddies)==type(""): buddies=[buddies] |
|---|
| 1257 |
for b in buddies: |
|---|
| 1258 |
s=s+" "+normalize(b) |
|---|
| 1259 |
self.sendFlap(2,"toc_add_buddy%s"%s) |
|---|
| 1260 |
|
|---|
| 1261 |
def del_buddy(self,buddies): |
|---|
| 1262 |
s="" |
|---|
| 1263 |
if type(buddies)==type(""): buddies=[buddies] |
|---|
| 1264 |
for b in buddies: |
|---|
| 1265 |
s=s+" "+b |
|---|
| 1266 |
self.sendFlap(2,"toc_remove_buddy%s"%s) |
|---|
| 1267 |
|
|---|
| 1268 |
def add_permit(self,users): |
|---|
| 1269 |
if type(users)==type(""): users=[users] |
|---|
| 1270 |
s="" |
|---|
| 1271 |
if self._privacymode!=PERMITSOME: |
|---|
| 1272 |
self._privacymode=PERMITSOME |
|---|
| 1273 |
self._permitlist=[] |
|---|
| 1274 |
for u in users: |
|---|
| 1275 |
u=normalize(u) |
|---|
| 1276 |
if u not in self._permitlist:self._permitlist.append(u) |
|---|
| 1277 |
s=s+" "+u |
|---|
| 1278 |
if not s: |
|---|
| 1279 |
self._privacymode=DENYALL |
|---|
| 1280 |
self._permitlist=[] |
|---|
| 1281 |
self._denylist=[] |
|---|
| 1282 |
self.sendFlap(2,"toc_add_permit"+s) |
|---|
| 1283 |
|
|---|
| 1284 |
def del_permit(self,users): |
|---|
| 1285 |
if type(users)==type(""): users=[users] |
|---|
| 1286 |
p=self._permitlist[:] |
|---|
| 1287 |
for u in users: |
|---|
| 1288 |
u=normalize(u) |
|---|
| 1289 |
if u in p: |
|---|
| 1290 |
p.remove(u) |
|---|
| 1291 |
self.add_permit([]) |
|---|
| 1292 |
self.add_permit(p) |
|---|
| 1293 |
|
|---|
| 1294 |
def add_deny(self,users): |
|---|
| 1295 |
if type(users)==type(""): users=[users] |
|---|
| 1296 |
s="" |
|---|
| 1297 |
if self._privacymode!=DENYSOME: |
|---|
| 1298 |
self._privacymode=DENYSOME |
|---|
| 1299 |
self._denylist=[] |
|---|
| 1300 |
for u in users: |
|---|
| 1301 |
u=normalize(u) |
|---|
| 1302 |
if u not in self._denylist:self._denylist.append(u) |
|---|
| 1303 |
s=s+" "+u |
|---|
| 1304 |
if not s: |
|---|
| 1305 |
self._privacymode=PERMITALL |
|---|
| 1306 |
self._permitlist=[] |
|---|
| 1307 |
self._denylist=[] |
|---|
| 1308 |
self.sendFlap(2,"toc_add_deny"+s) |
|---|
| 1309 |
|
|---|
| 1310 |
def del_deny(self,users): |
|---|
| 1311 |
if type(users)==type(""): users=[users] |
|---|
| 1312 |
d=self._denylist[:] |
|---|
| 1313 |
for u in users: |
|---|
| 1314 |
u=normalize(u) |
|---|
| 1315 |
if u in d: |
|---|
| 1316 |
d.remove(u) |
|---|
| 1317 |
self.add_deny([]) |
|---|
| 1318 |
if d: |
|---|
| 1319 |
self.add_deny(d) |
|---|
| 1320 |
|
|---|
| 1321 |
def signon(self): |
|---|
| 1322 |
""" |
|---|
| 1323 |
called to finish the setup, and signon to the network |
|---|
| 1324 |
""" |
|---|
| 1325 |
self.sendFlap(2,"toc_init_done") |
|---|
| 1326 |
self.sendFlap(2,"toc_set_caps %s" % (SEND_FILE_UID,)) |
|---|
| 1327 |
|
|---|
| 1328 |
def say(self,user,message,autoreply=0): |
|---|
| 1329 |
""" |
|---|
| 1330 |
send a message |
|---|
| 1331 |
user := the user to send to |
|---|
| 1332 |
message := the message |
|---|
| 1333 |
autoreply := true if the message is an autoreply (good for away messages) |
|---|
| 1334 |
""" |
|---|
| 1335 |
if autoreply: a=" auto" |
|---|
| 1336 |
else: a='' |
|---|
| 1337 |
self.sendFlap(2,"toc_send_im %s %s%s"%(normalize(user),quote(message),a)) |
|---|
| 1338 |
|
|---|
| 1339 |
def idle(self,idletime=0): |
|---|
| 1340 |
""" |
|---|
| 1341 |
change idle state |
|---|
| 1342 |
idletime := the seconds that the user has been away, or 0 if they're back |
|---|
| 1343 |
""" |
|---|
| 1344 |
self.sendFlap(2,"toc_set_idle %s" % int(idletime)) |
|---|
| 1345 |
|
|---|
| 1346 |
def evil(self,user,anon=0): |
|---|
| 1347 |
""" |
|---|
| 1348 |
warn a user |
|---|
| 1349 |
user := the user to warn |
|---|
| 1350 |
anon := if true, an anonymous warning |
|---|
| 1351 |
""" |
|---|
| 1352 |
self.sendFlap(2,"toc_evil %s %s"%(normalize(user), (not anon and "anon") or "norm")) |
|---|
| 1353 |
|
|---|
| 1354 |
def away(self,message=''): |
|---|
| 1355 |
""" |
|---|
| 1356 |
change away state |
|---|
| 1357 |
message := the message, or '' to come back from awayness |
|---|
| 1358 |
""" |
|---|
| 1359 |
self._awaymessage=message |
|---|
| 1360 |
if message: |
|---|
| 1361 |
message=' '+quote(message) |
|---|
| 1362 |
self.sendFlap(2,"toc_set_away%s"%message) |
|---|
| 1363 |
|
|---|
| 1364 |
def chat_join(self,exchange,roomname): |
|---|
| 1365 |
""" |
|---|
| 1366 |
join a chat room |
|---|
| 1367 |
exchange := should almost always be 4 |
|---|
| 1368 |
roomname := room name |
|---|
| 1369 |
""" |
|---|
| 1370 |
roomname=string.replace(roomname," ","") |
|---|
| 1371 |
self.sendFlap(2,"toc_chat_join %s %s"%(int(exchange),roomname)) |
|---|
| 1372 |
|
|---|
| 1373 |
def chat_say(self,roomid,message): |
|---|
| 1374 |
""" |
|---|
| 1375 |
send a message to a chatroom |
|---|
| 1376 |
roomid := the AIM id for the room |
|---|
| 1377 |
message := the message to send |
|---|
| 1378 |
""" |
|---|
| 1379 |
self.sendFlap(2,"toc_chat_send %s %s"%(int(roomid),quote(message))) |
|---|
| 1380 |
|
|---|
| 1381 |
def chat_whisper(self,roomid,user,message): |
|---|
| 1382 |
""" |
|---|
| 1383 |
whisper to another user in a chatroom |
|---|
| 1384 |
roomid := the AIM id for the room |
|---|
| 1385 |
user := the user to whisper to |
|---|
| 1386 |
message := the message to send |
|---|
| 1387 |
""" |
|---|
| 1388 |
self.sendFlap(2,"toc_chat_whisper %s %s %s"%(int(roomid),normalize(user),quote(message))) |
|---|
| 1389 |
|
|---|
| 1390 |
def chat_leave(self,roomid): |
|---|
| 1391 |
""" |
|---|
| 1392 |
leave a chat room. |
|---|
| 1393 |
roomid := the AIM id for the room |
|---|
| 1394 |
""" |
|---|
| 1395 |
self.sendFlap(2,"toc_chat_leave %s" % int(roomid)) |
|---|
| 1396 |
|
|---|
| 1397 |
def chat_invite(self,roomid,usernames,message): |
|---|
| 1398 |
""" |
|---|
| 1399 |
invite a user[s] to the chat room |
|---|
| 1400 |
roomid := the AIM id for the room |
|---|
| 1401 |
usernames := either a string (one username) or a list (more than one) |
|---|
| 1402 |
message := the message to invite them with |
|---|
| 1403 |
""" |
|---|
| 1404 |
if type(usernames)==type(""): |
|---|
| 1405 |
users=usernames |
|---|
| 1406 |
else: |
|---|
| 1407 |
users="" |
|---|
| 1408 |
for u in usernames: |
|---|
| 1409 |
users=users+u+" " |
|---|
| 1410 |
users=users[:-1] |
|---|
| 1411 |
self.sendFlap(2,"toc_chat_invite %s %s %s" % (int(roomid),quote(message),users)) |
|---|
| 1412 |
|
|---|
| 1413 |
def chat_accept(self,roomid): |
|---|
| 1414 |
""" |
|---|
| 1415 |
accept an invite to a chat room |
|---|
| 1416 |
roomid := the AIM id for the room |
|---|
| 1417 |
""" |
|---|
| 1418 |
self.sendFlap(2,"toc_chat_accept %s"%int(roomid)) |
|---|
| 1419 |
|
|---|
| 1420 |
def rvous_accept(self,cookie): |
|---|
| 1421 |
user,uuid,pip,port,d=self._cookies[cookie] |
|---|
| 1422 |
self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), |
|---|
| 1423 |
cookie,uuid)) |
|---|
| 1424 |
if uuid==SEND_FILE_UID: |
|---|
| 1425 |
protocol.ClientCreator(reactor, SendFileTransfer,self,cookie,user,d["name"]).connectTCP(pip,port) |
|---|
| 1426 |
|
|---|
| 1427 |
def rvous_cancel(self,cookie): |
|---|
| 1428 |
user,uuid,pip,port,d=self._cookies[cookie] |
|---|
| 1429 |
self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), |
|---|
| 1430 |
cookie,uuid)) |
|---|
| 1431 |
del self._cookies[cookie] |
|---|
| 1432 |
|
|---|
| 1433 |
|
|---|
| 1434 |
class SendFileTransfer(protocol.Protocol): |
|---|
| 1435 |
header_fmt="!4s2H8s6H10I32s3c69s16s2H64s" |
|---|
| 1436 |
|
|---|
| 1437 |
def __init__(self,client,cookie,user,filename): |
|---|
| 1438 |
self.client=client |
|---|
| 1439 |
self.cookie=cookie |
|---|
| 1440 |
self.user=user |
|---|
| 1441 |
self.filename=filename |
|---|
| 1442 |
self.hdr=[0,0,0] |
|---|
| 1443 |
self.sofar=0 |
|---|
| 1444 |
|
|---|
| 1445 |
def dataReceived(self,data): |
|---|
| 1446 |
if not self.hdr[2]==0x202: |
|---|
| 1447 |
self.hdr=list(struct.unpack(self.header_fmt,data[:256])) |
|---|
| 1448 |
self.hdr[2]=0x202 |
|---|
| 1449 |
self.hdr[3]=self.cookie |
|---|
| 1450 |
self.hdr[4]=0 |
|---|
| 1451 |
self.hdr[5]=0 |
|---|
| 1452 |
self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) |
|---|
| 1453 |
data=data[256:] |
|---|
| 1454 |
if self.hdr[6]==1: |
|---|
| 1455 |
self.name=self.filename |
|---|
| 1456 |
else: |
|---|
| 1457 |
self.name=self.filename+self.hdr[-1] |
|---|
| 1458 |
while self.name[-1]=="\000": |
|---|
| 1459 |
self.name=self.name[:-1] |
|---|
| 1460 |
if not data: return |
|---|
| 1461 |
self.sofar=self.sofar+len(data) |
|---|
| 1462 |
self.client.receiveBytes(self.user,self.name,data,self.sofar,self.hdr[11]) |
|---|
| 1463 |
if self.sofar==self.hdr[11]: |
|---|
| 1464 |
self.hdr[2]=0x204 |
|---|
| 1465 |
self.hdr[7]=self.hdr[7]-1 |
|---|
| 1466 |
self.hdr[9]=self.hdr[9]-1 |
|---|
| 1467 |
self.hdr[19]=DUMMY_CHECKSUM |
|---|
| 1468 |
self.hdr[18]=self.hdr[18]+1 |
|---|
| 1469 |
self.hdr[21]="\000" |
|---|
| 1470 |
self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) |
|---|
| 1471 |
self.sofar=0 |
|---|
| 1472 |
if self.hdr[7]==0: |
|---|
| 1473 |
self.transport.loseConnection() |
|---|
| 1474 |
|
|---|
| 1475 |
|
|---|
| 1476 |
class GetFileTransfer(protocol.Protocol): |
|---|
| 1477 |
header_fmt="!4s 2H 8s 6H 10I 32s 3c 69s 16s 2H 64s" |
|---|
| 1478 |
def __init__(self,client,cookie,dir): |
|---|
| 1479 |
self.client=client |
|---|
| 1480 |
self.cookie=cookie |
|---|
| 1481 |
self.dir=dir |
|---|
| 1482 |
self.buf="" |
|---|
| 1483 |
|
|---|
| 1484 |
def connectionMade(self): |
|---|
| 1485 |
def func(f,path,names): |
|---|
| 1486 |
names.sort(lambda x,y:cmp(string.lower(x),string.lower(y))) |
|---|
| 1487 |
for n in names: |
|---|
| 1488 |
name=os.path.join(path,n) |
|---|
| 1489 |
lt=time.localtime(os.path.getmtime(name)) |
|---|
| 1490 |
size=os.path.getsize(name) |
|---|
| 1491 |
f[1]=f[1]+size |
|---|
| 1492 |
f.append("%02d/%02d/%4d %02d:%02d %8d %s" % |
|---|
| 1493 |
(lt[1],lt[2],lt[0],lt[3],lt[4],size,name[f[0]:])) |
|---|
| 1494 |
f=[len(self.dir)+1,0] |
|---|
| 1495 |
os.path.walk(self.dir,func,f) |
|---|
| 1496 |
size=f[1] |
|---|
| 1497 |
self.listing=string.join(f[2:],"\r\n")+"\r\n" |
|---|
| 1498 |
open("\\listing.txt","w").write(self.listing) |
|---|
| 1499 |
hdr=["OFT2",256,0x1108,self.cookie,0,0,len(f)-2,len(f)-2,1,1,size, |
|---|
| 1500 |
len(self.listing),os.path.getmtime(self.dir), |
|---|
| 1501 |
checksum(self.listing),0,0,0,0,0,0,"OFT_Windows ICBMFT V1.1 32", |
|---|
| 1502 |
"\002",chr(0x1a),chr(0x10),"","",0,0,""] |
|---|
| 1503 |
self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) |
|---|
| 1504 |
|
|---|
| 1505 |
def dataReceived(self,data): |
|---|
| 1506 |
self.buf=self.buf+data |
|---|
| 1507 |
while len(self.buf)>=256: |
|---|
| 1508 |
hdr=list(struct.unpack(self.header_fmt,self.buf[:256])) |
|---|
| 1509 |
self.buf=self.buf[256:] |
|---|
| 1510 |
if hdr[2]==0x1209: |
|---|
| 1511 |
self.file=StringIO.StringIO(self.listing) |
|---|
| 1512 |
self.transport.registerProducer(self,0) |
|---|
| 1513 |
elif hdr[2]==0x120b: pass |
|---|
| 1514 |
elif hdr[2]==0x120c: |
|---|
| 1515 |
file=hdr[-1] |
|---|
| 1516 |
for k,v in [["\000",""],["\001",os.sep]]: |
|---|
| 1517 |
file=string.replace(file,k,v) |
|---|
| 1518 |
self.name=os.path.join(self.dir,file) |
|---|
| 1519 |
self.file=open(self.name,'rb') |
|---|
| 1520 |
hdr[2]=0x0101 |
|---|
| 1521 |
hdr[6]=hdr[7]=1 |
|---|
| 1522 |
hdr[10]=hdr[11]=os.path.getsize(self.name) |
|---|
| 1523 |
hdr[12]=os.path.getmtime(self.name) |
|---|
| 1524 |
hdr[13]=checksum_file(self.file) |
|---|
| 1525 |
self.file.seek(0) |
|---|
| 1526 |
hdr[18]=hdr[19]=0 |
|---|
| 1527 |
hdr[21]=chr(0x20) |
|---|
| 1528 |
self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) |
|---|
| 1529 |
log.msg("got file request for %s"%file,hex(hdr[13])) |
|---|
| 1530 |
elif hdr[2]==0x0202: |
|---|
| 1531 |
log.msg("sending file") |
|---|
| 1532 |
self.transport.registerProducer(self,0) |
|---|
| 1533 |
elif hdr[2]==0x0204: |
|---|
| 1534 |
log.msg("real checksum: %s"%hex(hdr[19])) |
|---|
| 1535 |
del self.file |
|---|
| 1536 |
elif hdr[2]==0x0205: |
|---|
| 1537 |
already=hdr[18] |
|---|
| 1538 |
if already: |
|---|
| 1539 |
data=self.file.read(already) |
|---|
| 1540 |
else: |
|---|
| 1541 |
data="" |
|---|
| 1542 |
log.msg("restarting at %s"%already) |
|---|
| 1543 |
hdr[2]=0x0106 |
|---|
| 1544 |
hdr[19]=checksum(data) |
|---|
| 1545 |
self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) |
|---|
| 1546 |
elif hdr[2]==0x0207: |
|---|
| 1547 |
self.transport.registerProducer(self,0) |
|---|
| 1548 |
else: |
|---|
| 1549 |
log.msg("don't understand 0x%04x"%hdr[2]) |
|---|
| 1550 |
log.msg(hdr) |
|---|
| 1551 |
|
|---|
| 1552 |
def resumeProducing(self): |
|---|
| 1553 |
data=self.file.read(4096) |
|---|
| 1554 |
log.msg(len(data)) |
|---|
| 1555 |
if not data: |
|---|
| 1556 |
self.transport.unregisterProducer() |
|---|
| 1557 |
self.transport.write(data) |
|---|
| 1558 |
|
|---|
| 1559 |
def pauseProducing(self): pass |
|---|
| 1560 |
|
|---|
| 1561 |
def stopProducing(self): del self.file |
|---|
| 1562 |
|
|---|
| 1563 |
|
|---|
| 1564 |
SEND_FILE_UID = "09461343-4C7F-11D1-8222-444553540000" |
|---|
| 1565 |
GET_FILE_UID = "09461348-4C7F-11D1-8222-444553540000" |
|---|
| 1566 |
UUIDS={ |
|---|
| 1567 |
SEND_FILE_UID:"SEND_FILE", |
|---|
| 1568 |
GET_FILE_UID:"GET_FILE" |
|---|
| 1569 |
} |
|---|
| 1570 |
|
|---|
| 1571 |
|
|---|
| 1572 |
|
|---|
| 1573 |
NOT_AVAILABLE=901 |
|---|
| 1574 |
CANT_WARN=902 |
|---|
| 1575 |
MESSAGES_TOO_FAST=903 |
|---|
| 1576 |
|
|---|
| 1577 |
BAD_INPUT=911 |
|---|
| 1578 |
BAD_ACCOUNT=912 |
|---|
| 1579 |
REQUEST_ERROR=913 |
|---|
| 1580 |
SERVICE_UNAVAILABLE=914 |
|---|
| 1581 |
|
|---|
| 1582 |
NO_CHAT_IN=950 |
|---|
| 1583 |
|
|---|
| 1584 |
SEND_TOO_FAST=960 |
|---|
| 1585 |
MISSED_BIG_IM=961 |
|---|
| 1586 |
MISSED_FAST_IM=962 |
|---|
| 1587 |
|
|---|
| 1588 |
DIR_FAILURE=970 |
|---|
| 1589 |
TOO_MANY_MATCHES=971 |
|---|
| 1590 |
NEED_MORE_QUALIFIERS=972 |
|---|
| 1591 |
DIR_UNAVAILABLE=973 |
|---|
| 1592 |
NO_EMAIL_LOOKUP=974 |
|---|
| 1593 |
KEYWORD_IGNORED=975 |
|---|
| 1594 |
NO_KEYWORDS=976 |
|---|
| 1595 |
BAD_LANGUAGE=977 |
|---|
| 1596 |
BAD_COUNTRY=978 |
|---|
| 1597 |
DIR_FAIL_UNKNOWN=979 |
|---|
| 1598 |
|
|---|
| 1599 |
BAD_NICKNAME=980 |
|---|
| 1600 |
SERVICE_TEMP_UNAVAILABLE=981 |
|---|
| 1601 |
WARNING_TOO_HIGH=982 |
|---|
| 1602 |
CONNECTING_TOO_QUICK=983 |
|---|
| 1603 |
UNKNOWN_SIGNON=989 |
|---|
| 1604 |
|
|---|
| 1605 |
STD_MESSAGE={} |
|---|
| 1606 |
STD_MESSAGE[NOT_AVAILABLE]="%s not currently available" |
|---|
| 1607 |
STD_MESSAGE[CANT_WARN]="Warning of %s not currently available" |
|---|
| 1608 |
STD_MESSAGE[MESSAGES_TOO_FAST]="A message has been dropped, you are exceeding the server speed limit" |
|---|
| 1609 |
STD_MESSAGE[BAD_INPUT]="Error validating input" |
|---|
| 1610 |
STD_MESSAGE[BAD_ACCOUNT]="Invalid account" |
|---|
| 1611 |
STD_MESSAGE[REQUEST_ERROR]="Error encountered while processing request" |
|---|
| 1612 |
STD_MESSAGE[SERVICE_UNAVAILABLE]="Service unavailable" |
|---|
| 1613 |
STD_MESSAGE[NO_CHAT_IN]="Chat in %s is unavailable" |
|---|
| 1614 |
STD_MESSAGE[SEND_TOO_FAST]="You are sending messages too fast to %s" |
|---|
| 1615 |
STD_MESSAGE[MISSED_BIG_IM]="You missed an IM from %s because it was too big" |
|---|
| 1616 |
STD_MESSAGE[MISSED_FAST_IM]="You missed an IM from %s because it was sent too fast" |
|---|
| 1617 |
|
|---|
| 1618 |
STD_MESSAGE[BAD_NICKNAME]="Incorrect nickname or password" |
|---|
| 1619 |
STD_MESSAGE[SERVICE_TEMP_UNAVAILABLE]="The service is temporarily unavailable" |
|---|
| 1620 |
STD_MESSAGE[WARNING_TOO_HIGH]="Your warning level is currently too high to sign on" |
|---|
| 1621 |
STD_MESSAGE[CONNECTING_TOO_QUICK]="You have been connecting and disconnecting too frequently. Wait 10 minutes and try again. If you continue to try, you will need to wait even longer." |
|---|
| 1622 |
STD_MESSAGE[UNKNOWN_SIGNON]="An unknown signon error has occurred %s" |
|---|