python workshop the edge 2007
Mac + PyObjC + Skype.app + α
2007.6.30
Daiji Hirata

Daiji Hirata, http://www.daijihirata.com/
1

Today’s outline• python on mac• pyobjc and py2app• skype cocoa framework• write codes of skypebot

Daiji Hirata, http://www.daijihirata.com/
2

Python on Mac• Bundled in MacOSX• 2.3.5 for panther (10.4)• Python Bindings for Quartz 2D, etc...
• see /System/Library/Frameworks/Python.framework

Daiji Hirata, http://www.daijihirata.com/
3

PyObjC - Objective-C bridge• Not only for MacOS X, but also Objective-C Bridge• The most important usage is writing Cocoa Applications, of course!
• You can create standalone application with py2app
http://pyobjc.sourceforge.net/
http://svn.pythonmac.org/py2app/py2app/

Daiji Hirata, http://www.daijihirata.com/
4Skype• Software VOIP application• voice and video• P2P structure• Powerful chat and group chat support• Conference Call, Public Chat, etc...
• Windows, Mac, Linux

Daiji Hirata, http://www.daijihirata.com/
5

Skype Protocol and API• closed network access to communicate each clients• protocol is open via Skype.app, client application• send/receive messages from/to Skype.app• MEMBER, CHAT, MESSAGE, CALL, AP2AP, etc..
• You can access Skype network via Skype.app

Daiji Hirata, http://www.daijihirata.com/
6

Skype.framework• Skype API is available in Skype for Mac OS X
• Carbon and Cocoa interfaces are implemented in Skype.framework• see https://developer.skype.com/Docs/ApiDoc/Skype_API_on_Mac

Daiji Hirata, http://www.daijihirata.com/
7

Skype API (cont)• SkypeAPI.setSkypeDelegate_()• SkypeAPI.connect() / disconnect()• SkypeAPI.sendSkypeCommand_()• SkypeAPI.skypeNotificationReceived_()Daiji Hirata, http://www.daijihirata.com/
8Main
def main():import sys
bot = delegate.alloc().init()
SkypeAPI.setSkypeDelegate_(bot)SkypeAPI.connect()print "connected."# object to be Skype delegate

b = task_bot()b.add(1, dump)
b.add(2, echo)
try:
AppHelper.runConsoleEventLoop(installInterrupt=True)
except KeyboardInterrupt:
print "Keyboard Interrupt"
AppHelper.stopEventLoop()
SkypeAPI.disconnect()print "disconnected."sys.exit(0)if __name__ == "__main__":main()Daiji Hirata, http://www.daijihirata.com/
9

SkypeAPI Delegate
SKYPE_APPLICATION_NAME = 'test'class delegate(NSObject):""" delegate class to be registed to setSkypeDelegate_()"""
def clientApplicationName(self):
return NSString.alloc().initWithString_(SKYPE_APPLICATION_NAME)
def skypeAttachResponse_(self):
print "accepted"
pass
def skypeNotificationReceived_(self, aNotificationString = ''):
bot = receiver(aNotificationString)bot.start()
def skypeBecameAvailable_(self, aNotification = ''):
pass
def skypeBecameUnavailable_(self, aNotification = ''):
pass

Daiji Hirata, http://www.daijihirata.com/
10

Receiverfrom threading import Threadclass receiver(Thread):def __init__(self, message = False):
self.message = message
Thread.__init__(self)
def run(self):
if self.message:
msg = self.message
self.message = False# MESSAGE from Skype.app stored as string# run registed tasks
task_receiver().run(msg)

Daiji Hirata, http://www.daijihirata.com/
11

Receiver (cont)# Notification of received message from someone# send command to retrive the object of chat message
m = re.compile('(?:CHAT)?MESSAGE (\d+) STATUS RECEIVED').match(msg)
message_props = ['timestamp', 'from_handle', 'from_dispname','chatname', 'type', 'body', 'users','leavereason']
if m:
cmd_string = '|'.join(message_props).upper()message_id = int(m.group(1))
msg = messages()for p in message_props:res = SkypeAPI.sendSkypeCommand_("GET CHATMESSAGE %d %s" % (message_id, p.upper()))
m = re.compile("MESSAGE (\d+) (%s)(.*)$" % p.upper(), re.DOTALL).match(res)message_id = int(m.group(1))
message_type = m.group(2).lower()
message_body = m.group(3).lstrip().rstrip()msg.set(message_id, message_type, message_body)s = bot(msg.get(message_id))s.start()msg.sent(message_id)

Daiji Hirata, http://www.daijihirata.com/
12

Skypebot - echoclass echo(Thread):def __init__(self, msg):
self.message = msg
Thread.__init__(self)
def run(self):s = sendMessage(self.message.chatname,'Re: ' + self.message.body)s.start()Daiji Hirata, http://www.daijihirata.com/
13

sendMeesageclass sendMessage(Thread):def __init__(self, chat_id, message, timestamp = 0):
self.timestamp = timestamp
self.chat_id = chat_id
self.message = message
self.running = False
Thread.__init__(self)
def run(self):
self.running = True
# timer
import time
while self.running is True and self.timestamp > time.time():time.sleep(5)pool = NSAutoreleasePool.alloc().init()
SkypeAPI.sendSkypeCommand_("CHATMESSAGE %s %s" % (self.chat_id, self.message))del pooldef stop(self):
self.running = False

Daiji Hirata, http://www.daijihirata.com/
14

applications possibility• logger (skype has better one...)• post URL to del.icio.us in chat messages• post everything to twitter• notification by email• chatbot / AI
• RSS notifier• clock, alarm• calendar, reminder• etc

Daiji Hirata, http://www.daijihirata.com/
15

sample is available• http://www.uva.ne.jp/test/skype.py• Skype API 2.5 or later• Sorry ugly code, no documentation and no warranty

Daiji Hirata, http://www.daijihirata.com/
16

Special Thanks to• Inspired by Dorio• みんなの Python

http://drikin.com/dorio/

Daiji Hirata, http://www.daijihirata.com/
17Thank you very much
ご静聴ありがとうございました
email: dh@uva.jp
web: http://daijihirata.com/

Daiji Hirata, http://www.daijihirata.com/
18