#Richard A. Nichols III (http://www.gate.net/~inhahe) #cases and spaces #subtract buddies when no more messages to them and add another #todo: can check pending outgoing messages import pysqlite2.dbapi2 as sql from toc import TocTalk #py-toc module by Jamie Turner. import time sn = "fu" pw = "bar" immediate_relay=True class MyBot(TocTalk): def queuemessages(sn): dbc.execute("select * from messages where to_sn = '%s' order by time asc" % sn) for id, to_sn, from_sn, datetime, message in dbc.fetchall(): m = message() m.id=id m.to_sn=to_sn m.message = "Message from %s at %s GMT: %s" % (from_sn, datetime, message)) messagequeue+=m #colors? def on_IM_IN(self,data): sn, message = data.split(":",2) if message.lower().split(" ",2)[0]=="send": dbc. v=message.split(" ",3) if len(v)<3: m = message() m.to_sn = sn m.message = "Usage: send screenname text. Note that if you include spaces in the screenname it'll send to the wrong person. Keep spaces out. Don't worry; AIM screen names are space- (and case-) insensitive." messagequeue+=m else: dbc.execute("select * from users where sn = '%s'" % sn) if dbc.fetchone: to_sn, message = v[1:] dbc.execute("insert into messages (to_sn, from_sn, datetime, message) values ('%s','%s','%s','%s')" % to_sn, sn, time.asctime(), message) if to_sn not in buddies: if len(buddies)==200: b = min((v.messagetime, k) for k, v in buddies.iteritems()) if not v.online)[1] del buddies[b] #doesnt protect against the case that all 200 buddies are online #doesnt check if a buddy is online but has no messages waiting #todo: remove a buddy frmo he list if all messages were sent buddies[to_sn] = buddy() self.do_REMOVE_BUDDY(b) self.do_ADD_BUDDY(to_sn) else: if buddies[sn].online: queuemessages(sn) m = message() m.to_sn = sn m.message = "Message to %s has been saved." % to_sn messagequeue+=m else: m = message() m.to_sn = sn m.message = "I do not have you in my known users database. You may not use the send command before reading the help on the send command. The help is this: Usage: send screenname text. Note that if you include spaces in the screenname it'll send to the wrong person. Keep spaces out. Don't worry; AIM screen names are space- (and case-) insensitive." messagequeue+=m dbc.execute("insert into users (sn) values ('%s')" % sn) db.commit() #todo: blacklist #todo: make interaction stateful. each on a thread. def readline(timeout): while: if gotmessage, timed out, disconnected.. eaxh thread needs a new db cursor else: if sn not in buddies or message.lower().split()==["read","messages"]: queuemessages(sn) #configure to autimatically read messages or not when logon or say something #this really needs send error detection, for invisible users def on_UPDATE_BUDDY(self, data): sn, online, warning, t, idle, flags = data.split(":") online=online=="T" unavailable = flags[2]=="U" buddies[sn.lower().replace(" ","")].online = online if online: queuemessages(sn) else: for i, x in enumerate(messagequeue): if x.to_sn == sn: del messagequeue[i] def start(self): for l in range(len(messages.keys()/20): self.do_ADD_BUDDY(messages.keys()[l*20:l*20+20]) self.do_AD_BUDDY(messages.keys()[-(l % 20):]) class message: id = None class buddy: online= False buddies = {} messagequeue = [] bot = MyBot(sn, pw) db = sql.connect("courierbot.db") dbc = db.cursor() #dbc.execute("select to_sn from messages group by to_sn having datetime = max(datetime) order by datetime desc limit 200") dbc.execute("select distinct to_sn from messages order by datetime desc limit 200") for x in dbc.fetchall(): bot.do_ADD_BUDDY(x[0]) buddies[x] = buddy() t = time.time() + 4 bot.go() while 1: if time.time()>t: if len(messagequeue): m = messagequeue[0] if m.to_sn in buddies: if buddies[m.to_sn].online: self.do_SEND_IM(m.to_sn, m.message) t=time.time()+4 if m.id != None: dbc.execute("delete from messages where id = '%d'" % m.id) #todo: dont delete if you get an error response before next outgoing db.commit() del messagequeue[0] db.commit() dbc.close() db.close() #todo: option to only send when not away # remember if a message dropped out of the queue or received message # drop according to oldest newest message #be careful of max message length #abuse feature - can't make too many messages in a day #handle discoennction, reconnect and buddies = {} #more sophisticated anti-flood can work in spurts