#!/usr/bin/python """IRC bot shell using IRC Async. Sean B. Palmer, 2002. GPL 2. (thanks to deltab)""" # # # # # # # # # # # # # # # # # # # Main config stuff NickName = 'blogbot' bloguri = 'http://sbp.f2o.org/noets/' password = '@@ Your Password Here' # End of main config stuff # # # # # # # # # # # # # # # # # # import ircAsync import sys, re, urllib, urllib2, time, asyncore ignore = [re.compile('^%s$' % s.replace('.', r'\.').replace('*', '.*')) for s in ( '216.159.127.*', '*.dialup.netins.net' )] from ircAsync import PRIVMSG, NOTICE, PING, PONG, USER from ircAsync import NICK, JOIN, PART, INVITE, QUIT from ircAsync import SPC, CR, LF, CRLF, RPL_WELCOME def ctcp(s): return '\x01%s\x01' % s def me(s): return ctcp('ACTION %s' % s) def parseOrigin(origin): nickid, host = tuple(origin.split('@')) nick, userid = tuple(nickid.split('!')) return (nick, userid, host) def runIRC(hostName, port, chan): c = ircAsync.T() c.startChannels(chan) c.nick = NickName c.userid = 'blogbot' c.bloggers = {} # Put any new functions here def hi(m, origin, args, text, c=c): c.tell(args[1], 'hi, %s' % origin.split('!')[0]) c.bind(hi, PRIVMSG, r"(?i)^(Hi|Hey|welcome),? %s!?$" % NickName) def help(m, origin, args, text, c=c): channel = args[1] for line in ( "Hi there. I'm a blogging bot", "To start an entry, type '<<< ' and then the entry title...", "For example: '<<< This is a Test Post'", "Everything you type from then on will be part of the entry", "To seperate paragraphs, use '..' on a single line", "The link syntax is {link title }", "I won't post any line starting with ':: '", "To change the title, use '@title My New Title'", "Then, to post the entry, use '>>>' on a single line", "To quit an entry whilst editing, use '@quit'."): c.tell(channel, line) time.sleep(1.5) c.bind(help, PRIVMSG, r"(?i)^(help),? %s!?$" % NickName) c.bind(help, PRIVMSG, r"(?i)^%s[:,]? help!?$" % NickName) def startEntry(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) for ignoral in ignore: if ignoral.match(host): return title = m.group(1) or None if title: title = title.lstrip() c.todo([NOTICE, nick], "%s: set title" % nick) else: title = None c.bloggers[nick] = {'title': title, 'content': '', 'pass': password, 'nick': nick, 'channel': channel} c.bind(startEntry, PRIVMSG, r"^<<<( .+)?$") def titleEntry(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) if c.bloggers.has_key(nick): title = m.group(1) if c.bloggers[nick]['title'] is None: c.bloggers[nick]['title'] = title c.todo([NOTICE, nick], "%s: set title" % nick) else: c.bloggers[nick]['title'] = title c.todo([NOTICE, nick], "%s: reset title" % nick) # else: just do nothing. @@ display a message? c.bind(titleEntry, PRIVMSG, r"^@title (.+)$") def entryText(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) if c.bloggers.has_key(nick): if (channel == c.bloggers[nick].get('channel') and text not in ('<<<', '>>>') and not text.startswith('<<< ') and not text.startswith('@title ') and not text.startswith(':: ') and not text.startswith(':s') and (nick != 'd8uv' or not text.startswith(';; '))): c.bloggers[nick]['content'] += text + '\n' c.bind(entryText, PRIVMSG, r"(.+)") def editEntry(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) stype, find, repl, flags = m.groups() find = find.replace('\\%s' % stype, '%s' % stype) repl = repl.replace('\\%s' % stype, '%s' % stype) if c.bloggers.has_key(nick): if channel == c.bloggers[nick].get('channel'): text = c.bloggers[nick]['content'] addNewline = '' if text.endswith('\n'): text = text[:-1] addNewline = '\n' i = text.rfind('\n') + 1 line = text[i:] text = text[:i] if 'g' in flags: line = line.replace(find, repl) else: line = line.replace(find, repl, 1) msg = 'New line is: %r' % line[:300] c.todo([NOTICE, nick], msg) c.bloggers[nick]['content'] = text + line + addNewline r_sol = r'[^/\\]*(?:\\.[^/\\]*)*' r_exc = r'[^!\\]*(?:\\.[^!\\]*)*' c.bind(editEntry, PRIVMSG, r"^:s(/)(%s)/(%s)/(g?)$" % (r_sol, r_sol)) c.bind(editEntry, PRIVMSG, r"^:s(!)(%s)!(%s)!(g?)$" % (r_exc, r_exc)) def finishEntry(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) if c.bloggers.has_key(nick): if not c.bloggers[nick]['title']: msg = "%s: you need to title the entry" % nick c.todo([NOTICE, nick], msg) return if not c.bloggers[nick]['content'].strip(): msg = "%s: you must supply some text" % nick c.todo([NOTICE, nick], msg) return form = urllib.urlencode(c.bloggers[nick]) try: u = urllib2.urlopen(bloguri, data=form) i = u.read() i = i.strip() assert i.isdigit(), "server returned non-digit: %r" % i u.close() except Exception, e: exp = "%s: %s" % (e.__class__, e) msg = "%s: publishing error: %s. try again!" % (nick, exp) c.tell(channel, msg) else: msg = "%s: published entry to %s%s" % (nick, bloguri, i) c.tell(channel, msg) del c.bloggers[nick] else: msg = "%s: you've not started an entry" % nick c.todo([NOTICE, nick], msg) c.bind(finishEntry, PRIVMSG, r"^>>>$") def quitEntry(m, origin, args, text, c=c): channel = args[1] nick, userid, host = parseOrigin(origin) if c.bloggers.has_key(nick): del c.bloggers[nick] c.todo([NOTICE, nick], "%s: abandoned current entry" % nick) c.bind(quitEntry, PRIVMSG, r"^@quit$") c.makeConn(hostName, port) while 1: try: asyncore.loop() except: time.sleep(10) def main(argv=None): if argv is None: argv = sys.argv if len(argv) > 2: server, chans = argv[1], argv[2:] chans = [('#%s' % c, c)[c.startswith('#')] for c in chans] if ':' in server: server, port = server.split(':') else: port = '6667' runIRC(server, int(port), chans) else: print __doc__ if __name__=='__main__': main()