Refactor atom into new module and disable it
Gajim lacks a good UI for microblogging Fixes #9218
This commit is contained in:
parent
70661b70d3
commit
d45fa13ee9
|
@ -1,176 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
## src/common/atom.py
|
|
||||||
##
|
|
||||||
## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
|
|
||||||
## Tomasz Melcer <liori AT exroot.org>
|
|
||||||
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
|
|
||||||
##
|
|
||||||
## This file is part of Gajim.
|
|
||||||
##
|
|
||||||
## Gajim is free software; you can redistribute it and/or modify
|
|
||||||
## it under the terms of the GNU General Public License as published
|
|
||||||
## by the Free Software Foundation; version 3 only.
|
|
||||||
##
|
|
||||||
## Gajim is distributed in the hope that it will be useful,
|
|
||||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
## GNU General Public License for more details.
|
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License
|
|
||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
##
|
|
||||||
|
|
||||||
"""
|
|
||||||
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 nbxmpp
|
|
||||||
import time
|
|
||||||
|
|
||||||
class PersonConstruct(nbxmpp.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. '''
|
|
||||||
nbxmpp.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(nbxmpp.Node, object):
|
|
||||||
def __init__(self, node=None):
|
|
||||||
nbxmpp.Node.__init__(self, 'entry', node=node)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '<Atom:Entry object of id="%r">' % self.getAttr('id')
|
|
||||||
|
|
||||||
class OldEntry(nbxmpp.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. '''
|
|
||||||
nbxmpp.Node.__init__(self, 'entry', node=node)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '<Atom0.3:Entry object of id="%r">' % self.getAttr('id')
|
|
||||||
|
|
||||||
def get_feed_title(self):
|
|
||||||
"""
|
|
||||||
Return title of feed, where the entry was created. The result is the feed
|
|
||||||
name concatenated with source-feed title
|
|
||||||
"""
|
|
||||||
if self.parent is not None:
|
|
||||||
main_feed = self.parent.getTagData('title')
|
|
||||||
else:
|
|
||||||
main_feed = None
|
|
||||||
|
|
||||||
if self.getTag('feed') is not None:
|
|
||||||
source_feed = self.getTag('feed').getTagData('title')
|
|
||||||
else:
|
|
||||||
source_feed = None
|
|
||||||
|
|
||||||
|
|
||||||
if main_feed is not None and source_feed is not None:
|
|
||||||
return '%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 ''
|
|
||||||
|
|
||||||
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 source link
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return self.getTag('feed').getTags('link', {'rel':'alternate'})[1].getData()
|
|
||||||
except Exception:
|
|
||||||
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 'rel' in element.attrs 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 = ''
|
|
|
@ -22,7 +22,6 @@
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
import datetime
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import logging
|
import logging
|
||||||
|
@ -33,7 +32,6 @@ import OpenSSL.crypto
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
from nbxmpp.protocol import NS_CHATSTATES
|
from nbxmpp.protocol import NS_CHATSTATES
|
||||||
|
|
||||||
from gajim.common import atom
|
|
||||||
from gajim.common import nec
|
from gajim.common import nec
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
|
@ -1759,24 +1757,6 @@ class PEPReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
self.pep_type = pep.type_
|
self.pep_type = pep.type_
|
||||||
return True
|
return True
|
||||||
|
|
||||||
items = self.event_tag.getTag('items')
|
|
||||||
if items:
|
|
||||||
# for each entry in feed (there shouldn't be more than one, but to
|
|
||||||
# be sure...
|
|
||||||
for item in items.getTags('item'):
|
|
||||||
entry = item.getTag('entry', namespace=nbxmpp.NS_ATOM)
|
|
||||||
if entry:
|
|
||||||
app.nec.push_incoming_event(AtomEntryReceived(None,
|
|
||||||
conn=self.conn, node=entry))
|
|
||||||
|
|
||||||
class AtomEntryReceived(nec.NetworkIncomingEvent):
|
|
||||||
name = 'atom-entry-received'
|
|
||||||
base_network_events = []
|
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
self.atom_entry = atom.OldEntry(node=self.node)
|
|
||||||
return True
|
|
||||||
|
|
||||||
class PlainConnectionEvent(nec.NetworkIncomingEvent):
|
class PlainConnectionEvent(nec.NetworkIncomingEvent):
|
||||||
name = 'plain-connection'
|
name = 'plain-connection'
|
||||||
base_network_events = []
|
base_network_events = []
|
||||||
|
|
|
@ -153,6 +153,7 @@ class PEPEventType(IntEnum):
|
||||||
LOCATION = 3
|
LOCATION = 3
|
||||||
NICKNAME = 4
|
NICKNAME = 4
|
||||||
AVATAR = 5
|
AVATAR = 5
|
||||||
|
ATOM = 6
|
||||||
|
|
||||||
|
|
||||||
ACTIVITIES = {
|
ACTIVITIES = {
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
# Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
|
||||||
|
# Tomasz Melcer <liori AT exroot.org>
|
||||||
|
# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
|
||||||
|
#
|
||||||
|
# This file is part of Gajim.
|
||||||
|
#
|
||||||
|
# Gajim is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published
|
||||||
|
# by the Free Software Foundation; version 3 only.
|
||||||
|
#
|
||||||
|
# Gajim is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
|
||||||
|
# XEP-0277: Microblogging over XMPP
|
||||||
|
|
||||||
|
# Module is disabled for now because Gajim lacks a good UI for that
|
||||||
|
# register the module in connection.py with register_module() to activate again
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import nbxmpp
|
||||||
|
import time
|
||||||
|
|
||||||
|
from gajim.common.const import PEPEventType
|
||||||
|
from gajim.common.exceptions import StanzaMalformed
|
||||||
|
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
|
||||||
|
|
||||||
|
log = logging.getLogger('gajim.c.m.atom')
|
||||||
|
|
||||||
|
|
||||||
|
class AtomData(AbstractPEPData):
|
||||||
|
|
||||||
|
type_ = PEPEventType.ATOM
|
||||||
|
|
||||||
|
def __init__(self, atom):
|
||||||
|
self._pep_specific_data = atom
|
||||||
|
|
||||||
|
def get_entry(self):
|
||||||
|
return self._pep_specific_data
|
||||||
|
|
||||||
|
|
||||||
|
class Atom(AbstractPEPModule):
|
||||||
|
|
||||||
|
name = 'atom'
|
||||||
|
namespace = 'urn:xmpp:microblog:0'
|
||||||
|
pep_class = AtomData
|
||||||
|
store_publish = False
|
||||||
|
_log = log
|
||||||
|
|
||||||
|
def __init__(self, con):
|
||||||
|
AbstractPEPModule.__init__(self, con, con.name)
|
||||||
|
|
||||||
|
self.handlers = []
|
||||||
|
|
||||||
|
def _extract_info(self, item):
|
||||||
|
entry = item.getTag('entry', namespace=nbxmpp.NS_ATOM)
|
||||||
|
if entry is None:
|
||||||
|
StanzaMalformed('no entry node')
|
||||||
|
|
||||||
|
return OldEntry(node=entry) or None
|
||||||
|
|
||||||
|
|
||||||
|
class PersonConstruct(nbxmpp.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. '''
|
||||||
|
nbxmpp.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(nbxmpp.Node, object):
|
||||||
|
def __init__(self, node=None):
|
||||||
|
nbxmpp.Node.__init__(self, 'entry', node=node)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Atom:Entry object of id="%r">' % self.getAttr('id')
|
||||||
|
|
||||||
|
|
||||||
|
class OldEntry(nbxmpp.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. '''
|
||||||
|
nbxmpp.Node.__init__(self, 'entry', node=node)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Atom0.3:Entry object of id="%r">' % self.getAttr('id')
|
||||||
|
|
||||||
|
def get_feed_title(self):
|
||||||
|
"""
|
||||||
|
Return title of feed, where the entry was created.
|
||||||
|
The result is the feed name concatenated with source-feed title
|
||||||
|
"""
|
||||||
|
if self.parent is not None:
|
||||||
|
main_feed = self.parent.getTagData('title')
|
||||||
|
else:
|
||||||
|
main_feed = None
|
||||||
|
|
||||||
|
if self.getTag('feed') is not None:
|
||||||
|
source_feed = self.getTag('feed').getTagData('title')
|
||||||
|
else:
|
||||||
|
source_feed = None
|
||||||
|
|
||||||
|
if main_feed is not None and source_feed is not None:
|
||||||
|
return '%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 ''
|
||||||
|
|
||||||
|
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 source link
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.getTag('feed').getTags('link', {'rel': 'alternate'})[1].getData()
|
||||||
|
except Exception:
|
||||||
|
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 'rel' in element.attrs 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 = ''
|
|
@ -1166,7 +1166,10 @@ class Interface:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_atom_entry(obj):
|
def handle_atom_entry(obj):
|
||||||
AtomWindow.newAtomEntry(obj.atom_entry)
|
if obj != PEPEventType.ATOM:
|
||||||
|
return
|
||||||
|
if obj.get_entry():
|
||||||
|
AtomWindow.newAtomEntry(obj.get_entry())
|
||||||
|
|
||||||
def handle_event_zc_name_conflict(self, obj):
|
def handle_event_zc_name_conflict(self, obj):
|
||||||
def on_ok(new_name):
|
def on_ok(new_name):
|
||||||
|
@ -1503,7 +1506,7 @@ class Interface:
|
||||||
self.handlers = {
|
self.handlers = {
|
||||||
'DB_ERROR': [self.handle_event_db_error],
|
'DB_ERROR': [self.handle_event_db_error],
|
||||||
'FILE_SEND_ERROR': [self.handle_event_file_send_error],
|
'FILE_SEND_ERROR': [self.handle_event_file_send_error],
|
||||||
'atom-entry-received': [self.handle_atom_entry],
|
'pep-received': [self.handle_atom_entry],
|
||||||
'bad-gpg-passphrase': [self.handle_event_bad_gpg_passphrase],
|
'bad-gpg-passphrase': [self.handle_event_bad_gpg_passphrase],
|
||||||
'bookmarks-received': [self.handle_event_bookmarks],
|
'bookmarks-received': [self.handle_event_bookmarks],
|
||||||
'client-cert-passphrase': [
|
'client-cert-passphrase': [
|
||||||
|
|
Loading…
Reference in New Issue