/growl/Growl.py
Python | 230 lines | 195 code | 23 blank | 12 comment | 13 complexity | 68823910725a039cad8776d1453998e1 MD5 | raw file
Possible License(s): GPL-3.0
- """
- A Python module that enables posting notifications to the Growl daemon.
- See <http://growl.info/> for more information.
- """
- __version__ = "0.7"
- __author__ = "Mark Rowe <bdash@users.sourceforge.net>"
- __copyright__ = "(C) 2003 Mark Rowe <bdash@users.sourceforge.net>. Released under the BSD license."
- __contributors__ = ["Ingmar J Stein (Growl Team)",
- "Rui Carmo (http://the.taoofmac.com)",
- "Jeremy Rossi <jeremy@jeremyrossi.com>",
- "Peter Hosey <http://boredzo.org/> (Growl Team)",
- ]
- import _growl
- import types
- import struct
- import md5
- import socket
- GROWL_UDP_PORT=9887
- GROWL_PROTOCOL_VERSION=1
- GROWL_TYPE_REGISTRATION=0
- GROWL_TYPE_NOTIFICATION=1
- GROWL_APP_NAME="ApplicationName"
- GROWL_APP_ICON="ApplicationIcon"
- GROWL_NOTIFICATIONS_DEFAULT="DefaultNotifications"
- GROWL_NOTIFICATIONS_ALL="AllNotifications"
- GROWL_NOTIFICATIONS_USER_SET="AllowedUserNotifications"
- GROWL_NOTIFICATION_NAME="NotificationName"
- GROWL_NOTIFICATION_TITLE="NotificationTitle"
- GROWL_NOTIFICATION_DESCRIPTION="NotificationDescription"
- GROWL_NOTIFICATION_ICON="NotificationIcon"
- GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon"
- GROWL_NOTIFICATION_PRIORITY="NotificationPriority"
-
- GROWL_NOTIFICATION_STICKY="NotificationSticky"
- GROWL_APP_REGISTRATION="GrowlApplicationRegistrationNotification"
- GROWL_APP_REGISTRATION_CONF="GrowlApplicationRegistrationConfirmationNotification"
- GROWL_NOTIFICATION="GrowlNotification"
- GROWL_SHUTDOWN="GrowlShutdown"
- GROWL_PING="Honey, Mind Taking Out The Trash"
- GROWL_PONG="What Do You Want From Me, Woman"
- GROWL_IS_READY="Lend Me Some Sugar; I Am Your Neighbor!"
-
- growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2}
- class netgrowl:
- """Builds a Growl Network Registration packet.
- Defaults to emulating the command-line growlnotify utility."""
- __notAllowed__ = [GROWL_APP_ICON, GROWL_NOTIFICATION_ICON, GROWL_NOTIFICATION_APP_ICON]
- def __init__(self, hostname, password ):
- self.hostname = hostname
- self.password = password
- self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- def send(self, data):
- self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT))
-
- def PostNotification(self, userInfo):
- if userInfo.has_key(GROWL_NOTIFICATION_PRIORITY):
- priority = userInfo[GROWL_NOTIFICATION_PRIORITY]
- else:
- priority = 0
- if userInfo.has_key(GROWL_NOTIFICATION_STICKY):
- sticky = userInfo[GROWL_NOTIFICATION_STICKY]
- else:
- sticky = False
- data = self.encodeNotify(userInfo[GROWL_APP_NAME],
- userInfo[GROWL_NOTIFICATION_NAME],
- userInfo[GROWL_NOTIFICATION_TITLE],
- userInfo[GROWL_NOTIFICATION_DESCRIPTION],
- priority,
- sticky)
- return self.send(data)
- def PostRegistration(self, userInfo):
- data = self.encodeRegistration(userInfo[GROWL_APP_NAME],
- userInfo[GROWL_NOTIFICATIONS_ALL],
- userInfo[GROWL_NOTIFICATIONS_DEFAULT])
- return self.send(data)
- def encodeRegistration(self, application, notifications, defaultNotifications):
- data = struct.pack("!BBH",
- GROWL_PROTOCOL_VERSION,
- GROWL_TYPE_REGISTRATION,
- len(application) )
- data += struct.pack("BB",
- len(notifications),
- len(defaultNotifications) )
- data += application
- for i in notifications:
- encoded = i.encode("utf-8")
- data += struct.pack("!H", len(encoded))
- data += encoded
- for i in defaultNotifications:
- data += struct.pack("B", i)
- return self.encodePassword(data)
- def encodeNotify(self, application, notification, title, description,
- priority = 0, sticky = False):
- application = application.encode("utf-8")
- notification = notification.encode("utf-8")
- title = title.encode("utf-8")
- description = description.encode("utf-8")
- flags = (priority & 0x07) * 2
- if priority < 0:
- flags |= 0x08
- if sticky:
- flags = flags | 0x0001
- data = struct.pack("!BBHHHHH",
- GROWL_PROTOCOL_VERSION,
- GROWL_TYPE_NOTIFICATION,
- flags,
- len(notification),
- len(title),
- len(description),
- len(application) )
- data += notification
- data += title
- data += description
- data += application
- return self.encodePassword(data)
- def encodePassword(self, data):
- checksum = md5.new()
- checksum.update(data)
- if self.password:
- checksum.update(self.password)
- data += checksum.digest()
- return data
- class _ImageHook(type):
- def __getattribute__(self, attr):
- global Image
- if Image is self:
- from _growlImage import Image
- return getattr(Image, attr)
- class Image(object):
- __metaclass__ = _ImageHook
- class _RawImage(object):
- def __init__(self, data): self.rawImageData = data
- class GrowlNotifier(object):
- """
- A class that abstracts the process of registering and posting
- notifications to the Growl daemon.
- You can either pass `applicationName', `notifications',
- `defaultNotifications' and `applicationIcon' to the constructor
- or you may define them as class-level variables in a sub-class.
- `defaultNotifications' is optional, and defaults to the value of
- `notifications'. `applicationIcon' is also optional but defaults
- to a pointless icon so is better to be specified.
- """
- applicationName = 'GrowlNotifier'
- notifications = []
- defaultNotifications = []
- applicationIcon = None
- _notifyMethod = _growl
- def __init__(self, applicationName=None, notifications=None, defaultNotifications=None, applicationIcon=None, hostname=None, password=None):
- if applicationName:
- self.applicationName = applicationName
- assert(self.applicationName, 'An application name is required.')
- if notifications:
- self.notifications = list(notifications)
- assert(self.notifications, 'A sequence of one or more notification names is required.')
- if defaultNotifications is not None:
- self.defaultNotifications = list(defaultNotifications)
- elif not self.defaultNotifications:
- self.defaultNotifications = list(self.notifications)
- if applicationIcon is not None:
- self.applicationIcon = self._checkIcon(applicationIcon)
- elif self.applicationIcon is not None:
- self.applicationIcon = self._checkIcon(self.applicationIcon)
- if hostname is not None and password is not None:
- self._notifyMethod = netgrowl(hostname, password)
- elif hostname is not None or password is not None:
- raise KeyError, "Hostname and Password are both required for a network notification"
- def _checkIcon(self, data):
- if isinstance(data, str):
- return _RawImage(data)
- else:
- return data
- def register(self):
- if self.applicationIcon is not None:
- self.applicationIcon = self._checkIcon(self.applicationIcon)
- regInfo = {GROWL_APP_NAME: self.applicationName,
- GROWL_NOTIFICATIONS_ALL: self.notifications,
- GROWL_NOTIFICATIONS_DEFAULT: self.defaultNotifications,
- GROWL_APP_ICON:self.applicationIcon,
- }
- self._notifyMethod.PostRegistration(regInfo)
- def notify(self, noteType, title, description, icon=None, sticky=False, priority=None):
- assert noteType in self.notifications
- notifyInfo = {GROWL_NOTIFICATION_NAME: noteType,
- GROWL_APP_NAME: self.applicationName,
- GROWL_NOTIFICATION_TITLE: title,
- GROWL_NOTIFICATION_DESCRIPTION: description,
- }
- if sticky:
- notifyInfo[GROWL_NOTIFICATION_STICKY] = 1
- if priority is not None:
- notifyInfo[GROWL_NOTIFICATION_PRIORITY] = priority
- if icon:
- notifyInfo[GROWL_NOTIFICATION_ICON] = self._checkIcon(icon)
- self._notifyMethod.PostNotification(notifyInfo)