#!/usr/bin/python # -*- vim: encoding: utf-8 -*- # Yves Fischer, xapek.org 2009 import struct #from twisted.words.protocols import oscar from tlib import oscar from twisted.internet import reactor, protocol, defer from twisted.internet.protocol import ClientFactory __all__ = ['ReconnectingOSCARLoginFactory', 'ExtendedBOSConnection'] CAP_TYPING = '\x56\x3f\xc8\x09\x0b\x6f\x41\xbd\x9f\x79\x42\x26\x09\xdf\xa2\xf3' class ExtendedBOSConnection( oscar.BOSConnection ): capabilities = [oscar.CAP_CHAT, CAP_TYPING] def __init__(self,username, cookie, authenticator = None): oscar.BOSConnection.__init__(self, username, cookie) self.authenticator = authenticator print self.authenticator """handles typing SNAC""" def oscar_04_14(self,snac): data = snac[3] if len(data) == len('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\t222840035\x00\x02'): user = data[11:20] state = data[20:22] if state == '\x00\x00': #finish self.receiveTyping(user, 'finish') elif state == '\x00\x01': #idle self.receiveTyping(user, 'idle') elif state == '\x00\x02': #begin self.receiveTyping(user, 'begin') else: print 'Unknown state in typing snac\nuser %s\ndata %s\nsnac %s\nstate %X%X' % (user,data,snac,state[0],sate[1]) else: print 'komisches tpying snac' def receiveTyping(self, user, state): pass def initDone( self ): self.requestSelfInfo() self.requestSSI().addCallback(self.gotBuddyList) def shutdown( self ): pass def updateBuddy(self, user): print 'updateBuddy %s' % user def gotBuddyList( self, buddylist ): self.activateSSI() self.setProfile('Forget ICQ, MSN, Yahoo and the other shitty protocols! Use XMPP/Jabber!') self.setIdleTime( 0 ) self.clientReady() for user in buddylist[0][0].users: print 'icq: Authorize %s' % user.name self.sendAuthorizationResponse(user.name, True, '') """message - utf8""" def receiveCleanMessage( self, user, message, flags ): raise NotImplementedError('receiveCleanMessage( self, user, message, flags )') def _getMessage(self,multiparts): message = None if len(multiparts[0]) == 2: if multiparts[0][1] == 'unicode': message = unicode(multiparts[0][0]) else: message = multiparts[0][0].decode(multiparts[0][1],'latin1') else: message = str(multiparts[0][0]) return message def receiveMessage( self, user, multiparts, flags ): print 'icq: receiveMessage(%s,%s,%s)' % (user,multiparts,flags) if flags != None and 'auto' in flags: return #skip 'auto' messages # because i cant receive the 'buddy added signal' i auth on every message self.sendAuthorizationResponse(user.name, True, '') #cleanup message try: message = self._getMessage( multiparts ) #filter qip \x00CHAR\x00CHAR - qip sucks at unicode? message = filter(lambda x: x!=u'\x00', message) self.receiveCleanMessage( user, message, flags ) except Exception,e: print 'Exception: %s' % e def sendAuthorizationResponse(self, uin, success, responsString): packet = struct.pack('b', len(uin)) + uin if success: packet += struct.pack('b', 1) else: packet += struct.pack('b', 0) packet += struct.pack('>H', len(responsString)) + responsString self.sendSNACnr(0x13, 0x1a, packet) def sendMessage(self, user, messageUtf8): message = messageUtf8.encode('latin1','replace') oscar.BOSConnection.sendMessage(self,user,message) def connectionLost(self, reason): self.factory.clientConnectionLost(self, reason) oscar.BOSConnection.connectionLost(self,reason) class ReconnectingOSCARFactory(protocol.ClientFactory): delay = 10.0 BOSClass = oscar.BOSConnection def __init__(self, uid, cookie, password, host, port): self.uid = uid self.cookie = cookie self.password = password self.host = host self.port = port def buildProtocol(self, addr): p = self.BOSClass(self.uid, self.cookie) p.factory = self return p def clientConnectionLost(self, connector, reason): reactor.callLater(self.delay, self._reconnect) def _reconnect(self): print "_reconnect" f = ReconnectingOSCARLoginFactory(self.uid, self.password) f.BOSClass = self.BOSClass return reactor.connectTCP(self.host, self.port, f) class Authenticator(oscar.OscarAuthenticator): BOSClass = oscar.BOSConnection def connectToBOS(self, host, port): f = ReconnectingOSCARFactory(self.username, self.cookie, self.password, host, port) f.BOSClass = self.BOSClass reactor.connectTCP(host, port, f) return defer.Deferred() #dummy class ReconnectingOSCARLoginFactory(protocol.ReconnectingClientFactory): BOSClass = oscar.BOSConnection def __init__(self, uid, password): self.uid = uid self.password = password def buildProtocol(self, addr): p = Authenticator(self.uid, self.password) p.BOSClass = self.BOSClass p.factory = self return p ## only reconnect on *failures* def clientConnectionLost(self, con, reason): pass