PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/netgrowl/netgrowl.py

https://github.com/timc3/netgrowl
Python | 188 lines | 151 code | 14 blank | 23 comment | 12 complexity | db0de17aff469ecc93d55c1fbf4903c2 MD5 | raw file
  1. #!/usr/bin/env python
  2. # Altered 1st October 2010 - Tim Child.
  3. # Have added the ability for the command line arguments to take a password.
  4. # Altered 1-17-2010 - Tanner Stokes - www.tannr.com
  5. # Added support for command line arguments
  6. # ORIGINAL CREDITS
  7. # """Growl 0.6 Network Protocol Client for Python"""
  8. # __version__ = "0.6.3"
  9. # __author__ = "Rui Carmo (http://the.taoofmac.com)"
  10. # __copyright__ = "(C) 2004 Rui Carmo. Code under BSD License."
  11. # __contributors__ = "Ingmar J Stein (Growl Team), John Morrissey (hashlib patch)"
  12. try:
  13. import hashlib
  14. md5_constructor = hashlib.md5
  15. except ImportError:
  16. import md5
  17. md5_constructor = md5.new
  18. import struct
  19. # needed for command line arguments
  20. import sys
  21. import getopt
  22. from socket import AF_INET, SOCK_DGRAM, socket
  23. GROWL_UDP_PORT=9887
  24. GROWL_PROTOCOL_VERSION=1
  25. GROWL_TYPE_REGISTRATION=0
  26. GROWL_TYPE_NOTIFICATION=1
  27. def main(argv):
  28. # default to sending to localhost
  29. host = "localhost"
  30. # default title
  31. title = "Title"
  32. # default description
  33. description = "Description"
  34. # default priority
  35. priority = 0
  36. # default stickiness
  37. sticky = False
  38. try:
  39. opts, args = getopt.getopt(argv, "hH:t:d:p:s:x:")
  40. except getopt.GetoptError:
  41. usage()
  42. sys.exit(2)
  43. for opt, arg in opts:
  44. if opt in ("-h"):
  45. usage()
  46. sys.exit()
  47. elif opt in ("-H"):
  48. host = arg
  49. elif opt in ("-t"):
  50. title = arg
  51. elif opt in ("-d"):
  52. description = arg
  53. elif opt in ("-x"):
  54. password = arg
  55. elif opt in ("-p"):
  56. # acceptable values: -2 to 2
  57. priority = int(arg)
  58. elif opt in ("-s"):
  59. sticky = True
  60. # connect up to Growl server machine
  61. addr = (host, GROWL_UDP_PORT)
  62. s = socket(AF_INET,SOCK_DGRAM)
  63. # register application with remote Growl
  64. p = GrowlRegistrationPacket(password=password)
  65. p.addNotification()
  66. # send registration packet
  67. s.sendto(p.payload(), addr)
  68. # assemble notification packet
  69. p = GrowlNotificationPacket(title=title, description=description, priority=priority, sticky=sticky,password=password)
  70. # send notification packet
  71. s.sendto(p.payload(), addr)
  72. s.close()
  73. def usage():
  74. print """Usage: ./netgrowl.py [-hs] [-H hostname] [-t title] [-d description] [-p priority] [-x password]
  75. Send Growl messages over UDP
  76. -h help
  77. -H specify host
  78. -t title
  79. -d description
  80. -p priority [-2 to 2]
  81. -s make sticky
  82. -x password
  83. """
  84. class GrowlRegistrationPacket:
  85. """Builds a Growl Network Registration packet.
  86. Defaults to emulating the command-line growlnotify utility."""
  87. def __init__(self, application="NetGrowl", password = None ):
  88. self.notifications = []
  89. self.defaults = [] # array of indexes into notifications
  90. self.application = application.encode("utf-8")
  91. self.password = password
  92. print password
  93. # end def
  94. def addNotification(self, notification="Command-Line Growl Notification", enabled=True):
  95. """Adds a notification type and sets whether it is enabled on the GUI"""
  96. self.notifications.append(notification)
  97. if enabled:
  98. self.defaults.append(len(self.notifications)-1)
  99. # end def
  100. def payload(self):
  101. """Returns the packet payload."""
  102. self.data = struct.pack( "!BBH",
  103. GROWL_PROTOCOL_VERSION,
  104. GROWL_TYPE_REGISTRATION,
  105. len(self.application) )
  106. self.data += struct.pack( "BB",
  107. len(self.notifications),
  108. len(self.defaults) )
  109. self.data += self.application
  110. for notification in self.notifications:
  111. encoded = notification.encode("utf-8")
  112. self.data += struct.pack("!H", len(encoded))
  113. self.data += encoded
  114. for default in self.defaults:
  115. self.data += struct.pack("B", default)
  116. self.checksum = md5_constructor()
  117. self.checksum.update(self.data)
  118. if self.password:
  119. self.checksum.update(self.password)
  120. self.data += self.checksum.digest()
  121. return self.data
  122. # end def
  123. # end class
  124. class GrowlNotificationPacket:
  125. """Builds a Growl Network Notification packet.
  126. Defaults to emulating the command-line growlnotify utility."""
  127. def __init__(self, application="NetGrowl",
  128. notification="Command-Line Growl Notification", title="Title",
  129. description="Description", priority = 0, sticky = False, password = None ):
  130. self.application = application.encode("utf-8")
  131. self.notification = notification.encode("utf-8")
  132. self.title = title.encode("utf-8")
  133. self.description = description.encode("utf-8")
  134. flags = (priority & 0x07) * 2
  135. if priority < 0:
  136. flags |= 0x08
  137. if sticky:
  138. flags = flags | 0x0100
  139. self.data = struct.pack( "!BBHHHHH",
  140. GROWL_PROTOCOL_VERSION,
  141. GROWL_TYPE_NOTIFICATION,
  142. flags,
  143. len(self.notification),
  144. len(self.title),
  145. len(self.description),
  146. len(self.application) )
  147. self.data += self.notification
  148. self.data += self.title
  149. self.data += self.description
  150. self.data += self.application
  151. self.checksum = md5_constructor()
  152. self.checksum.update(self.data)
  153. if password:
  154. self.checksum.update(password)
  155. self.data += self.checksum.digest()
  156. # end def
  157. def payload(self):
  158. """Returns the packet payload."""
  159. return self.data
  160. # end def
  161. # end class
  162. if __name__ == '__main__':
  163. # send command line arguments to main() function
  164. main(sys.argv[1:])