#!/usr/bin/python # $Id: irc.py,v 1.35 2005/04/20 21:47:10 mikealbon Exp $ # # xmpp->IRC transport # Jan 2004 Copyright (c) Mike Albon # # This program is free software licensed with the GNU Public License Version 2. # For a full copy of the license please go here http://www.gnu.org/licenses/licenses.html#GPL import xmpp, urllib2, sys, time, irclib, re, ConfigParser, os, select, codecs, shelve from xmpp.protocol import * from xmpp.features import * from xmpp.browser import * from xmpp.commands import * from jep0133 import * import xmpp.commands #Global definitions True = 1 False = 0 server = None hostname = None port = None secret = None localaddress = "" connection = None charset = 'utf-8' socketlist = {} timerlist = [] MALFORMED_JID=ErrorNode(ERR_JID_MALFORMED,text='Invalid room, must be in form #room%server') NS_MUC = 'http://jabber.org/protocol/muc' NS_MUC_USER = NS_MUC+'#user' NS_MUC_ADMIN = NS_MUC+'#admin' NS_MUC_OWNER = NS_MUC+'#owner' NS_COMMAND = 'http://jabber.org/protocol/commands' irccolour = ['#FFFFFF','#000000','#0000FF','#00FF00','#FF0000','#F08000','#8000FF','#FFF000','#FFFF00','#80FF00','#00FF80','#00FFFF','#0080FF','#FF80FF','#808080','#A0A0A0'] def irc_add_conn(con): socketlist[con]='irc' def irc_del_conn(con): if socketlist.has_key(con): del socketlist[con] def colourparse(str,charset): # Each tuple consists of String, foreground, background, bold. #str = str.replace('/','//') foreground=None background=None bold=None underline = None s = '' html=[] hs = '' ctrseq=None ctrfor=None #Has forground been processed? for e in str: if e == '\x00': pass #'Black' elif e == '\x01': pass #'Blue' CtCP Code elif e == '\x02':#'Green' Also Bold html.append((hs,foreground,background,bold,underline)) if bold == True: bold = None else: bold = True hs = '' elif e == '\x03':#'Cyan' Also Colour html.append((hs,foreground,background,bold,underline)) foreground = None #background = None if not ctrseq: ctrseq = True hs = '' elif e == '\x04': print 'Red' elif e == '\x05': print 'Purple' elif e == '\x06': print 'Brown' elif e == '\x07': print "Light Grey" elif e == '\x08': print 'Grey' elif e == '\x09': print 'Light Blue' elif e == '\x0a': print 'Light Green' elif e == '\x0b': print 'Light Cyan' elif e == '\x0c': print 'Light Red' elif e == '\x0d': print 'Pink' elif e == '\x0e': print 'Yellow' elif e == '\x0f': #go back to normal html.append((hs,foreground,background,bold,underline)) foreground = None background = None bold = None underline = None hs = '' #print 'White' elif e == '\x1f': html.append((hs,foreground,background,bold,underline)) if bold == True: bold = None else: bold = True hs = '' elif e in ['\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e']: print 'Other Escape' elif ctrseq == True: if e.isdigit(): if not ctrfor: try: if not foreground.len() <2: foreground = foreground +e else: ctrseq=None foreground = int(foreground) s = '%s%s'%(s,e) hs = '%s%s'%(hs,e) except AttributeError: foreground = e else: try: if background.len() <=2: foreground = foreground +e else: ctrseq=None ctrfor=None background = int(background) s = '%s%s'%(s,e) hs= '%s%s'%(hs,e) except AttributeError: background = e elif e == ',': ctrfor=True background = None else: ctrfor = None ctrseq = None s = '%s%s'%(s,e) hs = '%s%s'%(hs,e) else: s = '%s%s'%(s,e) hs = '%s%s'%(hs,e) html.append((hs,foreground,background,bold,underline)) chtml = [] try: s = unicode(s,'utf8','strict') # Language detection stuff should go here. for each in html: chtml.append((unicode(each[0],'utf-8','strict'),each[1],each[2],each[3],each[4])) except: s = unicode(s, charset,'replace') for each in html: chtml.append((unicode(each[0],charset,'replace'),each[1],each[2],each[3],each[4])) if len(chtml) >1: html = Node('html') html.setNamespace('http://jabber.org/protocol/xhtml-im') xhtml = html.addChild('body',namespace='http://www.w3.org/1999/xhtml') #print chtml for each in chtml: style = '' if each[1] != None and int(each[1])<16: foreground = irccolour[int(each[1])] print foreground style = '%scolor:%s;'%(style,foreground) if each[2] != None and int(each[2])<16: background = irccolour[int(each[2])] style = '%sbackground-color:%s;'%(style,background) if each[3]: style = '%sfont-weight:bold;'%style if each[4]: style = '%stext-decoration:underline;'%style if each[0] != '': if style == '': xhtml.addData(each[0]) else: xhtml.addChild(name = 'span', attrs = {'style':style},payload=each[0]) else: html = '' return s,html def connectxmpp(handlerreg = None): connected = connection.connect((server,port)) print connected if connected: if handlerreg != None: handlerreg() print "try auth" connected = connection.auth(hostname,secret) print "auth return",connected return connected while 1: time.sleep(5) xmpp.transports.TCPsocket((server,port)).PlugOut() connected=connection.reconnectAndReauth() if connected: break connection.UnregisterDisconnectHandler(connection.DisconnectHandler) return connected class Transport: # This class is the main collection of where all the handlers for both the IRC and Jabber #Global structures users = {} #This structure consists of each user of the transport having their own location of store. #The store per jid is then devided into two sections. #The first is the room and server for each room in use, used for directing messages, iq and subsiquent presence traffic #The second is used when adding channels in use. This will identify the servers and nick's in use. #Contrary to the above the new structure is dictionary of fromjid and a dictionary of servers connected. #All other information is stored in the connection. # Parameter order. Connection then options. def __init__(self,jabber,irc): self.jabber = jabber self.irc = irc def register_handlers(self): self.irc.add_global_handler('motd',self.irc_message) self.irc.add_global_handler('pubmsg',self.irc_message) self.irc.add_global_handler('pubnotice',self.irc_message) self.irc.add_global_handler('privmsg',self.irc_message) self.irc.add_global_handler('privnotice',self.irc_message) self.irc.add_global_handler('468',self.irc_message) self.irc.add_global_handler('whoreply',self.irc_whoreply) self.irc.add_global_handler('ctcp',self.irc_ctcp) self.irc.add_global_handler('nick',self.irc_nick) self.irc.add_global_handler('join',self.irc_join) self.irc.add_global_handler('part',self.irc_part) self.irc.add_global_handler('quit',self.irc_quit) self.irc.add_global_handler('kick',self.irc_kick) self.irc.add_global_handler('mode',self.irc_chanmode) self.irc.add_global_handler('error',self.irc_error) self.irc.add_global_handler('topic',self.irc_topic) self.irc.add_global_handler('nicknameinuse',self.irc_nicknameinuse) self.irc.add_global_handler('nosuchchannel',self.irc_nosuchchannel) self.irc.add_global_handler('nosuchnick',self.irc_nosuchnick) self.irc.add_global_handler('notregistered',self.irc_notregistered) self.irc.add_global_handler('cannotsendtochan',self.irc_cannotsend) self.irc.add_global_handler('379',self.irc_redirect) self.irc.add_global_handler('welcome',self.irc_welcome) self.jabber.RegisterHandler('message',self.xmpp_message) self.jabber.RegisterHandler('presence',self.xmpp_presence) #Disco stuff now done by disco object self.jabber.RegisterHandler('iq',self.xmpp_iq_version,typ = 'get', ns=NS_VERSION) self.jabber.RegisterHandler('iq',self.xmpp_iq_agents,typ = 'get', ns=NS_AGENTS) self.jabber.RegisterHandler('iq',self.xmpp_iq_browse,typ = 'get', ns=NS_BROWSE) self.jabber.RegisterHandler('iq',self.xmpp_iq_mucadmin_set,typ = 'set', ns=NS_MUC_ADMIN) self.jabber.RegisterHandler('iq',self.xmpp_iq_mucadmin_get,typ = 'get', ns=NS_MUC_ADMIN) self.jabber.RegisterHandler('iq',self.xmpp_iq_register_set,typ = 'set', ns=NS_REGISTER) self.jabber.RegisterHandler('iq',self.xmpp_iq_register_get,typ = 'get', ns=NS_REGISTER) self.disco = Browser() self.disco.plugin(self.jabber) self.command = Commands() self.command.plugin(self.jabber,self.disco) self.cmdactiveusers = Active_Users_Command(self, self.jabber) self.cmdactiveusers.plugin(self.command) self.cmdregisteredusers = Registered_Users_Command(self, self.jabber) self.cmdregisteredusers.plugin(self.command) self.disco.setDiscoHandler(self.xmpp_base_disco,node='',jid='') # New Disco Handlers def xmpp_base_disco(self, con, event, type): #Type is either 'info' or 'items' if type == 'info': return {'ids':[{'category':'conference','type':'irc','name':'IRC Transport'}],'features':[xmpp.NS_REGISTER,xmpp.NS_VERSION,NS_MUC,NS_COMMAND]} if type == 'items': return [] #XMPP Handlers def xmpp_presence(self, con, event): # Add ACL support fromjid = str(event.getFrom()) fromstripped = fromjid.encode('utf-8') type = event.getType() if type == None: type = 'available' to = event.getTo() room = to.getNode().lower() nick = to.getResource() try: channel, server = room.split('%') except ValueError: channel='' if irclib.is_channel(channel): if type == 'available': if nick != '': if not self.users.has_key(fromjid): # if a new user session c=self.irc_newconn(channel,server,nick,fromjid) if c != None: self.users[fromjid] = {server:c} else: if self.users[fromjid].has_key(server): if self.users[fromjid][server].memberlist.has_key(channel): self.users[fromjid][server].joinchan = channel self.irc_sendnick(self.users[fromjid][server],nick) elif self.users[fromjid].has_key(server): # if user already has a session open on same server self.irc_newroom(self.users[fromjid][server],channel) else: # the other cases c=self.irc_newconn(channel,server,nick,fromjid) if c != None: self.users[fromjid][server]=c elif type == 'unavailable': if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): if event.getTo().getResource() == self.users[fromjid][server].nickname or event.getTo().getResource() == '': if self.users[fromjid][server].memberlist.has_key(channel): connection = self.users[fromjid][server] self.irc_leaveroom(connection,channel) del self.users[fromjid][server].memberlist[channel] self.test_inuse(connection) else: self.jabber.send(Error(event,ERR_BAD_REQUEST)) else: self.jabber.send(Error(event,ERR_FEATURE_NOT_IMPLEMENTED)) elif to == hostname: if type == 'subscribe': if userfile.has_key(event.getFrom().getStripped().encode('utf8')): self.jabber.send(Presence(to=fromjid, frm = to, typ = 'subscribed')) conf = userfile[event.getFrom().getStripped().encode('utf8')] conf['usubscribed']=True userfile[event.getFrom().getStripped().encode('utf8')]=conf else: self.jabber.send(Error(event,ERR_BAD_REQUEST)) elif type == 'subscribed': if userfile.has_key(event.getFrom().getStripped().encode('utf8')): conf = userfile[event.getFrom().getStripped().encode('utf8')] conf['subscribed']=True userfile[event.getFrom().getStripped().encode('utf8')]=conf else: self.jabber.send(Error(event,ERR_BAD_REQUEST)) # #Add code so people can see transport presence here # elif type == 'probe': if not userfile.has_key(event.getFrom().getStripped().encode('utf8')): self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribe')) self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribed')) else: self.jabber.send(Error(event,MALFORMED_JID)) return def test_inuse(self,connection): inuse = False for each in self.users[connection.fromjid].keys(): if self.users[connection.fromjid][each].memberlist != {}: inuse = True if inuse == False: self.irc_doquit(connection) def xmpp_message(self, con, event): type = event.getType() fromjid = str(event.getFrom()) to = event.getTo() room = to.getNode().lower() try: if event.getSubject.strip() == '': event.setSubject(None) except AttributeError: pass try: channel, server = room.split('%') except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) return if not self.users.has_key(fromjid): self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) # another candidate: ERR_SUBSCRIPTION_REQUIRED return if not self.users[fromjid].has_key(server): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) # Another candidate: ERR_REMOTE_SERVER_NOT_FOUND (but it means that server doesn't exist at all) return if event.getBody() == None: return if type == 'groupchat': if irclib.is_channel(channel): if event.getSubject(): if self.users[fromjid][server].chanmode.has_key('topic'): if (self.users[fromjid][server].chanmode['topic']==True and self.users[fromjid][server].memberlist[self.users[fromjid][server].nickname]['role'] == 'moderator') or self.users[fromjid][server].chanmode['topic']==False: self.irc_settopic(self.users[fromjid][server],channel,event.getSubject()) else: self.jabber.send(Error(event,ERR_FORBIDDEN)) else: self.irc_settopic(self.users[fromjid][server],channel,event.getSubject()) elif event.getBody() != '': if event.getBody()[0:3] == '/me': self.irc_sendctcp('ACTION',self.users[fromjid][server],channel,event.getBody()[4:]) else: self.irc_sendroom(self.users[fromjid][server],channel,event.getBody()) t = Message(to=fromjid,body=event.getBody(),typ=type,frm='%s@%s/%s' %(room, hostname,self.users[fromjid][server].nickname)) self.jabber.send(t) else: self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) # or ERR_JID_MALFORMED maybe? elif type in ['chat', None]: if not irclib.is_channel(channel): # ARGH! need to know channel to find out nick. :( if event.getBody()[0:3] == '/me': self.irc_sendctcp('ACTION',self.users[fromjid][server],channel,event.getBody()[4:]) else: self.irc_sendroom(self.users[fromjid][server],channel,event.getBody()) else: if event.getBody()[0:3] == '/me': self.irc_sendctcp('ACTION',self.users[fromjid][server],channel,event.getBody()[4:]) else: self.irc_sendroom(self.users[fromjid][server],event.getTo().getResource(),event.getBody()) def xmpp_iq_discoinfo(self, con, event): fromjid = event.getFrom() to = event.getTo() id = event.getID() m = Iq(to=fromjid,frm=to, typ='result', queryNS=NS_DISCO_INFO, payload=[Node('identity',attrs={'category':'conference','type':'irc','name':'IRC Transport'}),Node('feature', attrs={'var':xmpp.NS_REGISTER}),Node('feature',attrs={'var':NS_MUC})]) m.setID(id) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_discoitems(self, con, event): fromjid = event.getFrom() to = event.getTo() id = event.getID() m = Iq(to=fromjid,frm=to, typ='result', queryNS=NS_DISCO_ITEMS) m.setID(id) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_agents(self, con, event): m = Iq(to=event.getFrom(), frm=event.getTo(), typ='result', payload=[Node('agent', attrs={'jid':hostname},payload=[Node('service',payload='irc'),Node('name',payload='xmpp IRC Transport'),Node('groupchat')])]) m.setID(event.getID()) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_browse(self, con, event): m = Iq(to = event.getFrom(), frm = event.getTo(), typ = 'result', queryNS = NS_BROWSE) if event.getTo() == hostname: m.setTagAttr('query','catagory','conference') m.setTagAttr('query','name','xmpp IRC Transport') m.setTagAttr('query','type','irc') m.setTagAttr('query','jid','hostname') m.setPayload([Node('ns',payload=NS_MUC),Node('ns',payload=xmpp.NS_REGISTER)]) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_version(self, con, event): fromjid = event.getFrom() to = event.getTo() id = event.getID() m = Iq(to = fromjid, frm = to, typ = 'result', queryNS=NS_VERSION, payload=[Node('name',payload='xmpp IRC Transport'), Node('version',payload='early release 12feb04'),Node('os',payload='%s %s %s' % (os.uname()[0],os.uname()[2],os.uname()[4]))]) m.setID(id) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_mucadmin_get(self, con, event): fromjid = event.getFrom() to = event.getTo() room = to.getNode().lower() id = event.getID() try: channel, server = room.split('%') except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) return if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].memberlist.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) return ns = event.getQueryNS() t = event.getQueryPayload() if t[0].getName() == 'item': attr = t[0].getAttrs() if 'role' in attr.keys(): role = attr['role'] affiliation = None elif 'affiliation' in attr.keys(): affiliation = attr['affiliation'] role = None m = Iq(to= fromjid, frm=to, typ='result', queryNS=ns) payload = [] for each in self.users[fromjid][server].memberlist[channel]: if role != None: if self.users[fromjid][server].memberlist[channel][each]['role'] == role: zattr = self.users[fromjid][server].memberlist[channel][each] zattr['nick'] = each payload.append(Node('item',attrs = zattr)) if affiliation != None: if self.users[fromjid][server].memberlist[channel][each]['affiliation'] == affiliation: zattr = self.users[fromjid][server].memberlist[channel][each] zattr['nick'] = each payload.append(Node('item',attrs = zattr)) m.setQueryPayload(payload) self.jabber.send(m) def xmpp_iq_mucadmin_set(self, con, event): fromjid = event.getFrom() to = event.getTo() room = to.getNode().lower() id = event.getID() try: channel, server = room.split('%') except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) return if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].memberlist.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) return ns = event.getQueryNS() t = event.getQueryPayload() if self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['role'] != 'moderator' or self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) return for each in t: if t[0].getName() == 'item': attr = t[0].getAttrs() if attr.has_key('role'): if attr['role'] == 'moderator': self.users[fromjid][server].mode(channel,'%s %s'%('+o',attr['nick'])) elif attr['role'] == 'participant': self.users[fromjid][server].mode(channel,'%s %s'%('+v',attr['nick'])) elif attr['role'] == 'visitor': self.users[fromjid][server].mode(channel,'%s %s'%('-v',attr['nick'])) self.users[fromjid][server].mode(channel,'%s %s'%('-o',attr['nick'])) elif attr['role'] == 'none': self.users[fromjid][server].kick(channel,attr['nick'],'Kicked')#Need to add reason gathering def xmpp_iq_mucowner_get(self, con, event): fromjid = event.getFrom() to = event.getTo() room = to.getNode().lower() id = event.getID() try: channel, server = room.split('%') except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) return if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].memberlist.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) return ns = event.getQueryNS() t = event.getQueryPayload() if self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['role'] != 'moderator' or self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) return datafrm = DataForm(data=self.users[fromjid][server].chanlist[channel]) self.jabber.send(Iq(frm = to, to = fromjid, id = id, type='result', queryNS= ns, queryPayload = datafrm)) def xmpp_iq_mucowner_set(self, con, event): fromjid = event.getFrom() to = event.getTo() room = to.getNode().lower() id = event.getID() try: channel, server = room.split('%') except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) return if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].memberlist.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) return ns = event.getQueryNS() t = event.getQueryPayload() if self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['role'] != 'moderator' or self.users[fromjid][server].memberlist[self.users[fromjid][server].nick]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) return datadrm = event.getQueryPayload()[0].asDict() for each in dataform.keys(): if datafrm[each] != self.users[fromjid][server].chanmode[each]: val = False if datafrm[each] == True: typ='+' else: typ='-' if each == 'private': cmd = 'b' elif each == 'secret': cmd = 's' elif each == 'invite': cmd = 'i' elif each == 'topic': cmd = 't' elif each == 'notmember': cmd = 'n' elif each == 'moderated': cmd = 'm' elif each == 'banlist': cmd = 'b' typ = '+' val = True for item in datafrm[each]: if item not in self.users[fromjid][server].chanmode[each]: self.users[fromjid][server].mode(channel,'+b %s' % item) for item in self.users[fromjid][server].chanmode[each]: if item not in datafrm[each]: self.users[fromjid][server].mode(channel,'-b %s' % item) elif each == 'limit': cmd = 'l' typ = '+' val = True self.users[fromjid][server].mode(channel,'+l %s' % each) elif each == 'key': cmd = 'k' typ = '+' val = True self.users[fromjid][server].mode(channel, '+k %s' % each) if not val: self.users[fromjid][server].mode(channel,'%s%s' % (typ,cmd)) # Registration code def xmpp_iq_register_get(self, con, event): charset = '' fromjid = event.getFrom().getStripped().encode('utf8') if userfile.has_key(fromjid): charset = userfile[fromjid]['charset'] m = event.buildReply('result') m.setQueryNS(NS_REGISTER) m.setQueryPayload([Node('instructions', payload = 'Please provide your legacy Character set or codepage. (eg cp437, cp1250, iso-8859-1, koi8-r)'),Node('charset',payload=charset)]) self.jabber.send(m) def xmpp_iq_register_set(self, con, event): remove = False fromjid = event.getFrom().getStripped().encode('utf8') ucharset = charset #for each in event.getQueryPayload(): # if type(each ) == u'': # pass # if each.getName() == 'charset': # ucharset = each.getData() # elif each.getName() == 'remove': # remove = True # else: # self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) query = event.getTag('query') if query.getTag('remove'): remove = True elif query.getTag('charset'): ucharset = query.getTagData('charset') else: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) if not remove: if userfile.has_key(fromjid): conf = userfile[fromjid] else: conf = {} try: codecs.lookup(ucharset) except LookupError: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) return except ValueError: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) return conf['charset']=ucharset userfile[fromjid]=conf self.jabber.send(Presence(to=event.getFrom(), frm = event.getTo())) if not conf.has_key('subscribed'): self.jabber.send(Presence(typ='subscribe',to=fromjid, frm=hostname)) else: if userfile.has_key(fromjid): del userfile[fromjid] m = event.buildReply('result') self.jabber.send(m) m = Presence(to = event.getFrom(), frm = hostname, typ = 'unsubscribe') self.jabber.send(m) m = Presence(to = event.getFrom(), frm = hostname, typ = 'unsubscribed') self.jabber.send(m) #IRC methods def irc_doquit(self,con): server = con.server nickname = con.nickname if self.users[con.fromjid].has_key(server): del self.users[con.fromjid][server] con.close() def irc_settopic(self,connection,channel,line): try: connection.topic(channel.encode(connection.charset),line.encode(connection.charset)) except: self.irc_doquit(connection) def irc_sendnick(self,connection,nick): try: connection.nick(nick) except: self.irc_doquit(connection) def irc_sendroom(self,connection,channel,line): lines = line.split('\x0a') for each in lines: #print channel, each if each != '' or each == None: try: connection.privmsg(channel.encode(connection.charset),each.encode(connection.charset)) except: self.irc_doquit(connection) def irc_sendctcp(self,type,connection,channel,line): lines = line.split('\x0a') for each in lines: try: connection.ctcp(type,channel.encode(connection.charset),each.encode(connection.charset)) except: self.irc_doquit(connection) def irc_newconn(self,channel,server,nick,fromjid): try: c=self.irc.server().connect(server,6667,nick,localaddress=localaddress) c.fromjid = fromjid fromstripped = JID(fromjid).getStripped().encode('utf-8') c.joinchan = channel c.memberlist = {} c.chanmode = {} if userfile.has_key(fromstripped): c.charset = userfile[fromstripped]['charset'] else: c.charset = charset return c except irclib.ServerConnectionError: self.jabber.send(Error(Presence(to = fromjid, frm = '%s%%%s@%s/%s' % (channel,server,hostname,nick)),ERR_SERVICE_UNAVAILABLE,reply=0)) # Other candidates: ERR_GONE, ERR_REMOTE_SERVER_NOT_FOUND, ERR_REMOTE_SERVER_TIMEOUT return None def irc_newroom(self,conn,channel): try: conn.join(channel) conn.who(channel) except: self.irc_doquit(connection) conn.memberlist[channel] = {} conn.chanmode[channel] = {'private':False, 'secret':False, 'invite':False, 'topic':False, 'notmember':False, 'moderated':False, 'banlist':[], 'limit':False, 'key':''} def irc_leaveroom(self,conn,channel): try: conn.part([channel]) except: self.irc_doquit(connection) # IRC message handlers def irc_error(self,conn,event): if conn.server in self.users[conn.fromjid].keys(): try: for each in conn.memberlist.keys(): t = Presence(to=conn.fromjid, typ = 'unavailable', frm='%s%%%s@%s' %(each,conn.server,hostname)) self.jabber.send(t) del self.users[conn.fromjid][conn.server] except AttributeError: pass def irc_quit(self,conn,event): type = 'unavailable' nick = irclib.nm_to_n(event.source()) for each in conn.memberlist.keys(): if nick in conn.memberlist[each].keys(): del conn.memberlist[each][nick] name = '%s%%%s' % (each, conn.server) m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, hostname,event.source().split('!')[0])) self.jabber.send(m) if activitymessages == True: line,xhtml = colourparse(event.arguments()[0],conn.charset) m = Message(to=conn.fromjid, typ='groupchat',frm='%s@%s' % (name, hostname), body='%s (%s) has quit (%s)' % (nick, irclib.nm_to_uh(event.source()), line)) self.jabber.send(m) def irc_nick(self, conn, event): old = irclib.nm_to_n(event.source()) new = event.target() if old == conn.nickname: conn.nickname = new for each in conn.memberlist.keys(): if old in conn.memberlist[each].keys(): m = Presence(to=conn.fromjid,typ = 'unavailable',frm = '%s%%%s@%s/%s' % (each,conn.server,hostname,old)) p = m.addChild(name='x', namespace=NS_MUC_USER) p.addChild(name='item', attrs={'nick':new}) p.addChild(name='status', attrs={'code':'303'}) self.jabber.send(m) m = Presence(to=conn.fromjid,typ = 'available', frm = '%s%%%s@%s/%s' % (each,conn.server,hostname,new)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.memberlist[each][old]) self.jabber.send(m) t=conn.memberlist[each][old] del conn.memberlist[each][old] conn.memberlist[each][new] = t if activitymessages == True: m = Message(to=conn.fromjid, typ='groupchat',frm='%s%%%s@%s' % (each,conn.server,hostname), body='%s is now known as %s' % (old, new)) self.jabber.send(m) def irc_welcome(self,conn,event): self.irc_newroom(conn,conn.joinchan) del conn.joinchan def irc_nicknameinuse(self,conn,event): error=ErrorNode(ERR_CONFLICT,text='Nickname is in use') self.jabber.send(Error(Presence(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' %(conn.joinchan, conn.server, hostname)),error,reply=0)) def irc_nosuchchannel(self,conn,event): error=ErrorNode(ERR_ITEM_NOT_FOUND,'The channel is not found') self.jabber.send(Presence(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' %(event.arguments()[0], conn.server, hostname),payload=[error])) def irc_notregistered(self,conn,event): error=ErrorNode(ERR_FORBIDDEN,text='Not registered and registration is not supported') self.jabber.send(Presence(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' %(conn.joinchan, conn.server, hostname),payload=[error])) def irc_nosuchnick(self, conn, event): error=ErrorNode(ERR_ITEM_NOT_FOUND,text='Nickname not found') self.jabber.send(Message(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' % (event.source(), conn.server, hostname),payload=[error])) def irc_cannotsend(self,conn,event): error=ErrorNode(ERR_FORBIDDEN) self.jabber.send(Message(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' % (event.source(), conn.server, hostname),payload=[error])) def irc_redirect(self,conn,event): new = '%s%%%s@%s'% (event.arguments()[1],conn.server, hostname) old = '%s%%%s@%s'% (event.arguments()[0],conn.server, hostname) error=ErrorNode(ERR_REDIRECT,new) self.jabber.send(Presence(to=conn.fromjid, typ='error', frm = old, payload=[error])) conn.memberlist[event.arguments()[1]]={} try: conn.part(event.arguments()[1]) except: self.irc_doquit(connection) def irc_mode(self,conn,event): # Mode handling currently is very poor. # # Issues: # Multiple +b's currently not handled # +l or -l with no parameter not handled faddr = '%s%%%s@%s' %(event.target().lower(),conn.server,hostname) if irclib.is_channel(event.target()): if event.arguments()[0] == '+o': # Give Chanop if irclib.irc_lower(event.target().lower()) in conn.memberlist.keys(): for each in event.arguments()[1:]: conn.memberlist[event.target().lower()][each]['role']='moderator' m = Presence(to=conn.fromjid,typ='available',frm = '%s/%s' %(faddr,each)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.memberlist[event.target().lower()][each]) self.jabber.send(m) elif event.arguments()[0] in ['-o', '-v']: # Take Chanop or Voice if irclib.irc_lower(event.target().lower()) in conn.memberlist.keys(): for each in event.arguments()[1:]: conn.memberlist[event.target().lower()][each]['role']='visitor' m = Presence(to=conn.fromjid,typ='available',frm = '%s/%s' %(faddr,each)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.memberlist[event.target().lower()][each]) self.jabber.send(m) elif event.arguments()[0] == '+v': # Give Voice if irclib.irc_lower(event.target().lower()) in conn.memberlist.keys(): for each in event.arguments()[1:]: conn.memberlist[event.target().lower()][each]['role']='participant' m = Presence(to=conn.fromjid,typ='available',frm = '%s/%s' %(faddr,each)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.memberlist[event.target().lower()][each]) self.jabber.send(m) def irc_chanmode(self,conn,event): # Very buggy, multiple items cases, ban etc. faddr = '%s%%%s@%s' %(event.target().lower(),conn.server,hostname) channel = event.target().lower() plus = None for each in event.arguments()[0]: if each == '+': plus = True elif each == '-': plus = False elif each == 'o': #Chanop status for each in event.arguments()[1:]: conn.who(channel,each) elif each == 'v': #Voice status for each in event.arguments()[1:]: conn.who(channel,each) elif each == 'p': #Private Room conn.chanmode[event.target().lower()]['private'] = plus elif each == 's': #Secret conn.chanmode[event.target().lower()]['secret'] = plus elif each == 'i': #invite only conn.chanmode[event.target().lower()]['invite'] = plus elif each == 't': #only chanop can set topic conn.chanmode[event.target().lower()]['topic'] = plus elif each == 'n': #no not in channel messages conn.chanmode[event.target().lower()]['notmember'] = plus elif each == 'm': #moderated chanel conn.chanmode[event.target().lower()]['moderated'] = plus elif each == 'l': #set channel limit conn.chanmode[event.target().lower()]['private'] = event.arguments()[1] elif each == 'b': #ban users # Need to fix multiple ban case. if plus: conn.chanmode[event.target().lower()]['banlist'].append(event.arguments()[1]) else: if event.arguments()[1] in conn.chanmode[event.target().lower()]['banlist']: conn.chanmode[event.target().lower()]['banlist'].remove(event.arguments()[1]) elif each == 'k': #set channel key pass def irc_part(self,conn,event): type = 'unavailable' name = '%s%%%s' % (irclib.irc_lower(event.target()), conn.server) nick = irclib.nm_to_n(event.source()) try: if nick in conn.memberlist[irclib.irc_lower(event.target())].keys(): del conn.memberlist[irclib.irc_lower(event.target())][event.source().split('!')[0]] except KeyError: pass m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, hostname,event.source().split('!')[0])) self.jabber.send(m) if activitymessages == True: m = Message(to=conn.fromjid, typ='groupchat',frm='%s@%s' % (name, hostname), body='%s (%s) has left' % (nick, irclib.nm_to_uh(event.source()))) self.jabber.send(m) def irc_kick(self,conn,event): type = 'unavailable' name = '%s%%%s' % (irclib.irc_lower(event.target()), conn.server) m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, hostname,irclib.irc_lower(event.arguments()[0]))) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs={'affiliation':'none','role':'none'}) p.addChild(name='reason',payload=[colourparse(event.arguments()[1],conn.charset)][0]) t.addChild(name='status',attrs={'code':'307'}) self.jabber.send(m) if event.arguments()[0] == conn.nickname: if conn.memberlist.has_key(irclib.irc_lower(event.target())): del conn.memberlist[irclib.irc_lower(event.target())] self.test_inuse(conn) def irc_topic(self,conn,event): nick = unicode(event.source().split('!')[0],conn.charset,'replace') channel = event.target().lower() if len(event.arguments())==2: line,xhtml = colourparse(event.arguments()[1],conn.charset) else: line,xhtml = colourparse(event.arguments()[0],conn.charset) if activitymessages == True: m = Message(to=conn.fromjid,frm = '%s%%%s@%s/%s' % (unicode(channel,conn.charset,'replace'),conn.server,hostname,nick),body='/me set the topic to: %s' % line, typ='groupchat', subject = line) else: m = Message(to=conn.fromjid,frm = '%s%%%s@%s/%s' % (unicode(channel,conn.charset,'replace'),conn.server,hostname,nick), typ='groupchat', subject = line) self.jabber.send(m) def irc_join(self,conn,event): type = 'available' name = '%s%%%s' % (unicode(irclib.irc_lower(event.target()),conn.charset,'replace'), conn.server) nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') if nick not in conn.memberlist[irclib.irc_lower(unicode(event.target(),'utf-8','replace').encode('utf-8'))].keys(): conn.memberlist[irclib.irc_lower(event.target())][nick]={'affiliation':'none','role':'none'} m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, hostname, nick)) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs={'affiliation':'none','role':'visitor'}) #print m.__str__() self.jabber.send(m) if activitymessages == True: m = Message(to=conn.fromjid, typ='groupchat',frm='%s@%s' % (name, hostname), body='%s (%s) has joined' % (nick, irclib.nm_to_uh(event.source()))) self.jabber.send(m) def irc_whoreply(self,conn,event): name = '%s%%%s' % (event.arguments()[0], conn.server) faddr = '%s@%s/%s' % (name, hostname, unicode(event.arguments()[4],conn.charset,'replace')) m = Presence(to=conn.fromjid,typ='available',frm=faddr) t = m.addChild(name='x', namespace=NS_MUC_USER) affiliation = 'none' role = 'none' if '@' in event.arguments()[5]: role = 'moderator' elif '+' in event.arguments()[5]: role = 'participant' elif '*' in event.arguments()[5]: affiliation = 'admin' elif role == 'none': role = 'visitor' p=t.addChild(name='item',attrs={'affiliation':affiliation,'role':role}) self.jabber.send(m) try: if (event.arguments()[0] != '*') and (unicode(event.arguments()[4],conn.charset,'replace') not in conn.memberlist[event.arguments()[0].lower()].keys()): conn.memberlist[event.arguments()[0].lower()][unicode(event.arguments()[4],conn.charset,'replace')]={'affiliation':affiliation,'role':role} except KeyError: pass def irc_message(self,conn,event): try: nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') except: nick = conn.server if irclib.is_channel(event.target()): type = 'groupchat' room = '%s%%%s' %(event.target().lower(),conn.server) line,xhtml = colourparse(event.arguments()[0],conn.charset) #print (line,xhtml) m = Message(to=conn.fromjid,body= line,typ=type,frm='%s@%s/%s' %(room, hostname,nick),payload = [xhtml]) else: type = 'chat' name = event.source() name = '%s%%%s' %(nick,conn.server) line,xhtml = colourparse(event.arguments()[0],conn.charset) m = Message(to=conn.fromjid,body= line,typ=type,frm='%s@%s' %(name, hostname),payload = [xhtml]) self.jabber.send(m) def irc_ctcp(self,conn,event): nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') if event.arguments()[0] == 'ACTION': if irclib.is_channel(event.target()): type = 'groupchat' room = '%s%%%s' %(event.target().lower(),conn.server) line,xhtml = colourparse('/me '+event.arguments()[1],conn.charset) m = Message(to=conn.fromjid,body=line,typ=type,frm='%s@%s/%s' %(room, hostname,nick),payload =[xhtml]) else: type = 'chat' name = event.source() try: name = '%s%%%s' %(nick,conn.server) except: name = '%s%%%s' %(conn.server,conn.server) line,xhtml = colourparse('/me '+event.arguments()[1],conn.charset) m = Message(to=conn.fromjid,body= line,typ=type,frm='%s@%s' %(name, hostname),payload = [xhtml]) self.jabber.send(m) elif event.arguments()[0] == 'VERSION': self.irc_sendctcp('VERSION',conn,event.source(),'xmpp IRC Transport') def xmpp_disconnect(self): for each in self.users.keys(): for item in self.users[each].keys(): self.irc_doquit(item) del self.users[each] #del connection while not connection.reconnectAndReauth(): time.sleep(5) if __name__ == '__main__': if 'PID' in os.environ: open(os.environ['PID'],'w').write(`os.getpid()`) configfile = ConfigParser.ConfigParser() configfile.add_section('transport') try: configfilename = 'transport.ini' cffile = open(configfilename,'r') except IOError: try: configfilename = '/etc/jabber/jabber-irc.conf' cffile = open(configfilename,'r') except IOError: print "Transport requires configuration file, please supply either transport.ini in the current directory or /etc/jabber/jabber-irc.conf" sys.exit(1) configfile.readfp(cffile) cffile.close() server = configfile.get('transport','Server') if configfile.has_option('transport','ServerType'): servertype = configfile.get('transport','ServerType') else: servertype=None hostname = configfile.get('transport','Hostname') port = int(configfile.get('transport','Port')) secret = configfile.get('transport','Secret') if configfile.has_option('transport','LocalAddress'): localaddress = configfile.get('transport','LocalAddress') if configfile.has_option('transport','Charset'): charset = configfile.get('transport','Charset') #JEP-0133 addition for administrators, comma seperated list of jids. if configfile.has_option('transport','Administrators'): administrators = configfile.get('transport','Administrators').split(',') else: administrators = [] activitymessages = True # For displaying user acitivity messages if configfile.has_option('transport','UserFile'): userfilepath = configfile.get('transport','UserFile') else: userfilepath = 'user.dbm' userfile = shelve.open(userfilepath) ircobj = irclib.IRC(fn_to_add_socket=irc_add_conn,fn_to_remove_socket=irc_del_conn) global connection connection = xmpp.client.Component(hostname,port,servertype) transport = Transport(connection,ircobj) if not connectxmpp(transport.register_handlers): print "Password mismatch!" sys.exit(1) socketlist[connection.Connection._sock]='xmpp' while 1: try: (i , o, e) = select.select(socketlist.keys(),[],[],1) except socket.error: for userkey in transport.users: user = transport.users[userkey] for serverkey, server in user.items(): if server._get_socket() == None: print "disconnected by %s" % server.get_server_name() transport.irc_doquit(server) for each in socketlist.keys(): try: (ci, co, ce) = select.select([],[],[each],0) except socket.error: # There is no "socket" module in this context irc_del_conn(each) (i , o, e) = select.select(socketlist.keys(),[],[],1) for each in i: if socketlist[each] == 'xmpp': connection.Process(1) if not connection.isConnected(): transport.xmpp_disconnect() else: ircobj.process_data([each])