jabber-irc_0.4cvs20080505.orig/0000755000175100017510000000000010731314047014656 5ustar kalfakalfajabber-irc_0.4cvs20080505.orig/xmpp-irc0000755000175100017510000000225610064052452016346 0ustar kalfakalfa#! /bin/sh # # This file was automatically customized by debmake on Thu, 20 Feb 1997 17:33:12 +0100 # # Written by Miquel van Smoorenburg . # Modified for Debian GNU/Linux by Ian Murdock . # Modified for Debian by Christoph Lameter . # Modified for Debian GNU/Linux by Martin Schulze . PATH=/bin:/usr/bin:/sbin:/usr/sbin DAEMON=/usr/bin/python PIDFILE=/home/snake/python/xmpppy/irc-transport/irc.pid USER=snake # Arguments to atd # ARGS=/home/snake/python/xmpppy/irc-transport/irc.py test -x $DAEMON || exit 0 case "$1" in start) echo -n "Starting python-xmpp-irc transport: xmpp-irc" start-stop-daemon --start --quiet --background --pidfile $PIDFILE --user $USER --exec $DAEMON -- $ARGS echo "." ;; stop) echo -n "Stopping python-xmpp-irc transport: xmpp-irc" start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON echo "." ;; reload) echo "Not implemented." ;; force-reload|restart) sh $0 stop sh $0 start ;; *) echo "Usage: /etc/init.d/xmpp-irc {start|stop|restart|force-reload|reload}" exit 1 ;; esac exit 0 jabber-irc_0.4cvs20080505.orig/xmlconfig.py0000644000175100017510000000444610434176534017235 0ustar kalfakalfa# Copyright 2004-2005 James Bunton # Licensed for distribution under the GPL version 2, check COPYING for details from xml.dom.minidom import parse from xml.dom import Node import sys, os import config def invalidError(text): print text print "Exiting..." sys.exit(1) def importFile(configFile): # Check the file exists if not os.path.isfile(configFile): print "Configuration file not found. You need to create a config.xml file in the PyIRCt directory." sys.exit(1) # Get ourself a DOM try: root = parse(configFile) except Exception, e: invalidError("Error parsing configuration file: " + str(e)) # Store all the options in config for el in [el for el in root.firstChild.childNodes if el.nodeType == Node.ELEMENT_NODE]: try: tag = el.tagName cdatas = [x.data for x in el.childNodes if x.nodeType == Node.TEXT_NODE] cdata = str("".join(cdatas)).strip() children = [x for x in el.childNodes if x.nodeType == Node.ELEMENT_NODE] if children: # For options like user1@host.comuser2@host.com if type(getattr(config, tag)) != list: invalidError("Tag %s in your configuration file should be a list (ie, must have subtags)." % (tag)) myList = getattr(config, tag) for child in [x for x in children if x.nodeType == Node.ELEMENT_NODE]: s = child.firstChild.data myList.append(s) elif cdata: # For config options like 127.0.0.1 if type(getattr(config, tag)) != str: invalidError("Tag %s in your configuration file should not be a string (ie, no cdata)." % (tag)) setattr(config, tag, cdata) else: # For config options like t = type(getattr(config, tag)) if not (t == bool or t == int): invalidError("Tag %s in your configuration file should not be a boolean (ie, must have cdata or subtags)." % (tag)) setattr(config, tag, True) except AttributeError: print "Tag %s in your configuration file is not a defined tag. Ignoring!" % (tag) root.unlink() def importOptions(options): for o in options: if hasattr(config, o): setattr(config, o, options[o]) else: print "Option %s is not a defined option. Ignoring!" % (o) def reloadConfig(file=None, options=None): if file: importFile(file) if options: importOptions(options) jabber-irc_0.4cvs20080505.orig/config_example.xml0000644000175100017510000000620410654740351020367 0ustar kalfakalfa irc.localhost ircuser.dbm PyIRCt.pid 127.0.0.1 jabber.localhost 5347 secret ircerror.log jabber-irc_0.4cvs20080505.orig/ChangeLog0000644000175100017510000003413210731314270016431 0ustar kalfakalfa2007-12-16 01:31 normanr * irc.py: Add labels to registration fields. Fix for initial channel join user mode not setting correctly. 2007-09-26 12:12 normanr * irc.py: irclib 1.40 update 2007-09-11 14:49 normanr * irc.py: Fix for payload processing, roles and affiliations tweaked to match the latest XEP, handle disconnection better, bugfix for no messages for join-on-connect rooms. 2007-09-10 13:02 normanr * irc.py: Quick tweak to try and handle advanced channel user modes on Unreal servers 2007-09-10 12:09 normanr * irc.py: Fix for XEP-0045 compliance when sending unavailable presence (thanks to franky) 2007-08-29 11:14 normanr * adhoc.py: Fix trying to disco commands against non-server jids 2007-08-28 12:05 normanr * irc.py: Handle message with specified default normal message type 2007-07-22 02:45 normanr * adhoc.py, jep0133.py: Added service admin commands for adding and deleting users 2007-07-22 02:45 normanr * config.py, config_example.xml, irc.py: Added option to require users to register before joining a room 2007-07-22 01:27 normanr * irc.py: Suppress MOTD and RULES if they have the same hash as the last copy we saw. 2007-07-22 00:26 normanr * irc.py: Make whitespace at the start and end of line significant when creating html text for messages 2007-05-31 13:37 normanr * irc.py: Implement a very simple allowRegister. (This won't stop already registered users from registering more servers, nor will it stop unregistered users from using adhoc connections) 2007-05-19 00:07 normanr * irc.py: Turn MOTD into new-style pending operations, and display as x-html 2007-05-18 22:37 normanr * irc.py: Show irc liststart text when listing raw data 2007-05-18 22:24 normanr * irc.py: Update irc color parsing code 2007-05-13 20:03 normanr * irc.py: Added channel list via iq:search, some fixes for encoding and calling convention 2007-04-09 22:23 normanr * jep0133.py: moving admin namespace constants from jep0133 to to protocol 2007-04-09 21:23 normanr * irc.py: use namespace constant 2007-04-09 19:51 normanr * irc.py: add support for multiple pending operations with the same key. add support for disco-info for channels 2007-04-09 17:59 normanr * irc.py: Bugfix: XEP 0077 violation: IQ query jabber:iq:register MUST return node if entity is already registered 2007-03-15 22:49 normanr * config.py, config_example.xml, irc.py: Handle XCP component:accept namespace 2006-10-03 22:33 normanr * irc.py: minor 'easier to read' typographic fixes 2006-10-01 02:04 normanr * irc.py: prevent multiple timer shots caused by received data 2006-10-01 01:07 normanr * irc.py: Fix service detection for None nickmask (broken in 1.99). Refactored nm_is_service to make the outcome easier to figure out. 2006-09-26 22:56 normanr * config_example.xml: minor config typo 2006-09-26 22:20 normanr * adhoc.py, commands.py: remove horrid naming conflict 2006-09-26 22:16 normanr * irc.py: remove horrid naming conflict 2006-09-21 01:34 normanr * commands.py, irc.py: extract ad hoc commands into their own class (helps tidy up the imports) 2006-09-21 01:31 normanr * irc.py: handle /rules like /motd (unreal ircd) 2006-09-21 01:28 normanr * irc.py, irc_helpers.py: move irc_ulower to irc_helpers 2006-09-21 01:25 normanr * irc.py: make transport retry initial connection 2006-09-21 01:23 normanr * irc.py: refactor and tweak services detection 2006-09-21 01:20 normanr * irc.py: fixed sending private messages in a channel (broken in 1.93) 2006-09-11 18:35 normanr * irc.py: re-organised admin disco nodes 2006-09-11 18:09 normanr * config.py, config_example.xml, irc.py: add dumpProtocol config option 2006-08-09 16:33 normanr * irc.py: Reverted some parameter name changing 2006-08-09 16:19 normanr * irc.py: fixing some trackbacks 2006-08-09 12:39 normanr * irc.py: Make service calls directly (without privmsg) 2006-08-06 22:04 normanr * irc.py: fixed disco result with wrong jid 2006-08-06 21:53 normanr * irc.py: fixed missing config file error 2006-06-03 16:40 normanr * irc.py: cleanup some non-error exceptions 2006-06-03 16:32 normanr * irc.py: detect irc disconnection better 2006-06-03 15:53 normanr * irc.py: added support for wildfire component binding 2006-06-03 14:15 normanr * irc.py, jep0133.py: fixed command namespaces 2006-06-02 00:35 normanr * irc.py: added real jids in the admin disco 2006-05-31 01:00 normanr * irc.py: Fix KeyError on stale groupchat 2006-05-31 00:32 normanr * irc.py: minor tweaks 2006-05-30 21:55 normanr * irc.py: General cleanups 2006-05-29 18:32 normanr * irc.py, jep0133.py: added admin disco functionality to view all registered and online users 2006-05-29 17:27 normanr * irc.py, jep0133.py: fixed registered users adhoc 2006-05-22 01:53 normanr * README.txt, config.py, config_example.xml, irc.py, jep0133.py, transport.ini, xmlconfig.py: migrated to xml configuration file, and added a 'connect all users' ad hoc command 2006-05-20 02:01 normanr * irc.py: handle presence via ison polling and get initial presence for subsequent resources 2006-05-19 21:01 normanr * irc.py: tried to clean up the initial presence spam a bit 2006-05-17 12:18 normanr * irc.py: Fixed chat timeout Traceback 2006-05-16 14:13 normanr * irc.py: Fixed bad loop creating material 2006-05-16 14:00 normanr * irc.py: Another KeyError, and updated charsets 2006-05-16 13:25 normanr * irc.py: Fixed KeyError caused by unregistered presences 2006-05-15 01:48 normanr * irc.py, jep0106.py: moved jep-0106 into xmpp 2006-05-14 21:41 normanr * irc.py: removed unused old disco code 2006-05-14 21:40 normanr * irc.py: added copyright - i'm helping out too 2006-05-14 21:38 normanr * irc.py: added common version strings 2006-05-13 16:42 normanr * irc.py: initial multiresource work 2006-01-02 21:40 normanr * irc.py, transport.ini: Jabberd2 component protocol support 2005-12-26 19:17 normanr * irc.py: Fixed default charset selection if user didn't have preferences 2005-12-11 21:35 normanr * irc.py: cleaned up subscriptions 2005-12-11 20:54 normanr * irc.py: made failed connections slightly more robust. 2005-11-08 00:23 normanr * irc.py: added timestamps to tracebacks 2005-10-22 23:23 normanr * irc.py, jep0133.py: added server registrations 2005-10-01 18:37 normanr * irc.py: unicode fixes and exception cleanups 2005-09-24 01:54 normanr * irc.py: added channel jid decoding, and fixed two minor typos 2005-09-21 18:44 normanr * irc.py: general whitespace and null check cleanups 2005-09-18 00:48 normanr * irc.py: tidied up namespaces, added commands, prep for enhanced disco 2005-09-17 17:19 normanr * jep0133.py: added restart and online users commands 2005-08-23 22:51 normanr * irc.py: config and vCard updates 2005-08-21 02:20 normanr * irc.py, jep0133.py: added shutdown command, added x:data forms to registration, fixed whois info 2005-08-18 22:03 normanr * irc.py, transport.ini: Added support for non-fatal exception handling, exceptions can also be logged to file. 2005-08-13 00:25 normanr * irc.py: Many unicode/lowercase fixes. This should make life much easier in future - All 'lowercasing' is done at the unicode level now. 2005-07-27 23:53 normanr * irc.py: Unicode fix for channel name when listing from server 2005-07-14 20:26 normanr * jep0133.py: active-users and registered-users now work 2005-07-13 22:28 normanr * irc.py: nicknameinuse now delivered correctly 2005-07-13 15:34 mikealbon * jep0133.py: Dataforms now attached properly. 2005-07-13 00:37 normanr * irc.py, jep0106.py, test_jep0106.py: initial jep-0106 implementation 2005-07-13 00:32 normanr * irc.py: channel listing for connected servers via disco interface 2005-07-12 16:55 mikealbon * irc.py: Fixes to display unicode based jids. All str() functions are now replaced with JID().__str__() which returns a unicode type. 2005-07-10 20:33 normanr * irc.py: fixed CTCP VERSION reply, it now includes global version (as reported to XMPP) too. 2005-07-10 20:14 normanr * irc.py: vCard requests cause a WHOIS to be executed, the WHOIS results are returned as a vCard 2005-07-08 23:50 normanr * irc.py: added support for server password on joining first channel 2005-07-08 00:40 normanr * irc.py: Cleaned up version reporting. This should make it easier to update the version on releases too. 2005-07-08 00:19 normanr * irc.py: motd is now delivered as a single message 2005-07-08 00:01 normanr * irc.py: Various fixes: global warning at startup, version reporting under windows, swapping splits for nm_to_n, and returns for raise NodeProcessed 2005-07-07 23:34 normanr * irc.py, jep0133.py: Commands now work. Errors are also returned if continuing an invalid session. 2005-06-24 20:48 mikealbon * irc.py: Lots of Unicode fixes. 2005-05-30 16:01 mikealbon * irc.py: Normans Fake presence patch. Allows Ad-hoc from Pedrito/Psi 2005-05-29 23:32 mikealbon * irc.py: Fixes to presence types for better RFC compliance. Thanks Norman. 2005-05-28 12:01 mikealbon * irc.py: Lots of bugsquashing by Norman -- thanks 2005-05-28 11:34 mikealbon * jep0133.py: Lots of bug fixes -- thanks Norman 2005-05-24 08:57 mikealbon * irc.py: socket exception name fix 2005-05-22 09:36 mikealbon * irc.py: Cleaned up some code in the registration function (changes spotted by Norman -- thanks) 2005-04-20 23:47 mikealbon * irc.py: Fixed missed role and affilition on nick change 2005-04-14 23:48 mikealbon * irc.py: Text representation fixes and stability fixes. /n now possible in messages. 2005-03-08 01:14 mikealbon * irc.py: Oops a little bug is in there. :( -- Fixed 2005-03-08 01:01 mikealbon * irc.py: Fix for register set and whitespace. 2005-03-02 01:10 mikealbon * jep0133.py: Initial version of jep0133.py Administration module 2005-02-25 16:00 mikealbon * irc.py: Jabberd2 connection support (ejabberd also works too) Many minor cosmetic changes, and Initial user activity messages added (as a configurable option) 2004-11-13 01:09 mikealbon * irc.py: Multiple resource support, 1st version. 2004-10-29 16:20 mikealbon * irc.py: Bugfix: Don't require a resource to leave a channel. 2004-09-30 15:57 mikealbon * irc.py: Zombie connection removal (thanks to Norman Rasmussen) 2004-09-30 15:44 mikealbon * irc.py: Topic problem fixed (thanks to Norman Rasmussen) 2004-07-26 00:38 mikealbon * irc.py: Bug fixes in XHTML generator 2004-07-05 17:52 mikealbon * irc.py: Typos and other small fixes 2004-07-05 13:19 mikealbon * irc.py: Changed ban handling code to not generate an exception when the removed item not in list. Also new error code '468' added for Undernet Bad username support. 2004-06-28 10:00 mikealbon * irc.py: Minor Fixes 2004-06-19 16:41 mikealbon * irc.py: Channel redirect support. 2004-06-18 09:07 mikealbon * irc.py: Fixes for registration on python2.1, uses codecs.lookup() now. 2004-06-16 16:11 snakeru * xmpp-irc: VEEERY preliminary (but working) version of init.d script. 2004-06-10 12:27 mikealbon * irc.py: Update to make user based character set selection work in both directions. 2004-06-03 14:13 mikealbon * irc.py: Initial registration support. Presence and user subscriptions are not yet supported. 8bit nicknames are supported but currently not per server. 2004-05-26 13:44 mikealbon * irc.py: Bugfix: Nick change now works from XMPP side. 2004-05-26 09:15 mikealbon * irc.py: Bug fix for clients sending whitespace in message subject tags. 2004-05-20 21:33 mikealbon * README.txt: Inital Import 2004-05-20 12:35 mikealbon * IRC-Transport-Howtouse.html: Inital import of user documentation. 2004-05-20 12:34 mikealbon * irclib.py.diff: Fixed Diff to reflect current use and all cases. 2004-05-18 13:48 mikealbon * irc.py: Removed string version of namespaces and used library equivelent. Also added muc#owner form prototype, not finished. 2004-05-17 14:02 mikealbon * irc.py: socket handling on jabber disconnect and autoreconnect was not handled correctly. 2004-05-17 12:49 snakeru * irc.py: Removed string module use in honour of string's builtin methods. Optimized several conditions for speed. 2004-05-17 12:35 snakeru * irc.py: Errors processing changed to xmpp's native (IM-XMPP style). Removed all "xmpp.protocol." strings since this namespace already merged with local. 2004-05-14 22:17 mikealbon * irc.py: Guarding to subject setting. Check permission locally. 2004-05-14 15:46 mikealbon * irc.py: New channel mode handler, hopefully better than the last. Paves way to local checking for changing topic etc. 2004-05-14 13:19 mikealbon * irc.py: Preliminary support for Membership list editing, also kicking, giving and removing Chanop and voice privileges. 2004-05-13 13:18 mikealbon * irc.py: Fixed a problem with 'Nosuchchannel' 2004-05-12 16:48 mikealbon * irc.py: Changes to the API relating to type becoming typ. 2004-05-12 14:53 mikealbon * irclib.py.diff: A non-reversed version. 2004-05-12 14:45 mikealbon * irclib.py.diff: Diff against python-irclib 0.4.1-1 package to make socket disconnection handling work in error cases. 2004-05-11 16:02 mikealbon * irc.py: Added config file option for character set. All messages are encoded in that format, UTF-8 inbound is detected. 2004-05-11 15:42 mikealbon * irc.py: Minor fixes 2004-05-04 15:11 mikealbon * irc.py: Initial mode change support from IRC network. 2004-05-04 14:07 mikealbon * irc.py: Removed all traces of splitting the event.source() and used irclib's functions instead. 2004-05-04 13:27 mikealbon * irc.py: Numerous fixes. Migration away from using local functions to those provided in the library. Single threaded instead of 3 threads. UTF-8 encoding for output to ircserver. 2004-03-04 18:47 snakeru * irc.py: Several bugfixes. Do not know exactly what is what :( 2004-03-03 14:00 snakeru * irc.py, transport.ini: Initial import. jabber-irc_0.4cvs20080505.orig/irc.py0000644000175100017510000036566110731062032016020 0ustar kalfakalfa#!/usr/bin/python # $Id: irc.py,v 1.125 2007/12/15 23:31:57 normanr Exp $ version = 'CVS ' + '$Revision: 1.125 $'.split()[1] # # IRC transport # January 2004 Copyright (c) Mike Albon # 2006 Copyright (c) Norman Rasmussen # # 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 codecs, ConfigParser, md5, os, platform, re, select, shelve, signal, socket, sys, time, traceback import irclib, xmpp.client from xmpp.protocol import * from xmpp.browser import * from xmpp.jep0106 import * import config, xmlconfig from adhoc import AdHocCommands from irc_helpers import irc_ulower #Global definitions VERSTR = 'IRC Transport' socketlist = {} #each item is a tuple of 4 values, 0 == frequency in seconds, 1 == offset from 0, 2 == function, 3 == arguments timerlist = [] MALFORMED_JID=ErrorNode(ERR_JID_MALFORMED,text='Invalid room, must be in form #room%server') NODE_REGISTERED_SERVERS='registered-servers' NODE_ONLINE_SERVERS='online-servers' NODE_ONLINE_CHANNELS='online-channels' NODE_ACTIVE_CHANNELS='active-channels' NODE_ADMIN='admin' NODE_ADMIN_USERS='users' NODE_ADMIN_REGISTERED_USERS='registered-users' NODE_ADMIN_ONLINE_USERS='online-users' NODE_ADMIN_REGISTERED_SERVERS='registered-servers' NODE_ADMIN_ONLINE_SERVERS='online-servers' ## Unicode Notes # # All data between irc and jabber must be translated to and from the connection character set. # # All internal datastructures are held in UTF8 unicode objects. # This is the list of charsets that python supports. Detecting this list at runtime is really difficult, so it's hardcoded here. charsets = ['','ascii','big5','big5hkscs','cp037','cp424','cp437','cp500','cp737','cp775','cp850','cp852','cp855','cp856','cp857','cp860','cp861','cp862','cp863','cp864','cp865','cp866','cp869','cp874','cp875','cp932','cp949','cp950','cp1006','cp1026','cp1140','cp1250','cp1251','cp1252','cp1253','cp1254','cp1255','cp1256','cp1257','cp1258','euc-jp','euc-jis-2004','euc-jisx0213','euc-kr','gb2312','gbk','gb18030','hz','iso2022-jp','iso2022-jp-1','iso2022-jp-2','iso2022-jp-2004','iso2022-jp-3','iso2022-jp-ext','iso2022-kr','latin-1','iso8859-1','iso8859-2','iso8859-3','iso8859-4','iso8859-5','iso8859-6','iso8859-7','iso8859-8','iso8859-9','iso8859-10','iso8859-13','iso8859-14','iso8859-15','johab','koi8-r','koi8-u','mac-cyrillic','mac-greek','mac-iceland','mac-latin2','mac-roman','mac-turkish','ptcp154','shift-jis','shift-jis-2004','shift-jisx0213','utf-16','utf-16-be','utf-16-le','utf-7','utf-8'] nonbreakingre1 = re.compile(u'(.) (?=(?: )*$)') # any char followed by a space (and followed by an even number of spaces and then the end of the string) nonbreakingre2 = re.compile(u'(^| ) ') # start of string, or any two spaces irccolour = ['#FFFFFF','#000000','#0000FF','#00FF00','#FF0000','#F08000','#8000FF','#FFF000','#FFFF00','#80FF00','#00FF80','#00FFFF','#0080FF','#FF80FF','#808080','#A0A0A0'] def colourparse(str,charset): # Each tuple consists of String, foreground, background, bold, underline, italic. #str = str.replace('/','//') foreground=None background=None bold=None underline=None italic=None s = '' html=[] hs = '' ctrseq=None ctrfor=None #Has forground been processed? for e in str: if ctrseq == True: if e.isdigit(): if not ctrfor: if not foreground: foreground = '' if len(foreground) < 2: foreground += e else: ctrseq=None else: if not background: background = '' if len(background) < 2: background += e else: ctrseq=None ctrfor=None elif e == ',': ctrfor=True background = None else: if not foreground and not ctrfor: background = None ctrfor = None ctrseq = None if ctrseq == True: pass elif e == '\x02': # Bold html.append((hs,foreground,background,bold,underline,italic)) if bold == True: bold = None else: bold = True hs = '' elif e == '\x12': # Reverse if config.dumpProtocol: print 'Reverse' elif e == '\x16' or e == '\x1d': # Deprecated Italic or Italic html.append((hs,foreground,background,bold,underline,italic)) if italic == True: italic = None else: italic = True hs = '' elif e == '\x1f': # Underline html.append((hs,foreground,background,bold,underline,italic)) if underline == True: underline = None else: underline = True hs = '' elif e == '\x03': # Colour Code html.append((hs,foreground,background,bold,underline,italic)) foreground = None if not ctrseq: ctrseq = True hs = '' elif e == '\x0f': # Normal html.append((hs,foreground,background,bold,underline,italic)) foreground = None background = None bold = None underline = None hs = '' elif e in ['\x00', '\x01', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0b', '\x0c', '\x0d', '\x0e']: if config.dumpProtocol: print 'Odd Escape' elif e in ['\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1e']: if config.dumpProtocol: print 'Other Escape' elif e == '\x0a': # New line html.append((hs,foreground,background,bold,underline,italic)) html.append(('\x0a',None,None,None,None,None)) s = '%s%s'%(s,e) hs = '' else: s = '%s%s'%(s,e) hs = '%s%s'%(hs,e) html.append((hs,foreground,background,bold,underline,italic)) chtml = [] try: s = unicode(s,'utf8','strict') # Language detection stuff should go here. for each in html: chtml.append((nonbreakingre2.sub(u'\\1\xa0', nonbreakingre1.sub(u'\\1\xa0', unicode(each[0],'utf-8','strict'))),each[1],each[2],each[3],each[4],each[5])) except UnicodeDecodeError: s = unicode(s,charset,'replace') for each in html: chtml.append((nonbreakingre2.sub(u'\\1\xa0', nonbreakingre1.sub(u'\\1\xa0', unicode(each[0],charset,'replace'))),each[1],each[2],each[3],each[4],each[5])) 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') #if config.dumpProtocol: print chtml for each in chtml: style = '' if each[1] != None and int(each[1])<16: foreground = irccolour[int(each[1])] #if config.dumpProtocol: 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[5]: style = '%sfont-style:italic;'%style if each[0] != '': if each[0] == '\x0a': xhtml.addChild('br') elif style == '': xhtml.addData(each[0]) else: xhtml.addChild(name = 'span', attrs = {'style':style},payload=each[0]) else: html = '' return s,html def pendingop_push(conn, op, callback, data): if not conn.pendingoperations.has_key(op): conn.pendingoperations[op]=[] conn.pendingoperations[op].append((op, callback, data)) conn.allpendingoperations.append((op, callback, data)) if config.dumpProtocol: print 'pendingoperations:',repr(conn.pendingoperations),'\nallpendingoperations:',repr(conn.allpendingoperations) def pendingop_call(conn, op, event): #if config.dumpProtocol: print 'pendingoperations:',repr(conn.pendingoperations),'\nallpendingoperations:',repr(conn.allpendingoperations) if conn.pendingoperations.has_key(op): info = conn.pendingoperations[op][0] return info[1](conn,event,op,info[2]) return None def pendingop_pop(conn, op): if conn.pendingoperations.has_key(op): info = conn.pendingoperations[op].pop(0) if conn.pendingoperations[op] == []: del conn.pendingoperations[op] conn.allpendingoperations.remove(info) if config.dumpProtocol: print 'pendingoperations:',repr(conn.pendingoperations),'\nallpendingoperations:',repr(conn.allpendingoperations) return info[2] if config.dumpProtocol: print 'pendingoperations:',repr(conn.pendingoperations),'\nallpendingoperations:',repr(conn.allpendingoperations) def pendingop_fail(conn, event): if conn.allpendingoperations == []: return None info = conn.allpendingoperations[0] pendingop_pop(conn, info[0]) if config.dumpProtocol: print 'pendingoperation',info[0],'failed!' return info[1](conn,event,'fail',info[2]) class Transport: # This class is the main collection of where all the handlers for both the IRC and Jabber #Global structures users = {} online = 1 restart = 0 offlinemsg = '' # This structure consists of each user of the transport having their own location of store. # users - hash - key is barejid, value is a hash: # - hash - key is server alias, value is irc connection object, with: # server - string # address - string # fromjid - string # joinchan - string # joinresource - string # xresources - hash - key is resource, value is tuple of: show, priority, status, login time # channels - hash - key is channel name, value is channel object: # private - bool # secret - bool # invite - bool # topic - bool # notmember - bool # moderated - bool # banlist - list # limit - number # key - string # currenttopic - string # members - hash - key is nick of member, value is hash, key is 'affiliation', 'role', 'jid', 'nick' # resources - hash - key is resource, value is tuple of: show, priority, status, login time # pendingoperations - hash - key is internal name of operation, joined with nick if applicable, value a list of tuples of (op,callback,data) # op - string # callback - function # data - generally an xmpp message to send on completion # allpendingoperations- list - list of tuples of all pending operations # activechats - hash - key is nick, value is list of: irc jid, xmpp jid, last message time, capabilities # charset - string # Parameter order. Connection then options. def __init__(self,jabber,irc): self.jabber = jabber self.irc = irc def register_handlers(self): # http://www.alien.net.au/irc/irc2numerics.html self.irc.add_global_handler('motd',self.irc_motd) self.irc.add_global_handler('motdstart',self.irc_motdstart) self.irc.add_global_handler('endofmotd',self.irc_endofmotd) self.irc.add_global_handler('endofservices',self.irc_motd) self.irc.add_global_handler('308',self.irc_motdstart) self.irc.add_global_handler('309',self.irc_endofmotd) 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('ctcpreply',self.irc_ctcpreply) 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_mode) self.irc.add_global_handler('channelmodeis',self.irc_channelmodeis) self.irc.add_global_handler('error',self.irc_error) self.irc.add_global_handler('topic',self.irc_topic) # irclib < 1.40 self.irc.add_global_handler('currenttopic',self.irc_topic) # irclib >= 1.40 self.irc.add_global_handler('away',self.irc_away) self.irc.add_global_handler('nowaway',self.irc_nowaway) self.irc.add_global_handler('unaway',self.irc_unaway) 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('nochanmodes',self.irc_notregistered) self.irc.add_global_handler('379',self.irc_redirect) self.irc.add_global_handler('featurelist',self.irc_featurelist) self.irc.add_global_handler('ison',self.irc_ison) self.irc.add_global_handler('welcome',self.irc_welcome) self.irc.add_global_handler('disconnect',self.irc_disconnected) self.irc.add_global_handler('600',self.irc_watchonline) self.irc.add_global_handler('604',self.irc_watchonline) self.irc.add_global_handler('601',self.irc_watchoffline) self.irc.add_global_handler('605',self.irc_watchoffline) self.irc.add_global_handler('whoisuser',self.irc_whoisuser) self.irc.add_global_handler('whoisserver',self.irc_whoisserver) self.irc.add_global_handler('whoisoperator',self.irc_whoisoperator) self.irc.add_global_handler('whoisidle',self.irc_whoisidle) self.irc.add_global_handler('whoischannels',self.irc_whoischannels) self.irc.add_global_handler('endofwhois',self.irc_endofwhois) self.irc.add_global_handler('liststart',self.irc_list) self.irc.add_global_handler('list',self.irc_list) self.irc.add_global_handler('listend',self.irc_listend) self.irc.add_global_handler('tryagain',self.irc_tryagain) 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_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_mucowner_set,typ = 'set', ns=NS_MUC_OWNER) self.jabber.RegisterHandler('iq',self.xmpp_iq_mucowner_get,typ = 'get', ns=NS_MUC_OWNER) 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.jabber.RegisterHandler('iq',self.xmpp_iq_search_set,typ = 'set', ns=NS_SEARCH) self.jabber.RegisterHandler('iq',self.xmpp_iq_search_get,typ = 'get', ns=NS_SEARCH) self.jabber.RegisterHandler('iq',self.xmpp_iq_vcard,typ = 'get', ns=NS_VCARD) self.disco = Browser() self.disco.PlugIn(self.jabber) self.adhoccommands = AdHocCommands(userfile) self.adhoccommands.PlugIn(self) self.disco.setDiscoHandler(self.xmpp_base_disco,node='',jid=config.jid) self.disco.setDiscoHandler(self.xmpp_base_disco,node='',jid='') # New Disco Handlers def xmpp_base_disco(self, con, event, type): fromjid = event.getFrom().getStripped().__str__() fromstripped = event.getFrom().getStripped().encode('utf8') to = event.getTo() node = event.getQuerynode(); room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() #Type is either 'info' or 'items' if to == config.jid: if node == None: if type == 'info': features = [NS_DISCO_INFO,NS_DISCO_ITEMS,NS_VERSION,NS_COMMANDS] if not config.requireRegister or userfile.has_key(fromjid): features = [NS_MUC] + features if config.allowRegister or userfile.has_key(fromjid): features = [NS_REGISTER] + features return { 'ids':[ {'category':'conference','type':'irc','name':VERSTR}, {'category':'gateway','type':'irc','name':VERSTR}], 'features':features} if type == 'items': list = [ {'node':NODE_REGISTERED_SERVERS,'name':config.discoName + ' Registered Servers','jid':config.jid}, {'node':NODE_ONLINE_SERVERS,'name':config.discoName + ' Online Servers','jid':config.jid}] if fromjid in config.admins: list.append({'node':NODE_ADMIN,'name':config.discoName + ' Admin','jid':config.jid}) return list elif node == NODE_ADMIN: if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': if not fromjid in config.admins: return [] return [ {'node':NS_COMMANDS,'name':config.discoName + ' Commands','jid':config.jid}, {'node':NODE_ADMIN_REGISTERED_USERS,'name':config.discoName + ' Registered Users','jid':config.jid}, {'node':NODE_ADMIN_ONLINE_USERS,'name':config.discoName + ' Online Users','jid':config.jid}] elif node == NODE_REGISTERED_SERVERS: if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': list = [] servers = [] if userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers'): servers = userfile[fromstripped]['servers'] for each in servers: list.append({'name':each,'jid':'%s@%s' % (each, config.jid)}) return list elif node == NODE_ONLINE_SERVERS: if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': list = [] if self.users.has_key(fromjid): for each in self.users[fromjid].keys(): list.append({'name':each,'jid':'%s@%s' % (each, config.jid)}) return list elif node == NODE_ADMIN_REGISTERED_USERS: if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': if not fromjid in config.admins: return [] list = [] for each in userfile.keys(): list.append({'node':'/'.join([NODE_ADMIN_USERS, each]),'name':each,'jid':config.jid}) return list elif node == NODE_ADMIN_ONLINE_USERS: if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': if not fromjid in config.admins: return [] list = [] for each in self.users.keys(): list.append({'node':'/'.join([NODE_ADMIN_USERS, each]),'name':each,'jid':config.jid}) return list elif node.startswith(NODE_ADMIN_USERS): if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': if not fromjid in config.admins: return [] nodeinfo = node.split('/') list = [] if len(nodeinfo) == 2: fromjid = nodeinfo[1] list = [ {'name':fromjid + ' JID','jid':fromjid}, {'node':'/'.join([NODE_ADMIN_USERS, fromjid, NODE_ADMIN_REGISTERED_SERVERS]),'name':fromjid + ' Registered Servers','jid':config.jid}, {'node':'/'.join([NODE_ADMIN_USERS, fromjid, NODE_ADMIN_ONLINE_SERVERS]),'name':fromjid + ' Online Servers','jid':config.jid}] elif len(nodeinfo) == 3: fromjid = nodeinfo[1] fromstripped = fromjid.encode('utf8') node = nodeinfo[2] if node == NODE_ADMIN_REGISTERED_SERVERS: servers = [] if userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers'): servers = userfile[fromstripped]['servers'] for each in servers: address = each if servers[each]['address']: address = servers[each]['address'] nick = '' if servers[each]['nick']: nick = servers[each]['nick'] list.append({'node':'/'.join([NODE_ADMIN_USERS, fromjid, NODE_ADMIN_REGISTERED_SERVERS, each]),'name':'%s/%s'%(address,nick),'jid':config.jid}) elif node == NODE_ADMIN_ONLINE_SERVERS: if self.users.has_key(fromjid): for each in self.users[fromjid].keys(): conn = self.users[fromjid][each] list.append({'node':'/'.join([NODE_ADMIN_USERS, fromjid, NODE_ADMIN_ONLINE_SERVERS, each]),'name':'%s:%s/%s'%(conn.address,conn.port,conn.nickname),'jid':config.jid}) return list else: self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed elif channel == '': if node == None: if type == 'info': return { 'ids':[ {'category':'conference','type':'irc','name':server}, {'category':'gateway','type':'irc','name':server}], 'features':[NS_DISCO_INFO,NS_DISCO_ITEMS,NS_REGISTER,NS_VERSION,NS_MUC,NS_COMMANDS,NS_SEARCH]} if type == 'items': list = [{'node':NS_COMMANDS,'name':'%s Commands'%server,'jid':'%s@%s' % (server, config.jid)}] if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): list.append({'node':NODE_ONLINE_CHANNELS,'name':'%s Online Channels'%server,'jid':'%s@%s' % (server, config.jid)}) list.append({'node':NODE_ACTIVE_CHANNELS,'name':'%s Active Channels'%server,'jid':'%s@%s' % (server, config.jid)}) return list elif node == NODE_ONLINE_CHANNELS: if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': rep=event.buildReply('result') rep.setQuerynode(node) conn = self.users[fromjid][server] pendingop_push(conn, 'list', self.irc_list_items, rep) conn.list() raise NodeProcessed self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) raise NodeProcessed elif node == NODE_ACTIVE_CHANNELS: if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): if type == 'info': return {'ids':[],'features':[NS_DISCO_ITEMS]} if type == 'items': list = [] if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): for each in self.users[fromjid][server].channels.keys(): list.append({'name':each,'jid':'%s%%%s@%s' % (JIDEncode(each), server, config.jid)}) return list self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) raise NodeProcessed else: self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed elif irclib.is_channel(channel): if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): if type == 'info': rep=event.buildReply('result') q=rep.getTag('query') q.addChild('feature',{'var':NS_DISCO_INFO}) q.addChild('feature',{'var':NS_MUC}) conn = self.users[fromjid][server] pendingop_push(conn, 'list', self.irc_list_info, rep) conn.list([channel.encode(conn.charset,'replace')]) raise NodeProcessed if type == 'items': return [] self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) raise NodeProcessed else: self.jabber.send(Error(event,MALFORMED_JID)) raise NodeProcessed #XMPP Handlers def xmpp_presence(self, con, event): # Add ACL support fromjid = event.getFrom() fromstripped = fromjid.getStripped().encode('utf8') type = event.getType() #if type == None: type = 'available' to = event.getTo() status = event.getStatus() room = irc_ulower(to.getNode()) nick = to.getResource() try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() x = event.getTag(name='x', namespace=NS_MUC) try: password = x.getTagData('password') except AttributeError: password = None sys.exc_clear() if to == config.jid or channel == '': conf = None if userfile.has_key(fromstripped): if to == config.jid: conf = userfile[fromstripped] elif server \ and userfile[fromstripped].has_key('servers') \ and userfile[fromstripped]['servers'].has_key(server): conf = userfile[fromstripped]['servers'][server] if not conf: if type != 'unsubscribed' and type != 'error': self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribe')) self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribed')) if type != 'unsubscribe': self.jabber.send(Error(event,ERR_BAD_REQUEST)) return if type == 'subscribe': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'subscribe')) conf['usubscribed']=True elif type == 'subscribed': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'subscribed')) conf['subscribed']=True elif type == 'unsubscribe': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'unsubscribe')) conf['usubscribed']=False elif type == 'unsubscribed': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'unsubscribed')) conf['subscribed']=False # #Add code so people can see transport presence here # elif type == 'probe': self.jabber.send(Presence(to=fromjid, frm = to)) elif type == 'error': return elif type == 'unavailable': #call self.irc_disconnect to disconnect from the server #when you see the user's presence become unavailable if server: if config.dumpProtocol: print 'disconnect %s'%repr(server) self.irc_disconnect('',server,fromjid,status) self.xmpp_presence_do_update(event,server,fromstripped) else: self.jabber.send(Presence(to=fromjid, frm = to, typ = 'unavailable')) if config.dumpProtocol: print 'disconnect all' if self.users.has_key(fromjid.getStripped()): for each in self.users[fromjid.getStripped()].keys(): self.irc_disconnect('',each,fromjid,status) else: #call self.irc_connect to connect to the server #when you see the user's presence become available if server: if config.dumpProtocol: print 'connect %s'%repr(server) self.irc_connect('',server,nick,password,fromjid,event) self.xmpp_presence_do_update(event,server,fromstripped) else: if not self.users.has_key(fromjid.getStripped()): self.users[fromjid.getStripped()] = {} self.jabber.send(Presence(to=fromjid, frm = to)) if userfile.has_key(fromstripped): if to == config.jid: userfile[fromstripped] = conf else: user = userfile[fromstripped] user['servers'][server] = conf userfile[fromstripped] = user userfile.sync() elif irclib.is_channel(channel): if type == None: if nick != '': self.irc_connect(channel,server,nick,password,fromjid,event) self.xmpp_presence_do_update(event,server,fromstripped) elif type == 'unavailable': self.irc_disconnect(channel,server,fromjid,status) self.xmpp_presence_do_update(event,server,fromstripped) elif type == 'error': return else: self.jabber.send(Error(event,ERR_FEATURE_NOT_IMPLEMENTED)) else: nick = channel conf = None if server \ and userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers') \ and userfile[fromstripped]['servers'].has_key(server): conf = userfile[fromstripped]['servers'][server] if not conf: if type != 'unsubscribed' and type != 'error': self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribe')) self.jabber.send(Presence(to=fromjid, frm=to, typ = 'unsubscribed')) if type != 'unsubscribe': self.jabber.send(Error(event,ERR_BAD_REQUEST)) return subscriptions = [] if conf.has_key('subscriptions'): subscriptions = conf['subscriptions'] if type == 'subscribe': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'subscribed')) if not nick in subscriptions: subscriptions.append(nick) if self.users.has_key(fromjid.getStripped()) \ and self.users[fromjid.getStripped()].has_key(server) \ and self.users[fromjid.getStripped()][server].features.has_key('WATCH'): conn = self.users[fromjid.getStripped()][server] conn.send_raw('WATCH +%s' % nick.encode(conn.charset,'replace')) elif type == 'unsubscribe' or type == 'unsubscribed': self.jabber.send(Presence(to=fromjid, frm = to, typ = 'unsubscribed')) if nick in subscriptions: subscriptions.remove(nick) if self.users.has_key(fromjid.getStripped()) \ and self.users[fromjid.getStripped()].has_key(server) \ and self.users[fromjid.getStripped()][server].features.has_key('WATCH'): conn = self.users[fromjid.getStripped()][server] conn.send_raw('WATCH -%s' % nick.encode(conn.charset,'replace')) conf['subscriptions'] = subscriptions user = userfile[fromstripped] user['servers'][server] = conf userfile[fromstripped] = user userfile.sync() if (type == 'subscribe' or type == 'unsubscribe' or type == 'unsubscribed') \ and self.users.has_key(fromjid.getStripped()) \ and self.users[fromjid.getStripped()].has_key(server): if not self.users[fromjid.getStripped()][server].features.has_key('WATCH'): self.irc_doison(self.users[fromjid.getStripped()][server],1) def xmpp_presence_do_update(self,event,server,fromjid): if fromjid not in self.users.keys() or \ server not in self.users[fromjid].keys(): return conn = self.users[fromjid][server] resources = [] for resource in conn.xresources.keys(): resources.append((resource,conn.xresources[resource])) for channel in conn.channels.keys(): for resource in conn.channels[channel].resources.keys(): resources.append((resource,conn.channels[channel].resources[resource])) age = None priority = None resource = None for each in resources: if each[1][1]>priority: #if priority is higher then take the highest age = each[1][3] priority = each[1][1] resource = each[0] elif each[1][1]==priority: #if priority is the same then take the oldest if each[1][3] 1: self.irc_sendctcp('CAPABILITIES',conn,nick,'') if not channel and nick == to.getResource(): conn.send_raw('%s %s' % (nick.upper().encode(conn.charset,'replace'),event.getBody().encode(conn.charset,'replace'))) elif event.getBody()[0:3] == '/me': self.irc_sendctcp('ACTION',conn,nick,event.getBody()[4:]) else: self.irc_sendroom(conn,nick,event.getBody()) else: self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) def xmpp_iq_vcard(self, con, event): fromjid = event.getFrom().getStripped() to = event.getTo() room = irc_ulower(to.getNode()) id = event.getID() # need to store this ID somewhere for the return trip try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if not self.users.has_key(fromjid): self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) # another candidate: ERR_SUBSCRIPTION_REQUIRED raise xmpp.NodeProcessed 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) raise xmpp.NodeProcessed conn = self.users[fromjid][server] nick = None if channel and not irclib.is_channel(channel): # ARGH! need to know channel to find out nick. :( nick = channel else: nick = to.getResource() m = Iq(to=event.getFrom(),frm=to, typ='result') m.setID(id) p = m.addChild(name='vCard', namespace=NS_VCARD) p.setTagData(tag='DESC', val='Additional Information:') conn.pendingoperations["whois:" + irc_ulower(nick)] = m conn.whois([(nick + ' ' + nick).encode(conn.charset,'replace')]) raise xmpp.NodeProcessed def xmpp_iq_version(self, con, event): # TODO: maybe real version requests via irc? - or maybe via ad hoc? fromjid = event.getFrom() to = event.getTo() id = event.getID() uname = platform.uname() m = Iq(to = fromjid, frm = to, typ = 'result', queryNS=NS_VERSION, payload=[Node('name',payload=VERSTR), Node('version',payload=version),Node('os',payload=('%s %s %s' % (uname[0],uname[2],uname[4])).strip())]) m.setID(id) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_mucadmin_get(self, con, event): fromjid = event.getFrom().getStripped() to = event.getTo() room = irc_ulower(to.getNode()) id = event.getID() try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) raise xmpp.NodeProcessed if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].channels.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise xmpp.NodeProcessed conn = self.users[fromjid][server] ns = event.getQueryNS() t = event.getQueryChildren() 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=event.getFrom(), frm=to, typ='result', queryNS=ns) m.setID(id) payload = [] for each in conn.channels[channel].members: if role != None: if conn.channels[channel].members[each]['role'] == role: zattr = conn.channels[channel].members[each] zattr['nick'] = each payload.append(Node('item',attrs = zattr)) if affiliation != None: if conn.channels[channel].members[each]['affiliation'] == affiliation: zattr = conn.channels[channel].members[each] zattr['nick'] = each payload.append(Node('item',attrs = zattr)) m.setQueryPayload(payload) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_mucadmin_set(self, con, event): fromjid = event.getFrom().getStripped() to = event.getTo() room = irc_ulower(to.getNode()) id = event.getID() try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) raise xmpp.NodeProcessed if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].channels.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise xmpp.NodeProcessed conn = self.users[fromjid][server] ns = event.getQueryNS() t = event.getQueryChildren() if conn.nickname not in conn.channels[channel].members.keys() \ or conn.channels[channel].members[conn.nickname]['role'] != 'moderator' \ or conn.channels[channel].members[conn.nickname]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) raise xmpp.NodeProcessed for each in t: if t[0].getName() == 'item': attr = t[0].getAttrs() if attr.has_key('role'): if attr['role'] == 'moderator': conn.mode(channel,'%s %s'%('-v',attr['nick'])) conn.mode(channel,'%s %s'%('+o',attr['nick'])) raise xmpp.NodeProcessed elif attr['role'] == 'participant': conn.mode(channel,'%s %s'%('-o',attr['nick'])) conn.mode(channel,'%s %s'%('+v',attr['nick'])) raise xmpp.NodeProcessed elif attr['role'] == 'visitor': conn.mode(channel,'%s %s'%('-v',attr['nick'])) conn.mode(channel,'%s %s'%('-o',attr['nick'])) raise xmpp.NodeProcessed elif attr['role'] == 'none': # TODO: Need to add reason gathering conn.kick(channel,attr['nick'],'Kicked') raise xmpp.NodeProcessed if attr.has_key('affiliation'): nick, room = attr['jid'].split('%',1) if attr['affiliation'] == 'member': # TODO: add invite raise xmpp.NodeProcessed elif attr['affiliation'] == 'none': # TODO: delete invite # TODO: delete ban raise xmpp.NodeProcessed elif attr['affiliation'] == 'outcast': # TODO: add ban conn.kick(channel,nick,'Kicked and banned') raise xmpp.NodeProcessed def xmpp_iq_mucowner_get(self, con, event): fromjid = event.getFrom().getStripped() to = event.getTo() room = irc_ulower(to.getNode()) id = event.getID() try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) raise xmpp.NodeProcessed if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].channels.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise xmpp.NodeProcessed conn = self.users[fromjid][server] ns = event.getQueryNS() if conn.nickname not in conn.channels[channel].members.keys() \ or conn.channels[channel].members[conn.nickname]['role'] != 'moderator' \ or conn.channels[channel].members[conn.nickname]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) raise xmpp.NodeProcessed chan = conn.channels[channel] datafrm = DataForm(typ='form',data=[ DataField(desc='Private' ,name='private' ,value=chan.private ,typ='boolean'), DataField(desc='Secret' ,name='secret' ,value=chan.secret ,typ='boolean'), DataField(desc='Invite Only' ,name='invite' ,value=chan.invite ,typ='boolean'), DataField(desc='Only ops can change the Topic' ,name='topic' ,value=chan.topic ,typ='boolean'), DataField(desc='No external channel messages' ,name='notmember' ,value=chan.notmember ,typ='boolean'), DataField(desc='Moderated Channel' ,name='moderated' ,value=chan.moderated ,typ='boolean'), DataField(desc='Ban List' ,name='banlist' ,value=chan.banlist ,typ='text-multi'), DataField(desc='Channel Limit' ,name='limit' ,value=chan.limit ,typ='text-single'), DataField(desc='Channel Key' ,name='key' ,value=chan.key ,typ='text-single')]) datafrm.setInstructions('Configure the room') m = Iq(frm = to, to = event.getFrom(), typ='result', queryNS=ns) m.setID(id) m.setQueryPayload([datafrm]) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_mucowner_set(self, con, event): fromjid = event.getFrom().getStripped() to = event.getTo() room = irc_ulower(to.getNode()) id = event.getID() try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: self.jabber.send(Error(event,MALFORMED_JID)) raise xmpp.NodeProcessed if fromjid not in self.users.keys() \ or server not in self.users[fromjid].keys() \ or channel not in self.users[fromjid][server].channels.keys(): self.jabber.send(Error(event,ERR_ITEM_NOT_FOUND)) raise xmpp.NodeProcessed conn = self.users[fromjid][server] ns = event.getQueryNS() t = event.getQueryChildren() if conn.nickname not in conn.channels[channel].members.keys() \ or conn.channels[channel].members[conn.nickname]['role'] != 'moderator' \ or conn.channels[channel].members[conn.nickname]['affiliation'] != 'owner': self.jabber.send(Error(event,ERR_FORBIDDEN)) raise xmpp.NodeProcessed for each in t: datafrm = DataForm(node=each).asDict() for each in datafrm.keys(): if config.dumpProtocol: print '%s:%s'%(repr(each),repr(datafrm[each])) fieldValue = False if type(datafrm[each]) in [type(''),type(u'')] and (datafrm[each] == '1' or datafrm[each].lower() == 'true'): fieldValue = True handled = False if fieldValue: typ='+' else: typ='-' if each == 'private': cmd = 'p' 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': handled = True for item in datafrm[each]: if item not in conn.channels[channel].banlist: conn.mode(channel,'+b %s' % item) for item in conn.channels[channel].banlist: if item not in datafrm[each]: conn.mode(channel,'-b %s' % item) elif each == 'limit': fieldValue = datafrm[each] if datafrm[each]: typ='+' cmd='l %s' % datafrm[each] else: typ='-' cmd='l' elif each == 'key': fieldValue = datafrm[each] if datafrm[each]: typ='+' cmd='k %s' % datafrm[each] else: typ='-' cmd='k %s' % conn.channels[channel].key if not handled and fieldValue != getattr(conn.channels[channel], each): conn.mode(channel,'%s%s' % (typ,cmd)) m = Iq(frm = to, to = event.getFrom(), typ='result', queryNS=ns) m.setID(id) self.jabber.send(m) raise xmpp.NodeProcessed # Registration code def xmpp_iq_register_get(self, con, event): charset = config.charset fromjid = event.getFrom().getStripped().encode('utf8') to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if not channel == '': self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed instructionText = 'Please provide your IRC connection information, along with the charset to use. (eg cp437, cp1250, iso-8859-1, koi8-r)' queryPayload = [Node('instructions', payload = instructionText)] serverdetails = {'address':'','nick':'','password':'','realname':'','username':''} if userfile.has_key(fromjid): if userfile[fromjid].has_key('charset'): charset = userfile[fromjid]['charset'] if not server == '' and userfile[fromjid].has_key('servers'): servers = userfile[fromjid]['servers'] if servers.has_key(server): serverdetails = servers[server] charset = serverdetails['charset'] queryPayload += [Node('registered')] else: if not config.allowRegister: return if server: nametype='hidden' else: nametype='text-single' form = DataForm(typ='form',data=[ DataField(desc='Character set',name='charset',label='Charset', value=charset,typ='list-single',options=((x,x) for x in charsets)), DataField(desc='Server alias used for jids',name='alias',label='Server alias', value=server,typ=nametype), DataField(desc='Server to connect to',name='address',label='Address', value=serverdetails['address'],typ='text-single'), DataField(desc='Familiar name of the user',name='nick',label='Nickname', value=serverdetails['nick'],typ='text-single'), DataField(desc='Password or secret for the user',name='password',label='Password', value=serverdetails['password'],typ='text-private'), DataField(desc='Full name of the user',name='name',label='Full name', value=serverdetails['realname'],typ='text-single'), DataField(desc='Account name associated with the user (ident)',name='username',label='Account name', value=serverdetails['username'],typ='text-single')]) form.setInstructions(instructionText) queryPayload += [ Node('charset' ,payload=charset), Node('address' ,payload=serverdetails['address']), Node('nick' ,payload=serverdetails['nick']), Node('password' ,payload=serverdetails['password']), Node('name' ,payload=serverdetails['realname']), Node('username' ,payload=serverdetails['username']), form] m = event.buildReply('result') m.setQueryNS(NS_REGISTER) m.setQueryPayload(queryPayload) self.jabber.send(m) raise xmpp.NodeProcessed def xmpp_iq_register_set(self, con, event): remove = False fromjid = event.getFrom().getStripped().encode('utf8') ucharset = config.charset to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if not channel == '': self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed serverdetails = {} query = event.getTag('query') if query.getTag('remove'): remove = True elif query.getTag(name='x',namespace=NS_DATA): form = DataForm(node=query.getTag(name='x',namespace=NS_DATA)) if form.getField('charset'): ucharset = form.getField('charset').getValue() else: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if form.getField('address'): if not server and form.getField('alias'): server = form.getField('alias').getValue() if not server: server = form.getField('address').getValue().split(':',1)[0] serverdetails['address'] = form.getField('address').getValue() serverdetails['charset'] = ucharset if form.getField('nick'): serverdetails['nick'] = form.getField('nick').getValue() if form.getField('password'): serverdetails['password'] = form.getField('password').getValue() if form.getField('name'): serverdetails['realname'] = form.getField('name').getValue() if form.getField('username'): serverdetails['username'] = form.getField('username').getValue() elif query.getTag('charset'): ucharset = query.getTagData('charset') if query.getTag('address'): if not server: server = query.getTagData('address').split(':',1)[0] serverdetails['address'] = query.getTagData('address') serverdetails['charset'] = ucharset if query.getTag('nick'): serverdetails['nick'] = query.getTagData('nick') if query.getTag('password'): serverdetails['password'] = query.getTagData('password') if query.getTag('name'): serverdetails['realname'] = query.getTagData('name') if query.getTag('username'): serverdetails['username'] = query.getTagData('username') else: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if not remove: if userfile.has_key(fromjid): conf = userfile[fromjid] else: if not config.allowRegister: return conf = {} try: codecs.lookup(ucharset) except LookupError: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed except ValueError: self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if server == '': conf['charset']=ucharset if not conf.has_key('subscribed'): self.jabber.send(Presence(typ='subscribe',to=fromjid, frm=to)) else: servers = {} if conf.has_key('servers'): servers = conf['servers'] if irc_ulower(to.getNode()) == '' and servers.has_key(server): self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if not serverdetails.has_key('nick') or serverdetails['nick'] == '': self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if not conf.has_key('charset'): conf['charset']=ucharset if not serverdetails.has_key('subscribed'): self.jabber.send(Presence(typ='subscribe',to=fromjid, frm='%s@%s'%(server,config.jid))) servers[server] = serverdetails conf['servers'] = servers userfile[fromjid]=conf self.jabber.send(Presence(to=event.getFrom(), frm = to)) self.jabber.send(event.buildReply('result')) else: if userfile.has_key(fromjid): conf = userfile[fromjid] else: conf = {} if server == '': if conf.has_key('servers'): servers = conf['servers'] for server in servers: m = Presence(to = fromjid, frm = '%s@%s'%(server,config.jid), typ = 'unsubscribe') self.jabber.send(m) m = Presence(to = fromjid, frm = '%s@%s'%(server,config.jid), typ = 'unsubscribed') self.jabber.send(m) if userfile.has_key(fromjid): del userfile[fromjid] else: servers = {} if conf.has_key('servers'): servers = conf['servers'] if not servers.has_key(server): self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed del servers[server] conf['servers'] = servers userfile[fromjid]=conf m = Presence(to = fromjid, frm = to, typ = 'unsubscribe') self.jabber.send(m) m = Presence(to = fromjid, frm = to, typ = 'unsubscribed') self.jabber.send(m) self.jabber.send(event.buildReply('result')) userfile.sync() raise xmpp.NodeProcessed def xmpp_iq_search_get(self, con, event): charset = config.charset fromjid = event.getFrom().getStripped().encode('utf8') to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if not server or not channel == '': self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): instructionText = 'Fill in the form to search for any matching room (Add * to the end of field to match substring)' queryPayload = [Node('instructions', payload = instructionText)] form = DataForm(typ='form',data=[ DataField(desc='Name of the channel',name='name',typ='text-single')]) form.setInstructions(instructionText) queryPayload += [ Node('name'), form] m = event.buildReply('result') m.setQueryNS(NS_SEARCH) m.setQueryPayload(queryPayload) self.jabber.send(m) raise xmpp.NodeProcessed self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) raise NodeProcessed def xmpp_iq_search_set(self, con, event): charset = config.charset fromjid = event.getFrom().getStripped().encode('utf8') to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if not channel == '': self.jabber.send(Error(event,ERR_NOT_ACCEPTABLE)) raise xmpp.NodeProcessed query = event.getTag('query') if query.getTag(name='x',namespace=NS_DATA): form = DataForm(node=query.getTag(name='x',namespace=NS_DATA)) if form.getField('name'): name = form.getField('name').getValue() elif query.getTag('name'): name = query.getTagData('name') if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): rep=event.buildReply('result') q=rep.getTag('query') reported = Node('reported',payload=[ DataField(label='JID' ,name='jid' ,typ='jid-single'), DataField(label='Channel' ,name='name' ,typ='text-single'), DataField(label='Subject' ,name='muc#roominfo_subject' ,typ='text-single'), DataField(label='Number of occupants',name='muc#roominfo_occupants',typ='text-single')]) form = DataForm(typ='result') form.setPayload([reported]) q.addChild(node=form) conn = self.users[fromjid][server] pendingop_push(conn, 'list', self.irc_list_search, rep) conn.list([name.encode(conn.charset,'replace')]) raise NodeProcessed self.jabber.send(Error(event,ERR_REGISTRATION_REQUIRED)) raise NodeProcessed #IRC methods def irc_doquit(self,conn,message=None): server = conn.server nickname = conn.nickname if conn.isontimer in timerlist: timerlist.remove(conn.isontimer) if self.jabber.isConnected(): for channel in conn.channels.keys(): name = '%s%%%s' % (channel, conn.server) if config.activityMessages == True: for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource), typ='groupchat',frm='%s@%s' % (name, config.jid), body='QUIT: %s' % message) self.jabber.send(m) m = Presence(to=conn.fromjid, typ = 'unavailable', frm='%s%%%s@%s/%s' %(channel,conn.server,config.jid,conn.nickname)) t=m.addChild(name='x',namespace=NS_MUC_USER) t.addChild(name='item',attrs={'affiliation':'none','role':'none'}) t.addChild(name='status', attrs={'code':'110'}) self.jabber.send(m) fromstripped = conn.fromjid.encode('utf8') if userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers') \ and userfile[fromstripped]['servers'].has_key(conn.server): conf = userfile[fromstripped]['servers'][conn.server] if conf.has_key('subscriptions'): subscriptions = conf['subscriptions'] for nick in subscriptions: self.jabber.send(Presence(to=conn.fromjid, frm = '%s%%%s@%s' % (nick, conn.server, config.jid), typ = 'unavailable')) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' % (conn.server, config.jid), typ = 'unavailable')) if self.users[conn.fromjid].has_key(server): del self.users[conn.fromjid][server] conn.disconnected = True try: conn.quit(message) except: pass conn.close() def irc_testinuse(self,conn,message=None): inuse = False for each in self.users[conn.fromjid].keys(): if self.users[conn.fromjid][each].channels != {}: inuse = True fromstripped = JID(conn.fromjid).getStripped().encode('utf8') if userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers') \ and userfile[fromstripped]['servers'].has_key(conn.server): inuse = True if inuse == False: self.irc_doquit(conn,message) def irc_disconnected(self,conn,event): if conn.disconnected: return message = "disconnected by %s" % conn.address if config.dumpProtocol: print message self.irc_doquit(conn, message) def irc_settopic(self,conn,channel,line): try: conn.topic(channel.encode(conn.charset,'replace'),line.encode(conn.charset,'replace')) except: self.irc_doquit(conn, 'set topic failed') def irc_sendnick(self,conn,nick): try: conn.nick(nick) except: self.irc_doquit(conn, 'set nick failed') def irc_sendroom(self,conn,channel,line): lines = line.split('\x0a') for each in lines: #if config.dumpProtocol: print channel, each if each != '' or each == None: try: conn.privmsg(channel.encode(conn.charset,'replace'),each.encode(conn.charset,'replace')) except: self.irc_doquit(conn, 'send room failed') def irc_sendctcp(self,type,conn,channel,line): lines = line.split('\x0a') for each in lines: #if config.dumpProtocol: print channel, each try: conn.ctcp(type,channel.encode(conn.charset,'replace'),each.encode(conn.charset,'replace')) except: self.irc_doquit(conn, 'send ctcp failed') def irc_connect(self,channel,server,nick,password,frm,event): fromjid = frm.getStripped().__str__() resource = frm.getResource() if not self.users.has_key(fromjid): # if a new user session self.users[fromjid] = {} if self.users[fromjid].has_key(server): conn = self.users[fromjid][server] if channel: if channel == '': return None if conn.nickname != nick and nick != '': conn.joinchan = channel conn.joinresource = resource self.irc_sendnick(conn,nick) if not conn.channels.has_key(channel): # it's a new channel, just join it self.irc_newroom(conn,channel) conn.channels[channel].resources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),time.time()) if config.dumpProtocol: print "New channel login: %s" % conn.channels[channel].resources else: if conn.channels[channel].resources.has_key(resource): #update resource record conn.channels[channel].resources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),conn.channels[channel].resources[resource][3]) if config.dumpProtocol: print "Update channel resource login: %s" % conn.channels[channel].resources else: #new resource login conn.channels[channel].resources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),time.time()) if config.dumpProtocol: print "New channel resource login: %s" % conn.channels[channel].resources # resource is joining an existing resource on the same channel # TODO: Send topic to new resource # TODO: Alert existing resources that a new resource has joined name = '%s%%%s@%s' % (channel, server, config.jid) for cnick in conn.channels[channel].members.keys(): if cnick == conn.nickname: #if config.dumpProtocol: print 'nnick %s %s %s'%(name,cnick,nick) m = Presence(to=conn.fromjid,frm='%s/%s' %(name, nick)) else: #if config.dumpProtocol: print 'cnick %s %s %s'%(name,cnick,nick) m = Presence(to=conn.fromjid,frm='%s/%s' %(name, cnick)) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs=conn.channels[channel].members[cnick]) self.jabber.send(m) return 1 else: if conn.xresources.has_key(resource): #update resource record conn.xresources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),conn.xresources[resource][3]) if config.dumpProtocol: print "Update server resource login: %s" % conn.xresources else: #new resource login conn.xresources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),time.time()) if config.dumpProtocol: print "New server resource login: %s" % conn.xresources self.jabber.send(Presence(to=frm, frm='%s@%s' % (server, config.jid))) if conn.features.has_key('WATCH'): conn.send_raw('WATCH') else: self.irc_doison(conn,1) else: # the other cases conn=self.irc_newconn(channel,server,nick,password,frm) if conn != None: conn.xresources[resource]=(event.getShow(),event.getPriority(),event.getStatus(),time.time()) self.users[fromjid][server] = conn return 1 else: return None def irc_newconn(self,channel,server,nick,password,frm): fromjid = frm.getStripped().__str__() fromstripped = frm.getStripped().encode('utf8') resource = frm.getResource() address = server username = realname = nick ucharset = config.charset motdhash = '' ruleshash = '' if userfile.has_key(fromstripped): if userfile[fromstripped].has_key('charset'): ucharset = userfile[fromstripped]['charset'] if userfile[fromstripped].has_key('servers'): servers = userfile[fromstripped]['servers'] if servers.has_key(server): serverdetails = servers[server] ucharset = serverdetails['charset'] if serverdetails['address']: address = serverdetails['address'] if not nick: nick = serverdetails['nick'] if not password: password = serverdetails['password'] if serverdetails['username']: username = serverdetails['username'] if serverdetails['realname']: realname = serverdetails['realname'] if serverdetails.has_key('motdhash'): motdhash = serverdetails['motdhash'] if serverdetails.has_key('ruleshash'): ruleshash = serverdetails['ruleshash'] else: if config.requireRegister: self.jabber.send(Error(Presence(to = fromjid, frm = '%s%%%s@%s/%s' % (channel,server,config.jid,nick)),ERR_REGISTRATION_REQUIRED,reply=0)) return None if not nick: return None try: addressdetails = address.split(':') if len(addressdetails) > 2: addressdetails = address.split('/') #probably ipv6, so split on / if len(addressdetails) > 2: return None port = 6667 if len(addressdetails) > 1: port = int(addressdetails[1]); address = addressdetails[0]; conn=self.irc.server().connect(address,port,nick,password,username,realname,config.host) conn.server = server conn.address = address conn.port = port conn.disconnected = False conn.fromjid = fromjid conn.features = {} conn.joinchan = channel conn.joinresource = resource conn.xresources = {} conn.channels = {} conn.pendingoperations = {} conn.allpendingoperations = [] conn.activechats = {} conn.away = '' conn.charset = ucharset conn.connectstatus = 'Connecting: ' conn.isonlist = [] conn.isontimer = None conn.motdhash = motdhash conn.ruleshash = ruleshash self.jabber.send(Presence(to=fromjid, frm = '%s@%s' % (server, config.jid), status='Connecting...')) return conn except irclib.ServerConnectionError: self.jabber.send(Error(Presence(to = fromjid, frm = '%s%%%s@%s/%s' % (channel,server,config.jid,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) conn.mode(channel,'') except: self.irc_doquit(conn, 'new room failed') class Channel: pass chan = Channel() chan.private = False chan.secret = False chan.invite = False chan.topic = False chan.notmember = False chan.moderated = False chan.banlist = [] chan.limit = 0 chan.key = '' chan.currenttopic = '' chan.members = {} # irc nicks in the channel chan.resources = {} conn.channels[channel] = chan def irc_disconnect(self,channel,server,frm,message): fromjid = frm.getStripped().__str__() resource = frm.getResource() if self.users.has_key(fromjid): if self.users[fromjid].has_key(server): conn = self.users[fromjid][server] for nick in conn.activechats.keys(): # TODO: remove any activechats with this resource, or with this room # irc jid, xmpp jid, last message time pass if channel: if conn.channels.has_key(channel): if conn.channels[channel].resources.has_key(resource): del conn.channels[channel].resources[resource] if config.dumpProtocol: print "Deleted channel resource login: %s" % conn.channels[channel].resources if conn.channels[channel].resources == {}: self.irc_leaveroom(conn,channel) del conn.channels[channel] self.irc_testinuse(conn,message) return 1 else: if conn.xresources.has_key(resource): del conn.xresources[resource] if config.dumpProtocol: print "Deleted server resource login: %s" % conn.xresources if conn.xresources == {}: if config.dumpProtocol: print 'No more resource logins' self.irc_doquit(conn,message) return 1 return None def find_highest_resource(self,resources): age = None priority = None resource = None for each in resources.keys(): #if config.dumpProtocol: print each,resources if resources[each][1]>priority: #if priority is higher then take the highest age = resources[each][3] priority = resources[each][1] resource = each elif resources[each][1]==priority: #if priority is the same then take the oldest if resources[each][3] 10: fromstripped = conn.fromjid.encode('utf8') if userfile.has_key(fromstripped) \ and userfile[fromstripped].has_key('servers') \ and userfile[fromstripped]['servers'].has_key(conn.server): conf = userfile[fromstripped]['servers'][conn.server] if conf.has_key('subscriptions'): subscriptions = conf['subscriptions'] if not conn.features.has_key('WATCH'): if len(subscriptions) > 0: conn.ison(subscriptions) else: for nick in conn.isonlist: name = '%s%%%s' % (nick, conn.server) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid), typ = 'unavailable')) conn.isonlist = [] conn.lastdoison = time.time() def irc_ison(self,conn,event): newlist = event.arguments()[0].split() for nick in newlist: if not nick in conn.isonlist: name = '%s%%%s' % (nick, conn.server) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid))) for nick in conn.isonlist: if not nick in newlist: name = '%s%%%s' % (nick, conn.server) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid), typ = 'unavailable')) conn.isonlist = newlist def irc_watchonline(self,conn,event): # TODO: store contact status for when new resource comes online # or, do we spam a watch list? nick = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) name = '%s%%%s' % (nick, conn.server) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid))) def irc_watchoffline(self,conn,event): # TODO: store contact status for when new resource comes online # or, do we spam a watch list? nick = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) name = '%s%%%s' % (nick, conn.server) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid), typ = 'unavailable')) def irc_welcome(self,conn,event): conn.connectstatus = None self.jabber.send(Presence(to = conn.fromjid, frm = '%s@%s' %(conn.server,config.jid))) freq = 90 # ison query frequency in seconds offset = int(time.time())%freq conn.isontimer=(freq,offset,self.irc_doison,[conn]) conn.lastdoison=0 timerlist.append(conn.isontimer) if conn.joinchan: self.irc_newroom(conn,conn.joinchan) if conn.xresources.has_key(conn.joinresource): conn.channels[conn.joinchan].resources[conn.joinresource]=conn.xresources[conn.joinresource] #TODO: channel join operations should become pending operations # so that they can be tracked correctly # and so that we can send errors to the right place conn.joinchan = None conn.joinresource = None def irc_nicknameinuse(self,conn,event): if conn.joinchan: name = '%s%%%s' % (conn.joinchan, conn.server) else: name = conn.server if conn.joinresource: to = '%s/%s'%(conn.fromjid,conn.joinresource) else: to = conn.fromjid error=ErrorNode(ERR_CONFLICT,text='Nickname is in use') self.jabber.send(Presence(to=to, typ = 'error', frm = '%s@%s' %(name, config.jid),payload=[error])) 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' %(unicode(event.arguments()[0],conn.charset,'replace'), conn.server, config.jid),payload=[error])) def irc_notregistered(self,conn,event): if conn.joinchan: name = '%s%%%s' % (conn.joinchan, conn.server) else: name = conn.server if conn.joinresource: to = '%s/%s'%(conn.fromjid,conn.joinresource) else: to = conn.fromjid error=ErrorNode(ERR_FORBIDDEN,text='Not registered and registration is not supported') self.jabber.send(Presence(to=to, typ = 'error', frm = '%s@%s' %(name, config.jid),payload=[error])) def irc_nosuchnick(self, conn, event): error=ErrorNode(ERR_ITEM_NOT_FOUND,text='Nickname not found') #TODO: resource handling? self.jabber.send(Message(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' % (event.source(), conn.server, config.jid),payload=[error])) def irc_cannotsend(self,conn,event): error=ErrorNode(ERR_FORBIDDEN) #TODO: resource handling? self.jabber.send(Message(to=conn.fromjid, typ = 'error', frm = '%s%%%s@%s' % (event.source(), conn.server, config.jid),payload=[error])) def irc_redirect(self,conn,event): new = '%s%%%s@%s'% (unicode(event.arguments()[1],conn.charset,'replace'),conn.server, config.jid) old = '%s%%%s@%s'% (unicode(event.arguments()[0],conn.charset,'replace'),conn.server, config.jid) error=ErrorNode(ERR_REDIRECT,new) self.jabber.send(Presence(to=conn.fromjid, typ='error', frm = old, payload=[error])) del conn.channels[unicode(event.arguments()[1],conn.charset,'replace')] try: conn.part(event.arguments()[1]) except: self.irc_doquit(conn, 'redirect failed') def irc_modeparseadmin(self,conn,event): # Mode handling currently is very poor. # # Issues: # Multiple +b's currently not handled # +l or -l with no parameter not handled # -o doesn't automatically mean -v too channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) faddr = '%s%%%s@%s' %(channel,conn.server,config.jid) if irclib.is_channel(event.target()): if event.arguments()[0] == '+o': # Give Chanop if channel in conn.channels.keys(): for each in event.arguments()[1:]: nick = unicode(each,conn.charset,'replace') conn.channels[channel].members[nick]['role']='moderator' if each == conn.nickname: conn.channels[channel].members[nick]['affiliation']='owner' m = Presence(to=conn.fromjid,typ=None,frm = '%s/%s' %(faddr,nick)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.channels[channel].members[nick]) self.jabber.send(m) elif event.arguments()[0] in ['-o', '-v']: # Take Chanop or Voice if channel in conn.channels.keys(): for each in event.arguments()[1:]: nick = unicode(each,conn.charset,'replace') # could be visitor or participant if -o conn.channels[channel].members[nick]['role']='visitor' conn.channels[channel].members[nick]['affiliation']='none' m = Presence(to=conn.fromjid,typ=None,frm = '%s/%s' %(faddr,nick)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.channels[channel].members[nick]) self.jabber.send(m) elif event.arguments()[0] == '+v': # Give Voice if channel in conn.channels.keys(): for each in event.arguments()[1:]: nick = unicode(each,conn.charset,'replace') conn.channels[channel].members[nick]['role']='participant' conn.channels[channel].members[nick]['affiliation']='none' m = Presence(to=conn.fromjid,typ=None,frm = '%s/%s' %(faddr,nick)) t = m.addChild(name='x',namespace=NS_MUC_USER) p = t.addChild(name='item',attrs=conn.channels[channel].members[nick]) self.jabber.send(m) def irc_channelmodeis(self,conn,event): channel = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) self.irc_modeparse(conn,event,channel,event.arguments()[1:]) def irc_mode(self,conn,event): channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) self.irc_modeparse(conn,event,channel,event.arguments()) def irc_modeparse(self,conn,event,channel,args): # Very buggy, multiple items cases, ban etc. plus = None for each in args[0]: if each == '+': plus = True elif each == '-': plus = False elif each == 'o': #Chanop status self.irc_modeparseadmin(conn,event) elif each == 'v': #Voice status self.irc_modeparseadmin(conn,event) elif each == 'p': #Private Room conn.channels[channel].private = plus elif each == 's': #Secret conn.channels[channel].secret = plus elif each == 'i': #invite only conn.channels[channel].invite = plus elif each == 't': #only chanop can set topic conn.channels[channel].topic = plus elif each == 'n': #no not in channel messages conn.channels[channel].notmember = plus elif each == 'm': #moderated chanel conn.channels[channel].moderated = plus elif each == 'l': #set channel limit if plus: conn.channels[channel].limit = args[1] else: conn.channels[channel].limit = 0 elif each == 'b': #ban users # TODO: maybe move to irc_modeparseadmin # handle as outcasts, would need to map @ to % # Need to fix multiple ban case. for each in args[1:]: if plus: conn.channels[channel].banlist.append(unicode(each,conn.charset,'replace')) else: if unicode(each,conn.charset,'replace') in conn.channels[channel].banlist: conn.channels[channel].banlist.remove(unicode(each,conn.charset,'replace')) elif each == 'k': #set channel key if plus: conn.channels[channel].key = args[1] else: conn.channels[channel].key = '' def irc_part(self,conn,event): type = 'unavailable' channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) name = '%s%%%s' % (channel, conn.server) nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') jid = '%s%%%s@%s' % (nick, conn.server, config.jid) line = None if len(event.arguments()) > 0: line,xhtml = colourparse(event.arguments()[0],conn.charset) us = irclib.nm_to_n(event.source()) == conn.nickname if conn.channels.has_key(channel): if nick in conn.channels[channel].members.keys(): del conn.channels[channel].members[nick] if config.activityMessages: msg = '' if line: msg = ' (%s)' % line for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource), typ='groupchat',frm='%s@%s' % (name, config.jid), body='%s (%s) has left%s' % (nick, unicode(irclib.nm_to_uh(event.source()),conn.charset,'replace'), msg)) self.jabber.send(m) m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, config.jid,nick)) if line: m.addChild(name='status',payload=line) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs={'affiliation':'none','role':'none','jid':jid}) if us: p.addChild(name='status', attrs={'code':'110'}) self.jabber.send(m) def irc_kick(self,conn,event): type = 'unavailable' channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) name = '%s%%%s' % (channel, conn.server) nick = unicode(event.arguments()[0],conn.charset,'replace') jid = '%s%%%s@%s' % (nick, conn.server, config.jid) line,xhtml = colourparse(event.arguments()[1],conn.charset) us = event.arguments()[0] == conn.nickname if conn.channels.has_key(channel): if nick in conn.channels[channel].members.keys(): del conn.channels[channel].members[nick] if us: del conn.channels[channel].members if config.activityMessages == True: for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource), typ='groupchat',frm='%s@%s' % (name, config.jid), body='%s (%s) was kicked by %s (%s)' % (nick, unicode(irclib.nm_to_uh(event.source()),conn.charset,'replace'), unicode(irclib.nm_to_n(event.source()),conn.charset,'replace'), line)) self.jabber.send(m) m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, config.jid,nick)) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs={'affiliation':'none','role':'none','jid':jid}) p.addChild(name='reason',payload=line) p.addChild(name='actor',attrs={'jid':'%s%%%s@%s' % (unicode(irclib.nm_to_n(event.source()),conn.charset,'replace'), conn.server, config.jid)}) t.addChild(name='status',attrs={'code':'307'}) if us: p.addChild(name='status', attrs={'code':'110'}) self.jabber.send(m) self.irc_testinuse(conn) def irc_topic(self,conn,event): nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') if len(event.arguments())==2: channel = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) line,xhtml = colourparse(event.arguments()[1],conn.charset) else: channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) line,xhtml = colourparse(event.arguments()[0],conn.charset) conn.channels[channel].currenttopic = line for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource),frm = '%s%%%s@%s/%s' % (channel,conn.server,config.jid,nick), typ='groupchat', subject = line) if config.activityMessages == True: m.setBody('/me set the topic to: %s' % line) self.jabber.send(m) def irc_join(self,conn,event): type = None channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) name = '%s%%%s' % (channel, conn.server) nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') jid = '%s%%%s@%s' % (nick, conn.server, config.jid) if not conn.channels.has_key(channel): self.irc_newroom(conn,channel) if nick not in conn.channels[channel].members.keys(): conn.channels[channel].members[nick]={'affiliation':'none','role':'visitor','jid':jid} m = Presence(to=conn.fromjid,typ=type,frm='%s@%s/%s' %(name, config.jid, nick)) t=m.addChild(name='x',namespace=NS_MUC_USER) p=t.addChild(name='item',attrs=conn.channels[channel].members[nick]) #if config.dumpProtocol: print m.__str__() self.jabber.send(m) if config.activityMessages == True: for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource), typ='groupchat',frm='%s@%s' % (name, config.jid), body='%s (%s) has joined' % (nick, unicode(irclib.nm_to_uh(event.source()),conn.charset,'replace'))) self.jabber.send(m) def irc_whoreply(self,conn,event): channel = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) nick = unicode(event.arguments()[4],conn.charset,'replace') faddr = '%s%%%s@%s/%s' % (channel, conn.server, config.jid, nick) m = Presence(to=conn.fromjid,typ=None,frm=faddr) t = m.addChild(name='x', namespace=NS_MUC_USER) affiliation = 'none' role = 'none' # TODO: Should really parse SUPPORT/PREFIX value if '@' in event.arguments()[5] or '&' in event.arguments()[5] or '~' in event.arguments()[5]: role = 'moderator' if unicode(event.arguments()[4],conn.charset,'replace') == conn.nickname: affiliation='owner' elif '+' in event.arguments()[5]: role = 'participant' elif '*' in event.arguments()[5]: affiliation = 'admin' elif role == 'none': role = 'visitor' jid = '%s%%%s@%s' % (unicode(event.arguments()[4],conn.charset,'replace'), conn.server, config.jid) p=t.addChild(name='item',attrs={'affiliation':affiliation,'role':role,'jid':jid}) self.jabber.send(m) if event.arguments()[0] != '*' and conn.channels.has_key(channel): conn.channels[channel].members[nick]={'affiliation':affiliation,'role':role,'jid':jid} def irc_whoisgetvcard(self,conn,event): nick = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) key = "whois:" + nick if conn.pendingoperations.has_key(key): m = conn.pendingoperations[key] return m.getTag('vCard', namespace=NS_VCARD) else: self.irc_rawtext(conn,'whois',event,' '.join(event.arguments()[1:])) def irc_whoisuser(self,conn,event): p = self.irc_whoisgetvcard(conn,event) if p: p.setTagData(tag='FN', val=unicode(event.arguments()[4],conn.charset,'replace')) p.setTagData(tag='NICKNAME', val=unicode(event.arguments()[0],conn.charset,'replace')) e = p.addChild(name='EMAIL') e.setTagData(tag='USERID', val=unicode(event.arguments()[1],conn.charset,'replace') + '@' + unicode(event.arguments()[2],conn.charset,'replace')) def irc_whoisserver(self,conn,event): p = self.irc_whoisgetvcard(conn,event) if p: o = p.addChild(name='ORG') o.setTagData(tag='ORGUNIT', val=unicode(event.arguments()[1],conn.charset,'replace')) o.setTagData(tag='ORGNAME', val=unicode(event.arguments()[2],conn.charset,'replace')) def irc_whoisoperator(self,conn,event): p = self.irc_whoisgetvcard(conn,event) if p: p.setTagData(tag='ROLE', val=unicode(event.arguments()[1],conn.charset,'replace')) def irc_whoisidle(self,conn,event): p = self.irc_whoisgetvcard(conn,event) if p: seconds = int(event.arguments()[1]) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) p.setTagData(tag='DESC', val=p.getTagData(tag='DESC') + '\x0a' + 'Idle: %s hours %s mins %s secs' % (hours, minutes, seconds)) if len(event.arguments()) > 3: p.setTagData(tag='DESC', val=p.getTagData(tag='DESC') + '\x0a' + 'Signon Time: ' + time.ctime(float(event.arguments()[2]))) def irc_whoischannels(self,conn,event): p = self.irc_whoisgetvcard(conn,event) if p: p.setTagData(tag='TITLE', val=unicode(event.arguments()[1],conn.charset,'replace')) def irc_endofwhois(self,conn,event): nick = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) key = "whois:" + nick if conn.pendingoperations.has_key(key): m = conn.pendingoperations[key] del conn.pendingoperations[key] self.jabber.send(m) else: self.irc_rawtext(conn,'whois',event,' '.join(event.arguments()[1:])) def irc_list(self,conn,event): if not pendingop_call(conn, 'list', event): self.irc_rawtext(conn,'list',event,' '.join(event.arguments())) def irc_list_items(self,conn,event,op,rep): if event.eventtype() == 'liststart': pass if op == 'fail': self.jabber.send(Error(rep,ERR_RESOURCE_CONSTRAINT,reply=0)) return True chan = event.arguments()[0] if irclib.is_channel(chan): chan = unicode(chan,conn.charset,'replace') q=rep.getTag('query') q.addChild('item',{'name':chan,'jid':'%s%%%s@%s' % (JIDEncode(chan), conn.server, config.jid)}) return True def irc_list_info(self,conn,event,op,rep): if event.eventtype() == 'liststart': pass if op == 'fail': self.jabber.send(Error(rep,ERR_RESOURCE_CONSTRAINT,reply=0)) return True chan = event.arguments()[0] if irclib.is_channel(chan): membercount = event.arguments()[1] line,xhtml = colourparse(event.arguments()[2],conn.charset) chan = unicode(chan,conn.charset,'replace') q=rep.getTag('query') q.addChild('identity',{'category':'conference','type':'irc','name':chan}) form = DataForm(typ='result',data=[ DataField( name='FORM_TYPE' ,value=NS_MUC_ROOMINFO,typ='hidden'), DataField(label='Subject' ,name='muc#roominfo_subject' ,value=line ,typ='text-single'), DataField(label='Number of occupants',name='muc#roominfo_occupants',value=membercount ,typ='text-single')]) q.addChild(node=form) return True def irc_list_search(self,conn,event,op,rep): if event.eventtype() == 'liststart': pass if op == 'fail': self.jabber.send(Error(rep,ERR_RESOURCE_CONSTRAINT,reply=0)) return True chan = event.arguments()[0] if irclib.is_channel(chan): membercount = event.arguments()[1] line,xhtml = colourparse(event.arguments()[2],conn.charset) chan = unicode(chan,conn.charset,'replace') q=rep.getTag('query') form = q.getTag('x',namespace=NS_DATA) item = Node('item',payload=[ DataField(name='jid' ,value='%s%%%s@%s' % (JIDEncode(chan), conn.server, config.jid)), DataField(name='name' ,value=chan), DataField(name='muc#roominfo_subject' ,value=line), DataField(name='muc#roominfo_occupants',value=membercount)]) form.addChild(node=item) return True def irc_listend(self,conn,event): rep = pendingop_pop(conn,'list') if rep: self.jabber.send(rep) else: self.irc_rawtext(conn,'list',event,' '.join(event.arguments())) def irc_tryagain(self,conn,event): if not pendingop_fail(conn, event): self.irc_rawtext(conn,conn.get_server_name(),event,' '.join(event.arguments())) def irc_motdstart(self,conn,event): if not pendingop_call(conn, 'motd', event): try: nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') except: nick = conn.server sys.exc_clear() #TODO: resource handling? conn.joinresource? what about adhoc? m = Message(to=conn.fromjid,frm='%s@%s/%s' %(conn.server, config.jid,nick)) m.ircbody = None pendingop_push(conn, 'motd', self.irc_motd_line, m) if not pendingop_call(conn, 'motd', event): self.irc_rawtext(conn,'motd',event,' '.join(event.arguments())) def irc_motd(self,conn,event): if not pendingop_call(conn, 'motd', event): self.irc_rawtext(conn,'motd',event,' '.join(event.arguments())) def irc_motd_line(self,conn,event,op,msg): if event.eventtype() == 'motdstart' or event.eventtype() == '308': line,xhtml = colourparse(event.arguments()[0],conn.charset) if line[-3:] == ' - ': line = line[:-3] if line[:2] == '- ': line = line[2:] msg.setSubject(line) return True line = event.arguments()[0] if line[:2] == '- ': line = line[2:] if msg.ircbody: msg.ircbody = msg.ircbody + '\x0a' + line msg.hashbody = msg.hashbody + '\x0a' + line else: msg.ircbody = line msg.hashbody = '' return True def irc_endofmotd(self,conn,event): msg = pendingop_pop(conn,'motd') if msg: line,xhtml = colourparse(msg.ircbody,conn.charset) motdhash = md5.new(msg.hashbody).hexdigest() if event.eventtype() == '309': hashfield = 'ruleshash' else: hashfield = 'motdhash' if motdhash != getattr(conn, hashfield): setattr(conn, hashfield, motdhash) if userfile.has_key(conn.fromjid): user = userfile[conn.fromjid] if user.has_key('servers') \ and user['servers'].has_key(conn.server): user['servers'][conn.server][hashfield] = motdhash userfile[conn.fromjid] = user userfile.sync() msg = Message(to=msg.getTo(),subject=msg.getSubject(),typ='headline',frm=msg.getFrom(),body=line,payload = [xhtml]) self.jabber.send(msg) else: self.irc_rawtext(conn,'motd',event,' '.join(event.arguments())) def irc_rawtext(self,conn,resource,event,msg): frm = '%s@%s/%s' %(conn.server,config.jid,resource) line,xhtml = colourparse(msg,conn.charset) m = Message(to=conn.fromjid,body=line,typ='chat',frm=frm,payload = [xhtml]) self.jabber.send(m) def nm_is_service(self,conn,nickmask): if not nickmask: return True try: userhost = unicode(irclib.nm_to_uh(nickmask),conn.charset,'replace') except IndexError: sys.exc_clear() return True try: user,host = userhost.lower().split('@', 1) servername = conn.get_server_name().lower() serverprefix,serverdomain = servername.split('.', 1) #server_name nickname!ident@host #irc.zanet.net: NickServ!services@zanet.net #irc.lagnet.org.za: NickServ!services@lagnet.org.za #irc.zanet.org.za: NickServ!NickServ@zanet.org.za if host == serverdomain: return True #irc.za.ethereal.web.za: Nik!services@ethereal.web.za if user == 'services' and ('.%s'%host == servername[-len(host)-1:]): return True #irc.oftc.net: NickServ!services@services.oftc.net #irc.za.somewhere: NickServ!services@services.somewhere if user == 'services' and (host == 'services%s'%servername[-len(host)+8:]): return True #irc.freenode.net: NickServ!NickServ@services. if host == 'services.': return True except: sys.exc_clear() return False def nm_to_jidinfo(self,conn,nickmask): try: nick = unicode(irclib.nm_to_n(nickmask),conn.charset,'replace') except: nick = conn.server sys.exc_clear() if conn.activechats.has_key(irc_ulower(nick)): chat = conn.activechats[irc_ulower(nick)] # irc jid, xmpp jid, last message time, capabilites if chat[2] + 300 > time.time(): return chat[0],chat[1],chat[3] room = irc_ulower(chat[0].getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if conn.channels.has_key(channel): resources = conn.channels[channel].resources else: resources = conn.xresources if resources != {}: return chat[0],'%s/%s'%(conn.fromjid,self.find_highest_resource(resources)),chat[3] else: return chat[0],conn.fromjid,chat[3] if self.nm_is_service(conn,nickmask): frm = '%s@%s/%s' %(conn.server,config.jid,nick) else: frm = '%s%%%s@%s' %(nick,conn.server,config.jid) return frm,conn.fromjid,{} def irc_privmsg(self,conn,event,msg): if irclib.is_channel(event.target()): type = 'groupchat' channel = irc_ulower(unicode(event.target(),conn.charset,'replace')) line,xhtml = colourparse(msg,conn.charset) #if config.dumpProtocol: print (line,xhtml) if conn.channels.has_key(channel): nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') for resource in conn.channels[channel].resources.keys(): m = Message(to='%s/%s'%(conn.fromjid,resource),body= line,typ=type,frm='%s%%%s@%s/%s' %(channel,conn.server,config.jid,nick),payload = [xhtml]) self.jabber.send(m) else: type = 'chat' line,xhtml = colourparse(msg,conn.charset) frm,to,caps = self.nm_to_jidinfo(conn,event.source()) # if we're still connecting then send server messages as presence information if conn.connectstatus != None and frm.find('/') > -1: if line[:4] == '*** ': line = line[4:] m = Presence(to=to,frm='%s@%s'%(conn.server,config.jid), status=conn.connectstatus + line) else: m = Message(to=to,body=line,typ=type,frm=frm,payload = [xhtml]) if 'x:event' in caps: m.setTag('x',namespace=NS_EVENT).setTag('composing') self.jabber.send(m) def irc_message(self,conn,event): self.irc_privmsg(conn,event,event.arguments()[0]) def irc_away(self,conn,event): # TODO: store a contacts away status? (or later broadcast with new resources) nick = irc_ulower(unicode(event.arguments()[0],conn.charset,'replace')) name = '%s%%%s'%(nick,conn.server) line,xhtml = colourparse(event.arguments()[1],conn.charset) self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(name, config.jid), show='away', status=line)) # TODO: poll (via whois?) away status of online contacts def irc_nowaway(self,conn,event): self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(conn.server, config.jid), show='away')) def irc_unaway(self,conn,event): self.jabber.send(Presence(to=conn.fromjid, frm = '%s@%s' %(conn.server, config.jid))) def irc_ctcp(self,conn,event): nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') if event.arguments()[0] == 'ACTION': self.irc_privmsg(conn,event,'/me '+event.arguments()[1]) elif event.arguments()[0] == 'VERSION': conn.ctcp_reply(irclib.nm_to_n(event.source()).encode(conn.charset,'replace'),'VERSION ' + VERSTR + ' ' + version) elif event.arguments()[0] == 'CAPABILITIES': conn.ctcp_reply(irclib.nm_to_n(event.source()).encode(conn.charset,'replace'),'CAPABILITIES version,x:event') elif event.arguments()[0] == 'X:EVENT': frm,to,caps = self.nm_to_jidinfo(conn,event.source()) m = Message(to=to,frm=frm) xevent = m.setTag('x',namespace=NS_EVENT) if len(event.arguments()) > 1: for each in event.arguments()[1].split(','): xevent.setTag(each) self.jabber.send(m) def irc_ctcpreply(self,conn,event): nick = unicode(irclib.nm_to_n(event.source()),conn.charset,'replace') if event.arguments()[0] == 'CAPABILITIES': if conn.activechats.has_key(irc_ulower(nick)): if len(event.arguments()) > 1: caps = event.arguments()[1].split(',') conn.activechats[irc_ulower(nick)][3] = caps elif event.arguments()[0] == 'VERSION': # TODO: real version reply back to the xmpp world? pass def xmpp_connect(self): connected = self.jabber.connect((config.mainServer,config.port)) if config.dumpProtocol: print "connected:",connected while not connected: time.sleep(5) connected = self.jabber.connect((config.mainServer,config.port)) if config.dumpProtocol: print "connected:",connected self.register_handlers() if config.dumpProtocol: print "trying auth" connected = self.jabber.auth(config.saslUsername,config.secret) if config.dumpProtocol: print "auth return:",connected return connected def xmpp_disconnect(self): for each in self.users.keys(): for item in self.users[each].keys(): self.irc_doquit(self.users[each][item], 'xmpp disconnected') del self.users[each] del socketlist[self.jabber.Connection._sock] time.sleep(5) while not self.jabber.reconnectAndReauth(): time.sleep(5) socketlist[self.jabber.Connection._sock]='xmpp' def loadConfig(): configOptions = {} for configFile in config.configFiles: if os.path.isfile(configFile): xmlconfig.reloadConfig(configFile, configOptions) config.configFile = configFile return print "Configuration file not found. You need to create a config file and put it in one of these locations:\n " + "\n ".join(config.configFiles) sys.exit(1) def irc_add_conn(conn): socketlist[conn]='irc' def irc_del_conn(conn): if socketlist.has_key(conn): del socketlist[conn] def logError(): err = '%s - %s\n'%(time.strftime('%a %d %b %Y %H:%M:%S'),version) if logfile != None: logfile.write(err) traceback.print_exc(file=logfile) logfile.flush() sys.stderr.write(err) traceback.print_exc() sys.exc_clear() def sigHandler(signum, frame): transport.offlinemsg = 'Signal handler called with signal %s'%signum if config.dumpProtocol: print 'Signal handler called with signal %s'%signum transport.online = 0 if __name__ == '__main__': if 'PID' in os.environ: config.pid = os.environ['PID'] loadConfig() if config.pid: pidfile = open(config.pid,'w') pidfile.write(`os.getpid()`) pidfile.close() if config.compjid: xcp=1 else: xcp=0 config.compjid = config.jid if config.saslUsername: sasl = 1 else: config.saslUsername = config.jid sasl = 0 userfile = shelve.open(config.spoolFile) logfile = None if config.debugFile: logfile = open(config.debugFile,'a') ircobj = irclib.IRC(fn_to_add_socket=irc_add_conn,fn_to_remove_socket=irc_del_conn) if config.dumpProtocol: debug=['always', 'nodebuilder'] else: debug=[] connection = xmpp.client.Component(config.compjid,config.port,debug=debug,sasl=sasl,bind=config.useComponentBinding,route=config.useRouteWrap,xcp=xcp) transport = Transport(connection,ircobj) if not transport.xmpp_connect(): print "Could not connect to server, or password mismatch!" sys.exit(1) # Set the signal handlers signal.signal(signal.SIGINT, sigHandler) signal.signal(signal.SIGTERM, sigHandler) socketlist[connection.Connection._sock]='xmpp' while transport.online: try: (i , o, e) = select.select(socketlist.keys(),[],[],1) except (select.error, socket.error): for userkey in transport.users: user = transport.users[userkey] for serverkey, server in user.items(): if server._get_socket() == None: transport.irc_disconnected(server, None) for each in socketlist.keys(): try: (ci, co, ce) = select.select([],[],[each],0) except socket.error: irc_del_conn(each) sys.exc_clear() (i , o, e) = select.select(socketlist.keys(),[],[],1) for each in i: if socketlist[each] == 'xmpp': try: connection.Process(1) except IOError: transport.xmpp_disconnect() sys.exc_clear() except: logError() if not connection.isConnected(): transport.xmpp_disconnect() elif socketlist[each] == 'irc': try: ircobj.process_data([each]) except: logError() else: try: raise Exception("Unknown socket type: %s" % repr(socketlist[each])) except: logError() #delayed execution method modified from python-irclib written by Joel Rosdahl for each in timerlist: #print int(time.time())%each[0]-each[1] if not (int(time.time())%each[0]-each[1]): try: apply(each[2],each[3]) except: logError() for each in [x for x in transport.users.keys()]: for item in transport.users[each].keys(): transport.irc_doquit(transport.users[each][item], transport.offlinemsg) connection.send(Presence(to=each, frm = config.jid, typ = 'unavailable', status = transport.offlinemsg)) del transport.users[each] del socketlist[connection.Connection._sock] userfile.close() connection.disconnect() if config.pid: os.unlink(config.pid) if logfile: logfile.close() if transport.restart: args=[sys.executable]+sys.argv if os.name == 'nt': args = ["\"%s\"" % a for a in args] if config.dumpProtocol: print sys.executable, args os.execv(sys.executable, args) jabber-irc_0.4cvs20080505.orig/IRC-Transport-Howtouse.html0000644000175100017510000000665110053105010021757 0ustar kalfakalfa IRC-Transport-Howtouse

