## Stick this in the <browse/> element of your jabber.xml ## <service jid="mailcheck" name="IMAP Mail Checker"> ## <ns>jabber:iq:register</ns> ## <ns>jabber:iq:gateway</ns> ## </service> ## ## Stick this in with the other <service/> elements ## <service id="mailcheck"> ## <accept> ## <ip/> ## <secret>secret</secret> ## <port>6969</port> ## </accept> ## </service> import jabber import sys import sha import imaplib import pickle import string # mailchecker client class MCClient: jid = None username = None password = None hostname = None directory = None folders = [] online = 0 status = None imap = None def __init__(self, jid, username, password, hostname, directory, folders): self.jid = jid self.username = username self.password = password self.hostname = hostname self.directory = directory self.folders = string.split(folders, ':') def doit(self, con): """query the mail server for new messages""" pass def cleanup(self): """Close down IMAP connection and perform any other necessary cleanup""" pass def setStatus(self, status): """Set the client's "verbose" status""" self.status = status def setShow(self, show): """Set the client's show mode; one of away, chat, xa, dnd, or 'None'""" # http://docs.jabber.org/jpg/html/main.html#REFSHOW # One of away, chat, xa, or dnd. self.show = show self.setOnline(1) def setOnline(self, online): """Set whether the user is online or not""" self.online = online def isOnline(self): """Return the state of the user's online'ness""" return(self.online) def isAvailable(self): """Return a boolean based on the user's show status""" # return false if xa, dnd or away (?) if (self.show == None) or (self.show == 'chat'): return(1) else: return(0) # dict of keys keys = {} def iqCB(con, iq): print "Iq:", str(iq) resultIq = jabber.Iq(to=iq.getFrom()) resultIq.setID(iq.getID()) resultIq.setFrom(iq.getTo()) query_result = resultIq.setQuery(iq.getQuery()) type = iq.getType() query_ns = iq.getQuery() # switch on type: get, set, result error # switch on namespaces if query_ns == jabber.NS_REGISTER: if type == 'get': resultIq.setType('result') # generate a key to be passed to the user; it will be checked # later. yes, we're storing a sha object iq_from = str(iq.getFrom()) keys[iq_from] = sha.new(iq_from) # tell the client the fields we want fields = { 'username': None, 'password': None, 'instructions': 'Enter your username, password, IMAP hostname, directory, and :-separated list of folders to check', 'key': keys[iq_from].hexdigest(), 'hostname': None, 'directory': None, 'folders': 'INBOX' } for field in fields.keys(): field_node = query_result.insertTag(field) if fields[field]: field_node.putData(fields[field]) con.send(resultIq) elif type == 'set': # before anything else, verify the key client_key_node = iq.getQueryNode().getTag('key') if not client_key_node: resultIq.setType('error') resultIq.setError('no key given!') con.send(resultIq) else: # verify key if keys[str(iq.getFrom())].hexdigest() == client_key_node.getData(): # key is good if iq.getQueryNode().getTag('remove'): # user is trying to unregister # TODO. :-) del clients[iq.getFrom().getStripped()] else: # someone is trying to register jid = iq.getFrom().getStripped() username = iq.getQueryNode().getTag('username') if username: username = str(username.getData()) password = iq.getQueryNode().getTag('password') if password: password = str(password.getData()) hostname = iq.getQueryNode().getTag('hostname') if hostname: hostname = str(hostname.getData()) directory = iq.getQueryNode().getTag('directory') if directory: directory = str(directory.getData()) folders = iq.getQueryNode().getTag('folders') if folders: folders = str(folders.getData()) client = MCClient(jid, username, password, hostname, directory, folders) clients[client.jid] = client # subscribe to the client's presence sub_req = jabber.Presence(iq.getFrom(), type='subscribe') sub_req.setFrom(str(iq.getTo()) + "/registered") con.send(sub_req) resultIq.setType('result') con.send(resultIq) else: resultIq.setType('error') resultIq.setError('invalid key', 400) con.send(resultIq) # done with key; delete it del keys[str(iq.getFrom())] else: print "don't know how to handle type", type, "for query", query_ns elif (query_ns == jabber.NS_AGENT) and (type == 'get'): # someone wants information about us resultIq.setType('result') responses = { 'name': "Mailchecker", # 'url': None, 'description': "This is the mailchecker component", 'transport': "don't know what should go here...", 'register': None, # we can be registered with 'service': 'test' # nothing really standardized here... } for response in responses.keys(): resp_node = query_result.insertTag(response) if responses[response]: resp_node.putData(responses[response]) con.send(resultIq) else: print "don't know how to handle type", type, "for query", query_ns def presenceCB(con, pres): print "Presence:", str(pres) # presence reply to use later on p = jabber.Presence(to=pres.getFrom()) p.setFrom(pres.getTo()) type = pres.getType() # find the client object if str(pres.getFrom().getStripped()) in clients.keys(): client = clients[pres.getFrom().getStripped()] else: print("not able to find client for " + pres.getFrom().getStripped()) client = None if type != 'unsubscribed': type = 'unsubscribe' if not type: type = 'available' print(pres.getFrom().getStripped() + " is " + type) if type == 'unavailable': # user went offline client.setOnline(0) p.setType('unavailable') con.send(p) elif type == 'subscribe': # user wants to subscribe to our presence; oblige, and ask for his p.setType('subscribed') con.send(p) p.setType('subscribe') con.send(p) elif type == 'unsubscribe': p.setType('unsubscribed') con.send(p) p.setType('unsubscribe') con.send(p) elif type == 'unsubscribed': # now unsubscribe from the user's presence pass elif type == 'probe': # send our presence p.setType('available') con.send(p) elif type == 'available': # user is online client.setStatus(pres.getStatus()) client.setShow(pres.getShow()) p.setType('available') con.send(p) con = jabber.Component(host='webtechtunes.hq.insight.com', debug=0, port=6969, log='log') try: clients = pickle.load(open('clients.p')) except IOError, e: print(e) clients = {} try: con.connect() except IOError, e: print "Couldn't connect: %s" % e sys.exit(0) else: print "Connected" con.process(1) if con.auth('secret'): print "connected" else: print "problems with handshake: ", con.lastErr, con.lastErrCode sys.exit(1) # con.registerHandler('message',messageCB) con.registerHandler('presence',presenceCB) con.registerHandler('iq',iqCB) p = jabber.Presence(type='available') p.setFrom('mailcheck/registered') for c in clients.keys(): p.setTo(clients[c].jid) con.send(p) try: while(1): con.process(10) # whoo baby, is this a kludge. Should really have a bona-fide event # loop or thread that processes the user's email checking, or at least # build up a timer type element that only runs this once every five # minutes or so... for c in clients.keys(): clients[c].doit() except KeyboardInterrupt: p = jabber.Presence(type='unavailable') p.setFrom('mailcheck/registered') for c in clients.keys(): p.setTo(clients[c].jid) con.send(p) pickle.dump(clients, open('clients.p', 'w')) con.disconnect()