PageRenderTime 26ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/taskcoach/taskcoachlib/thirdparty/Growl.py

https://github.com/dfainstein/seng_taskcoach
Python | 230 lines | 195 code | 23 blank | 12 comment | 13 complexity | 005efe489ce3f29339e198fdf9e02c21 MD5 | raw file
  1. """
  2. A Python module that enables posting notifications to the Growl daemon.
  3. See <http://growl.info/> for more information.
  4. """
  5. __version__ = "0.7"
  6. __author__ = "Mark Rowe <bdash@users.sourceforge.net>"
  7. __copyright__ = "(C) 2003 Mark Rowe <bdash@users.sourceforge.net>. Released under the BSD license."
  8. __contributors__ = ["Ingmar J Stein (Growl Team)",
  9. "Rui Carmo (http://the.taoofmac.com)",
  10. "Jeremy Rossi <jeremy@jeremyrossi.com>",
  11. "Peter Hosey <http://boredzo.org/> (Growl Team)",
  12. ]
  13. import _growl
  14. import types
  15. import struct
  16. import hashlib
  17. import socket
  18. GROWL_UDP_PORT=9887
  19. GROWL_PROTOCOL_VERSION=1
  20. GROWL_TYPE_REGISTRATION=0
  21. GROWL_TYPE_NOTIFICATION=1
  22. GROWL_APP_NAME="ApplicationName"
  23. GROWL_APP_ICON="ApplicationIcon"
  24. GROWL_NOTIFICATIONS_DEFAULT="DefaultNotifications"
  25. GROWL_NOTIFICATIONS_ALL="AllNotifications"
  26. GROWL_NOTIFICATIONS_USER_SET="AllowedUserNotifications"
  27. GROWL_NOTIFICATION_NAME="NotificationName"
  28. GROWL_NOTIFICATION_TITLE="NotificationTitle"
  29. GROWL_NOTIFICATION_DESCRIPTION="NotificationDescription"
  30. GROWL_NOTIFICATION_ICON="NotificationIcon"
  31. GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon"
  32. GROWL_NOTIFICATION_PRIORITY="NotificationPriority"
  33. GROWL_NOTIFICATION_STICKY="NotificationSticky"
  34. GROWL_APP_REGISTRATION="GrowlApplicationRegistrationNotification"
  35. GROWL_APP_REGISTRATION_CONF="GrowlApplicationRegistrationConfirmationNotification"
  36. GROWL_NOTIFICATION="GrowlNotification"
  37. GROWL_SHUTDOWN="GrowlShutdown"
  38. GROWL_PING="Honey, Mind Taking Out The Trash"
  39. GROWL_PONG="What Do You Want From Me, Woman"
  40. GROWL_IS_READY="Lend Me Some Sugar; I Am Your Neighbor!"
  41. growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2}
  42. class netgrowl:
  43. """Builds a Growl Network Registration packet.
  44. Defaults to emulating the command-line growlnotify utility."""
  45. __notAllowed__ = [GROWL_APP_ICON, GROWL_NOTIFICATION_ICON, GROWL_NOTIFICATION_APP_ICON]
  46. def __init__(self, hostname, password ):
  47. self.hostname = hostname
  48. self.password = password
  49. self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  50. def send(self, data):
  51. self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT))
  52. def PostNotification(self, userInfo):
  53. if userInfo.has_key(GROWL_NOTIFICATION_PRIORITY):
  54. priority = userInfo[GROWL_NOTIFICATION_PRIORITY]
  55. else:
  56. priority = 0
  57. if userInfo.has_key(GROWL_NOTIFICATION_STICKY):
  58. sticky = userInfo[GROWL_NOTIFICATION_STICKY]
  59. else:
  60. sticky = False
  61. data = self.encodeNotify(userInfo[GROWL_APP_NAME],
  62. userInfo[GROWL_NOTIFICATION_NAME],
  63. userInfo[GROWL_NOTIFICATION_TITLE],
  64. userInfo[GROWL_NOTIFICATION_DESCRIPTION],
  65. priority,
  66. sticky)
  67. return self.send(data)
  68. def PostRegistration(self, userInfo):
  69. data = self.encodeRegistration(userInfo[GROWL_APP_NAME],
  70. userInfo[GROWL_NOTIFICATIONS_ALL],
  71. userInfo[GROWL_NOTIFICATIONS_DEFAULT])
  72. return self.send(data)
  73. def encodeRegistration(self, application, notifications, defaultNotifications):
  74. data = struct.pack("!BBH",
  75. GROWL_PROTOCOL_VERSION,
  76. GROWL_TYPE_REGISTRATION,
  77. len(application) )
  78. data += struct.pack("BB",
  79. len(notifications),
  80. len(defaultNotifications) )
  81. data += application
  82. for i in notifications:
  83. encoded = i.encode("utf-8")
  84. data += struct.pack("!H", len(encoded))
  85. data += encoded
  86. for i in defaultNotifications:
  87. data += struct.pack("B", i)
  88. return self.encodePassword(data)
  89. def encodeNotify(self, application, notification, title, description,
  90. priority = 0, sticky = False):
  91. application = application.encode("utf-8")
  92. notification = notification.encode("utf-8")
  93. title = title.encode("utf-8")
  94. description = description.encode("utf-8")
  95. flags = (priority & 0x07) * 2
  96. if priority < 0:
  97. flags |= 0x08
  98. if sticky:
  99. flags = flags | 0x0001
  100. data = struct.pack("!BBHHHHH",
  101. GROWL_PROTOCOL_VERSION,
  102. GROWL_TYPE_NOTIFICATION,
  103. flags,
  104. len(notification),
  105. len(title),
  106. len(description),
  107. len(application) )
  108. data += notification
  109. data += title
  110. data += description
  111. data += application
  112. return self.encodePassword(data)
  113. def encodePassword(self, data):
  114. checksum = hashlib.md5()
  115. checksum.update(data)
  116. if self.password:
  117. checksum.update(self.password)
  118. data += checksum.digest()
  119. return data
  120. class _ImageHook(type):
  121. def __getattribute__(self, attr):
  122. global Image
  123. if Image is self:
  124. from _growlImage import Image
  125. return getattr(Image, attr)
  126. class Image(object):
  127. __metaclass__ = _ImageHook
  128. class _RawImage(object):
  129. def __init__(self, data): self.rawImageData = data
  130. class GrowlNotifier(object):
  131. """
  132. A class that abstracts the process of registering and posting
  133. notifications to the Growl daemon.
  134. You can either pass `applicationName', `notifications',
  135. `defaultNotifications' and `applicationIcon' to the constructor
  136. or you may define them as class-level variables in a sub-class.
  137. `defaultNotifications' is optional, and defaults to the value of
  138. `notifications'. `applicationIcon' is also optional but defaults
  139. to a pointless icon so is better to be specified.
  140. """
  141. applicationName = 'GrowlNotifier'
  142. notifications = []
  143. defaultNotifications = []
  144. applicationIcon = None
  145. _notifyMethod = _growl
  146. def __init__(self, applicationName=None, notifications=None, defaultNotifications=None, applicationIcon=None, hostname=None, password=None):
  147. if applicationName:
  148. self.applicationName = applicationName
  149. assert self.applicationName, 'An application name is required.'
  150. if notifications:
  151. self.notifications = list(notifications)
  152. assert self.notifications, 'A sequence of one or more notification names is required.'
  153. if defaultNotifications is not None:
  154. self.defaultNotifications = list(defaultNotifications)
  155. elif not self.defaultNotifications:
  156. self.defaultNotifications = list(self.notifications)
  157. if applicationIcon is not None:
  158. self.applicationIcon = self._checkIcon(applicationIcon)
  159. elif self.applicationIcon is not None:
  160. self.applicationIcon = self._checkIcon(self.applicationIcon)
  161. if hostname is not None and password is not None:
  162. self._notifyMethod = netgrowl(hostname, password)
  163. elif hostname is not None or password is not None:
  164. raise KeyError, "Hostname and Password are both required for a network notification"
  165. def _checkIcon(self, data):
  166. if isinstance(data, str):
  167. return _RawImage(data)
  168. else:
  169. return data
  170. def register(self):
  171. if self.applicationIcon is not None:
  172. self.applicationIcon = self._checkIcon(self.applicationIcon)
  173. regInfo = {GROWL_APP_NAME: self.applicationName,
  174. GROWL_NOTIFICATIONS_ALL: self.notifications,
  175. GROWL_NOTIFICATIONS_DEFAULT: self.defaultNotifications,
  176. GROWL_APP_ICON:self.applicationIcon,
  177. }
  178. self._notifyMethod.PostRegistration(regInfo)
  179. def notify(self, noteType, title, description, icon=None, sticky=False, priority=None):
  180. assert noteType in self.notifications
  181. notifyInfo = {GROWL_NOTIFICATION_NAME: noteType,
  182. GROWL_APP_NAME: self.applicationName,
  183. GROWL_NOTIFICATION_TITLE: title,
  184. GROWL_NOTIFICATION_DESCRIPTION: description,
  185. }
  186. if sticky:
  187. notifyInfo[GROWL_NOTIFICATION_STICKY] = 1
  188. if priority is not None:
  189. notifyInfo[GROWL_NOTIFICATION_PRIORITY] = priority
  190. if icon:
  191. notifyInfo[GROWL_NOTIFICATION_ICON] = self._checkIcon(icon)
  192. self._notifyMethod.PostNotification(notifyInfo)