GrowlにUDPでメッセージを送る

PyPIを見てみたけど、OS X用のコマンドをsystem()で起動するのであったり、OS Xでしかコンパイルできなさそうなファイルが必要(GrowlSDKのやつ)だったりして。
私は隣の部屋のWindowsから私のMacBookに送ってきてほしかっただけなので、最終的にDelphiのサンプルをそのまま変換した。
Stickyが効いてませんね。まぁ、こういうのはある程度動けば良いのであって、書かずに動かないことに比べたら無限大の良さがあるわけですよ。宝くじを買うのと同じですね。そして動かすこと自体が目的なのでいろいろおかしいです。なんでパスワードにデフォルトがあるんだ、とか、localhostっておい、とか。まぁそういうところは「面白さ」だと解釈すべきです。

ちなみにOS Xで作業してて目的のWindowsではテストしてないし、しかもなぜかPython3.0。

hashlib を使うために sudo port install py30-hashlib が必要らしくてしばらく悩んでました。

import socket
import struct
import hashlib

class Growl(object):
    def __init__(self, ApplicationName, NotificationName = 'Warning', Password='hogehoge'):
        self.ApplicationName = ApplicationName
        self.NotificationName = NotificationName
        self.Password = Password
    
    def Register(self):
        buf = struct.pack('!bbhbb', 1, 0, len(self.ApplicationName.encode('utf-8')), 1, 1)
        buf += self.ApplicationName.encode('utf-8')
        buf += struct.pack('!h', len(self.NotificationName))
        buf += self.NotificationName.encode('utf-8')
        buf += struct.pack('b', 0)
        hash = hashlib.md5(buf + bytes(self.Password, 'ascii')).digest()
        # print('hash:',hash)
        buf += struct.pack('!16s', hash)
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # print('rgst:',buf)
        s.sendto(buf, ('localhost', 9887))

    def SendNotification(self, title ,description, priority, sticky=False):
        flag = ((priority & 0x07) << 1 ) | 1 if sticky else 0
        # print('flag:', hex(flag))
        buf = struct.pack("!bbh", 1, 1, flag)
        buf += struct.pack("!hhhh",
                           len(self.NotificationName.encode('utf-8')),
                           len(title.encode('utf-8')),
                           len(description.encode('utf-8')),
                           len(self.ApplicationName.encode('utf-8')))
        buf += self.NotificationName.encode('utf-8')
        buf += title.encode('utf-8')
        buf += description.encode('utf-8')
        buf += self.ApplicationName.encode('utf-8')

        hash = hashlib.md5(buf + bytes(self.Password, 'ascii')).digest()
        buf += struct.pack('!16s', hash)
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # print('send:', buf)
        s.sendto(buf, ('localhost', 9887))

if __name__ == '__main__':
    g = Growl('grwoltest')
    g.Register()
    g.SendNotification('日本語です', '説明でっす。', 0, True)