pubsubclient: 728ff4b8ebf68255e5bcddd9d00e05b720806c74

     1: #!/usr/bin/env python
     2: 
     3: # Import what we need
     4: import xmpp
     5: import sys
     6: import os
     7: import time
     8: import pubsubclient
     9: from pubsubclient import Node
    10: import lxml.etree as etree
    11: from random import Random
    12: import string
    13: from lxml.etree import ElementTree, Element, SubElement
    14: import pygtk
    15: import gtk
    16: import gobject
    17: #import webkit
    18: import feedparser
    19: from StringIO import StringIO
    20: from kiwi.ui.objectlist import Column, ObjectTree, ObjectList
    21: import xdg.BaseDirectory
    22: 
    23: class LeftRow:
    24: 	"""This is a row on the left-hand pane."""
    25: 
    26: 	def __init__(self, name, count, unread):
    27: 		"""name is the name to display, count is the number of items,
    28: 		unread is the number of unread items."""
    29: 		self.name = name
    30: 		self.count = count
    31: 		self.unread = unread
    32: 
    33: class FoundRow:
    34: 	"""This is a row in the window which finds and subscribes new nodes."""
    35: 
    36: 	def __init__(self, name, node):
    37: 		"""name is the name to display, node is the path of the node on
    38: 		the server."""
    39: 		self.name = name
    40: 		self.node = node
    41: 
    42: class Display:
    43: 	"""This is the main window class."""
    44: 
    45: 	def __init__(self, cache_directory, username, password):
    46: 		"""cache_directory is the directory to store downloaded data in,
    47: 		username is the JID to login with, password is the password used
    48: 		to log in."""
    49: 		# Make a connection
    50: 		self.jid = username
    51: 		self.password = password
    52: 		self.client = pubsubclient.PubSubClient(self.jid, self.password)
    53: 
    54: 		# Make the window
    55: 		self.draw_window()
    56: 
    57: 	def draw_window(self):
    58: 		"""Display related things."""
    59: 
    60: 		# Make a window and split it into sections
    61: 		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    62: 		self.hpaned = gtk.HPaned()
    63: 		self.window.add(self.hpaned)
    64: 		self.right_vpaned = gtk.VPaned()
    65: 		self.hpaned.pack2(self.right_vpaned)
    66: 		self.left_vbox = gtk.VBox()
    67: 		self.hpaned.pack1(self.left_vbox)
    68: 
    69: 		# Make a Kiwi ObjectList with columns "name" and "count" for
    70: 		# subscription names and the
    71: 		name_column = Column('name', 'Name')
    72: 		name_column.expand = True
    73: 		unread_column = Column('unread', 'Unread')
    74: 		count_column = Column('count', 'Total')
    75: 		self.node_list = ObjectList([name_column, unread_column, count_column])
    76: 		self.left_vbox.pack_start(self.node_list)
    77: 
    78: 		self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
    79: 		self.add_button.set_label("New Subscription")
    80: 		self.add_button.connect("released", self.add_released)
    81: 		self.left_vbox.pack_end(self.add_button, expand=False)
    82: 
    83: 		title_column = Column('title')
    84: 		author_column = Column('author')
    85: 		date_column = Column('date')
    86: 		title_column.expand = True
    87: 		self.entry_list = ObjectList([title_column, author_column, date_column])
    88: 		self.right_vpaned.pack1(self.entry_list)
    89: 
    90: 		#self.webscroll = gtk.ScrolledWindow()
    91: 		#self.webview = webkit.WebView()
    92: 		#self.webscroll.add(self.webview)
    93: 		#self.right_vpaned.pack2(self.webscroll)
    94: 
    95: 		self.window.show_all()
    96: 
    97: 	def disable_subscribe_button(self, args):
    98: 		"""Makes the subscribe button in the add-new-subscription
    99: 		dialogue insensitive."""
   100: 		self.add_window['add_button'].set_sensitive(False)
   101: 
   102: 	def subscribe_to_node(self, args):
   103: 		"""Subscribes the logged in account to the node selected in the
   104: 		add-new-subscription dialogue."""
   105: 		self.add_window['node_list'].get_selected().subscribe(self.client, self.jid, return_function=self.subscription_finished)
   106: 
   107: 	def subscription_finished(self, reply):
   108: 		"""Handles replies to subscription requests."""
   109: 		print 'Reply received"'
   110: 		if reply.find(".//error") is not None:
   111: 			print "Error subscribing"
   112: 		elif reply.find(".//result") is not None:
   113: 			print "Subscription successful!"
   114: 			# Close the new-subscription dialogue
   115: 			self.add_window['window'].destroy()
   116: 			# Add the subscribed-to node to the list of subscriptions
   117: 			self.node_list.append(LeftRow("test", 0, 0))
   118: 
   119: 	def add_released(self, args):
   120: 		"""Run when the "Subscribe" button is pressed."""
   121: 		# Make a place to store all of the new GTK stuff
   122: 		self.add_window = {}
   123: 
   124: 		# Make the Add Node window and put it in there
   125: 		self.add_window['window'] = gtk.Window()
   126: 		self.add_window['window'].set_title("Add New Subscription")
   127: 
   128: 		# Split it vertically
   129: 		self.add_window['vbox'] = gtk.VBox()
   130: 		self.add_window['window'].add(self.add_window['vbox'])
   131: 
   132: 		# Split the top horizontally
   133: 		self.add_window['top_hbox'] = gtk.HBox()
   134: 		self.add_window['vbox'].pack_start(self.add_window['top_hbox'], expand=False)
   135: 
   136: 		# Add the "Location:" label to the top
   137: 		self.add_window['location_label'] = gtk.Label("Location: ")
   138: 		self.add_window['top_hbox'].pack_start(self.add_window['location_label'], expand=False)
   139: 
   140: 		# Add the "Find" button to the top
   141: 		self.add_window['find_button'] = gtk.Button(label="Find", stock=gtk.STOCK_FIND)
   142: 		self.add_window['find_button'].connect("released", self.find_new_nodes)
   143: 		self.add_window['top_hbox'].pack_end(self.add_window['find_button'], expand=False)
   144: 
   145: 		# Add the location entry box in between
   146: 		self.add_window['location_entry'] = gtk.Entry()
   147: 		self.add_window['top_hbox'].pack_end(self.add_window['location_entry'], expand=True)
   148: 
   149: 		self.add_window['bottom_hbox'] = gtk.HBox()
   150: 		self.add_window['vbox'].pack_end(self.add_window['bottom_hbox'], expand=False)
   151: 
   152: 		self.add_window['find_progress'] = gtk.ProgressBar()
   153: 		self.add_window['bottom_hbox'].pack_end(self.add_window['find_progress'], expand=True)
   154: 
   155: 		self.add_window['add_button'] = gtk.Button(label="Subscribe", stock=gtk.STOCK_ADD)
   156: 		self.add_window['add_button'].set_label("Subscribe")
   157: 		## FIXME: The Subscribe button should be insensitive to start
   158: 		## with, then activate when a node is selected.
   159: 		#self.add_window['add_button'].set_sensitive(False)
   160: 		self.add_window['add_button'].connect("released", self.subscribe_to_node)
   161: 		self.add_window['bottom_hbox'].pack_end(self.add_window['add_button'], expand=False)
   162: 
   163: 		# Add the list of found nodes
   164: 		self.add_window['name_column'] = Column('name', 'Name')
   165: 		self.add_window['location_column'] = Column('name', 'Location')
   166: 		self.add_window['name_column'].expand = True
   167: 		self.add_window['location_column'].expand = True
   168: 		self.add_window['node_list'] = ObjectList([self.add_window['name_column'], self.add_window['location_column']])
   169: 		self.add_window['vbox'].pack_end(self.add_window['node_list'], expand=True, fill=True)
   170: 
   171: 		# Display everything
   172: 		self.add_window['window'].show_all()
   173: 
   174: 	def pulse_find_progress(self):
   175: 		"""Updates the progress bar when finding new nodes."""
   176: 		# Sleep here so that we aren't checking for replies constantly
   177: 		time.sleep(0.05)
   178: 		# Do the pulsing
   179: 		self.add_window['find_progress'].pulse()
   180: 		# Return whether we're still searching
   181: 		return self.finding
   182: 
   183: 	def find_new_nodes(self, arg):
   184: 		"""Search for nodes at the server entered in the add-new-subscription window."""
   185: 		self.add_window["entered_server"] = pubsubclient.Server(name=self.add_window['location_entry'].get_text())
   186: 		self.client.get_nodes(self.add_window["entered_server"], None, return_function=self.found_new_nodes)
   187: 		# Remember that we're still on the lookout for nodes
   188: 		self.finding = True
   189: 		gobject.idle_add(self.pulse_find_progress)
   190: 
   191: 	def found_new_nodes(self, reply):
   192: 		"""The program waits until this is run. Could be more elegant
   193: 		using a signal though"""
   194: 		# We don't need to search any more
   195: 		self.finding = False
   196: 		# Run the following if we end up with a failure
   197: 		if reply == "error":
   198: 			# Reset the search progress
   199: 			self.add_window['find_progress'].set_fraction(0.0)
   200: 			# Tell the user we've failed to find anything due to an error
   201: 			self.add_window['find_progress'].set_text('Error finding nodes at ' + self.add_window['location_entry'].get_text())
   202: 		# Run the following if we end up with a success
   203: 		else:
   204: 			# Traverse the nodes we've received
   205: 			for node in reply:
   206: 				# Add each one to the add-subscription-dialogue's list
   207: 				self.add_window['node_list'].append(node)
   208: 				# Get any children of the discovered nodes
   209: 				node.get_sub_nodes(self.client, self.found_new_nodes)
   210: 				# We're now finding for children, so keep up the search
   211: 				self.finding = True
   212: 
   213: 		# Display the new window contents
   214: 		self.add_window['window'].show_all()
   215: 
   216: 	def connect(self):
   217: 		"""Connect the account given during initialisation."""
   218: 		# Try to connect
   219: 		connected = self.client.connect()
   220: 		# Check if we succeeded
   221: 		if connected == 1:
   222: 			print 'Failed to connect, exiting'
   223: 			sys.exit(1)
   224: 		self.connected = True
   225: 		# Process new messages when there's nothing else to do
   226: 		gobject.idle_add(self.idle_process)
   227: 		self.client.retrieve_subscriptions(self.jid.getDomain(), return_function=self.subscriptions_received)
   228: 
   229: 	def subscriptions_received(self, subscriptions):
   230: 		"""Handles replies to retrieve_subscriptions."""
   231: 
   232: 
   233: 	def add_nodes(self, nodes):
   234: 		"""Adds the given nodes to the subscribed list."""
   235: 		for node in nodes:
   236: 			if node not in self.node_list:
   237: 				self.node_list.append(LeftRow(node.name, 0, 0))
   238: 
   239: 	def handle_incoming(self, stanza):
   240: 		#os.popen("mkdir -p pages/")
   241: 		#while True:
   242: 		#	filename = ''.join(Random().sample(string.letters+string.digits, 16))
   243: 		#	if filename not in os.listdir("pages"): break
   244: 		#page_file = open("pages/" + filename, 'w')
   245: 		#page = Element('html')
   246: 		#head = SubElement(page, 'head')
   247: 		#css_link = SubElement(head, 'link', attrib={"rel":"stylesheet", "type":"text/css", "href":os.getcwd() + "/page_settings/test1/item.css"})
   248: 		#body = SubElement(page, 'body')
   249: 		#wholediv = SubElement(body, 'div', attrib={'class':'whole'})
   250: 		#titlediv = SubElement(wholediv, 'div', attrib={"class":"title"})
   251: 		#maindiv = SubElement(wholediv, 'div', attrib={"class":"main"})
   252: 		#for event in stanza.xpath("//e:event", namespaces={"e":"http://jabber.org/protocol/pubsub#event"}):
   253: 		#	for item_node in event.xpath("//i:items", namespaces={"i":"http://jabber.org/protocol/pubsub#event"}):
   254: 		#		title = SubElement(titlediv, 'a')
   255: 		#		title.text = "TITLE: " + item_node.get("node")
   256: 		#		body_text = SubElement(maindiv, 'a')
   257: 		#		body_text.text = "MAIN: " + item_node.get("node")
   258: 		#page_file.write(etree.tostring(page))
   259: 		#page_file.close()
   260: 		#self.webview.open(os.getcwd() + "/pages/" + filename)
   261: 		pass
   262: 
   263: 	def process(self):
   264: 		"""Handle any pending XMPP events."""
   265: 		self.client.process()
   266: 
   267: 	def idle_process(self):
   268: 		"""Check for new messages. Good to run in gobject idle time."""
   269: 		# It's a good idea to wait a bit betweeen updates, to stop
   270: 		# overworking the machine
   271: 		time.sleep(0.1)
   272: 		# Do the processing
   273: 		self.process()
   274: 		# Idle functions stop being called when they return False, in
   275: 		# this case when we disconnect
   276: 		return self.connected
   277: 
   278: 	def destroy(self, widget, data=None):
   279: 		"""Close the program"""
   280: 		gtk.main_quit()
   281: 
   282: 	def main(self):
   283: 		"""Initialises and starts the GTK main loop."""
   284: 		#gobject.idle_add(self.idle_process)
   285: 		self.window.connect("destroy", self.destroy)
   286: 		self.client.assign_message_handler(self.handle_incoming)
   287: 		gtk.main()
   288: 
   289: if __name__ == '__main__':
   290: 	# Check for a writable cache folder, if none is found then make one
   291: 	if not 'pubsubclient' in os.listdir(xdg.BaseDirectory.xdg_cache_home):
   292: 		try:
   293: 			os.mkdir(xdg.BaseDirectory.xdg_cache_home + '/pubsubclient')
   294: 		except:
   295: 			print 'Error: Could not create cache directory ' + xdg.BaseDirectory.xdg_cache_home + '/pubsubclient'
   296: 	# Check for a configuration folder, if none is found then make one
   297: 	if not 'pubsubclient' in os.listdir(xdg.BaseDirectory.xdg_config_dirs[0]):
   298: 		try:
   299: 			os.mkdir(xdg.BaseDirectory.xdg_config_dirs[0] + '/pubsubclient')
   300: 		except:
   301: 			print 'Error: Could not create config directory ' + xdg.BaseDirectory.xdg_config_dirs[0] + '/pubsubclient'
   302: 	# Check for a configuration file, if none is found then make one
   303: 	if not 'login' in os.listdir(xdg.BaseDirectory.xdg_config_dirs[0] + '/pubsubclient'):
   304: 		id = raw_input("Please enter your Jabber ID: ")
   305: 		password = raw_input("Please enter your password: ")
   306: 	else:
   307: 		try:
   308: 			login_file = open(xdg.BaseDirectory.xdg_config_dirs[0] + '/pubsubclient/login', 'r')
   309: 			for line in login_file.readlines():
   310: 				if line[:4] == 'jid:':
   311: 					id = line[4:].strip()
   312: 					print "Found jid " + id
   313: 				elif line[:5] == 'pass:':
   314: 					password = line[5:].strip()
   315: 					print "Found password " + password
   316: 		except:
   317: 			print 'Error: Could not read login details from '+ xdg.BaseDirectory.xdg_config_dirs[0] + '/pubsubclient/login'
   318: 			id = raw_input("Please enter your Jabber ID: ")
   319: 			password = raw_input("Please enter your password: ")
   320: 	# Make a main window
   321: 	display = Display(xdg.BaseDirectory.xdg_cache_home + '/pubsubclient', id, password)
   322: 
   323: 	#display.webview.open(os.getcwd() + "/start.html")
   324: 
   325: 	# Log on to XMPP
   326: 	display.connect()
   327: 
   328: 	#display.client.subscribe('pubsub.localhost', '/home')
   329: 	#display.populate('pubsub.localhost')
   330: 
   331: 	# Run the program
   332: 	display.main()

Generated by git2html.