From 9fc737865ab67fa1302cc1f49f3f563ef057782b Mon Sep 17 00:00:00 2001 From: yvesf Date: Thu, 14 Jan 2010 23:03:06 +0000 Subject: save git-svn-id: http://xapek.org/svn/common/omegle@1538 d0e8fea9-7529-0410-93fb-d39fd5b9c1dd --- icqRoombot.tac | 10 +- omegle/icq.py | 146 +++++++++++++-------------- omegle/icqBuddy.py | 14 ++- omegle/icqChatroomBuddy.py | 5 +- omegle/icqRoombot.py | 4 +- unfoggedbot.py | 241 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 334 insertions(+), 86 deletions(-) create mode 100644 unfoggedbot.py diff --git a/icqRoombot.tac b/icqRoombot.tac index 2f6fba1..a883d76 100644 --- a/icqRoombot.tac +++ b/icqRoombot.tac @@ -1,15 +1,17 @@ #!/usr/bin/env twistd # vim: set ft=python sw=4 et syntax=python: -from omegle.icq import ReconnectOscarFactory +from omegle.icq import ReconnectingOSCARLoginFactory from omegle.icqRoombot import ICQRoombot from twisted.application import internet, service -uin, password = ('370496181', 'megahal123') +#uin, password = ('370496181', 'megahal123') +uin, password = ('566193419', 'gagagaga') host, port = ('login.oscar.aol.com', 5190) -factory = ReconnectOscarFactory(ICQRoombot, uin, password, icq=1) +f = ReconnectingOSCARLoginFactory(uin, password) +f.BOSClass = ICQRoombot application = service.Application('icqRoombot') -service = internet.TCPClient(host, port, factory) +service = internet.TCPClient(host, port, f) service.setServiceParent(application) diff --git a/omegle/icq.py b/omegle/icq.py index 3cb5c7f..b134dd6 100644 --- a/omegle/icq.py +++ b/omegle/icq.py @@ -3,36 +3,38 @@ # Yves Fischer, xapek.org 2009 import struct -from twisted.words.protocols import oscar -from twisted.internet import reactor, protocol +#from twisted.words.protocols import oscar +from tlib import oscar +from twisted.internet import reactor, protocol, defer from twisted.internet.protocol import ClientFactory -CAP_TYPING = '\x56\x3f\xc8\x09\x0b\x6f\x41\xbd\x9f\x79\x42\x26\x09\xdf\xa2\xf3' +__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] + capabilities = [oscar.CAP_CHAT, CAP_TYPING] - def __init__(self,s,p,**kwargs): - oscar.BOSConnection.__init__(self, s, p,**kwargs) + def __init__(self,username, cookie, authenticator = None): + oscar.BOSConnection.__init__(self, username, cookie) + self.authenticator = authenticator + print self.authenticator - """ - handles typing SNAC - """ + """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"): + 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") + 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]) + 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" + print 'komisches tpying snac' def receiveTyping(self, user, state): pass @@ -45,25 +47,25 @@ class ExtendedBOSConnection( oscar.BOSConnection ): pass def updateBuddy(self, user): - print "updateBuddy %s" % 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.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 + print 'icq: Authorize %s' % user.name self.sendAuthorizationResponse(user.name, True, '') - """message - utf8 """ + """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": + if multiparts[0][1] == 'unicode': message = unicode(multiparts[0][0]) else: message = multiparts[0][0].decode(multiparts[0][1],'latin1') @@ -73,80 +75,80 @@ class ExtendedBOSConnection( oscar.BOSConnection ): def receiveMessage( self, user, multiparts, flags ): - print "icq: receiveMessage(%s,%s,%s)" % (user,multiparts,flags) - if flags != None and "auto" in flags: - print "'auto' message, abort" - return + 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 "budded added signal" i auth on every message + # 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) + message = filter(lambda x: x!=u'\x00', message) self.receiveCleanMessage( user, message, flags ) except Exception,e: - print "Exception: %s" % e - - def chatReceiveMessage( self, chat, user, message ): - self.receiveMessage( self, user, message, [] ) + print 'Exception: %s' % e def sendAuthorizationResponse(self, uin, success, responsString): - packet = struct.pack("b", len(uin)) + uin + packet = struct.pack('b', len(uin)) + uin if success: - packet += struct.pack("b", 1) + packet += struct.pack('b', 1) else: - packet += struct.pack("b", 0) - packet += struct.pack(">H", len(responsString)) + responsString + 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): - print "Connection lost" - oscar.BOSConnection.connectionLost(self,reason) - self.shutdown() - self.transport.loseConnection() - self.authenticator.connectionLost(reason) - -class Authenticator( oscar.OscarAuthenticator ): - def connectionLost(self,reason): - oscar.OscarAuthenticator.connectionLost(self,reason) - self.factory.connectionLost(reason) - - def connectToBOS(self, server, port): - c = protocol.ClientCreator(reactor, self.BOSClass, - self.username, self.cookie) - c.authenticator = self - return c.connectTCP(server, port) - + def connectionLost(self, reason): + self.factory.clientConnectionLost(self, reason) + oscar.BOSConnection.connectionLost(self,reason) -class ReconnectOscarFactory(ClientFactory): - def __init__(self, BOSClass, uid, password,icq=1): - self.BOSClass = BOSClass +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.icq = icq - + self.host = host + self.port = port def buildProtocol(self, addr): - p = Authenticator(self.uid, self.password,icq=self.icq) + 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 - - def startedConnecting(self, connector): - print 'Started to connect to oscar' - - def connectionLost(self,reason): - print "CONECTION LOST - start njew factory" - reactor.callLater(4.0, reactor.connectTCP, - 'login.icq.com', 5238, self) -# reactor.connectTCP('login.icq.com', 5238, OscarFactory(self.uin, self.password,icq=1)) - - + ## only reconnect on *failures* + def clientConnectionLost(self, con, reason): + pass diff --git a/omegle/icqBuddy.py b/omegle/icqBuddy.py index c51419f..1a9d609 100644 --- a/omegle/icqBuddy.py +++ b/omegle/icqBuddy.py @@ -9,10 +9,9 @@ from twisted.internet import reactor from twisted.python import log from omegle import OmegleChat -from icq import ExtendedBOSConnection, ReconnectOscarFactory +from icq import ExtendedBOSConnection, ReconnectingOSCARLoginFactory -ICQ_UIN = '446323989' -ICQ_PASSWORD = 'gagaga' +ICQ_UIN, ICQ_PASSWORD = ('446323989', 'gagaga') def random_greetings(): gr = ( @@ -20,7 +19,9 @@ def random_greetings(): "Connected with Omegle, be retarted with strangers!", "Omegle ... its like pedo-roulette", "Under law 153:276:935 section 864, Omegle is required to inform you that the person you are currently chatting with owns the IP address of a registered sex offender. Please be careful when chatting with this person, and remember never to give out your personal information. The person you are chatting with cannot see this message.", + "You're Now On Omegle, Note: In China Too Young Is Just a Name", ) + return "==== %s" % gr[random.randint(0,len(gr)-1)] class OmegleICQChat(OmegleChat): @@ -67,7 +68,8 @@ class ICQBuddy( ExtendedBOSConnection ): self.omegleConns = {} def shutdown( self ): - for conn in self.omegleConns: + for k in self.omegleConns.keys(): + conn = self.omegleConns[k] if conn.is_connected: conn.disconnect() @@ -116,6 +118,8 @@ if __name__ == '__main__': logging.basicConfig(level=logging.INFO) log.startLogging(sys.stdout) - factory = ReconnectOscarFactory(ICQBuddy, ICQ_UIN,ICQ_PASSWORD,icq=1) + f = ReconnectingOSCARLoginFactory(ICQ_UIN, ICQ_PASSWORD) + f.BOSClass = ICQBuddy + reactor.connectTCP('login.icq.com', 5238, f) reactor.run() diff --git a/omegle/icqChatroomBuddy.py b/omegle/icqChatroomBuddy.py index a235334..be92c58 100644 --- a/omegle/icqChatroomBuddy.py +++ b/omegle/icqChatroomBuddy.py @@ -8,7 +8,7 @@ from twisted.internet import reactor, protocol from twisted.python import log from omegle.icqBuddy import ICQBuddy -from icq import ReconnectOscarFactory +from icq import ReconnectingOSCARLoginFactory ICQ_UIN = '446323989' ICQ_PASSWORD = 'gagaga' @@ -29,6 +29,7 @@ if __name__ == '__main__': logging.basicConfig(level=logging.INFO) log.startLogging(sys.stdout) - factory = ReconnectOscarFactory(OmegleICQChatroomBuddy, ICQ_UIN,ICQ_PASSWORD,icq=1) + factory = ReconnectingOSCARLoginFactory(ICQ_UIN,ICQ_PASSWORD) + factory.BOSClass = OmegleICQChatroomBuddy reactor.connectTCP('login.icq.com', 5238, factory) reactor.run() diff --git a/omegle/icqRoombot.py b/omegle/icqRoombot.py index 3f463a5..17a0a3d 100644 --- a/omegle/icqRoombot.py +++ b/omegle/icqRoombot.py @@ -1,8 +1,6 @@ #!/usr/bin/python # Yves Fischer, xapek.org 2009 - -import sys -from icq import ExtendedBOSConnection, ReconnectOscarFactory +from icq import ExtendedBOSConnection from random import randint from twisted.internet import reactor diff --git a/unfoggedbot.py b/unfoggedbot.py new file mode 100644 index 0000000..4c943ba --- /dev/null +++ b/unfoggedbot.py @@ -0,0 +1,241 @@ +#! /usr/bin/python +#from twisted.words.protocols import oscar +import oscar +## local copy taken from the py-aimt project. +## some API differences, but it automagically does rate-limiting stuff. +from twisted.internet import protocol, reactor +from twisted.enterprise.adbapi import ConnectionPool +from twisted.python import log +import re, feedparser, socket, sets, os +#socket.setdefaulttimeout(60) + + +DB = "ubotdb" +RC = ".unfoggedbotrc" +host, port = ('login.oscar.aol.com', 5190) + +## longer SQL. +GETCOMMENT = "SELECT comment_id,link,thread_url,author,content,title FROM rss_items WHERE processed = 0 ORDER BY comment_id ASC LIMIT 1" +GETPOST = "SELECT post_id, post_url, title FROM posts WHERE processed = 0 ORDER BY post_id ASC LIMIT 1" +GETSUBSCRIBERS = "SELECT screen_name FROM subscriptions WHERE thread_url = ?" +INSERTCOMMENTS = "INSERT OR IGNORE INTO rss_items (link, processed, thread_url, author, content, title) VALUES (?, ?, ?, ?, ?, ?)" +INSERTPOSTS = "INSERT OR IGNORE INTO posts (post_url, title, processed) VALUES (?, ?, ?)" + +db = ConnectionPool("pysqlite2.dbapi2", DB) + +permalink = re.compile("http://(www\.)?unfogged\.com/archives/week_...._.._..\.html#(\d+)") +commentlink = re.compile("http://(www\.)?unfogged\.com/archives/comments_(\d+).html") + +ignorefirst = lambda f: lambda *a: f(*a[1:]) +mkmsg = lambda txt: [[txt.decode('utf-8').encode('utf-16-be'), 'unicode']] + +class UnfoggedBot(oscar.BOSConnection): + def __init__(self, username, cookie): + oscar.BOSConnection.__init__(self, username, cookie) + self.offlines = sets.Set() + self.lost = False + db.runOperation("UPDATE posts SET processed = 1")\ + .addCallback(ignorefirst(db.runOperation), + "UPDATE rss_items SET processed = 1")\ + .addCallback(ignorefirst(self.getnew)) + + def connectionMade(self): + oscar.BOSConnection.connectionMade(self) + self.lost = False + + def connectionLost(self, reason): + oscar.BOSConnection.connectionLost(self, reason) + self.lost = True + + def initDone(self): + log.msg("%s: in initDone" % self) + self.requestSelfInfo() + self.requestSSI().addCallback(self.gotBuddylist) + + def gotBuddylist(self, l): + self.activateSSI() + self.clientReady() + + def offlineBuddy(self, user): + log.msg("User %s went offline" % user) + self.offlines.add(user.name) + + def updateBuddy(self, user): + msg = "User %s status change" % user.name + if user.name in self.offlines: + msg += "; removing from offlines set" + self.offlines.remove(user.name) + log.msg(msg) + + + def _getnew(self, txn): + if self.lost: return + comment = txn.execute(GETCOMMENT).fetchall() + if comment: + turl = comment[0][2] + crecipients = txn.execute(GETSUBSCRIBERS, (turl,)).fetchall() + else: crecipients = [[[]]] + post = txn.execute(GETPOST).fetchall() + precipients = txn.execute("SELECT screen_name FROM subscriptions WHERE thread_url = ?", ("posts",)).fetchall() + return (comment, + post, + [cr[0] for cr in crecipients], + [pr[0] for pr in precipients], + ) + + def getnew(self): + if self.lost: return + reactor.callLater(3, self.getnew) + db.runInteraction(self._getnew).addCallback(self.sendnew) + + def markread(self, txn, cid, pid): + if self.lost: return + if cid: + txn.execute("UPDATE rss_items SET processed = 1 WHERE comment_id = ?", (cid,)) + if pid: + txn.execute("UPDATE posts SET processed = 1 WHERE post_id = ?", (pid,)) + + def sendnew(self, (comment, post, crecs, precs)): + if comment: + cid, link, turl, auth, cnt, title = comment[0] + if len(cnt) >= 500: + cnt = cnt[:497]+"..." #possibly cutting off tags + msg = mkmsg('%s on %s: %s' %\ + (auth, link, title, cnt)) + crecs = [c for c in crecs if c not in self.offlines] + if crecs: log.msg("Sending message to %s" % crecs) + for crec in crecs: + self.sendMessage(crec, msg) + else: cid = None + if post: + pid, link, title = post[0] + msg = mkmsg('New post!\n%s' % (link, title)) + precs = [p for p in precs if p not in self.offlines] + if precs: log.msg("Sending new post alert to %s" % precs) + for prec in precs: + self.sendMessage(prec, msg) + else: pid = None + db.runInteraction(self.markread, cid, pid) + + def receiveMessage(self, user, multiparts, flags): + try: + msg = str(multiparts[0][0]) + except IndexError: + log.msg("Index error on msg: \"%s\"?" % multiparts) + return + if self.trycommentsub(user, msg): return + if re.search("(un)?subscribe posts", msg): + db.runQuery("SELECT screen_name FROM subscriptions WHERE thread_url = ?", ("posts",)).addCallback(self.addremovepostsub, user.name) + + def trycommentsub(self, user, msg): + for pat in (permalink, commentlink): + m = pat.search(msg) + if m: + thread_id = re.sub('^0+', '', m.group(2)) + thread_url = "http://www.unfogged.com/archives/comments_%s.html" % thread_id + break + else: + return + return db.runInteraction(self._subinfo, thread_url).addCallback(self.addremovecommentsub, thread_url, user.name) + + + def _subinfo(self, txn, turl): + subscribers = txn.execute(GETSUBSCRIBERS, (turl,)).fetchall() + try: + threadname = txn.execute("SELECT title FROM posts WHERE post_url = ?", (turl,)).fetchall()[0][0] + except IndexError: + threadname = turl + return ((str(s[0]) for s in subscribers), str(threadname)) + + def addremovecommentsub(self, (subscribers, threadname), threadurl, uname): + def sendfromcb(_, msg): self.sendMessage(uname, mkmsg(msg)) + if uname in subscribers: + log.msg("unsubscribe %s from %s" % (uname, threadname)) + db.runOperation("DELETE FROM subscriptions WHERE screen_name = ? AND thread_url = ?", (uname, threadurl)).addCallback(sendfromcb, 'subscription to "%s" disabled.' % threadname) + else: + log.msg("subscribe %s to %s" % (uname, threadname)) + db.runOperation("INSERT INTO subscriptions (screen_name, thread_url) VALUES (?, ?)", (uname, threadurl)).addCallback(sendfromcb, 'subscription to "%s" enabled.' % threadname) + + def addremovepostsub(self, subscribers, uname): + def sendfromcb(_, msg): self.sendMessage(uname, mkmsg(msg)) + if uname in (str(s[0]) for s in subscribers): + log.msg("unsubscribe %s from posts" % uname) + db.runOperation("DELETE FROM subscriptions WHERE screen_name = ? AND thread_url = ?", (uname, "posts")).addCallback(sendfromcb, "subscription to posts disabled.") + else: + log.msg("subscribe %s to posts" % uname) + db.runOperation("INSERT INTO subscriptions (screen_name, thread_url) VALUES (?, ?)", (uname, "posts")).addCallback(sendfromcb, "subscription to posts enabled.") + +class ReconnectingOSCARFactory(protocol.ClientFactory): + delay = 10.0 + protocol = UnfoggedBot + def __init__(self, un, cookie): + self.un = un + self.cookie = cookie + def buildProtocol(self, addr): + p = self.protocol(self.un, self.cookie) + p.factory = self + return p + def clientConnectionLost(self, connector, reason): + reactor.callLater(self.delay, self._reconnect) + def _reconnect(self): + f = ReconnectingOSCARLoginFactory(sn, pass_) + return reactor.connectTCP(host, port, f) + +class OA(oscar.OscarAuthenticator): + BOSClass = UnfoggedBot + connectfactory = ReconnectingOSCARFactory + def connectToBOS(self, server, port): + if not self.connectfactory: + c = protocol.ClientCreator(reactor, self.BOSClass, self.username, self.cookie) + return c.connectTCP(server, int(port)) + else: + f = self.connectfactory(self.username, self.cookie) + return reactor.connectTCP(server, int(port), f) + +class ReconnectingOSCARLoginFactory(protocol.ReconnectingClientFactory): + protocol = OA + def __init__(self, sn, pass_): + self.sn = sn + self.pass_ = pass_ + def buildProtocol(self, addr): + p = self.protocol(self.sn, self.pass_, icq=0) + p.factory = self + return p + ## only reconnect on *failures* + def clientConnectionLost(self, con, reason): + pass + +def getrss(): +##on the assumption that this can be done w/o using too much time, +##I have taken this out of a separate thread. + comments = feedparser.parse("/home/unfogged/unfogged/html/bridgeplate.rdf") + posts = feedparser.parse("/home/unfogged/unfogged/html/index.xml") + updaterss(comments, posts) + reactor.callLater(15, getrss) + +def updaterss(comments, posts): + def doinsertions(txn, commentdata, postdata): + txn.executemany(INSERTCOMMENTS, commentdata) + txn.executemany(INSERTPOSTS, postdata) + commentdata, postdata = [], [] + for e in comments.entries: + title = e.title.split("comments on ")[1][1:-1] + thread_url = e.link.split('#')[0] + commentdata.append((e.link, 0, thread_url, e.contributors[0]['name'], + e.description, title)) + postdata = [] + for e in posts.entries: + postdata.append((e.link, e.title, 0)) + db.runInteraction(doinsertions, commentdata, postdata) + + +if __name__ == '__main__': + execfile(RC) # values of "sn" and "pass_" + import sys + sys.stderr = sys.stdout = open("ubot.log", "a+") + log.startLogging(sys.stdout) + f = ReconnectingOSCARLoginFactory(sn, pass_) + reactor.connectTCP(host, port, f) + + getrss() + reactor.run() -- cgit v1.2.1