Index: /snippets/commit-notifier.py
===================================================================
--- /snippets/commit-notifier.py (revision 12)
+++ /snippets/commit-notifier.py (revision 12)
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+# *-* coding: utf-8 -*-
+
+"""
+This is a very simple bot to show how automation using msnlib could be done.
+It's not quite useful as-is, but provides a good example.
+
+If you play with it, please let me know.
+"""
+
+
+# sys, for getting the parameters
+import sys, os
+
+# time, for sleeping
+import time
+
+# select to wait for events
+import select
+
+# socket, to catch errors
+import socket
+
+# thread, for creating the worker thread
+import thread
+
+# and, of course, msnlib
+import msnlib
+import msncb
+
+os.environ["LANG"] = "ko_KR.utf-8"
+
+def null(s):
+	"Null function, useful to void debug ones"
+	pass
+
+msnlib.debug = null
+msncb.debug = null
+
+m = msnlib.msnd()
+m.cb = msncb.cb()
+
+def get_grouped_list(md):
+	contacts = []
+	db = {}
+	for gid in md.groups.keys():
+		db[gid] = []
+	for gid in md.groups.keys():
+		for e in md.users.keys():
+			if md.users[e].gid == gid:
+				db[gid].append(e)
+	gids = db.keys()
+	gids.sort()
+	for gid in gids:
+		ul = db[gid]
+		ul.sort()
+		for email in ul:
+			u = m.users[email]
+			if u.status == 'FLN':
+				continue
+			contacts.append(email)
+	return contacts
+
+def lookSvn(command, repos, rev):
+	result = os.popen("/usr/bin/svnlook %s %s -r %s"%(command, repos, rev))
+	log = ""
+	for i in result.readlines():
+		if i[-1:] == "\n":
+			i = i[:-1]
+		log += i + "\r\n"
+	if log[-4:] == "\r\n\r\n":
+		log = log[:-2]
+	return log
+
+def getAuthor(repos, rev):
+	return lookSvn("author", repos, rev)
+
+def getLog(repos, rev):
+	return lookSvn("log", repos, rev)
+
+def getChanged(repos, rev):
+	return lookSvn("changed", repos, rev)
+
+def getContacts():
+	return get_grouped_list(m)
+
+def sendToAll(log):
+	contacts = getContacts()
+	for contact in contacts:
+		m.sendmsg(contact, log)
+		time.sleep(1)
+	time.sleep(1)
+
+def appendLog(log, string):
+	log += string
+	if 1400 <= len(log):
+		sendToAll(log[:1500])
+		print 'Send with overflow: '+log[:1500]
+		log = log[1500:]
+	return log
+
+def do_work():
+	"""
+	Here you do your stuff and send messages using m.sendmsg()
+	This is the only place your code lives
+	"""
+	
+	# wait a bit for everything to settle down (sync taking efect
+	# basically)
+	print 'Wait to login'
+	time.sleep(3)
+	print 'Making log..'
+	
+	repos = sys.argv[1]
+	rev = sys.argv[2]
+
+	m.encoding="UTF-8"
+
+	log = ""
+	log = appendLog(log, "Author: " + getAuthor(repos, rev))
+	log = appendLog(log, "Revision: " + rev + "\r\n")
+	log = appendLog(log, "----\r\n")
+	log = appendLog(log, getChanged(repos, rev))
+	log = appendLog(log, "----\r\n")
+	log = appendLog(log, getLog(repos, rev))
+
+	print 'Made a log'
+	sendToAll(log)
+
+	print 'Send messages: ', log
+
+	# give time to send the messages
+	print 'Wait to send'
+	time.sleep(10)
+	print 'Quit'
+
+	# and then quit
+	quit()
+	
+
+# you shouldn't need to touch anything past here
+
+
+# get the login email and password from the parameters
+try:
+	m.email = "PUT YOUR MSN E-MAIL"
+	m.pwd = "PUT YOUR MSN PASSWORD"
+except:
+	print "Use: msnbot email password"
+	sys.exit(1)
+
+
+m.login()
+
+# this makes the server send you the contact list, and it's recommended that
+# you do it because you can get in trouble when getting certain events from
+# people that are not on your list; and it's not that expensive anyway
+m.sync()
+
+# any non-offline status will do, otherwise we'll get an error from msn when
+# sending a message
+m.change_status("away")
+
+def quit():
+	try:
+		m.disconnect()
+	except:
+		pass
+	print "Exit"
+	sys.exit(0)
+
+# we start a thread to do the work. it's a thread because we want to share
+# everything, and fork cow semantics cause problems here
+thread.start_new_thread(do_work, ())
+
+
+# we loop over the network socket to get events
+while 1:
+	# we get pollable fds
+	t = m.pollable()
+	infd = t[0]
+	outfd = t[1]
+
+	# we select, waiting for events
+	try:
+		fds = select.select(infd, outfd, [], 0)
+	except:
+		quit()
+	
+	for i in fds[0] + fds[1]:       # see msnlib.msnd.pollable.__doc__
+		try:
+			m.read(i)
+		except ('SocketError', socket.error), err:
+			print 'Socket Error'
+			if i != m:
+				# user closed a connection
+				# note that messages can be lost here
+				m.close(i)
+			else:
+				# main socket closed
+				quit()
+
+	# sleep a bit so we don't take over the cpu
+	time.sleep(0.01)
+
+
+
