Simple support for pubsub.com notifications.
This commit is contained in:
parent
fd5294bd21
commit
fa6ae3b4be
|
@ -0,0 +1,371 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="atom_entry_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">New entry received</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox112">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="new_entry_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">You have received new entry:</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator14">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table4">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">4</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">0</property>
|
||||
<property name="column_spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Feed name:</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_RIGHT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Entry:</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Last modified:</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="feed_tagline_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><small>Romeo and Juliet</small></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="last_modified_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">2003-12-13T18:30:02Z</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="feed_title_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
<signal name="button_press_event" handler="on_feed_title_eventbox_button_press_event" last_modification_time="Thu, 20 Jul 2006 21:53:07 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="feed_title_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Old stories</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="entry_title_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
<signal name="button_press_event" handler="on_entry_title_eventbox_button_press_event" last_modification_time="Thu, 20 Jul 2006 21:53:12 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="entry_title_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Soliloquy</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator15">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked" last_modification_time="Thu, 20 Jul 2006 21:29:17 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="next_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">Next entry</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_next_button_clicked" last_modification_time="Thu, 20 Jul 2006 21:29:21 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
|
@ -0,0 +1,115 @@
|
|||
'''atom_window.py - a window to display atom entries from pubsub. For now greatly simplified,
|
||||
supports only simple feeds like the one from pubsub.com. '''
|
||||
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
|
||||
import gtkgui_helpers
|
||||
from common import helpers
|
||||
|
||||
class AtomWindow:
|
||||
window = None
|
||||
entries = []
|
||||
|
||||
@classmethod # python2.4 decorator
|
||||
def newAtomEntry(cls, entry):
|
||||
''' Queue new entry, open window if there's no one opened. '''
|
||||
cls.entries.append(entry)
|
||||
|
||||
if cls.window is None:
|
||||
cls.window = AtomWindow()
|
||||
else:
|
||||
cls.window.updateCounter()
|
||||
|
||||
def __init__(self):
|
||||
''' Create new window... only if we have anything to show. '''
|
||||
assert len(self.__class__.entries)>0
|
||||
|
||||
self.entry = None # the entry actually displayed
|
||||
|
||||
self.xml = gtkgui_helpers.get_glade('atom_entry_window.glade')
|
||||
self.window = self.xml.get_widget('atom_entry_window')
|
||||
for name in ('new_entry_label', 'feed_title_label', 'feed_title_eventbox',
|
||||
'feed_tagline_label', 'entry_title_label', 'entry_title_eventbox',
|
||||
'last_modified_label', 'close_button', 'next_button'):
|
||||
self.__dict__[name] = self.xml.get_widget(name)
|
||||
|
||||
self.displayNextEntry()
|
||||
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
self.entry_title_eventbox.add_events(gtk.gdk.BUTTON_PRESS_MASK)
|
||||
self.feed_title_eventbox.add_events(gtk.gdk.BUTTON_PRESS_MASK)
|
||||
|
||||
def displayNextEntry(self):
|
||||
''' Get next entry from the queue and display it in the window. '''
|
||||
assert len(self.__class__.entries)>0
|
||||
|
||||
newentry = self.__class__.entries.pop(0)
|
||||
|
||||
# fill the fields
|
||||
if newentry.feed_link is not None:
|
||||
self.feed_title_label.set_markup(
|
||||
u'<span foreground="blue" underline="single">%s</span>' % \
|
||||
gtkgui_helpers.escape_for_pango_markup(newentry.feed_title))
|
||||
else:
|
||||
self.feed_title_label.set_markup(
|
||||
gtkgui_helpers.escape_for_pango_markup(newentry.feed_title))
|
||||
|
||||
self.feed_tagline_label.set_markup(
|
||||
u'<small>%s</small>' % \
|
||||
gtkgui_helpers.escape_for_pango_markup(newentry.feed_tagline))
|
||||
|
||||
if newentry.uri is not None:
|
||||
self.entry_title_label.set_markup(
|
||||
u'<span foreground="blue" underline="single">%s</span>' % \
|
||||
gtkgui_helpers.escape_for_pango_markup(newentry.title))
|
||||
else:
|
||||
self.entry_title_label.set_markup(
|
||||
gtkgui_helpers.escape_for_pango_markup(newentry.title))
|
||||
|
||||
self.last_modified_label.set_text(newentry.updated)
|
||||
|
||||
# update the counters
|
||||
self.updateCounter()
|
||||
|
||||
self.entry = newentry
|
||||
|
||||
def updateCounter(self):
|
||||
''' We display number of events on the top of window, sometimes it needs to be
|
||||
changed...'''
|
||||
count = len(self.__class__.entries)
|
||||
# TODO: translate
|
||||
if count>0:
|
||||
self.new_entry_label.set_text( \
|
||||
'You have received new entries (and %(count)d not displayed):' % \
|
||||
{'count': count})
|
||||
self.next_button.set_sensitive(True)
|
||||
else:
|
||||
self.new_entry_label.set_text('You have received new entry:')
|
||||
self.next_button.set_sensitive(False)
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def on_next_button_clicked(self, widget):
|
||||
self.displayNextEntry()
|
||||
|
||||
def on_entry_title_button_press_event(self, widget, event):
|
||||
# TODO: make it using special gtk2.10 widget
|
||||
print 1
|
||||
if event.button == 1: # left click
|
||||
uri = self.entry.uri
|
||||
if uri is not None:
|
||||
helpers.launch_browser_mailer('url', uri)
|
||||
return True
|
||||
|
||||
def on_feed_title_button_press_event(self, widget, event):
|
||||
# TODO: make it using special gtk2.10 widget
|
||||
print 2
|
||||
if event.button == 1: # left click
|
||||
uri = self.entry.feed_uri
|
||||
if uri is not None:
|
||||
helpers.launch_browser_mailer('url', uri)
|
||||
return True
|
|
@ -0,0 +1,138 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
''' Atom (rfc 4287) feed parser, used to read data from atom-over-pubsub transports
|
||||
and services. Very simple. Actually implements only atom:entry. Implement more features
|
||||
if you need. '''
|
||||
|
||||
# suggestion: rewrite functions that return dates to return standard python time tuples,
|
||||
# exteneded to contain timezone
|
||||
|
||||
import xmpp
|
||||
import time
|
||||
|
||||
class PersonConstruct(xmpp.Node, object):
|
||||
''' Not used for now, as we don't need authors/contributors in pubsub.com feeds.
|
||||
They rarely exist there. '''
|
||||
def __init__(self, node):
|
||||
''' Create person construct from node. '''
|
||||
xmpp.Node.__init__(self, node=node)
|
||||
|
||||
def get_name(self):
|
||||
return self.getTagData('name')
|
||||
|
||||
name = property(get_name, None, None,
|
||||
'''Conveys a human-readable name for the person. Should not be None,
|
||||
although some badly generated atom feeds don't put anything here
|
||||
(this is non-standard behavior, still pubsub.com sometimes does that.)''')
|
||||
|
||||
def get_uri(self):
|
||||
return self.getTagData('uri')
|
||||
|
||||
uri = property(get_uri, None, None,
|
||||
'''Conveys an IRI associated with the person. Might be None when not set.''')
|
||||
|
||||
def get_email(self):
|
||||
return self.getTagData('email')
|
||||
|
||||
email = property(get_email, None, None,
|
||||
'''Conveys an e-mail address associated with the person. Might be None when
|
||||
not set.''')
|
||||
|
||||
class Entry(xmpp.Node, object):
|
||||
def __init__(self, node=None):
|
||||
''' Create new atom entry object. '''
|
||||
xmpp.Node.__init__(self, 'entry', node=node)
|
||||
|
||||
def __repr__(self):
|
||||
return '<Atom:Entry object of id="%r">' % self.id
|
||||
|
||||
class OldEntry(xmpp.Node, object):
|
||||
''' Parser for feeds from pubsub.com. They use old Atom 0.3 format with
|
||||
their extensions. '''
|
||||
def __init__(self, node=None):
|
||||
''' Create new Atom 0.3 entry object. '''
|
||||
xmpp.Node.__init__(self, 'entry', node=node)
|
||||
|
||||
def __repr__(self):
|
||||
return '<Atom0.3:Entry object of id="%r">' % self.id
|
||||
|
||||
def get_feed_title(self):
|
||||
''' Returns title of feed, where the entry was created. The result is the feed name
|
||||
concatenated with source-feed title. '''
|
||||
title = u''
|
||||
|
||||
if self.parent is not None:
|
||||
main_feed = self.parent.getTagData('title')
|
||||
else:
|
||||
main_feed = None
|
||||
|
||||
if self.getTag('source-feed') is not None:
|
||||
source_feed = self.getTag('source-feed').getTagData('title')
|
||||
else:
|
||||
source_feed = None
|
||||
|
||||
if main_feed is not None and source_feed is not None:
|
||||
return u'%s: %s' % (main_feed, source_feed)
|
||||
elif main_feed is not None:
|
||||
return main_feed
|
||||
elif source_feed is not None:
|
||||
return source_feed
|
||||
else:
|
||||
return u''
|
||||
|
||||
feed_title = property(get_feed_title, None, None,
|
||||
''' Title of feed. It is built from entry's original feed title and title of feed
|
||||
which delivered this entry. ''')
|
||||
|
||||
def get_feed_link(self):
|
||||
''' Get a link to main page of feed (in pubsub.com: second link of rel='alternate',
|
||||
first contains raw xml data). '''
|
||||
try:
|
||||
return self.getTag('source-feed').getTags('link', {'rel':'alternate'})[1].getData()
|
||||
except:
|
||||
return None
|
||||
|
||||
feed_link = property(get_feed_link, None, None,
|
||||
''' Link to main webpage of the feed. ''')
|
||||
|
||||
def get_title(self):
|
||||
''' Get an entry's title. '''
|
||||
return self.getTagData('title')
|
||||
|
||||
title = property(get_title, None, None,
|
||||
''' Entry's title. ''')
|
||||
|
||||
def get_uri(self):
|
||||
''' Get the uri the entry points to (entry's first link element with rel='alternate'
|
||||
or without rel attribute). '''
|
||||
for element in self.getTags('link'):
|
||||
if element.attrs.has_key('rel') and element.attrs['rel']<>'alternate': continue
|
||||
try:
|
||||
return element.attrs['href']
|
||||
except AttributeError:
|
||||
pass
|
||||
return None
|
||||
|
||||
uri = property(get_uri, None, None,
|
||||
''' URI that is pointed by the entry. ''')
|
||||
|
||||
def get_updated(self):
|
||||
''' Get the time the entry was updated last time. This should be standarized,
|
||||
but pubsub.com sends it in human-readable format. We won't try to parse it.
|
||||
(Atom 0.3 uses the word «modified» for that).
|
||||
|
||||
If there's no time given in the entry, we try with <published>
|
||||
and <issued> elements. '''
|
||||
for name in ('updated', 'modified', 'published', 'issued'):
|
||||
date = self.getTagData(name)
|
||||
if date is not None: break
|
||||
|
||||
if date is None:
|
||||
# it is not in the standard format
|
||||
return time.asctime()
|
||||
|
||||
return date
|
||||
|
||||
updated = property(get_updated, None, None,
|
||||
''' Last significant modification time. ''')
|
||||
|
||||
feed_tagline = u''
|
|
@ -33,6 +33,7 @@ from common import GnuPG
|
|||
from common import helpers
|
||||
from common import gajim
|
||||
from common import dataforms
|
||||
from common import atom
|
||||
from common.commands import ConnectionCommands
|
||||
|
||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||
|
@ -1275,6 +1276,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
|
||||
def _messageCB(self, con, msg):
|
||||
'''Called when we receive a message'''
|
||||
# check if the message is pubsub#event
|
||||
if msg.getTag('event') is not None:
|
||||
self._pubsubEventCB(con, msg)
|
||||
return
|
||||
msgtxt = msg.getBody()
|
||||
mtype = msg.getType()
|
||||
subject = msg.getSubject() # if not there, it's None
|
||||
|
@ -1394,6 +1399,32 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
subject, chatstate, msg_id, composing_jep, user_nick))
|
||||
# END messageCB
|
||||
|
||||
def _pubsubEventCB(self, con, msg):
|
||||
''' Called when we receive <message/> with pubsub event. '''
|
||||
# TODO: Logging? (actually services where logging would be useful, should
|
||||
# TODO: allow to access archives remotely...)
|
||||
event = msg.getTag('event')
|
||||
|
||||
items = event.getTag('items')
|
||||
if items is None: return
|
||||
|
||||
for item in items.getTags('item'):
|
||||
# check for event type (for now only one type supported: pubsub.com events)
|
||||
child = item.getTag('pubsub-message')
|
||||
if child is not None:
|
||||
# we have pubsub.com notification
|
||||
child = child.getTag('feed')
|
||||
if child is None: continue
|
||||
|
||||
for entry in child.getTags('entry'):
|
||||
# for each entry in feed (there shouldn't be more than one,
|
||||
# but to be sure...
|
||||
self.dispatch('ATOM_ENTRY', (atom.OldEntry(node=entry),))
|
||||
continue
|
||||
# unknown type... probably user has another client who understands that event
|
||||
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
def _presenceCB(self, con, prs):
|
||||
'''Called when we receive a presence'''
|
||||
ptype = prs.getType()
|
||||
|
|
|
@ -38,6 +38,7 @@ from common import i18n
|
|||
import message_control
|
||||
|
||||
from chat_control import ChatControlBase
|
||||
from atom_window import AtomWindow
|
||||
|
||||
from common import exceptions
|
||||
|
||||
|
@ -1346,6 +1347,10 @@ class Interface:
|
|||
def handle_event_metacontacts(self, account, tags_list):
|
||||
gajim.contacts.define_metacontacts(account, tags_list)
|
||||
|
||||
def handle_atom_entry(self, account, data):
|
||||
atom_entry, = data
|
||||
AtomWindow.newAtomEntry(atom_entry)
|
||||
|
||||
def handle_event_privacy_lists_received(self, account, data):
|
||||
# ('PRIVACY_LISTS_RECEIVED', account, list)
|
||||
if not self.instances.has_key(account):
|
||||
|
@ -1671,6 +1676,7 @@ class Interface:
|
|||
'ASK_NEW_NICK': self.handle_event_ask_new_nick,
|
||||
'SIGNED_IN': self.handle_event_signed_in,
|
||||
'METACONTACTS': self.handle_event_metacontacts,
|
||||
'ATOM_ENTRY': self.handle_atom_entry,
|
||||
'PRIVACY_LISTS_RECEIVED': self.handle_event_privacy_lists_received,
|
||||
'PRIVACY_LIST_RECEIVED': self.handle_event_privacy_list_received,
|
||||
'PRIVACY_LISTS_ACTIVE_DEFAULT': \
|
||||
|
|
Loading…
Reference in New Issue