2009-09-30 15:45:48 -04:00
#!/usr/bin/env python
"""
Telepaatti , IRC to Jabber / XMPP gateway .
Copyright ( C ) 2007 - 2009 Petteri Klemola
Telepaatti is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License version 3 as
published by the Free Software Foundation .
Telepaatti is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
02110 - 1301 , USA .
For more information about Telepaatti see http : / / 23. fi / telepaatti
"""
import socket
import time , datetime
import exceptions
from threading import *
from xmpp import *
import getopt , sys
STATUSSTATES = [ ' AVAILABLE ' , ' CHAT ' , ' AWAY ' , ' XA ' , ' DND ' , ' INVISIBLE ' ]
TELEPAATTIVERSION = 1
class JabberThread ( Thread ) :
""" Class for Jabber connection thread """
def __init__ ( self , client ) :
""" Constructor for JabberThread Class
@type client : Client
@param client : instace of xmpp . Client class
"""
Thread . __init__ ( self )
self . client = client
self . connected = True
def process ( self ) :
""" Starts the xmpp client process """
try :
self . client . Process ( 1 )
except :
return False
return True
def run ( self ) :
""" When xmpp client is connected runs the client process """
time . sleep ( 5 )
while self . client . Process ( 1 ) and self . connected :
pass
self . client . disconnect ( )
self . connected = False
class ClientThread ( Thread ) :
""" ClientThread class for handling IRC and Jabber connections. """
2010-05-08 08:58:18 -04:00
def __init__ ( self , socket , port , JabberID , passwd , debug = False , nickname = None ) :
2009-09-30 15:45:48 -04:00
""" Constructor for ClientThread class
@type socket : socket
@type port : integer
@type JabberID : JID
@type passwd : string
@param socket : socket on which the connection is made
@param port : port of the connection
@param JabberID : the Jabber ID of the connetor
@param passwd : the passwd of the Jabber ID
"""
Thread . __init__ ( self )
self . socket = socket
self . port = port
self . passwd = passwd
self . JID = JID ( " %s / %s " % ( JabberID , ' telepaatti ' ) )
client = Client ( self . JID . getDomain ( ) , debug = [ ] )
client . connect ( proxy = { } )
client . RegisterHandler ( ' message ' , self . messageHandler )
client . RegisterHandler ( ' presence ' , self . presenceHandler )
client . RegisterHandler ( ' iq ' , self . iqHandler )
client . auth ( self . JID . getNode ( ) , self . passwd , self . JID . getResource ( ) )
client . sendInitPresence ( )
self . client = client
2010-05-08 08:58:18 -04:00
if nickname is None :
self . nickname = JabberID [ : JabberID . find ( ' @ ' ) ]
else :
self . nickname = nickname
2009-09-30 15:45:48 -04:00
self . newnick = ' '
self . notFirstNick = False
self . mucs = { }
self . mucs [ ' roster ' ] = { }
self . rosterMessages = list ( )
self . joinedRoster = False
self . connected = True
self . nickmapper = { }
self . nickChangeInMucs = { }
self . joinQueue = { }
self . roomPingQueue = { }
self . disconnectedMucs = { }
self . pingCounter = 0
self . xmppSem = BoundedSemaphore ( value = 1 )
# if set to True debug messages are printed to sdt out
self . debug = debug
def printError ( self , msg ) :
""" Error message printing for std out
@type msg : string
@param msg : error message
"""
dt = " %s " % datetime . datetime . now ( )
dt = dt [ : - 7 ]
print " ERROR: [ %s ] %s " % ( dt , msg )
def printDebug ( self , msg ) :
""" print Debug message to std out
@type msg : string
@param msg : debug message
"""
if not self . debug :
return
dt = " %s " % datetime . datetime . now ( )
dt = dt [ : - 7 ]
print " DEBUG [ %s ] %s " % ( dt , msg )
def getMucs ( self ) :
""" Return joined MUC without roster MUC
@rtype : list
@return : list of mucs joined ( without roster )
"""
mucs = self . mucs . keys ( )
mucs . remove ( ' roster ' )
return mucs
def fixNick ( self , nick ) :
""" Fixes strange character nicknames that don ' t work nicely with
IRC . This function may cause conflicts and thus unfinished .
@type nick : string
@param nick : nickname to fix
@rtype : string
@return : fixed nick
"""
nick = unicode ( nick )
fixednick = nick . replace ( ' ' , ' _ ' )
fixednick = fixednick . replace ( ' ! ' , ' _ ' )
fixednick = fixednick . replace ( ' : ' , ' _ ' )
self . nickmapper [ fixednick ] = nick
return fixednick
def unfixNick ( self , fixednick ) :
""" Reverses nicks fixed with fixNick function. Is also unfinished
@type fixednick : string
@param fixednick : nickname to unfix
@rtype : string
@return : unfixed nick
"""
nick = fixednick
try :
nick = self . nickmapper [ fixednick ]
except :
self . printError ( ' unfixNick did not work ' )
return nick
def makeIRCACTION ( self , msg ) :
""" Makes IRC action message
@type msg : string
@param msg : message from which to make IRC action
@rtype : string
@return : IRC action message
"""
msg = ' \001 ACTION %s \001 ' % msg
return msg
def sendToIRC ( self , msg ) :
""" Sends message IRC client
@type msg : string
@param msg : message to send
"""
msg = msg . encode ( ' utf-8 ' )
msg = " %s \r \n " % msg
self . printDebug ( msg )
try :
self . socket . send ( msg )
except :
self . connected = False
self . printError ( ' FATAL ERROR WHILE TRYING TO WRITE IRC MESSAGE TO SOCKET, DISCONNECTING ' )
def sendToXMPP ( self , msg ) :
""" Sends message XMPP server
@type msg : string
@param msg : message to send
"""
self . xmppSem . acquire ( )
self . client . send ( msg )
self . xmppSem . release ( )
def ircGetStatus ( self , nick , channel ) :
""" Get IRC status
@type nick : string
@type channel : string
@param nick : nick whos status to get
@param channel : the channel on which status to get
@rtype : string
@return : IRC - style status string
"""
sta = ' H '
show = ' '
role = ' '
if self . mucs . has_key ( channel ) :
show = self . mucs [ channel ] [ nick ] [ ' show ' ]
role = self . mucs [ channel ] [ nick ] [ ' role ' ]
if show in [ ' away ' , ' xa ' , ' dnd ' ] :
sta = ' G '
if role == ' moderator ' :
sta = ' %s @ ' % sta
elif role == ' participant ' :
sta = ' %s + ' % sta
return sta
def ircCommandJOIN ( self , nick , channel ) :
""" IRC command join channel
@type nick : string
@type channel : string
@param nick : nick who is joining
@param channel : channel whats been joined
"""
onick = nick
resource = self . fixNick ( nick . getResource ( ) )
nick = self . fixNick ( nick )
msg = ' : %s ! %s JOIN :# %s ' % (
resource ,
nick ,
channel )
self . sendToIRC ( msg )
role = self . mucs [ channel ] [ onick ] [ ' role ' ]
args = ' '
if role == ' moderator ' :
args = ' +o '
elif role == ' participant ' :
args = ' +v '
if args :
self . ircCommandMODEMUCUSER ( JID ( ' %s /telepaatti ' % channel ) , onick , channel , args )
def ircCommandSELFJOIN ( self , nick , room ) :
""" IRC command join channel
@type nick : string
@type room : string
@param nick : nick who is joining
@param room : channel whats been joined
"""
snick = self . fixNick ( self . nickname )
lines = list ( )
lines . append ( ' : %s JOIN :# %s ' % ( snick , room ) )
lines . append ( ' :localhost MODE # %s ' % room )
for nick in self . mucs [ room ] . iterkeys ( ) :
onick = nick
nick = nick . getResource ( )
nick = self . fixNick ( nick )
oonick = nick
if self . mucs [ room ] [ onick ] [ ' role ' ] == ' moderator ' :
oonick = " @ %s " % oonick
elif self . mucs [ room ] [ onick ] [ ' role ' ] == ' participant ' :
oonick = " + %s " % oonick
lines . append ( ' :localhost 353 %s = # %s : %s ' % ( snick , room , oonick ) )
lines . append ( ' :localhost 366 %s # %s :End of /NAMES list. ' % ( snick , room ) )
while lines :
msg = lines . pop ( 0 )
self . sendToIRC ( msg )
def ircCommandPART ( self , nick , channel , text ) :
""" IRC command part channel
@type nick : string
@type channel : string
@type text : string
@param nick : nick who is parting
@param channel : channel whats been parted
@param text : the part message
"""
resource = self . fixNick ( nick . getResource ( ) )
nick = self . fixNick ( nick )
msg = ' : %s ! %s PART # %s : %s ' % (
resource ,
nick ,
channel ,
text )
self . sendToIRC ( msg )
def ircCommandROSTERPART ( self ) :
""" Part roster channel """
self . joinedRoster = False
msg = ' : %s ! %s PART #roster : ' % ( self . nickname ,
unicode ( self . JID ) )
self . sendToIRC ( msg )
def ircCommandROSTERPRIVMSGMUC ( self , msg ) :
""" Handles messages in roster channel. For example if user types HELP
in roster channel ( s ) he gets list of available commands
@type msg : string
@param msg : message to roster channel
"""
if msg . upper ( ) . startswith ( ' HELP ' ) :
msg = ' : %s PRIVMSG # %s : %s ' % \
( ' Telepaatti ' ,
' roster ' ,
' Awailable commands !subscribe, !unsubscribe, !subscribed, !unsubscribed ' )
self . sendToIRC ( msg )
elif msg . startswith ( ' ! ' ) :
msglist = msg [ 1 : ] . split ( )
msglist [ 0 ] = msglist [ 0 ] . upper ( )
if len ( msglist ) == 2 :
if msglist [ 0 ] == ' SUBSCRIBE ' :
self . xmppCommandSUBSCRIBE ( msglist [ 1 ] )
elif msglist [ 0 ] == ' UNSUBSCRIBE ' :
self . xmppCommandUNSUBSCRIBE ( msglist [ 1 ] )
elif msglist [ 0 ] == ' SUBSCRIBED ' :
self . xmppCommandSUBSCRIBED ( msglist [ 1 ] )
elif msglist [ 0 ] == ' UNSUBSCRIBED ' :
self . xmppCommandUNSUBSCRIBED ( msglist [ 1 ] )
return
def ircCommandROSTERSELFJOIN ( self ) :
""" Join roster channel. This handles cases when user self joins to
roster channel """
snick = self . fixNick ( self . nickname )
lines = list ( )
room = ' roster '
lines . append ( ' : %s JOIN :# %s ' % ( snick , room ) )
lines . append ( ' :localhost 332 %s # %s :Roster Channel. Telepaatti is tracking here your roster changes. Type Help for help! ' %
( snick , room ) )
lines . append ( ' :localhost 333 %s # %s telepaatti 000000001 ' % ( snick , room ) )
lines . append ( ' :localhost MODE # %s ' % room )
lines . append ( ' :localhost 353 %s = # %s : %s ' % ( snick , room , snick ) )
for nick in self . mucs [ room ] . iterkeys ( ) :
nick = self . fixNick ( nick )
if not ( snick == nick ) :
lines . append ( ' :localhost 353 %s = # %s : %s ' % ( snick , room , nick ) )
lines . append ( ' :localhost 366 %s # %s :End of /NAMES list. ' % ( snick , room ) )
while lines :
msg = lines . pop ( 0 )
self . sendToIRC ( msg )
self . joinedRoster = True
for msg in self . rosterMessages :
self . sendToIRC ( msg )
def ircCommandROSTERMSG ( self , pres ) :
""" Roster channel messages. Here is traced roster users statas
@type pres : Presence
@param pres : Presence of the roster user
"""
nick = pres . getFrom ( )
jid = pres . getFrom ( )
message = ' '
dt = " %s " % datetime . datetime . now ( )
dt = dt [ : - 7 ]
if jid != str ( self . JID ) and pres . getType ( ) == ' unavailable ' : # left
message = ' : %s ! %s PART #roster :[ %s ] Offline ' % ( nick , jid , dt )
try : # remove
del ( self . mucs [ ' roster ' ] [ jid ] )
except :
self . printError ( ' GOT UNEXPECTED ERROR ' )
elif jid != str ( self . JID ) and not self . mucs [ ' roster ' ] . has_key ( jid ) :
message = ' : %s ! %s JOIN :#roster ' % ( nick , jid )
self . mucs [ ' roster ' ] [ jid ] = { ' role ' : ' participant ' ,
' affiliation ' : ' member ' }
else :
action = self . makeIRCACTION ( ' [ %s ] %s - %s ' % (
dt ,
pres . getShow ( ) ,
pres . getStatus ( ) ) )
message = ' : %s ! %s PRIVMSG #roster : %s ' % (
nick ,
jid ,
action )
self . rosterMessages . append ( message )
if self . joinedRoster :
self . sendToIRC ( message )
def ircCommandPRIVMSG ( self , nick , text , timestamp = ' ' ) :
""" Converts private messages to IRC client
@type nick : string
@type text : string
@type timestamp : string
@param nick : the nickname whois messaging
@param text : the message
@param timestamp : timestamp of the message
"""
nick = self . fixNick ( nick )
nick = unicode ( nick )
lines = text . splitlines ( )
messages = list ( )
for line in lines :
action = False
if line . upper ( ) . startswith ( ' /ME ' ) :
line = line [ 4 : ]
action = True
if timestamp :
line = " [ %s ] %s " % ( timestamp , line )
if action :
line = self . makeIRCACTION ( line )
msg = ' : %s ! %s PRIVMSG %s : %s ' % ( nick , nick , self . fixNick ( self . nickname ) , line )
messages . append ( msg )
for msg in messages :
self . sendToIRC ( msg )
def ircCommandPRIVMSGMUC ( self , orgnick , channel , text , timestamp = ' ' ) :
""" Converts MUC messages to IRC channel messages
@type orgnick : string
@type channel : string
@type text : string
@type timestamp : string
@param orgnick : the nickname whois messaging
@param channel : the channel
@param text : the message
@param timestamp : timestamp of the message
"""
lines = text . splitlines ( )
messages = list ( )
for line in lines :
action = False
if line . upper ( ) . startswith ( ' /ME ' ) :
line = line [ 4 : ]
action = True
if timestamp :
line = " [ %s ] %s " % ( timestamp , line )
if action :
line = self . makeIRCACTION ( line )
nick = orgnick . getResource ( )
nick = self . fixNick ( nick )
msg = ' : %s PRIVMSG # %s : %s ' % ( nick ,
channel ,
line )
messages . append ( msg )
for msg in messages :
self . sendToIRC ( msg )
def ircCommandTOPIC ( self , nick , channel , text ) :
""" Converts MUC topic to IRC channel topic
@type nick : string
@type channel : string
@type text : string
@param channel : name of the channel
@param nick : the nickname whois messaging
@param text : the message
"""
snick = self . fixNick ( nick . getResource ( ) )
nick = self . fixNick ( nick )
msg = ' : %s ! %s TOPIC # %s : %s ' % ( snick , nick , channel , text )
self . sendToIRC ( msg )
def ircCommandMODEMUC ( self , channel , args ) :
""" Converts MUC mode to IRC channel mode
@type channel : string
@type args : string
@param channel : anme of the channel
@param args : arguments of the mode
"""
nick = self . fixNick ( self . nickname )
msg = ' :localhost 324 %s # %s %s ' % ( nick , channel , args )
self . sendToIRC ( msg )
msg = ' :localhost 329 %s # %s %s ' % ( nick , channel , ' 1031538353 ' )
self . sendToIRC ( msg )
def ircCommandMODEMUCBANLIST ( self , channel ) :
""" Converts MUC ban list to IRC channel banlist, is unfinished
@type channel : string
@param channel : name of the channel
"""
nick = self . fixNick ( self . nickname )
msg = ' :localhost 368 %s # %s :End of Channel Ban List ' % ( nick , channel )
self . sendToIRC ( msg )
def ircCommandMODEMUCUSER ( self , giver , taker , muc , args ) :
""" Convers MUC user mode to IRC channel user mode. Example use cases
are when someone is granted a voice or admin rights on a MUC .
@type giver : string
@type taker : string
@type muc : string
@type args : string
@param giver : giver of the new mode
@param taker : taker of the new mode
@param muc : MUC on which the mode takes place
@param args : arguments of the mode
"""
givernick = self . fixNick ( giver . getResource ( ) )
giver = self . fixNick ( giver )
taker = self . fixNick ( taker . getResource ( ) )
msg = ' : %s ! %s MODE # %s %s %s ' % ( givernick ,
giver ,
muc ,
args ,
taker )
self . sendToIRC ( msg )
def ircCommandMODE ( self , args ) :
""" Converts XMPP mode to IRC mode. Unfinished
@type args : string
@param args : arguments of the mode
"""
# just to keep irssi happy, fix later to more meaningfull
nick = self . fixNick ( self . nickname )
msg = ' : %s MODE %s : %s ' % ( nick , nick , args )
self . sendToIRC ( msg )
def ircCommandERROR ( self , message = ' ' , ircerror = 0 ) :
""" Convert XMPP errors to IRC errors
@type message : string
@type ircerror : integer
@param message : the error message
@param ircerror : number of the error
"""
msg = ' '
if ircerror == 0 :
msg = ' ERROR :XMPP ERROR %s ' % message
elif ircerror == - 1 :
msg = ' ERROR :Telepaatti error %s ' % message
elif ircerror == 403 :
msg = ' :localhost 403 %s localhost :That channel doesn \' t exist ' % self . fixNick ( self . nickname )
self . sendToIRC ( msg )
def ircCommandERRORMUC ( self , number , errormess , room ) :
""" Convert XMPP MUC errors to IRC channel errors
@type number : integer
@type errormess : string
@type room : string
@param number : number of the error
@param errormess : the error message
@param room : the MUC
"""
text = ' '
if number == 403 :
text = ' No such channel '
elif number == 404 :
text = ' Cannot send to channel '
elif number == 467 :
text = ' Channel key already set '
elif number == 471 :
text = ' Cannot join channel (+l) '
elif number == 473 :
text = ' Cannot join channel (+i) '
elif number == 474 :
text = ' Cannot join channel (+b) '
elif number == 475 :
text = ' Cannot join channel (+k) '
elif number == 476 :
text = ' Bad Channel Mask '
elif number == 477 :
text = ' Channel doesn \' t support modes '
elif number == 478 :
text = ' Channel list is full '
elif number == 481 :
text = ' Permission Denied- You \' re not an IRC operator '
elif number == 482 :
text = ' You \' re not channel operator '
else :
text = ' No text '
msg = ' :localhost %s %s # %s : %s ' % (
number , self . fixNick ( self . nickname ) , room , text )
self . sendToIRC ( msg )
self . ircCommandERROR ( errormess )
def ircCommandWHO ( self , users , channel ) :
""" Convert XMPP vcard query to IRC who
@type users : list
@type channel : string
@param users : list of users
@param channel : the channel ( MUC )
"""
for user in users :
oruser = user
user = unicode ( user )
at = user . find ( ' @ ' )
slash = user . find ( ' / ' )
domain = channel [ at + 1 : ]
if at > 0 and slash > at :
onick = user [ slash + 1 : ]
user = self . fixNick ( user )
nick = self . fixNick ( onick )
msg = ' :localhost 352 %s # %s %s %s localhost %s %s :0 %s ' % (
self . fixNick ( self . nickname ) ,
channel ,
self . fixNick ( user [ : at ] ) ,
self . fixNick ( user [ at + 1 : ] ) ,
nick ,
self . ircGetStatus ( oruser , channel ) ,
onick )
self . sendToIRC ( msg )
msg = ' :localhost 315 %s # %s :End of /WHO list. ' % ( self . fixNick ( self . nickname ) , channel )
self . sendToIRC ( msg )
def ircCommandWHOIS ( self , jid ) :
""" Convert XMPP vcard query to IRC whois
@type jid : JID
@param jid : Jabber id of the user whos vcard is quered
"""
nick = self . fixNick ( self . nickname )
whonick = jid
if self . mucs . has_key ( jid . getStripped ( ) ) :
whonick = self . fixNick ( jid . getResource ( ) )
lines = [
' :localhost 311 %s %s %s %s * : %s ' % ( nick ,
whonick ,
jid . getNode ( ) ,
jid . getDomain ( ) ,
whonick ) ,
' :localhost 312 %s %s localhost : XMPP telepaatti ' % ( nick , whonick ) ,
' :localhost 318 %s %s :End of /WHOIS list. ' % ( nick , whonick ) ]
while lines :
self . sendToIRC ( lines . pop ( 0 ) )
def ircCommandUNAWAY ( self ) :
""" Convert XMPP status to IRC away """
nick = self . fixNick ( self . nickname )
msg = ' :localhost 305 %s : %s ' % (
nick ,
' You are no longer marked as being away ' )
self . sendToIRC ( msg )
def ircCommandNOWAWAY ( self ) :
""" Convert XMPP status to IRC not away """
nick = self . fixNick ( self . nickname )
msg = ' :localhost 306 %s : %s ' % (
nick ,
' You have been marked as being away ' )
self . sendToIRC ( msg )
def ircCommandNOTICE ( self , text ) :
""" Convert XMPP message to IRC notice
@type text : string
@param text : notice text
"""
nick = self . fixNick ( self . nickname )
msg = ' NOTICE %s : %s ' % ( nick , text )
self . sendToIRC ( msg )
def ircCommandSUBSCRIBE ( self , pres ) :
""" Convert XMPP subscribe message to IRC message
@type pres : presence
@param pres : presence of which to subscribe
"""
text = " is making subsciption request to you with message: \" %s \" You MUST either approve the request or refuse the request. You can approve it by joinin #roster channel andthen type \" !subscribed %s \" if you wish to subscibe to contact or \" !unsubscribed %s \" if you wish not to subscibe to contact " % ( pres . getStatus ( ) , pres . getFrom ( ) , pres . getFrom ( ) )
text = self . makeIRCACTION ( text )
self . printDebug ( str ( pres ) )
self . ircCommandPRIVMSG ( pres . getFrom ( ) , text )
def ircCommandUNSUBSCRIBE ( self , pres ) :
""" Convert XMPP unsubscribe message to IRC message. Unfinished.
@type pres : presence
@param pres : presence of which to unsubscribe
"""
self . printDebug ( str ( pres ) )
def ircCommandSUBSCRIBED ( self , pres ) :
""" Convert XMPP subscribed message to IRC message. Unfinished.
@type pres : presence
@param pres : presence of which to subscribed
"""
self . printDebug ( str ( pres ) )
def ircCommandUNSUBSCRIBED ( self , pres ) :
""" Convert XMPP unsubscribed message to IRC message. Unfinished.
@type pres : presence
@param pres : presence of which to unsubscribed
"""
self . printDebug ( str ( pres ) )
def xmppCommandSUBSCRIBE ( self , jid ) :
""" Send XMPP subscribe message.
@type jid : string
@param jid : Jabber ID to subscribe
"""
self . sendToXMPP ( Presence ( to = ' %s ' % jid ,
typ = ' subscribe ' ) )
def xmppCommandUNSUBSCRIBE ( self , jid ) :
""" Send XMPP unsubscribe message.
@type jid : string
@param jid : Jabber ID to unsubscribe
"""
self . sendToXMPP ( Presence ( to = ' %s ' % jid ,
typ = ' unsubscribe ' ) )
def xmppCommandSUBSCRIBED ( self , jid ) :
""" Send XMPP subscribed message.
@type jid : string
@param jid : Jabber ID to subscribed
"""
self . sendToXMPP ( Presence ( to = ' %s ' % jid ,
typ = ' subscribed ' ) )
def xmppCommandUNSUBSCRIBED ( self , jid ) :
""" Send XMPP unsubscribed message.
@type jid : string
@param jid : Jabber ID to unsubscribed
"""
self . sendToXMPP ( Presence ( to = ' %s ' % jid ,
typ = ' unsubscribed ' ) )
def xmppCommandMUCMODE ( self , jid ) :
""" Send XMPP MUC mode change
@type jid : string
@param jid : Jabber id of the MUC
"""
if jid == ' roster ' : # no query for roster
return
iq = protocol . Iq ( to = jid ,
queryNS = NS_DISCO_INFO ,
typ = ' get ' )
iq . setID ( ' disco3 ' )
self . sendToXMPP ( iq )
def xmppCommandMUCUSERS ( self , jid ) :
""" Send XMPP MUC users query
@type jid : string
@param jid : Jabber id of the MUC
"""
if jid == ' roster ' : # no query for roster
return
iq = protocol . Iq ( frm = unicode ( self . JID ) ,
to = jid ,
queryNS = NS_DISCO_ITEMS ,
typ = ' get ' )
iq . setID ( ' disco4 ' )
self . sendToXMPP ( iq )
def xmppCommandSTATUS ( self , show , status ) :
""" Send XMPP status change
@type show : string
@type status : string
@param show : status
@param status : status
"""
for muc in self . mucs . keys ( ) :
if muc != ' roster ' :
p = Presence ( to = ' %s / %s ' % (
muc ,
self . nickname ) )
if not show == ' ' :
p . setShow ( show )
p . setStatus ( status )
self . sendToXMPP ( p )
p = Presence ( )
p . setShow ( show )
p . setStatus ( status )
self . sendToXMPP ( p )
if show . upper ( ) in STATUSSTATES [ 2 : ] : # available, chat
self . ircCommandNOWAWAY ( )
else :
self . ircCommandUNAWAY ( )
def xmppCommandMUCPRESENCE ( self , muc , nick ) :
""" Send XMPP presence to MUC room
@type muc : string
@type nick : string
@param muc : Jabber ID of the MUC
@param nick : users nickname for the MUC
"""
self . sendToXMPP ( Presence ( to = ' %s / %s ' %
( muc ,
nick ) ) )
def xmppCommandMUCROLE ( self , muc , nick , role ) :
""" Send XMPP MUC role to MUC room
@type muc : string
@type nick : string
@type role : role
@param muc : Jabber ID of the MUC
@param nick : users nickname in the MUC
@param role : role of the user
"""
iq = protocol . Iq ( to = muc ,
queryNS = NS_MUC_ADMIN ,
typ = ' set ' )
item = iq . getTag ( ' query ' ) . setTag ( ' item ' )
item . setAttr ( ' nick ' , nick )
item . setAttr ( ' role ' , role )
self . sendToXMPP ( iq )
def xmppCommandGETWHOIS ( self , jid ) :
""" Send XMPP vcard, last activity and sofware version request for some
Jabber ID .
@type jid : string
@param jid : Jabber ID
"""
# vcard
iq = protocol . Iq ( to = jid ,
typ = ' get ' )
iq . setTag ( NS_VCARD + ' vCard ' )
iq . setID ( ' v3 ' )
self . sendToXMPP ( iq )
# last activity
iq = protocol . Iq ( to = jid ,
typ = ' get ' ,
queryNS = NS_LAST )
self . sendToXMPP ( iq )
# software version
if not jid . getResource ( ) :
# try to find match in roster
rosternicks = self . mucs [ ' roster ' ] . keys ( )
for x in rosternicks :
if x . getStripped ( ) == jid . getStripped ( ) :
jid = x
if not jid . getResource ( ) :
return
iq = protocol . Iq ( to = jid ,
typ = ' get ' ,
queryNS = NS_VERSION )
self . sendToXMPP ( iq )
2010-05-08 08:59:58 -04:00
def xmppCommandINFOGET ( self , jid ) :
""" Not finished """
pass
2009-09-30 15:45:48 -04:00
def xmppCommandSOFTWAREVERSION ( self , jid ) :
""" Send set software version XMPP. Not finished """
pass
def xmppCommandLASTACTIVITY ( self , jid ) :
""" Send last activity XMPP. Not finished """
pass
def run ( self ) :
""" Here is this threads main functionality. Jabber-thread is started
and polling of socket for IRC - messages is in here . """
jt = JabberThread ( self . client )
jt . start ( )
nick = self . fixNick ( self . nickname )
lines = [ " NOTICE AUTH :*** Looking up your hostname... " ,
" NOTICE AUTH :*** Found your hostname, welcome back " ,
" NOTICE AUTH :*** Checking ident " ,
" NOTICE AUTH :*** No identd (auth) response " ,
" :localhost 001 %s :Welcome to Telepaatti, IRC to XMPP gateway " %
nick ,
" :localhost 002 %s :Your host is localhost [localhost port %s ] running version telepaatti- %s " % (
nick ,
self . port ,
TELEPAATTIVERSION )
]
while self . connected and jt . connected :
try :
data = self . socket . recv ( 4096 )
except :
self . printError ( ' GOT ERROR SHUTTING DOWN ' )
self . connected = False
if data . find ( ' PING ' ) != - 1 :
# check that our rooms are still alive
if self . pingCounter == 5 :
self . pingCounter = 0
for muc in self . mucs . keys ( ) :
if muc != ' roster ' :
if self . disconnectedMucs . has_key ( muc ) :
if self . disconnectedMucs [ muc ] < 5 :
self . disconnectedMucs [ muc ] = self . disconnectedMucs [ muc ] + 1
else :
self . disconnectedMucs [ muc ] = 0
self . roomPingQueue [ muc ] = ' '
self . xmppCommandMUCMODE ( muc )
else :
self . roomPingQueue [ muc ] = ' '
self . xmppCommandMUCMODE ( muc )
else :
self . pingCounter = self . pingCounter + 1
self . sendToIRC ( ' PONG localhost ' )
while lines :
self . sendToIRC ( lines . pop ( 0 ) )
if data :
for line in data . splitlines ( ) :
self . commandHandler ( line )
else :
self . connected = False
if not jt . connected :
self . ircCommandNOTICE ( ' XMPP server disconnected, shutting down Telepaatti. ' )
jt . connected = False
self . socket . shutdown ( socket . SHUT_RDWR )
def messageHandlerError ( self , sess , mess ) :
""" Handle incoming error messages from XMPP
@type sess : string
@type mess : Message
@param sess : session
@param mess : error message
"""
text = ' '
try :
text = mess . getTag ( ' error ' ) . getTag ( ' text ' ) . getData ( )
except :
pass
erc = mess . getErrorCode ( )
jidFrom = mess . getFrom ( )
to = mess . getTo ( )
if erc == ' 403 ' :
self . ircCommandERRORMUC ( 482 , text , jidFrom )
else :
self . printDebug ( ' MUC ERROR NOT IMPLEMENTED ' )
def messageHandler ( self , sess , mess ) :
""" Handle incoming XMPP with type message
@type sess : string
@type mess : Message
@param sess : session
@param mess : XMPP Message
"""
if mess . getType ( ) == ' error ' :
self . messageHandlerError ( sess , mess )
return
nick = mess . getFrom ( )
text = mess . getBody ( )
topic = mess . getSubject ( )
room = unicode ( mess . getFrom ( ) )
x = room . find ( ' / ' )
if x > 0 :
room = room [ : room . find ( ' / ' ) ]
ts = ' '
if mess . getTag ( ' x ' , namespace = NS_DELAY ) :
ts = mess . getTimestamp ( )
if not ts :
ts = mess . setTimestamp ( )
ts = mess . getTimestamp ( )
ts = time . strptime ( ts , ' % Y % m %d T % H: % M: % S ' )
ts = datetime . datetime ( * ts [ : - 3 ] )
if not text and not topic :
return
MUC = False
if mess . getType ( ) == ' groupchat ' :
MUC = True
if not MUC :
self . ircCommandPRIVMSG ( nick , text , ts )
elif topic :
self . ircCommandTOPIC ( nick , room , topic )
elif not nick . getResource ( ) == self . nickname or ts :
self . ircCommandPRIVMSGMUC ( nick , room , text , ts )
def iqHandler ( self , con , iq ) :
""" Handle incoming XMPP with type Iq
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
ns = iq . getQueryNS ( )
if ns is None :
ns = iq . getProperties ( ) [ 0 ]
if ns == NS_DISCO and iq . getType ( ) in [ ' get ' , ' error ' ] :
self . iqHandlerInfo ( con , iq )
elif ns == NS_DISCO_ITEMS and iq . getType ( ) == ' result ' :
self . iqHandlerItems ( con , iq )
elif ns == NS_DISCO_INFO and iq . getType ( ) == ' result ' :
self . iqHandlerInfo ( con , iq )
elif ns == NS_DISCO_INFO and iq . getType ( ) == ' get ' :
self . xmppCommandINFOGET ( iq . getFrom ( ) )
elif ns == NS_DISCO_ITEMS and iq . getType ( ) == ' error ' :
self . iqHandlerError ( con , iq )
elif ns == NS_DISCO_INFO and iq . getType ( ) == ' error ' :
self . iqHandlerError ( con , iq )
elif ns == NS_VCARD and iq . getType ( ) == ' result ' :
self . iqHandlerVcard ( con , iq )
elif ns == NS_VCARD and iq . getType ( ) == ' error ' :
self . iqHandlerVcardError ( con , iq )
elif ns == NS_LAST and iq . getType ( ) == ' result ' :
self . iqHandlerLast ( con , iq )
elif ns == NS_LAST and iq . getType ( ) == ' get ' :
self . xmppCommandLASTACTIVITY ( iq . getFrom ( ) )
elif ns == NS_LAST and iq . getType ( ) == ' error ' :
self . iqHandlerLastError ( con , iq )
elif ns == NS_VERSION and iq . getType ( ) == ' result ' :
self . iqHandlerVersion ( con , iq )
elif ns == NS_VERSION and iq . getType ( ) == ' error ' :
self . iqHandlerVersionError ( con , iq )
elif ns == NS_VERSION and iq . getType ( ) == ' get ' :
self . xmppCommandSOFTWAREVERSION ( iq . getFrom ( ) )
else :
self . printDebug ( ' IQ HANDLER FOR THIS NAMESPACE NOT IMPLEMENTED YET ' )
def iqHandlerLastError ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and last activity error
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
self . printDebug ( ' iqHandlerLastError ' )
def iqHandlerLast ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and last activity
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
ch = iq . getTag ( ' query ' )
seconds = ch . getAttr ( ' seconds ' )
self . ircCommandNOTICE ( ' ** Last active information for %s ** ' % iq . getFrom ( ) )
self . ircCommandNOTICE ( ' Idle %s second** ' % seconds )
def iqHandlerVersionError ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and version error
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
self . printDebug ( ' iqHandlerVersionError ' )
def iqHandlerVersion ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and version
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
ch = iq . getTag ( ' query ' ) . getChildren ( )
self . ircCommandNOTICE ( ' ** Software version information for %s ** ' % iq . getFrom ( ) )
for c in ch :
self . ircCommandNOTICE ( ' %s : %s ' % ( c . getName ( ) , c . getData ( ) ) )
def iqHandlerVcardError ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and vcard error
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
self . printDebug ( ' iqHandlerVcardError ' )
def iqHandlerVcard ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and vcard
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
card = { }
ch = iq . getTag ( ' vCard ' ) . getChildren ( )
for c in ch :
name = c . getName ( )
if name != ' PHOTO ' :
if name == ' EMAIL ' :
emailv = c . getChildren ( )
card [ ' EMAIL %s ' % emailv [ 0 ] . getName ( ) ] = emailv [ 1 ] . getData ( )
card [ c . getName ( ) ] = c . getData ( )
self . ircCommandNOTICE ( ' ** Vcard information for %s ** ' % iq . getFrom ( ) )
for key in card . keys ( ) :
for line in card [ key ] . splitlines ( ) :
self . ircCommandNOTICE ( ' %s : %s ' % ( key , line ) )
def iqHandlerError ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and error
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
jid = iq . getFrom ( )
# this can mess things up, fix later
if self . roomPingQueue . has_key ( jid ) :
del ( self . roomPingQueue [ jid ] )
# room errors
errornum = iq . getErrorCode ( )
if jid in self . mucs . keys ( ) :
if errornum == ' 404 ' and jid not in self . disconnectedMucs . keys ( ) :
self . ircCommandERRORMUC ( 404 , ' MUC DISCONNECTED ' , jid )
self . ircCommandPRIVMSGMUC ( JID ( " %s / %s " % ( jid , ' telepaatti ' ) ) ,
jid ,
' MUC IS DISCONNECTED YOUR TEXT WILL NOT SHOW ON CHANNEL. YOU CAN WAIT UNTIL MUC CONNECTS AGAIN OR USE /PART TO LEAVE THIS MUC! ' ,
timestamp = ' ' )
self . disconnectedMucs [ jid ] = 0
return
else :
return
else :
self . ircCommandERROR ( ' iq error num %s jid not room! jid %s ' % ( errornum , jid ) )
def iqHandlerItems ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and items
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
jid = iq . getFrom ( )
if iq . getType ( ) == ' error ' :
# some fixing is needed
self . ircCommandERROR ( ' %s %s ' % ( iq . getErrorCode ( ) , iq . getErrorCode ( ) ) )
elif iq . getID ( ) == ' disco4 ' : # muc users
ch = iq . getQueryChildren ( )
mucusers = list ( )
for c in ch :
name = c . getName ( )
if name == ' item ' :
mucusers . append ( c . getAttrs ( ) [ ' jid ' ] )
if self . mucs . has_key ( jid ) :
pass # we keep track of users else where
self . ircCommandWHO ( mucusers , unicode ( jid ) )
return
else :
self . printDebug ( ' UNKNOWN DISCO ITEM %s ' % jid )
def iqHandlerInfo ( self , con , iq ) :
""" Handle incoming XMPP with type Iq and info
@type con : Connection
@type iq : Iq
@param con : XMPP Connection
@param iq : XMPP Iq
"""
roomname = iq . getFrom ( )
# this can mess things up, fix
if self . roomPingQueue . has_key ( roomname ) :
del ( self . roomPingQueue [ roomname ] )
return
MUC = False
roomfeats = list ( )
if iq . getType ( ) == ' error ' :
# fix this later
self . ircCommandERROR ( ' %s %s ' % ( iq . getErrorCode ( ) , iq . getErrorCode ( ) ) )
else :
ch = iq . getQueryChildren ( )
for c in ch :
name = c . getName ( )
if name == ' identity ' :
atrs = c . getAttrs ( )
if atrs . has_key ( ' type ' ) and atrs . has_key ( ' category ' ) :
if atrs [ ' type ' ] == ' text ' and \
atrs [ ' category ' ] == ' conference ' :
MUC = True
elif name == ' var ' :
roomfeats . append ( c . getAttrs ( ) [ ' var ' ] )
elif name == ' feature ' :
roomfeats . append ( c . getAttrs ( ) [ ' var ' ] )
else :
self . printDebug ( ' %s NOT IMPLeMENTED ' % name )
if MUC : # for MODE
modestr = ' + '
for feat in roomfeats :
if feat == ' muc_hidden ' :
modestr + = ' s '
if feat == ' muc_membersonly ' :
modestr + = ' p '
if feat == ' muc_moderated ' :
modestr + = ' m '
if feat == ' muc_nonanonymous ' :
modestr + = ' A '
if feat == ' muc_open ' :
modestr + = ' F '
if feat == ' muc_passwordprotected ' :
modestr + = ' k '
if feat == ' muc_persistent ' :
modestr + = ' P '
if feat == ' muc_public ' :
modestr + = ' B '
if feat == ' muc_rooms ' :
self . printDebug ( ' muc_rooms not implemented ' )
if feat == ' muc_semianonymous ' :
modestr + = ' a '
if feat == ' muc_temporary ' :
modestr + = ' T '
if feat == ' muc_unmoderated ' :
modestr + = ' u '
if feat == ' muc_unsecured ' :
modestr + = ' U '
self . ircCommandMODEMUC ( roomname , modestr )
else :
self . printDebug ( " IQ stuff still missing here " )
def presenceHandler ( self , sess , pres ) :
""" Handle incoming XMPP with type presence
@type sess : Connection
@type pres : Presence
@param sess : XMPP Connection
@param press : XMPP Presence
"""
MUC = False
ptype = pres . getType ( )
nick = pres . getFrom ( )
tags = pres . getTags ( ' x ' )
for tag in tags :
ns = tag . getNamespace ( )
if ns . startswith ( NS_MUC ) :
MUC = True
role = pres . getRole ( )
affiliation = pres . getAffiliation ( )
show = pres . getShow ( )
status = pres . getStatus ( )
room = unicode ( pres . getFrom ( ) )
room = room [ : room . find ( ' / ' ) ]
# for affiliation and role changes
if MUC and \
self . mucs . has_key ( room ) and \
nick in self . mucs [ room ] . keys ( ) :
xrole = self . mucs [ room ] [ nick ] [ ' role ' ]
xaffiliation = self . mucs [ room ] [ nick ] [ ' affiliation ' ]
if role != xrole : # role has changed
giver = JID ( ' %s /telepaatti ' % room )
if role . upper ( ) == ' MODERATOR ' :
self . ircCommandMODEMUCUSER ( giver , nick , room , ' +o ' )
self . ircCommandMODEMUCUSER ( giver , nick , room , ' -v ' )
if role . upper ( ) == ' PARTICIPANT ' :
self . ircCommandMODEMUCUSER ( giver , nick , room , ' -o ' )
self . ircCommandMODEMUCUSER ( giver , nick , room , ' +v ' )
if role . upper ( ) == ' VISITOR ' :
self . ircCommandMODEMUCUSER ( giver , nick , room , ' -o ' )
self . ircCommandMODEMUCUSER ( giver , nick , room , ' -v ' )
else :
self . printDebug ( ' MODE NONE ' )
if xaffiliation != affiliation : # affiliation has changed
pass
# for nick changes
if ( pres . getNick ( ) == self . newnick or pres . getNick ( ) == self . nickname ) \
and pres . getStatusCode ( ) == ' 303 ' :
self . nickChangeInMucs [ room ] = { ' checked ' : True ,
' changed ' : True }
# check if we have checked all MUCs
for muc in self . nickChangeInMucs . keys ( ) :
if not self . nickChangeInMucs [ muc ] [ ' checked ' ] :
return # no need to go any further
# check if it changed in all MUCs
for muc in self . nickChangeInMucs . keys ( ) :
if not self . nickChangeInMucs [ muc ] [ ' changed ' ] :
changedMucs = list ( )
for gei in self . nickChangeInMucs . keys ( ) :
if self . nickChangeInMucs [ gei ] [ ' changed ' ] :
changedMucs . append ( gei )
self . nickChangeInMucs = { }
for muc2 in changedMucs :
self . nickChangeInMucs [ muc2 ] = { ' checked ' : False ,
' changed ' : False }
self . xmppCommandMUCPRESENCE ( muc2 , self . nickname )
self . ircCommandERROR ( ' Nick conflicts in some MUC wont change ' )
return # out
# remove, all have changed
self . nickChangeInMucs = { }
if pres . getNick ( ) == self . nickname :
self . newnick = ' '
return
self . sendToIRC ( ' : %s NICK : %s ' %
( self . nickname ,
self . newnick ) )
for muc in self . getMucs ( ) :
del ( self . mucs [ muc ] [ JID ( " %s / %s " % ( muc , self . nickname ) ) ] ) # remove the old
# add the new
self . mucs [ muc ] [ JID ( " %s / %s " % ( muc , self . newnick ) ) ] = { ' role ' : role ,
' affiliation ' : affiliation }
self . nickname = self . newnick
self . newnick = ' '
return
if not MUC and ptype == ' error ' :
erc = pres . getErrorCode ( )
if erc == ' 409 ' and self . mucs . has_key ( nick . getStripped ( ) ) :
self . nickChangeInMucs [ room ] = { ' checked ' : True ,
' changed ' : False }
# all must have come
self . printDebug ( str ( self . nickChangeInMucs ) )
for muc in self . nickChangeInMucs . keys ( ) :
if not self . nickChangeInMucs [ muc ] [ ' checked ' ] :
return
changedMucs = list ( )
for gei in self . nickChangeInMucs . keys ( ) :
if self . nickChangeInMucs [ gei ] [ ' changed ' ] :
changedMucs . append ( gei )
self . nickChangeInMucs = { }
for muc2 in changedMucs :
self . nickChangeInMucs [ muc2 ] = { ' checked ' : False ,
' changed ' : False }
self . xmppCommandMUCPRESENCE ( muc2 , self . nickname )
self . ircCommandERROR ( ' Nick conflicts in some MUC wont change ' )
else :
self . ircCommandERROR ( ' Got some error %s ' % unicode ( pres ) )
return
if not MUC : # normal presence
if ptype in [ ' subscribe ' ] :
self . ircCommandSUBSCRIBE ( pres )
elif ptype in [ ' unsubscribe ' ] :
self . ircCommandUNSUBSCRIBE ( pres )
elif ptype in [ ' subscribed ' ] :
self . ircCommandSUBSCRIBED ( pres )
elif ptype in [ ' unsubscribed ' ] :
self . ircCommandUNSUBSCRIBED ( pres )
else :
self . ircCommandROSTERMSG ( pres )
elif MUC :
if ptype == ' error ' :
er = pres . getError ( )
erc = pres . getErrorCode ( )
if erc == ' 401 ' :
self . ircCommandERRORMUC ( 475 , ' Password requeired to join ' , room )
elif erc == ' 403 ' :
self . ircCommandERRORMUC ( 474 , ' Cannot join MUC, you are banned ' , room )
elif erc == ' 404 ' :
self . ircCommandERRORMUC ( 404 , ' No such MUC ' , room )
elif erc == ' 405 ' :
self . ircCommandERRORMUC ( 478 , ' Can \' t create MUC ' , room )
elif erc == ' 406 ' :
self . ircCommandERRORMUC ( 437 , ' You must use reserverd nick to enter ' , room )
elif erc == ' 407 ' :
self . ircCommandERRORMUC ( 473 , ' Must be a member to enter ' , room )
elif erc == ' 409 ' :
self . ircCommandERRORMUC ( 437 , ' You must change nickname to enter ' , room )
elif erc == ' 503 ' :
self . ircCommandERRORMUC ( 471 , ' MUC is full ' , room )
else :
2010-05-08 08:59:58 -04:00
self . ircCommandERROR ( ' MUC error not yet implemented ( %d %s ) ' % ( erc , er ) )
2009-09-30 15:45:48 -04:00
else :
joining = self . joinQueue . has_key ( room )
inroom = self . mucs . has_key ( room )
if ptype == ' unavailable ' :
self . printDebug ( ' unavailable ' )
if nick . getResource ( ) == self . nickname :
self . printDebug ( ' our self ' )
if joining :
del ( self . joinQueue [ room ] )
elif self . nickChangeInMucs . has_key ( room ) :
# between nick change
self . printDebug ( ' we are between nick change ' )
return
elif inroom :
self . ircCommandPART ( nick , room , ' left ' )
del ( self . mucs [ room ] )
else :
line = " %s is doing something " % nick
self . printDebug ( line . encode ( ' utf-8 ' ) )
else : # someonerin else
if joining :
self . printDebug ( " %s left while we are joining room %s " % (
nick , room ) )
elif inroom :
self . ircCommandPART ( nick , room , ' left ' )
del ( self . mucs [ room ] [ nick ] )
else :
line = " %s is doing something " % nick
self . printDebug ( line . encode ( ' utf-8 ' ) )
else : # not unavailable type
self . printDebug ( ' not unavailable ' )
if nick . getResource ( ) == self . nickname :
if joining :
# fix this also later
self . mucs [ room ] = self . joinQueue [ room ] [ ' users ' ]
self . mucs [ room ] [ JID ( " %s / %s " % ( room , self . nickname ) ) ] = { ' role ' : role ,
' affiliation ' : affiliation ,
' show ' : show ,
' status ' : status }
del ( self . joinQueue [ room ] )
self . ircCommandSELFJOIN ( self . nickname , room )
elif inroom :
self . mucs [ room ] [ JID ( " %s / %s " % ( room , self . nickname ) ) ] = { ' role ' : role ,
' affiliation ' : affiliation ,
' show ' : show ,
' status ' : status }
else :
line = " %s is doing something " % nick
self . printDebug ( line . encode ( ' utf-8 ' ) )
elif nick . getResource ( ) == self . newnick :
pass
else : # someone else
if joining :
if nick not in self . joinQueue [ room ] [ ' users ' ] . keys ( ) :
self . joinQueue [ room ] [ ' users ' ] [ nick ] = { ' role ' : role ,
' affiliation ' : affiliation ,
' show ' : show ,
' status ' : status }
elif inroom :
if nick not in self . mucs [ room ] . keys ( ) :
self . mucs [ room ] [ nick ] = { ' role ' : role ,
' affiliation ' : affiliation ,
' show ' : show ,
' status ' : status }
self . ircCommandJOIN ( nick , room )
else :
self . mucs [ room ] [ nick ] = { ' role ' : role ,
' affiliation ' : affiliation ,
' show ' : show ,
' status ' : status }
else :
self . printDebug ( ' TROUBLE LINE ' )
def commandHandler ( self , data ) :
""" Command handler for commands and text coming in from IRC-client
@type data : string
@param data : IRC data coming from IRC - client
"""
self . printDebug ( ' got ircline: %s ' % data )
# utf-8 test
try :
unicode ( data , ' utf-8 ' )
except exceptions . UnicodeDecodeError :
self . printError ( ' GOT ERROR ' )
self . ircCommandERROR ( ' Input form IRC client was not in utf-8. Turn utf-8 support on from your IRC client or input only pure ascii ' , - 1 )
return
args = data . split ( ' ' , 1 )
arguments = u ' '
command = args [ 0 ]
if len ( args ) == 2 :
arguments = args [ 1 ]
command = command . upper ( )
arguments = arguments . strip ( )
MUC = False
if arguments . startswith ( ' # ' ) :
arguments = arguments [ 1 : ]
MUC = True
if command == ' JOIN ' :
room = arguments
if room == ' roster ' :
if self . joinedRoster : # already in #roster
return
self . ircCommandROSTERSELFJOIN ( )
else :
if room . find ( ' @ ' ) < 1 :
self . ircCommandERRORMUC ( 404 , ' No such MUC ' , room )
return
if room in self . mucs . keys ( ) : # already in MUC
return
self . joinQueue [ arguments ] = { ' messages ' : list ( ) ,
' users ' : { } }
p = Presence ( to = ' %s / %s ' % (
room ,
self . nickname ) )
p . setTag ( ' x ' , namespace = NS_MUC ) . setTagData ( ' password ' , ' ' )
p . getTag ( ' x ' ) . addChild ( ' history ' , { ' maxchars ' : ' 10000 ' , ' maxstanzas ' : ' 100 ' } )
self . sendToXMPP ( p )
elif command == ' PART ' :
x = arguments . find ( ' : ' )
room = arguments . strip ( )
text = ' '
if x > 0 :
text = arguments [ x + 2 : ]
text = text . strip ( )
room = arguments [ : x ]
room = room . strip ( )
if room == ' roster ' :
if not self . joinedRoster : # not in roster
return
self . ircCommandROSTERPART ( )
else :
if room not in self . mucs . keys ( ) : # not in room
return
self . sendToXMPP ( Presence ( to = ' %s / %s ' % ( room , self . newnick ) ,
typ = ' unavailable ' ,
status = text ) )
elif command == ' PRIVMSG ' :
x = arguments . find ( ' : ' )
jid = arguments . strip ( )
text = ' '
if x > 0 :
text = arguments [ x + 2 : ]
text = text . strip ( )
sact = text . find ( ' \001 ACTION ' )
eact = text . rfind ( ' \001 ' )
if sact > - 1 and eact > - 1 :
text = ' /me %s ' % text [ sact + 8 : eact ]
jid = arguments [ : x ]
jid = jid . strip ( )
type = ' chat '
if MUC :
type = ' groupchat '
at = jid . find ( ' @ ' )
slash = jid . find ( ' / ' )
if jid == ' roster ' :
self . ircCommandROSTERPRIVMSGMUC ( text )
return
elif ( at < 0 ) and not MUC : # private msg from muc
self . ircCommandERROR ( ' You are trying to send private message someone in MUC room. Jabber can \' t send messages with nick only. Try to sen message to whole MUC jid, for example if you are in room jabber@conference.jabber.org and are trying to send message to nick petteri use /msg jabber@conference.jabber.org/petteri message! ' )
targetnicks = list ( )
for muc in self . mucs . iterkeys ( ) :
for mn in self . mucs [ muc ] . keys ( ) :
mn = unicode ( mn )
mn = mn . encode ( ' utf-8 ' )
if mn [ mn . find ( ' / ' ) + 1 : ] == jid :
targetnicks . append ( mn )
if len ( targetnicks ) != 1 :
self . printError ( ' Problems ' )
else :
jid = targetnicks [ 0 ]
self . ircCommandERROR ( ' Telepaatti forwarded your message to JID: %s ' % jid )
self . sendToXMPP ( protocol . Message ( jid ,
text ,
typ = type ) )
elif command == ' NICK ' :
if self . notFirstNick :
self . newnick = arguments
for muc in self . getMucs ( ) :
self . nickChangeInMucs [ muc ] = { ' checked ' : False ,
' changed ' : False }
for muc in self . nickChangeInMucs . keys ( ) :
self . xmppCommandMUCPRESENCE ( muc , self . newnick )
else :
self . notFirstNick = True
elif command == ' TOPIC ' :
x = arguments . find ( ' : ' )
jid = arguments . strip ( )
text = ' '
if x > 0 :
text = arguments [ x + 2 : ]
text = text . strip ( )
jid = arguments [ : x ]
jid = jid . strip ( )
if jid not in self . mucs . keys ( ) :
self . ircCommandERROR ( ' ' , 403 )
return
if jid == ' roster ' :
self . ircCommandERRORMUC ( 482 , ' TOPIC ON ROSTER CANNOT BE CHANGED ' , jid )
return
self . sendToXMPP ( protocol . Message ( jid ,
typ = ' groupchat ' ,
subject = text ) )
elif command == ' MODE ' :
if not arguments :
return
x = arguments . find ( ' ' )
params = ' '
jid = arguments
if x > - 1 :
jid = arguments [ : x ]
params = arguments [ x + 1 : ]
x = params . find ( ' ' )
tonick = ' '
if x > - 1 :
tonick = params [ x + 1 : ]
params = params [ x : ]
params . strip ( )
if jid == ' roster ' :
return
elif jid == self . nickname :
self . ircCommandMODE ( params )
else :
if params . find ( ' b ' ) > - 1 : # get bandlist
self . ircCommandMODEMUCBANLIST ( jid )
return
elif params . find ( ' +o ' ) > - 1 : # trying to op someone
self . xmppCommandMUCROLE ( jid , tonick , ' moderator ' )
elif params . find ( ' -o ' ) > - 1 : # trying to deop someone
self . xmppCommandMUCROLE ( jid , tonick , ' participant ' )
elif params . find ( ' +v ' ) > - 1 : # trying to voice someone
self . xmppCommandMUCROLE ( jid , tonick , ' participant ' )
elif params . find ( ' -v ' ) > - 1 : # trying to voice someone
self . xmppCommandMUCROLE ( jid , tonick , ' visitor ' )
else :
self . xmppCommandMUCMODE ( jid )
elif command == ' WHO ' :
if not arguments :
return
jid = arguments
self . xmppCommandMUCUSERS ( jid )
elif command == ' WHOIS ' :
self . ircCommandWHOIS ( JID ( arguments ) )
self . xmppCommandGETWHOIS ( JID ( arguments ) )
elif command == ' AWAY ' :
arguments = arguments [ 1 : ] # remove the :
show = ' '
if arguments != ' ' :
show = ' away '
args = arguments . split ( ' ' , 1 )
status = arguments
if args [ 0 ] . upper ( ) in STATUSSTATES :
show = args [ 0 ]
if len ( args ) == 2 :
status = args [ 1 ]
self . xmppCommandSTATUS ( show , status )
def usage ( ) :
""" Usage function for showing commandline options """
print " Usage: telepaatti [OPTION]... "
print " OPTIONS "
print " -h, --help \t telepaatti help "
print " -p, --port \t port which telepaatti listens "
print " -u, --user \t Jabber/XMPP username in the format name@xmppserver.tld "
print " -w, --password \t Password for Jabber/XMPP account "
print " -d, --debug \t turn debug messages on "
2010-05-08 08:58:18 -04:00
print " -n, --nick \t nickname to be used in MUCS "
2009-09-30 15:45:48 -04:00
def main ( ) :
""" Main function where the control flow stars """
port = 6667
user = ' '
password = ' '
debug = False
2010-05-08 08:58:18 -04:00
nickname = None
2009-09-30 15:45:48 -04:00
try :
opts , args = getopt . getopt ( sys . argv [ 1 : ] ,
2010-05-08 08:58:18 -04:00
" u:p:w:n:h:d " ,
2009-09-30 15:45:48 -04:00
[ " user= " ,
" port= " ,
" password= " ,
2010-05-08 08:58:18 -04:00
" nick= " ,
2009-09-30 15:45:48 -04:00
" help " ,
" debug " ] )
except getopt . GetoptError :
usage ( )
sys . exit ( 2 )
if len ( opts ) == 0 :
usage ( )
sys . exit ( 2 )
for o , a in opts :
if o in ( " -h " , " --help " ) :
usage ( )
sys . exit ( )
if o in ( " -p " , " --port " ) :
try :
port = int ( a )
except :
print " port should be an integer "
sys . exit ( )
if o in ( " -u " , " --user " ) :
if a . find ( ' @ ' ) < 1 :
print " user name should be in form user@xmppserver.tld "
sys . exit ( )
else :
user = a
if o in ( " -w " , " --password " ) :
password = a
if o in ( " -d " , " --debug " ) :
print " debug messages on "
debug = True
2010-05-08 08:58:18 -04:00
if o in ( " -n " , " --nick " ) :
nickname = a
2009-09-30 15:45:48 -04:00
service = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
service . bind ( ( " " , port ) )
service . listen ( 1 )
print " listening on port " , port
( clientsocket , address ) = service . accept ( )
2010-05-08 08:58:18 -04:00
ct = ClientThread ( clientsocket , port , user , password , debug , nickname )
2009-09-30 15:45:48 -04:00
ct . start ( )
service . shutdown ( socket . SHUT_RDWR )
if __name__ == " __main__ " :
main ( )