#!/usr/local/bin/python2.5 # -*- coding: utf-8 -*- # Changes: # # 2007-11-5: Catch exceptions caused by regex injection, set resource to be non-random # 2007-11-2: set message type explicitly to "chat", and assume commands are # search requests unless they match another command # 2007-07-12: fix bug with typing notifications and newer versions of # Adium. # import xmpp import sys import string import re import time # user-configurable stuff dictionary="/usr/local/share/dict/edict-utf-8/edict" maxresults=50 # only appropriate that I support japanese error messages i18n={'jp':{},'en':{}} commands={} # read in the dictionary try: f = open(dictionary,'r') except IOError: print "Error opening edict." dict = unicode(f.read(),"utf-8") dict = dict.split('\n') f.close() ####################### user handlers start ################################## i18n['en']['HELP']='Hi! I\'m a UTF-8 EDICT gateway. I can translate from English to Japanese, or from Japanese to English. You can translate words by asking "search ", or just typing the word.' i18n['jp']['HELP']='こんにいちは!ぼくは UTF-8 EDICT 訳者です。 英語で日本語に(fill this in). "search"訳すします。' def helpHandler(user,command,args,mess): return "HELP" def doSearch(pattern,lines): matches="" x=0 for line in lines: if x==maxresults: matches=matches + "\nResults truncated to %d. Please try a more specific query.\n"%maxresults; return matches if pattern.search(line): matches=matches+line + "\n"; x=x+1 return matches i18n['en']['EMPTY']="%s" i18n['en']['search']='%s' def searchHandler(user,command,args,mess): try: # get our regexes ready # english word match pat1 = re.compile('[/ ]%s[/ ]'%args, re.I) # kana word exact match pat2 = re.compile(r'\[\b%s\b\]'%args, re.U) # kanji match pat3 = re.compile('^%s '%args, re.U) # last ditch effort pat4 = re.compile('%s'%args, re.I) except: return "SEARCH" ,'Cut that out.' # # Ok, this is super messy, but the idea is to keep huge numbers of # results from coming back. Basically, try all 4 lookup types in # order, and only go onto the next one if the previous failed to # yield results. # results = doSearch(pat1,dict) if results=="": results = doSearch(pat2,dict) if results=="": results = doSearch(pat3,dict) if results=="": results = doSearch(pat4,dict) if results=="": results="Sorry, I can\'t find that word." return "SEARCH",'Matches for "%s":\n\n%s'%(args, results) ####################### user handlers stop ################################### ######################## bot logic start ##################################### i18n['en']["UNKNOWN COMMAND"]='Unknown command "%s". Try "help".' i18n['jp']["UNKNOWN COMMAND"]='コマンドは正しくありません − %s' i18n['en']["UNKNOWN USER"]="I do not know you. Register first." i18n['jp']["UNKNOWN USER"]="登録して下さい。" def messageCB(conn,mess): text=mess.getBody() user=mess.getFrom() user.lang='en' # make sure text isn't null, like with typing notification messages # from Adium if text: if text.find(' ')+1: command,args=text.split(' ',1) else: command,args=text,'' cmd=command.lower() if commands.has_key(cmd): reply=commands[cmd](user,command,args,mess) #else: reply=("UNKNOWN COMMAND",cmd) else: # if no command matches, assume it's a search. reply=searchHandler(user,"search",command,mess) if type(reply)==type(()): key,args=reply if i18n[user.lang].has_key(key): pat=i18n[user.lang][key] elif i18n['en'].has_key(key): pat=i18n['en'][key] else: pat="%s" if type(pat)==type(''): reply=pat%args else: reply=pat(**args) else: try: reply=i18n[user.lang][reply] except KeyError: try: reply=i18n['en'][reply] except KeyError: pass if reply: conn.send(xmpp.Message(mess.getFrom(), body=reply, typ='chat')) for i in globals().keys(): if i[-7:]=='Handler' and i[:-7].lower()==i[:-7]: commands[i[:-7]]=globals()[i] # Handle subscription/unsubscription requests def presenceCB(conn,pres): type=pres.getType() user=pres.getFrom() if type=='subscribe': conn.send(xmpp.Presence(user,'subscribed')) if type=='unsubscribe': conn.send(xmpp.Presence(user,'unsubscribed')) ######################### bot logic stop ##################################### def connect(): password="setyourpasswordhere" jid=xmpp.JID(sys.argv[1]) user,server,password=jid.getNode(),jid.getDomain(),password conn=xmpp.Client(server)#,debug=[]) conres=conn.connect() conn.RegisterDisconnectHandler(disconnectCB) if not conres: print "Unable to connect to server %s!"%server sys.exit(1) if conres<>'tls': print "Warning: unable to establish secure connection - TLS failed!" authres=conn.auth(user,password,"Redundancy") if not authres: print "Unable to authorize on %s - check login/password."%server sys.exit(1) if authres<>'sasl': print "Warning: unable to perform SASL auth os %s. Old authentication method used!"%server conn.RegisterHandler('message',messageCB) conn.RegisterHandler('presence',presenceCB) conn.sendInitPresence() print "Bot started." return conn def disconnectCB(): time.sleep(120) connect() def StepOn(conn): try: conn.Process(1) except KeyboardInterrupt, sslerror: return 0 return 1 def GoOn(conn): while StepOn(conn): pass if len(sys.argv)!=2: print "Usage: " + sys.argv[0] + " username@server.net" else: conn=connect() GoOn(conn) conn.sendPresence(server,'offline') conn.disconnect() sys.exit(0)