How to use the IRC transport.


The IRC transport is a dynamic gateway that allows XMPP/Jabber users to connect to IRC using their Groupchat & MUC clients.

Features

  • Every IRC network should be supported.
  • A user can have many rooms open on different networks.
  • Your nick name must be the same on all channels on one irc server, but can be different when using another irc server.

Limitations

  • When using the IRC transport trying to discover rooms using a service browser is not currently implemented.
  • Groupchat clients will only get basic chat support. All advanced features are only supported in MUC clients.

Joining a room

To open a room you will need the irc channel name and the irc server name. For our example we will use the channel #debian in server irc.debian.org

To connect to an irc channel in your XMPP client you will take the irc channel and irc server and combine them together to form an XMPP room name. To do this you need to add the channel and server names together using a % as a seperator. For our example you would use #debian%irc.debian.org as the room name in your XMPP client. You can then enter the transport name that your XMPP or Jabber server supplies, eg irc.jabber.org.uk, as well as your nickname.  The nickname has to be unique not only on the channel you are joining (#debian in our example) but also on the irc server (irc.debian.org).

If you open more than one room to the same server they must have the same nickname, so if I were mikea on #debian%irc.debian.org, I would also need to be mikea on #test%irc.debian.org. If you try and open #test%irc.debian.org while logged on already the transport will use your old name, and change your new name to match it.

