/netgrowl.py

https://github.com/philips/cheekh · Python · 112 lines · 79 code · 17 blank · 16 comment · 9 complexity · fb38e2d74b8c5bedb0ad0b30afbe6d77 MD5 · raw file

  1. #!/usr/bin/env python
  2. """Growl 0.6 Network Protocol Client for Python"""
  3. __version__ = "0.6.3"
  4. __author__ = "Rui Carmo (http://the.taoofmac.com)"
  5. __copyright__ = "(C) 2004 Rui Carmo. Code under BSD License."
  6. __contributors__ = "Ingmar J Stein (Growl Team), John Morrissey (hashlib patch)"
  7. try:
  8. import hashlib
  9. md5_constructor = hashlib.md5
  10. except ImportError:
  11. import md5
  12. md5_constructor = md5.new
  13. import struct
  14. from socket import AF_INET, SOCK_DGRAM, socket
  15. GROWL_UDP_PORT=9887
  16. GROWL_PROTOCOL_VERSION=1
  17. GROWL_TYPE_REGISTRATION=0
  18. GROWL_TYPE_NOTIFICATION=1
  19. class GrowlRegistrationPacket:
  20. """Builds a Growl Network Registration packet.
  21. Defaults to emulating the command-line growlnotify utility."""
  22. def __init__(self, application="growlnotify", password = None ):
  23. self.notifications = []
  24. self.defaults = [] # array of indexes into notifications
  25. self.application = application.encode("utf-8")
  26. self.password = password
  27. # end def
  28. def addNotification(self, notification="Command-Line Growl Notification", enabled=True):
  29. """Adds a notification type and sets whether it is enabled on the GUI"""
  30. self.notifications.append(notification)
  31. if enabled:
  32. self.defaults.append(len(self.notifications)-1)
  33. # end def
  34. def payload(self):
  35. """Returns the packet payload."""
  36. self.data = struct.pack( "!BBH",
  37. GROWL_PROTOCOL_VERSION,
  38. GROWL_TYPE_REGISTRATION,
  39. len(self.application) )
  40. self.data += struct.pack( "BB",
  41. len(self.notifications),
  42. len(self.defaults) )
  43. self.data += self.application
  44. for notification in self.notifications:
  45. encoded = notification.encode("utf-8")
  46. self.data += struct.pack("!H", len(encoded))
  47. self.data += encoded
  48. for default in self.defaults:
  49. self.data += struct.pack("B", default)
  50. self.checksum = md5_constructor()
  51. self.checksum.update(self.data)
  52. if self.password:
  53. self.checksum.update(self.password)
  54. self.data += self.checksum.digest()
  55. return self.data
  56. # end def
  57. # end class
  58. class GrowlNotificationPacket:
  59. """Builds a Growl Network Notification packet.
  60. Defaults to emulating the command-line growlnotify utility."""
  61. def __init__(self, application="growlnotify",
  62. notification="Command-Line Growl Notification", title="Title",
  63. description="Description", priority = 0, sticky = False, password = None ):
  64. self.application = application.encode("utf-8")
  65. self.notification = notification.encode("utf-8")
  66. self.title = title.encode("utf-8")
  67. self.description = description.encode("utf-8")
  68. flags = (priority & 0x07) * 2
  69. if priority < 0:
  70. flags |= 0x08
  71. if sticky:
  72. flags = flags | 0x0100
  73. self.data = struct.pack( "!BBHHHHH",
  74. GROWL_PROTOCOL_VERSION,
  75. GROWL_TYPE_NOTIFICATION,
  76. flags,
  77. len(self.notification),
  78. len(self.title),
  79. len(self.description),
  80. len(self.application) )
  81. self.data += self.notification
  82. self.data += self.title
  83. self.data += self.description
  84. self.data += self.application
  85. self.checksum = md5_constructor()
  86. self.checksum.update(self.data)
  87. if password:
  88. self.checksum.update(password)
  89. self.data += self.checksum.digest()
  90. # end def
  91. def payload(self):
  92. """Returns the packet payload."""
  93. return self.data
  94. # end def
  95. # end class