If  you choose a name that is already in use then the will return an error.

IRC emote and commands

None of the special irc commands other than '/me' work. All will be relayed to the channel.

Private Messages

Private messages sent to a member of a room will be returned as a network user. If you try and chat to me as mikea in room #debian%irc.debian.org then you will get the responce from mikea%irc.debian.org as private messages in IRC are network based not room based.

Mode changes

All mode changes are supported only by the MUC interface.

jabber-irc_0.4cvs20080505.orig/config.py0000644000175100017510000000115610654740350016504 0ustar kalfakalfa# This file contains the default settings for various options. # Please edit config.xml instead of this file configFiles = ['config.xml', '/etc/pyirct.conf.xml'] configFile = None jid = "irc" compjid = "" host = "" discoName = "IRC Transport" spoolFile = "user.dbm" pid = "" mainServer = "127.0.0.1" mainServerJID = "jabber.localhost" port = "5347" secret = "secret" allowRegister = False requireRegister = False activityMessages = False # For displaying user acitivity messages admins = [] useComponentBinding = False useRouteWrap = False saslUsername = "" debugFile = "" dumpProtocol = False charset = 'utf-8' jabber-irc_0.4cvs20080505.orig/jep0133.py0000644000175100017510000006006210654740351016326 0ustar kalfakalfa # Service administration commands XEP-0133 for the xmpppy based transports written by Mike Albon import xmpp, string from xmpp.protocol import * import xmpp.commands import config from xml.dom.minidom import parse """This file is the XEP-0133 commands that are applicable to the transports. Implemented commands as follows: 4.1. Add_User_Command: 4.2. Delete_User_Command: 4.18. List_Registered_Users_Command: Return a list of Registered Users 4.20. List_Online_Users_Command: Return a list of Online Users 4.21. List_Active_Users_Command: Return a list of Active Users 4.29. Edit_Admin_List_Command: Edit the Administrators list 4.30. Restart_Service_Command: Restarts the Service 4.31. Shutdown_Service_Command: Shuts down the Service """ class Add_User_Command(xmpp.commands.Command_Handler_Prototype): """This is the add user command as documented in section 4.1 of XEP-0133.""" name = NS_ADMIN_ADD_USER description = 'Add User' discofeatures = [xmpp.commands.NS_COMMANDS, xmpp.NS_DATA] def __init__(self,userfile,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = {'execute':self.cmdFirstStage } self.userfile = userfile def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Set the session ID, and return the form containing the user's jid""" if request.getFrom().getStripped() in config.admins: # Setup session ready for form reply session = self.getSessionID() self.sessions[session] = {'jid':request.getFrom(),'actions':{'cancel':self.cmdCancel,'next':self.cmdSecondStage,'execute':self.cmdSecondStage}} # Setup form with existing data in reply = request.buildReply('result') form = DataForm(title='Adding a User',data=['Fill out this form to add a user', DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The Jabber ID for the account to be added', typ='jid-single', name='accountjid')]) replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form] reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed def cmdSecondStage(self,conn,request): """Apply and save the config""" form = DataForm(node=request.getTag(name='command').getTag(name='x',namespace=NS_DATA)) session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): if self.sessions[session]['jid'] == request.getFrom(): reply = request.buildReply('result') fromstripped = form.getField('accountjid').getValue().encode('utf8') if not self.userfile.has_key(fromstripped): self.userfile[fromstripped] = {} self.userfile.sync() reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'completed'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed def cmdCancel(self,conn,request): session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): del self.sessions[session] reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'canceled'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed class Delete_User_Command(xmpp.commands.Command_Handler_Prototype): """This is the delete user command as documented in section 4.1 of XEP-0133.""" name = NS_ADMIN_DELETE_USER description = 'Delete User' discofeatures = [xmpp.commands.NS_COMMANDS, xmpp.NS_DATA] def __init__(self,userfile,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = {'execute':self.cmdFirstStage } self.userfile = userfile def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Set the session ID, and return the form containing the user's jid""" if request.getFrom().getStripped() in config.admins: # Setup session ready for form reply session = self.getSessionID() self.sessions[session] = {'jid':request.getFrom(),'actions':{'cancel':self.cmdCancel,'next':self.cmdSecondStage,'execute':self.cmdSecondStage}} # Setup form with existing data in reply = request.buildReply('result') form = DataForm(title='Deleting a User',data=['Fill out this form to delete a user', DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The Jabber ID for the account to be deleted', typ='jid-single', name='accountjid')]) replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form] reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed def cmdSecondStage(self,conn,request): """Apply and save the config""" form = DataForm(node=request.getTag(name='command').getTag(name='x',namespace=NS_DATA)) session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): if self.sessions[session]['jid'] == request.getFrom(): reply = request.buildReply('result') fromstripped = form.getField('accountjid').getValue().encode('utf8') if self.userfile.has_key(fromstripped): del self.userfile[fromstripped] self.userfile.sync() reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'completed'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed def cmdCancel(self,conn,request): session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): del self.sessions[session] reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'canceled'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed class List_Registered_Users_Command(xmpp.commands.Command_Handler_Prototype): """This is the registered users command as documented in section 4.18 of XEP-0133. At the current time, no provision is made for splitting the userlist into sections""" name = NS_ADMIN_REGISTERED_USERS_LIST description = 'Get List of Registered Users' discofeatures = [xmpp.commands.NS_COMMANDS,xmpp.NS_DATA] def __init__(self,userfile,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = { 'execute':self.cmdFirstStage } self.userfile = userfile def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Build the reply to complete the request""" if request.getFrom().getStripped() in config.admins: reply = request.buildReply('result') form = DataForm(typ='result',data=[DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The list of registered users',name='registereduserjids',value=self.userfile.keys(),typ='jid-multi')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed class List_Online_Users_Command(xmpp.commands.Command_Handler_Prototype): """This is the online users command as documented in section 4.20 of XEP-0133. At the current time, no provision is made for splitting the userlist into sections""" name = NS_ADMIN_ONLINE_USERS_LIST description = 'Get List of Online Users' discofeatures = [xmpp.commands.NS_COMMANDS,xmpp.NS_DATA] def __init__(self,users,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = { 'execute':self.cmdFirstStage } self.users = users def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Build the reply to complete the request""" if request.getFrom().getStripped() in config.admins: reply = request.buildReply('result') form = DataForm(typ='result',data=[DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The list of online users',name='onlineuserjids',value=self.users.keys(),typ='jid-multi')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed class List_Active_Users_Command(xmpp.commands.Command_Handler_Prototype): """This is the active users command as documented in section 4.21 of XEP-0133. At the current time, no provision is made for splitting the userlist into sections""" name = NS_ADMIN_ACTIVE_USERS_LIST description = 'Get List of Active Users' discofeatures = [xmpp.commands.NS_COMMANDS,xmpp.NS_DATA] def __init__(self,users,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = { 'execute':self.cmdFirstStage } self.users = users def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Build the reply to complete the request""" if request.getFrom().getStripped() in config.admins: reply = request.buildReply('result') form = DataForm(typ='result',data=[DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The list of active users',name='activeuserjids',value=self.users.keys(),typ='jid-multi')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed class Edit_Admin_List_Command(xmpp.commands.Command_Handler_Prototype): """This command enables the editing of the administrators list as documented in section 4.29 of XEP-0133. (the users of XEP-0133 commands in this case)""" name = NS_ADMIN_EDIT_ADMIN description = 'Edit Admin List' discofeatures = [xmpp.commands.NS_COMMANDS, xmpp.NS_DATA] def __init__(self,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = {'execute':self.cmdFirstStage } def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Set the session ID, and return the form containing the current administrators""" if request.getFrom().getStripped() in config.admins: # Setup session ready for form reply session = self.getSessionID() self.sessions[session] = {'jid':request.getFrom(),'actions':{'cancel':self.cmdCancel,'next':self.cmdSecondStage,'execute':self.cmdSecondStage}} # Setup form with existing data in reply = request.buildReply('result') form = DataForm(title='Editing the Admin List',data=['Fill out this form to edit the list of entities who have administrative privileges', DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='The Admin List', typ='jid-multi', name='adminjids',value=config.admins)]) replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form] reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed def cmdSecondStage(self,conn,request): """Apply and save the config""" form = DataForm(node=request.getTag(name='command').getTag(name='x',namespace=NS_DATA)) session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): if self.sessions[session]['jid'] == request.getFrom(): config.admins = form.getField('adminjids').getValues() if len(config.admins) == 1 and len(config.admins[0]) == 0: config.admins = [] doc = parse(config.configFile) admins = doc.getElementsByTagName('admins')[0] for el in [x for x in admins.childNodes]: admins.removeChild(el) el.unlink() for admin in config.admins: txt = doc.createTextNode('\n ') admins.appendChild(txt) txt = doc.createTextNode(admin) el = doc.createElement('jid') el.appendChild(txt) admins.appendChild(el) txt = doc.createTextNode('\n ') admins.appendChild(txt) attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'completed'} payload=[] try: f = open(config.configFile,'w') doc.writexml(f) f.close() except IOError, (errno, strerror): # attrs['status'] = 'canceled' # Psi doesn't display the form if we cancel the command form = DataForm(typ='result',data=[DataField(value="I/O error(%s): %s" % (errno, strerror),typ='fixed')]) payload.append(form) doc.unlink() reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs=attrs,payload=payload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed def cmdCancel(self,conn,request): session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): del self.sessions[session] reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'canceled'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed class Restart_Service_Command(xmpp.commands.Command_Handler_Prototype): """This is the restart service command as documented in section 4.30 of XEP-0133.""" name = NS_ADMIN_RESTART description = 'Restart Service' discofeatures = [xmpp.commands.NS_COMMANDS, xmpp.NS_DATA] def __init__(self,transport,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = {'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Set the session ID, and return the form containing the restart reason""" if request.getFrom().getStripped() in config.admins: # Setup session ready for form reply session = self.getSessionID() self.sessions[session] = {'jid':request.getFrom(),'actions':{'cancel':self.cmdCancel,'next':self.cmdSecondStage,'execute':self.cmdSecondStage}} # Setup form with existing data in reply = request.buildReply('result') form = DataForm(title='Restarting the Service',data=['Fill out this form to restart the service', DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='Announcement', typ='text-multi', name='announcement')]) replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form] reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed def cmdSecondStage(self,conn,request): """Apply and save the config""" form = DataForm(node=request.getTag(name='command').getTag(name='x',namespace=NS_DATA)) session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): if self.sessions[session]['jid'] == request.getFrom(): self.transport.offlinemsg = '\n'.join(form.getField('announcement').getValues()) self.transport.restart = 1 self.transport.online = 0 reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'completed'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed def cmdCancel(self,conn,request): session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): del self.sessions[session] reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'canceled'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed class Shutdown_Service_Command(xmpp.commands.Command_Handler_Prototype): """This is the shutdown service command as documented in section 4.31 of XEP-0133.""" name = NS_ADMIN_SHUTDOWN description = 'Shut Down Service' discofeatures = [xmpp.commands.NS_COMMANDS, xmpp.NS_DATA] def __init__(self,transport,jid=''): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,jid) self.initial = {'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Set the session ID, and return the form containing the shutdown reason""" if request.getFrom().getStripped() in config.admins: # Setup session ready for form reply session = self.getSessionID() self.sessions[session] = {'jid':request.getFrom(),'actions':{'cancel':self.cmdCancel,'next':self.cmdSecondStage,'execute':self.cmdSecondStage}} # Setup form with existing data in reply = request.buildReply('result') form = DataForm(title='Shutting Down the Service',data=['Fill out this form to shut down the service', DataField(typ='hidden',name='FORM_TYPE',value=NS_ADMIN),DataField(desc='Announcement', typ='text-multi', name='announcement')]) replypayload = [Node('actions',attrs={'execute':'next'},payload=[Node('next')]),form] reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'executing'},payload=replypayload) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed def cmdSecondStage(self,conn,request): """Apply and save the config""" form = DataForm(node=request.getTag(name='command').getTag(name='x',namespace=NS_DATA)) session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): if self.sessions[session]['jid'] == request.getFrom(): self.transport.offlinemsg = '\n'.join(form.getField('announcement').getValues()) self.transport.online = 0 reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'completed'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed def cmdCancel(self,conn,request): session = request.getTagAttr('command','sessionid') if self.sessions.has_key(session): del self.sessions[session] reply = request.buildReply('result') reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':session,'status':'canceled'}) self._owner.send(reply) else: self._owner.send(Error(request,ERR_BAD_REQUEST)) raise NodeProcessed jabber-irc_0.4cvs20080505.orig/adhoc.py0000644000175100017510000003334510665234367016332 0ustar kalfakalfa# $Id: adhoc.py,v 1.3 2007/08/29 09:14:31 normanr Exp $ import sys, xmpp from xmpp.protocol import * from xmpp.jep0106 import * import config from jep0133 import * from irc_helpers import irc_ulower class AdHocCommands: def __init__(self, userfile): self.userfile = userfile def PlugIn(self, transport): self.commands = xmpp.commands.Commands(transport.disco) self.commands.PlugIn(transport.jabber) # XEP-0133 commands: transport.cmdadduser = Add_User_Command(self.userfile,jid=config.jid) transport.cmdadduser.plugin(self.commands) transport.cmddeleteuser = Delete_User_Command(self.userfile,jid=config.jid) transport.cmddeleteuser.plugin(self.commands) transport.cmdlistregisteredusers = List_Registered_Users_Command(self.userfile,jid=config.jid) transport.cmdlistregisteredusers.plugin(self.commands) transport.cmdlistonlineusers = List_Online_Users_Command(transport.users,jid=config.jid) transport.cmdlistonlineusers.plugin(self.commands) transport.cmdlistactiveusers = List_Active_Users_Command(transport.users,jid=config.jid) transport.cmdlistactiveusers.plugin(self.commands) transport.cmdeditadminusers = Edit_Admin_List_Command(jid=config.jid) transport.cmdeditadminusers.plugin(self.commands) transport.cmdrestartservice = Restart_Service_Command(transport,jid=config.jid) transport.cmdrestartservice.plugin(self.commands) transport.cmdshutdownservice = Shutdown_Service_Command(transport,jid=config.jid) transport.cmdshutdownservice.plugin(self.commands) # transport wide commands: transport.cmdconnectusers = Connect_Registered_Users_Command(self.userfile) transport.cmdconnectusers.plugin(self.commands) # server commands transport.cmdconnectserver = Connect_Server_Command(transport) transport.cmdconnectserver.plugin(self.commands) transport.cmddisconnectserver = Disconnect_Server_Command(transport) transport.cmddisconnectserver.plugin(self.commands) transport.cmdretrievemessageoftheday = Retrieve_Message_Of_The_Day(transport) transport.cmdretrievemessageoftheday.plugin(self.commands) transport.cmdretrieverules = Retrieve_Rules(transport) transport.cmdretrieverules.plugin(self.commands) class Connect_Registered_Users_Command(xmpp.commands.Command_Handler_Prototype): """This is the """ name = "connect-users" description = 'Connect all registered users' discofeatures = [xmpp.commands.NS_COMMANDS] def __init__(self,userfile): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,config.jid) self.initial = { 'execute':self.cmdFirstStage } self.userfile = userfile def _DiscoHandler(self,conn,request,type): """The handler for discovery events""" if request.getFrom().getStripped() in config.admins: return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,request,type) else: return None def cmdFirstStage(self,conn,request): """Build the reply to complete the request""" if request.getFrom().getStripped() in config.admins: for each in self.userfile.keys(): conn.send(Presence(to=each, frm = config.jid, typ = 'probe')) if self.userfile[each].has_key('servers'): for server in self.userfile[each]['servers']: conn.send(Presence(to=each, frm = '%s@%s'%(server,config.jid), typ = 'probe')) reply = request.buildReply('result') form = DataForm(typ='result',data=[DataField(value='Command completed.',typ='fixed')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':request.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) else: self._owner.send(Error(request,ERR_FORBIDDEN)) raise NodeProcessed class Connect_Server_Command(xmpp.commands.Command_Handler_Prototype): """This is the connect server command""" name = 'connect-server' description = 'Connect to server' discofeatures = [xmpp.commands.NS_COMMANDS] def __init__(self,transport): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,'') self.initial = { 'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,event,type): """The handler for discovery events""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '' and (not self.transport.users.has_key(fromjid) or not self.transport.users[fromjid].has_key(server)): return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,event,type) else: return None def cmdFirstStage(self,conn,event): """Build the reply to complete the request""" frm = event.getFrom() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '': if self.transport.irc_connect('',server,'','',frm,Presence()): self.transport.xmpp_presence_do_update(Presence(),server,frm.getStripped()) reply = event.buildReply('result') form = DataForm(typ='result',data=[DataField(value='Command completed.',typ='fixed')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':event.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) raise NodeProcessed else: self._owner.send(Error(event,ERR_CONFLICT)) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed class Disconnect_Server_Command(xmpp.commands.Command_Handler_Prototype): """This is the disconnect server command""" name = 'disconnect-server' description = 'Disconnect from server' discofeatures = [xmpp.commands.NS_COMMANDS] def __init__(self,transport): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,'') self.initial = { 'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,event,type): """The handler for discovery events""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '' and self.transport.users.has_key(fromjid) and self.transport.users[fromjid].has_key(server): return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,event,type) else: return None def cmdFirstStage(self,conn,event): """Build the reply to complete the request""" frm = event.getFrom() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '': if self.transport.irc_disconnect('',server,frm,None): self.transport.xmpp_presence_do_update(None,server,frm.getStripped()) reply = event.buildReply('result') form = DataForm(typ='result',data=[DataField(value='Command completed.',typ='fixed')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':event.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed class Retrieve_Message_Of_The_Day(xmpp.commands.Command_Handler_Prototype): """This is the message of the day server command""" name = 'motd' description = 'Retrieve Message of the Day' discofeatures = [xmpp.commands.NS_COMMANDS] def __init__(self,transport): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,'') self.initial = { 'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,event,type): """The handler for discovery events""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '' and self.transport.users.has_key(fromjid) and self.transport.users[fromjid].has_key(server): return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,event,type) else: return None def cmdFirstStage(self,conn,event): """Build the reply to complete the request""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '': if self.transport.users.has_key(fromjid) \ and self.transport.users[fromjid].has_key(server): # TODO: MOTD must become pending event, so it can go back to the right resource self.transport.users[fromjid][server].motdhash = '' self.transport.users[fromjid][server].motd() reply = event.buildReply('result') form = DataForm(typ='result',data=[DataField(value='Command completed.',typ='fixed')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':event.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed class Retrieve_Rules(xmpp.commands.Command_Handler_Prototype): """This is the message of the day server command""" name = 'rules' description = 'Retrieve Rules' discofeatures = [xmpp.commands.NS_COMMANDS] def __init__(self,transport): """Initialise the command object""" xmpp.commands.Command_Handler_Prototype.__init__(self,'') self.initial = { 'execute':self.cmdFirstStage } self.transport = transport def _DiscoHandler(self,conn,event,type): """The handler for discovery events""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '' and self.transport.users.has_key(fromjid) and self.transport.users[fromjid].has_key(server): return xmpp.commands.Command_Handler_Prototype._DiscoHandler(self,conn,event,type) else: return None def cmdFirstStage(self,conn,event): """Build the reply to complete the request""" fromjid = event.getFrom().getStripped().__str__() to = event.getTo() room = irc_ulower(to.getNode()) try: channel, server = room.split('%',1) channel = JIDDecode(channel) except ValueError: channel='' server=room sys.exc_clear() if channel == '': if self.transport.users.has_key(fromjid) \ and self.transport.users[fromjid].has_key(server): # TODO: RULES must become pending event, so it can go back to the right resource self.transport.users[fromjid][server].ruleshash = '' self.transport.users[fromjid][server].send_raw('RULES') reply = event.buildReply('result') form = DataForm(typ='result',data=[DataField(value='Command completed.',typ='fixed')]) reply.addChild(name='command',namespace=NS_COMMANDS,attrs={'node':event.getTagAttr('command','node'),'sessionid':self.getSessionID(),'status':'completed'},payload=[form]) self._owner.send(reply) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed else: self._owner.send(Error(event,ERR_ITEM_NOT_FOUND)) raise NodeProcessed jabber-irc_0.4cvs20080505.orig/README.txt0000644000175100017510000000265210434274544016370 0ustar kalfakalfaXMPP IRC-Transport Readme. ========================== Installing the transport: ------------------------- To install the transport you need a copy of the xmpppy (by Alexey Nezhdanov) library on your system and a copy of the irclib (by Joel Rosdahl). You can find both of these at the following addresses: http://xmpppy.sourceforge.net http://python-irclib.sourceforge.net To make the irclib library integrate with the transport more effectively you need to patch it with the supplied diff file: irclib.py.diff. (patch