A big portion of doc-string refactoring

This commit is contained in:
Alexander Cherniuk 2009-11-26 13:58:12 +02:00
parent cea7c66f75
commit 6bf2246de5
28 changed files with 1133 additions and 615 deletions

View File

@ -21,8 +21,10 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
""" This module contains wrappers for different parts of data forms (JEP 0004).
For information how to use them, read documentation. """
"""
This module contains wrappers for different parts of data forms (JEP 0004). For
information how to use them, read documentation
"""
import xmpp
@ -72,7 +74,9 @@ def Field(typ, **attrs):
return f
def ExtendField(node):
''' Helper function to extend a node to field of appropriate type. '''
"""
Helper function to extend a node to field of appropriate type
"""
# when validation (XEP-122) will go in, we could have another classes
# like DateTimeField - so that dicts in Field() and ExtendField() will
# be different...
@ -94,19 +98,23 @@ def ExtendField(node):
return f[typ](extend=node)
def ExtendForm(node):
''' Helper function to extend a node to form of appropriate type. '''
"""
Helper function to extend a node to form of appropriate type
"""
if node.getTag('reported') is not None:
return MultipleDataForm(extend=node)
else:
return SimpleDataForm(extend=node)
class DataField(ExtendedNode):
""" Keeps data about one field - var, field type, labels, instructions...
Base class for different kinds of fields. Use Field() function to
construct one of these. """
"""
Keeps data about one field - var, field type, labels, instructions... Base
class for different kinds of fields. Use Field() function to construct one
of these
"""
def __init__(self, typ=None, var=None, value=None, label=None, desc=None,
required=False, options=None, extend=None):
required=False, options=None, extend=None):
if extend is None:
ExtendedNode.__init__(self, 'field')
@ -124,10 +132,12 @@ class DataField(ExtendedNode):
@nested_property
def type():
'''Type of field. Recognized values are: 'boolean', 'fixed', 'hidden',
"""
Type of field. Recognized values are: 'boolean', 'fixed', 'hidden',
'jid-multi', 'jid-single', 'list-multi', 'list-single', 'text-multi',
'text-private', 'text-single'. If you set this to something different,
DataField will store given name, but treat all data as text-single.'''
DataField will store given name, but treat all data as text-single
"""
def fget(self):
t = self.getAttr('type')
if t is None:
@ -142,7 +152,9 @@ class DataField(ExtendedNode):
@nested_property
def var():
'''Field identifier.'''
"""
Field identifier
"""
def fget(self):
return self.getAttr('var')
@ -157,7 +169,9 @@ class DataField(ExtendedNode):
@nested_property
def label():
'''Human-readable field name.'''
"""
Human-readable field name
"""
def fget(self):
l = self.getAttr('label')
if not l:
@ -176,7 +190,9 @@ class DataField(ExtendedNode):
@nested_property
def description():
'''Human-readable description of field meaning.'''
"""
Human-readable description of field meaning
"""
def fget(self):
return self.getTagData('desc') or u''
@ -196,7 +212,9 @@ class DataField(ExtendedNode):
@nested_property
def required():
'''Controls whether this field required to fill. Boolean.'''
"""
Controls whether this field required to fill. Boolean
"""
def fget(self):
return bool(self.getTag('required'))
@ -212,7 +230,9 @@ class DataField(ExtendedNode):
class BooleanField(DataField):
@nested_property
def value():
'''Value of field. May contain True, False or None.'''
"""
Value of field. May contain True, False or None
"""
def fget(self):
v = self.getTagData('value')
if v in ('0', 'false'):
@ -234,10 +254,15 @@ class BooleanField(DataField):
return locals()
class StringField(DataField):
''' Covers fields of types: fixed, hidden, text-private, text-single. '''
"""
Covers fields of types: fixed, hidden, text-private, text-single
"""
@nested_property
def value():
'''Value of field. May be any unicode string.'''
"""
Value of field. May be any unicode string
"""
def fget(self):
return self.getTagData('value') or u''
@ -256,10 +281,15 @@ class StringField(DataField):
return locals()
class ListField(DataField):
'''Covers fields of types: jid-multi, jid-single, list-multi, list-single.'''
"""
Covers fields of types: jid-multi, jid-single, list-multi, list-single
"""
@nested_property
def options():
'''Options.'''
"""
Options
"""
def fget(self):
options = []
for element in self.getTags('option'):
@ -294,14 +324,21 @@ class ListField(DataField):
yield (v, l)
class ListSingleField(ListField, StringField):
'''Covers list-single and jid-single fields.'''
"""
Covers list-single and jid-single fields
"""
pass
class ListMultiField(ListField):
'''Covers list-multi and jid-multi fields.'''
"""
Covers list-multi and jid-multi fields
"""
@nested_property
def values():
'''Values held in field.'''
"""
Values held in field
"""
def fget(self):
values = []
for element in self.getTags('value'):
@ -326,7 +363,9 @@ class ListMultiField(ListField):
class TextMultiField(DataField):
@nested_property
def value():
'''Value held in field.'''
"""
Value held in field
"""
def fget(self):
value = u''
for element in self.iterTags('value'):
@ -347,8 +386,10 @@ class TextMultiField(DataField):
return locals()
class DataRecord(ExtendedNode):
'''The container for data fields - an xml element which has DataField
elements as children.'''
"""
The container for data fields - an xml element which has DataField elements
as children
"""
def __init__(self, fields=None, associated=None, extend=None):
self.associated = associated
self.vars = {}
@ -373,7 +414,9 @@ class DataRecord(ExtendedNode):
@nested_property
def fields():
'''List of fields in this record.'''
"""
List of fields in this record
"""
def fget(self):
return self.getTags('field')
@ -391,14 +434,17 @@ class DataRecord(ExtendedNode):
return locals()
def iter_fields(self):
''' Iterate over fields in this record. Do not take associated
into account. '''
"""
Iterate over fields in this record. Do not take associated into account
"""
for field in self.iterTags('field'):
yield field
def iter_with_associated(self):
''' Iterate over associated, yielding both our field and
associated one together. '''
"""
Iterate over associated, yielding both our field and associated one
together
"""
for field in self.associated.iter_fields():
yield self[field.var], field
@ -420,9 +466,11 @@ class DataForm(ExtendedNode):
@nested_property
def type():
''' Type of the form. Must be one of: 'form', 'submit', 'cancel', 'result'.
"""
Type of the form. Must be one of: 'form', 'submit', 'cancel', 'result'.
'form' - this form is to be filled in; you will be able soon to do:
filledform = DataForm(replyto=thisform)...'''
filledform = DataForm(replyto=thisform)
"""
def fget(self):
return self.getAttr('type')
@ -434,7 +482,11 @@ class DataForm(ExtendedNode):
@nested_property
def title():
''' Title of the form. Human-readable, should not contain any \\r\\n.'''
"""
Title of the form
Human-readable, should not contain any \\r\\n.
"""
def fget(self):
return self.getTagData('title')
@ -451,7 +503,11 @@ class DataForm(ExtendedNode):
@nested_property
def instructions():
''' Instructions for this form. Human-readable, may contain \\r\\n. '''
"""
Instructions for this form
Human-readable, may contain \\r\\n.
"""
# TODO: the same code is in TextMultiField. join them
def fget(self):
value = u''
@ -520,7 +576,9 @@ class MultipleDataForm(DataForm):
@nested_property
def items():
''' A list of all records. '''
"""
A list of all records
"""
def fget(self):
return list(self.iter_records())
@ -543,7 +601,9 @@ class MultipleDataForm(DataForm):
# @nested_property
# def reported():
# ''' DataRecord that contains descriptions of fields in records.'''
# """
# DataRecord that contains descriptions of fields in records
# """
# def fget(self):
# return self.getTag('reported')
# def fset(self, record):

View File

@ -51,7 +51,10 @@ else:
print _('D-Bus capabilities of Gajim cannot be used')
class SystemBus:
'''A Singleton for the DBus SystemBus'''
"""
A Singleton for the DBus SystemBus
"""
def __init__(self):
self.system_bus = None
@ -84,7 +87,10 @@ class SystemBus:
system_bus = SystemBus()
class SessionBus:
'''A Singleton for the D-Bus SessionBus'''
"""
A Singleton for the D-Bus SessionBus
"""
def __init__(self):
self.session_bus = None
@ -115,8 +121,10 @@ class SessionBus:
session_bus = SessionBus()
def get_interface(interface, path, start_service=True):
'''Returns an interface on the current SessionBus. If the interface isn\'t
running, it tries to start it first.'''
"""
Get an interface on the current SessionBus. If the interface isn't running,
try to start it first
"""
if not supported:
return None
if session_bus.present():
@ -144,9 +152,11 @@ def get_interface(interface, path, start_service=True):
def get_notifications_interface(notif=None):
'''Returns the notifications interface.
"""
Get the notifications interface
:param notif: DesktopNotification instance'''
:param notif: DesktopNotification instance
"""
# try to see if KDE notifications are available
iface = get_interface('org.kde.VisualNotifications', '/VisualNotifications',
start_service=False)

View File

@ -19,12 +19,13 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
'''
"""
This module defines a number of constants; specifically, large primes suitable
for use with the Diffie-Hellman key exchange.
for use with the Diffie-Hellman key exchange
These constants have been obtained from RFC2409 and RFC3526.
'''
"""
import string
generators = [ None, # one to get the right offset

View File

@ -27,13 +27,18 @@
import time
class Event:
'''Information concerning each event'''
"""
Information concerning each event
"""
def __init__(self, type_, time_, parameters, show_in_roster=False,
show_in_systray=True):
''' type_ in chat, normal, file-request, file-error, file-completed,
show_in_systray=True):
"""
type_ in chat, normal, file-request, file-error, file-completed,
file-request-error, file-send-error, file-stopped, gc_msg, pm,
printed_chat, printed_gc_msg, printed_marked_gc_msg, printed_pm,
gc-invitation, subscription_request, unsubscribedm jingle-incoming
parameters is (per type_):
chat, normal, pm: [message, subject, kind, time, encrypted, resource,
msg_id]
@ -47,7 +52,7 @@ class Event:
subscription_request: [text, nick]
unsubscribed: contact
jingle-incoming: (fulljid, sessionid, content_types)
'''
"""
self.type_ = type_
self.time_ = time_
self.parameters = parameters
@ -58,29 +63,40 @@ class Event:
self.account = None
class Events:
'''Information concerning all events'''
"""
Information concerning all events
"""
def __init__(self):
self._events = {} # list of events {acct: {jid1: [E1, E2]}, }
self._event_added_listeners = []
self._event_removed_listeners = []
def event_added_subscribe(self, listener):
'''Add a listener when an event is added to the queue'''
"""
Add a listener when an event is added to the queue
"""
if not listener in self._event_added_listeners:
self._event_added_listeners.append(listener)
def event_added_unsubscribe(self, listener):
'''Remove a listener when an event is added to the queue'''
"""
Remove a listener when an event is added to the queue
"""
if listener in self._event_added_listeners:
self._event_added_listeners.remove(listener)
def event_removed_subscribe(self, listener):
'''Add a listener when an event is removed from the queue'''
"""
Add a listener when an event is removed from the queue
"""
if not listener in self._event_removed_listeners:
self._event_removed_listeners.append(listener)
def event_removed_unsubscribe(self, listener):
'''Remove a listener when an event is removed from the queue'''
"""
Remove a listener when an event is removed from the queue
"""
if listener in self._event_removed_listeners:
self._event_removed_listeners.remove(listener)
@ -125,9 +141,10 @@ class Events:
self.fire_event_added(event)
def remove_events(self, account, jid, event = None, types = []):
'''if event is not specified, remove all events from this jid,
optionally only from given type
return True if no such event found'''
"""
If event is not specified, remove all events from this jid, optionally
only from given type return True if no such event found
"""
if account not in self._events:
return True
if jid not in self._events[account]:
@ -177,10 +194,11 @@ class Events:
return self._get_nb_events(types = types, account = account)
def get_events(self, account, jid = None, types = []):
'''returns all events from the given account of the form
{jid1: [], jid2: []}
if jid is given, returns all events from the given jid in a list: []
optionally only from given type'''
"""
Return all events from the given account of the form {jid1: [], jid2:
[]}. If jid is given, returns all events from the given jid in a list: []
optionally only from given type
"""
if account not in self._events:
return []
if not jid:
@ -202,7 +220,9 @@ class Events:
return events_list
def get_first_event(self, account, jid = None, type_ = None):
'''Return the first event of type type_ if given'''
"""
Return the first event of type type_ if given
"""
events_list = self.get_events(account, jid, type_)
# be sure it's bigger than latest event
first_event_time = time.time() + 1
@ -213,9 +233,11 @@ class Events:
first_event = event
return first_event
def _get_nb_events(self, account = None, jid = None, attribute = None,
types = []):
'''return the number of pending events'''
def _get_nb_events(self, account = None, jid = None, attribute = None, types
= []):
"""
Return the number of pending events
"""
nb = 0
if account:
accounts = [account]
@ -241,7 +263,9 @@ class Events:
return nb
def _get_some_events(self, attribute):
'''attribute in systray, roster'''
"""
Attribute in systray, roster
"""
events = {}
for account in self._events:
events[account] = {}
@ -258,8 +282,11 @@ class Events:
return events
def _get_first_event_with_attribute(self, events):
'''get the first event
events is in the form {account1: {jid1: [ev1, ev2], },. }'''
"""
Get the first event
events is in the form {account1: {jid1: [ev1, ev2], },. }
"""
# be sure it's bigger than latest event
first_event_time = time.time() + 1
first_account = None
@ -276,12 +303,16 @@ class Events:
return first_account, first_jid, first_event
def get_nb_systray_events(self, types = []):
'''returns the number of events displayed in roster'''
"""
Return the number of events displayed in roster
"""
return self._get_nb_events(attribute = 'systray', types = types)
def get_systray_events(self):
'''return all events that must be displayed in systray:
{account1: {jid1: [ev1, ev2], },. }'''
"""
Return all events that must be displayed in systray:
{account1: {jid1: [ev1, ev2], },. }
"""
return self._get_some_events('systray')
def get_first_systray_event(self):
@ -289,13 +320,17 @@ class Events:
return self._get_first_event_with_attribute(events)
def get_nb_roster_events(self, account = None, jid = None, types = []):
'''returns the number of events displayed in roster'''
"""
Return the number of events displayed in roster
"""
return self._get_nb_events(attribute = 'roster', account = account,
jid = jid, types = types)
def get_roster_events(self):
'''return all events that must be displayed in roster:
{account1: {jid1: [ev1, ev2], },. }'''
"""
Return all events that must be displayed in roster:
{account1: {jid1: [ev1, ev2], },. }
"""
return self._get_some_events('roster')
# vim: se ts=3:

View File

@ -22,7 +22,10 @@
##
class PysqliteNotAvailable(Exception):
'''sqlite2 is not installed or python bindings are missing'''
"""
Sqlite2 is not installed or python bindings are missing
"""
def __init__(self):
Exception.__init__(self)
@ -30,7 +33,10 @@ class PysqliteNotAvailable(Exception):
return _('pysqlite2 (aka python-pysqlite2) dependency is missing. Exiting...')
class PysqliteOperationalError(Exception):
'''sqlite2 raised pysqlite2.dbapi2.OperationalError'''
"""
Sqlite2 raised pysqlite2.dbapi2.OperationalError
"""
def __init__(self, text=''):
Exception.__init__(self)
self.text = text
@ -39,7 +45,10 @@ class PysqliteOperationalError(Exception):
return self.text
class DatabaseMalformed(Exception):
'''The databas can't be read'''
"""
The databas can't be read
"""
def __init__(self):
Exception.__init__(self)
@ -47,7 +56,10 @@ class DatabaseMalformed(Exception):
return _('Database cannot be read.')
class ServiceNotAvailable(Exception):
'''This exception is raised when we cannot use Gajim remotely'''
"""
This exception is raised when we cannot use Gajim remotely'
"""
def __init__(self):
Exception.__init__(self)
@ -55,7 +67,10 @@ class ServiceNotAvailable(Exception):
return _('Service not available: Gajim is not running, or remote_control is False')
class DbusNotSupported(Exception):
'''D-Bus is not installed or python bindings are missing'''
"""
D-Bus is not installed or python bindings are missing
"""
def __init__(self):
Exception.__init__(self)
@ -63,7 +78,10 @@ class DbusNotSupported(Exception):
return _('D-Bus is not present on this machine or python module is missing')
class SessionBusNotPresent(Exception):
'''This exception indicates that there is no session daemon'''
"""
This exception indicates that there is no session daemon
"""
def __init__(self):
Exception.__init__(self)
@ -71,19 +89,28 @@ class SessionBusNotPresent(Exception):
return _('Session bus is not available.\nTry reading http://trac.gajim.org/wiki/GajimDBus')
class NegotiationError(Exception):
'''A session negotiation failed'''
"""
A session negotiation failed
"""
pass
class DecryptionError(Exception):
'''A message couldn't be decrypted into usable XML'''
"""
A message couldn't be decrypted into usable XML
"""
pass
class Cancelled(Exception):
'''The user cancelled an operation'''
"""
The user cancelled an operation
"""
pass
class LatexError(Exception):
'''LaTeX processing failed for some reason'''
"""
LaTeX processing failed for some reason
"""
def __init__(self, text=''):
Exception.__init__(self)
self.text = text
@ -92,7 +119,10 @@ class LatexError(Exception):
return self.text
class GajimGeneralException(Exception):
'''This exception is our general exception'''
"""
This exception is our general exception
"""
def __init__(self, text=''):
Exception.__init__(self)
self.text = text

View File

@ -21,7 +21,7 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
'''
"""
Python class to show a "fuzzy clock".
Homepage of the original: http://home.gna.org/fuzzyclock/
Project Page of the original: http://gna.org/projects/fuzzyclock
@ -30,7 +30,7 @@ The class is based on a port from PHP code by
Henrique Recidive <henrique at recidive.com> which was
in turn based on the Fuzzy Clock Applet of Frerich Raabe (KDE).
So most of the credit goes to this guys, thanks :-)
'''
"""
import time
@ -46,7 +46,7 @@ class FuzzyClock:
_('half past %(0)s'), _('twenty five to %(1)s'), _('twenty to %(1)s'),
_('quarter to %(1)s'), _('ten to %(1)s'), _('five to %(1)s'), _("%(1)s o'clock") ]
FUZZY_DAYTIME = [ _('Night'), _('Early morning'), _('Morning'),
FUZZY_DAYTIME = [ _('Night'), _('Early morning'), _('Morning'),
_('Almost noon'), _('Noon'), _('Afternoon'), _('Evening'),
_('Late evening'), _('Night') ]

View File

@ -241,8 +241,9 @@ def get_room_and_nick_from_fjid(jid):
return l
def get_real_jid_from_fjid(account, fjid):
'''returns real jid or returns None
if we don't know the real jid'''
"""
Return real jid or returns None, if we don't know the real jid
"""
room_jid, nick = get_room_and_nick_from_fjid(fjid)
if not nick: # It's not a fake_jid, it is a real jid
return fjid # we return the real jid
@ -267,7 +268,9 @@ def get_jid_without_resource(jid):
return jid.split('/')[0]
def construct_fjid(room_jid, nick):
''' nick is in utf8 (taken from treeview); room_jid is in unicode'''
"""
Nick is in UTF-8 (taken from treeview); room_jid is in unicode
"""
# fake jid is the jid for a contact in a room
# gaim@conference.jabber.org/nick
if isinstance(nick, str):
@ -281,19 +284,17 @@ def get_resource_from_jid(jid):
else:
return ''
# [15:34:28] <asterix> we should add contact.fake_jid I think
# [15:34:46] <asterix> so if we know real jid, it wil be in contact.jid, or we look in contact.fake_jid
# [15:32:54] <asterix> they can have resource if we know the real jid
# [15:33:07] <asterix> and that resource is in contact.resource
def get_number_of_accounts():
'''returns the number of ALL accounts'''
"""
Return the number of ALL accounts
"""
return len(connections.keys())
def get_number_of_connected_accounts(accounts_list = None):
'''returns the number of CONNECTED accounts
you can optionally pass an accounts_list
and if you do those will be checked, else all will be checked'''
"""
Returns the number of CONNECTED accounts. Uou can optionally pass an
accounts_list and if you do those will be checked, else all will be checked
"""
connected_accounts = 0
if accounts_list is None:
accounts = connections.keys()
@ -320,7 +321,9 @@ def zeroconf_is_connected():
config.get_per('accounts', ZEROCONF_ACC_NAME, 'is_zeroconf')
def get_number_of_securely_connected_accounts():
'''returns the number of the accounts that are SSL/TLS connected'''
"""
Return the number of the accounts that are SSL/TLS connected
"""
num_of_secured = 0
for account in connections.keys():
if account_is_securely_connected(account):
@ -335,8 +338,11 @@ def account_is_securely_connected(account):
return False
def get_transport_name_from_jid(jid, use_config_setting = True):
'''returns 'aim', 'gg', 'irc' etc
if JID is not from transport returns None'''
"""
Returns 'aim', 'gg', 'irc' etc
If JID is not from transport returns None.
"""
#FIXME: jid can be None! one TB I saw had this problem:
# in the code block # it is a groupchat presence in handle_event_notify
# jid was None. Yann why?
@ -372,21 +378,27 @@ def jid_is_transport(jid):
return False
def get_jid_from_account(account_name):
'''return the jid we use in the given account'''
"""
Return the jid we use in the given account
"""
name = config.get_per('accounts', account_name, 'name')
hostname = config.get_per('accounts', account_name, 'hostname')
jid = name + '@' + hostname
return jid
def get_our_jids():
'''returns a list of the jids we use in our accounts'''
"""
Returns a list of the jids we use in our accounts
"""
our_jids = list()
for account in contacts.get_accounts():
our_jids.append(get_jid_from_account(account))
return our_jids
def get_hostname_from_account(account_name, use_srv = False):
'''returns hostname (if custom hostname is used, that is returned)'''
"""
Returns hostname (if custom hostname is used, that is returned)
"""
if use_srv and connections[account_name].connected_hostname:
return connections[account_name].connected_hostname
if config.get_per('accounts', account_name, 'use_custom_host'):
@ -394,7 +406,9 @@ def get_hostname_from_account(account_name, use_srv = False):
return config.get_per('accounts', account_name, 'hostname')
def get_notification_image_prefix(jid):
'''returns the prefix for the notification images'''
"""
Returns the prefix for the notification images
"""
transport_name = get_transport_name_from_jid(jid)
if transport_name in ('aim', 'icq', 'msn', 'yahoo', 'facebook'):
prefix = transport_name
@ -403,7 +417,9 @@ def get_notification_image_prefix(jid):
return prefix
def get_name_from_jid(account, jid):
'''returns from JID's shown name and if no contact returns jids'''
"""
Return from JID's shown name and if no contact returns jids
"""
contact = contacts.get_first_contact_from_jid(account, jid)
if contact:
actor = contact.get_shown_name()
@ -412,7 +428,9 @@ def get_name_from_jid(account, jid):
return actor
def get_priority(account, show):
'''return the priority an account must have'''
"""
Return the priority an account must have
"""
if not show:
show = 'online'

View File

@ -92,15 +92,19 @@ def decompose_jid(jidstring):
return user, server, resource
def parse_jid(jidstring):
'''Perform stringprep on all JID fragments from a string
and return the full jid'''
"""
Perform stringprep on all JID fragments from a string and return the full
jid
"""
# This function comes from http://svn.twistedmatrix.com/cvs/trunk/twisted/words/protocols/jabber/jid.py
return prep(*decompose_jid(jidstring))
def idn_to_ascii(host):
'''convert IDN (Internationalized Domain Names) to ACE
(ASCII-compatible encoding)'''
"""
Convert IDN (Internationalized Domain Names) to ACE (ASCII-compatible
encoding)
"""
from encodings import idna
labels = idna.dots.split(host)
converted_labels = []
@ -109,8 +113,10 @@ def idn_to_ascii(host):
return ".".join(converted_labels)
def ascii_to_idn(host):
'''convert ACE (ASCII-compatible encoding) to IDN
(Internationalized Domain Names)'''
"""
Convert ACE (ASCII-compatible encoding) to IDN (Internationalized Domain
Names)
"""
from encodings import idna
labels = idna.dots.split(host)
converted_labels = []
@ -119,7 +125,9 @@ def ascii_to_idn(host):
return ".".join(converted_labels)
def parse_resource(resource):
'''Perform stringprep on resource and return it'''
"""
Perform stringprep on resource and return it
"""
if resource:
try:
from xmpp.stringprepare import resourceprep
@ -128,10 +136,11 @@ def parse_resource(resource):
raise InvalidFormat, 'Invalid character in resource.'
def prep(user, server, resource):
'''Perform stringprep on all JID fragments and return the full jid'''
"""
Perform stringprep on all JID fragments and return the full jid
"""
# This function comes from
#http://svn.twistedmatrix.com/cvs/trunk/twisted/words/protocols/jabber/jid.py
if user:
try:
from xmpp.stringprepare import nodeprep
@ -186,10 +195,13 @@ def temp_failure_retry(func, *args, **kwargs):
raise
def get_uf_show(show, use_mnemonic = False):
'''returns a userfriendly string for dnd/xa/chat
and makes all strings translatable
if use_mnemonic is True, it adds _ so GUI should call with True
for accessibility issues'''
"""
Return a userfriendly string for dnd/xa/chat and make all strings
translatable
If use_mnemonic is True, it adds _ so GUI should call with True for
accessibility issues
"""
if show == 'dnd':
if use_mnemonic:
uf_show = _('_Busy')
@ -324,7 +336,9 @@ def from_one_line(msg):
return msg
def get_uf_chatstate(chatstate):
'''removes chatstate jargon and returns user friendly messages'''
"""
Remove chatstate jargon and returns user friendly messages
"""
if chatstate == 'active':
return _('is paying attention to the conversation')
elif chatstate == 'inactive':
@ -339,10 +353,11 @@ def get_uf_chatstate(chatstate):
return ''
def is_in_path(command, return_abs_path=False):
'''Returns True if 'command' is found in one of the directories in the
user's path. If 'return_abs_path' is True, returns the absolute path of
the first found command instead. Returns False otherwise and on errors.'''
"""
Return True if 'command' is found in one of the directories in the user's
path. If 'return_abs_path' is True, return the absolute path of the first
found command instead. Return False otherwise and on errors
"""
for directory in os.getenv('PATH').split(os.pathsep):
try:
if command in os.listdir(directory):
@ -405,7 +420,9 @@ def get_output_of_command(command):
return output
def decode_string(string):
'''try to decode (to make it Unicode instance) given string'''
"""
Try to decode (to make it Unicode instance) given string
"""
if isinstance(string, unicode):
return string
# by the time we go to iso15 it better be the one else we show bad characters
@ -420,7 +437,9 @@ def decode_string(string):
return string
def ensure_utf8_string(string):
'''make sure string is in UTF-8'''
"""
Make sure string is in UTF-8
"""
try:
string = decode_string(string).encode('utf-8')
except Exception:
@ -428,28 +447,28 @@ def ensure_utf8_string(string):
return string
def get_windows_reg_env(varname, default=''):
'''asks for paths commonly used but not exposed as ENVs
in english Windows 2003 those are:
'AppData' = %USERPROFILE%\Application Data (also an ENV)
'Desktop' = %USERPROFILE%\Desktop
'Favorites' = %USERPROFILE%\Favorites
'NetHood' = %USERPROFILE%\NetHood
'Personal' = D:\My Documents (PATH TO MY DOCUMENTS)
'PrintHood' = %USERPROFILE%\PrintHood
'Programs' = %USERPROFILE%\Start Menu\Programs
'Recent' = %USERPROFILE%\Recent
'SendTo' = %USERPROFILE%\SendTo
'Start Menu' = %USERPROFILE%\Start Menu
'Startup' = %USERPROFILE%\Start Menu\Programs\Startup
'Templates' = %USERPROFILE%\Templates
'My Pictures' = D:\My Documents\My Pictures
'Local Settings' = %USERPROFILE%\Local Settings
'Local AppData' = %USERPROFILE%\Local Settings\Application Data
'Cache' = %USERPROFILE%\Local Settings\Temporary Internet Files
'Cookies' = %USERPROFILE%\Cookies
'History' = %USERPROFILE%\Local Settings\History
'''
"""
Ask for paths commonly used but not exposed as ENVs in english Windows 2003
those are:
'AppData' = %USERPROFILE%\Application Data (also an ENV)
'Desktop' = %USERPROFILE%\Desktop
'Favorites' = %USERPROFILE%\Favorites
'NetHood' = %USERPROFILE%\NetHood
'Personal' = D:\My Documents (PATH TO MY DOCUMENTS)
'PrintHood' = %USERPROFILE%\PrintHood
'Programs' = %USERPROFILE%\Start Menu\Programs
'Recent' = %USERPROFILE%\Recent
'SendTo' = %USERPROFILE%\SendTo
'Start Menu' = %USERPROFILE%\Start Menu
'Startup' = %USERPROFILE%\Start Menu\Programs\Startup
'Templates' = %USERPROFILE%\Templates
'My Pictures' = D:\My Documents\My Pictures
'Local Settings' = %USERPROFILE%\Local Settings
'Local AppData' = %USERPROFILE%\Local Settings\Application Data
'Cache' = %USERPROFILE%\Local Settings\Temporary Internet Files
'Cookies' = %USERPROFILE%\Cookies
'History' = %USERPROFILE%\Local Settings\History
"""
if os.name != 'nt':
return ''
@ -467,7 +486,9 @@ r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders')
return val
def get_my_pictures_path():
'''windows-only atm. [Unix lives in the past]'''
"""
Windows-only atm
"""
return get_windows_reg_env('My Pictures')
def get_desktop_path():
@ -485,8 +506,10 @@ def get_documents_path():
return path
def sanitize_filename(filename):
'''makes sure the filename we will write does contain only acceptable and
latin characters, and is not too long (in that case hash it)'''
"""
Make sure the filename we will write does contain only acceptable and latin
characters, and is not too long (in that case hash it)
"""
# 48 is the limit
if len(filename) > 48:
hash = hashlib.md5(filename)
@ -502,11 +525,13 @@ def sanitize_filename(filename):
return filename
def reduce_chars_newlines(text, max_chars = 0, max_lines = 0):
'''Cut the chars after 'max_chars' on each line
and show only the first 'max_lines'.
If any of the params is not present (None or 0) the action
on it is not performed'''
"""
Cut the chars after 'max_chars' on each line and show only the first
'max_lines'
If any of the params is not present (None or 0) the action on it is not
performed
"""
def _cut_if_long(string):
if len(string) > max_chars:
string = string[:max_chars - 3] + '...'
@ -535,10 +560,11 @@ def get_account_status(account):
return status
def get_avatar_path(prefix):
'''Returns the filename of the avatar, distinguishes between user- and
contact-provided one. Returns None if no avatar was found at all.
prefix is the path to the requested avatar just before the ".png" or
".jpeg".'''
"""
Return the filename of the avatar, distinguishes between user- and contact-
provided one. Return None if no avatar was found at all. prefix is the path
to the requested avatar just before the ".png" or ".jpeg"
"""
# First, scan for a local, user-set avatar
for type_ in ('jpeg', 'png'):
file_ = prefix + '_local.' + type_
@ -552,13 +578,16 @@ def get_avatar_path(prefix):
return None
def datetime_tuple(timestamp):
'''Converts timestamp using strptime and the format: %Y%m%dT%H:%M:%S
"""
Convert timestamp using strptime and the format: %Y%m%dT%H:%M:%S
Because of various datetime formats are used the following exceptions
are handled:
- Optional milliseconds appened to the string are removed
- Optional Z (that means UTC) appened to the string are removed
- XEP-082 datetime strings have all '-' cahrs removed to meet
the above format.'''
the above format.
"""
timestamp = timestamp.split('.')[0]
timestamp = timestamp.replace('-', '')
timestamp = timestamp.replace('z', '')
@ -609,8 +638,11 @@ def convert_bytes(string):
return suffix % unicode(bytes)
def get_contact_dict_for_account(account):
''' create a dict of jid, nick -> contact with all contacts of account.
Can be used for completion lists'''
"""
Create a dict of jid, nick -> contact with all contacts of account.
Can be used for completion lists
"""
contacts_dict = {}
for jid in gajim.contacts.get_jid_list(account):
contact = gajim.contacts.get_contact_with_highest_priority(account,
@ -692,13 +724,15 @@ def play_sound(event):
path_to_soundfile = gajim.config.get_per('soundevents', event, 'path')
play_sound_file(path_to_soundfile)
def check_soundfile_path(file,
dirs=(gajim.gajimpaths.root, gajim.DATA_DIR)):
'''Check if the sound file exists.
def check_soundfile_path(file, dirs=(gajim.gajimpaths.root, gajim.DATA_DIR)):
"""
Check if the sound file exists
:param file: the file to check, absolute or relative to 'dirs' path
:param dirs: list of knows paths to fallback if the file doesn't exists
(eg: ~/.gajim/sounds/, DATADIR/sounds...).
:return the path to file or None if it doesn't exists.'''
:return the path to file or None if it doesn't exists.
"""
if not file:
return None
elif os.path.exists(file):
@ -710,16 +744,17 @@ def check_soundfile_path(file,
return d
return None
def strip_soundfile_path(file,
dirs=(gajim.gajimpaths.root, gajim.DATA_DIR),
abs=True):
'''Remove knowns paths from a sound file:
def strip_soundfile_path(file, dirs=(gajim.gajimpaths.root, gajim.DATA_DIR),
abs=True):
"""
Remove knowns paths from a sound file
Filechooser returns absolute path. If path is a known fallback path, we remove it.
So config have no hardcoded path to DATA_DIR and text in textfield is shorther.
param: file: the filename to strip.
param: dirs: list of knowns paths from which the filename should be stripped.
param: abs: force absolute path on dirs
'''
"""
if not file:
return None
@ -777,7 +812,9 @@ def get_global_status():
def statuses_unified():
'''testing if all statuses are the same.'''
"""
Test if all statuses are the same
"""
reference = None
for account in gajim.connections:
if not gajim.config.get_per('accounts', account,
@ -790,7 +827,9 @@ def statuses_unified():
return True
def get_icon_name_to_show(contact, account = None):
'''Get the icon name to show in online, away, requested, ...'''
"""
Get the icon name to show in online, away, requested, etc
"""
if account and gajim.events.get_nb_roster_events(account, contact.jid):
return 'event'
if account and gajim.events.get_nb_roster_events(account,
@ -819,16 +858,22 @@ def get_icon_name_to_show(contact, account = None):
return 'not in roster'
def get_full_jid_from_iq(iq_obj):
'''return the full jid (with resource) from an iq as unicode'''
"""
Return the full jid (with resource) from an iq as unicode
"""
return parse_jid(str(iq_obj.getFrom()))
def get_jid_from_iq(iq_obj):
'''return the jid (without resource) from an iq as unicode'''
"""
Return the jid (without resource) from an iq as unicode
"""
jid = get_full_jid_from_iq(iq_obj)
return gajim.get_jid_without_resource(jid)
def get_auth_sha(sid, initiator, target):
''' return sha of sid + initiator + target used for proxy auth'''
"""
Return sha of sid + initiator + target used for proxy auth
"""
return hashlib.sha1("%s%s%s" % (sid, initiator, target)).hexdigest()
def remove_invalid_xml_chars(string):
@ -861,7 +906,9 @@ distro_info = {
}
def get_random_string_16():
''' create random string of length 16'''
"""
Create random string of length 16
"""
rng = range(65, 90)
rng.extend(range(48, 57))
char_sequence = [chr(e) for e in rng]
@ -946,11 +993,14 @@ def get_os_info():
def allow_showing_notification(account, type_ = 'notify_on_new_message',
advanced_notif_num = None, is_first_message = True):
'''is it allowed to show nofication?
check OUR status and if we allow notifications for that status
type is the option that need to be True e.g.: notify_on_signing
is_first_message: set it to false when it's not the first message'''
advanced_notif_num = None, is_first_message = True):
"""
Is it allowed to show nofication?
Check OUR status and if we allow notifications for that status type is the
option that need to be True e.g.: notify_on_signing is_first_message: set it
to false when it's not the first message
"""
if advanced_notif_num is not None:
popup = gajim.config.get_per('notifications', str(advanced_notif_num),
'popup')
@ -967,7 +1017,9 @@ advanced_notif_num = None, is_first_message = True):
return False
def allow_popup_window(account, advanced_notif_num = None):
'''is it allowed to popup windows?'''
"""
Is it allowed to popup windows?
"""
if advanced_notif_num is not None:
popup = gajim.config.get_per('notifications', str(advanced_notif_num),
'auto_open')
@ -1018,8 +1070,10 @@ def get_chat_control(account, contact):
return gajim.interface.msg_win_mgr.get_control(contact.jid, account)
def get_notification_icon_tooltip_dict():
'''returns a dict of the form {acct: {'show': show, 'message': message,
'event_lines': [list of text lines to show in tooltip]}'''
"""
Return a dict of the form {acct: {'show': show, 'message': message,
'event_lines': [list of text lines to show in tooltip]}
"""
# How many events must there be before they're shown summarized, not per-user
max_ungrouped_events = 10
@ -1131,7 +1185,9 @@ def get_notification_icon_tooltip_text():
return text
def get_accounts_info():
'''helper for notification icon tooltip'''
"""
Helper for notification icon tooltip
"""
accounts = []
accounts_list = sorted(gajim.contacts.get_accounts())
for account in accounts_list:
@ -1182,9 +1238,14 @@ def get_transport_path(transport):
return get_iconset_path(gajim.config.get('iconset'))
def prepare_and_validate_gpg_keyID(account, jid, keyID):
'''Returns an eight char long keyID that can be used with for GPG encryption with this contact.
If the given keyID is None, return UNKNOWN; if the key does not match the assigned key
XXXXXXXXMISMATCH is returned. If the key is trusted and not yet assigned, assign it'''
"""
Return an eight char long keyID that can be used with for GPG encryption
with this contact
If the given keyID is None, return UNKNOWN; if the key does not match the
assigned key XXXXXXXXMISMATCH is returned. If the key is trusted and not yet
assigned, assign it.
"""
if gajim.connections[account].USE_GPG:
if keyID and len(keyID) == 16:
keyID = keyID[8:]

View File

@ -32,7 +32,7 @@ def paragraph_direction_mark(text):
"""
Determine paragraph writing direction according to
http://www.unicode.org/reports/tr9/#The_Paragraph_Level
Returns either Unicode LTR mark or RTL mark.
"""
for char in text:
@ -84,11 +84,12 @@ def Q_(s):
return s
def ngettext(s_sing, s_plural, n, replace_sing = None, replace_plural = None):
'''use as:
i18n.ngettext('leave room %s', 'leave rooms %s', len(rooms), 'a', 'a, b, c')
"""
Use as:
i18n.ngettext('leave room %s', 'leave rooms %s', len(rooms), 'a', 'a, b, c')
in other words this is a hack to ngettext() to support %s %d etc..
'''
In other words this is a hack to ngettext() to support %s %d etc..
"""
text = _translation.ungettext(s_sing, s_plural, n)
if n == 1 and replace_sing is not None:
text = text % replace_sing

View File

@ -73,7 +73,9 @@ except OSError, e:
xss_available = False
def getIdleSec():
"""Returns the idle time in seconds"""
"""
Return the idle time in seconds
"""
if not xss_available:
return 0
if libXss.XScreenSaverQueryInfo(dpy_p, rootwindow, xss_info_p) == 0:

View File

@ -10,7 +10,9 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
''' Handles the jingle signalling protocol. '''
"""
Handles the jingle signalling protocol
"""
#TODO:
# * things in XEP 0176, including:
@ -37,7 +39,10 @@ from jingle_rtp import JingleAudio, JingleVideo
class ConnectionJingle(object):
''' This object depends on that it is a part of Connection class. '''
"""
This object depends on that it is a part of Connection class.
"""
def __init__(self):
# dictionary: (jid, sessionid) => JingleSession object
self.__sessions = {}
@ -47,13 +52,17 @@ class ConnectionJingle(object):
self.__iq_responses = {}
def add_jingle(self, jingle):
''' Add a jingle session to a jingle stanza dispatcher
"""
Add a jingle session to a jingle stanza dispatcher
jingle - a JingleSession object.
'''
"""
self.__sessions[(jingle.peerjid, jingle.sid)] = jingle
def delete_jingle_session(self, peerjid, sid):
''' Remove a jingle session from a jingle stanza dispatcher '''
"""
Remove a jingle session from a jingle stanza dispatcher
"""
key = (peerjid, sid)
if key in self.__sessions:
#FIXME: Move this elsewhere?
@ -63,12 +72,15 @@ class ConnectionJingle(object):
del self.__sessions[key]
def _JingleCB(self, con, stanza):
''' The jingle stanza dispatcher.
Route jingle stanza to proper JingleSession object,
or create one if it is a new session.
TODO: Also check if the stanza isn't an error stanza, if so
route it adequatelly.'''
"""
The jingle stanza dispatcher
Route jingle stanza to proper JingleSession object, or create one if it
is a new session.
TODO: Also check if the stanza isn't an error stanza, if so route it
adequatelly.
"""
# get data
jid = helpers.get_full_jid_from_iq(stanza)
id = stanza.getID()

View File

@ -10,7 +10,10 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
''' Handles Jingle contents (XEP 0166). '''
"""
Handles Jingle contents (XEP 0166)
"""
contents = {}
@ -23,7 +26,10 @@ def get_jingle_content(node):
class JingleContent(object):
''' An abstraction of content in Jingle sessions. '''
"""
An abstraction of content in Jingle sessions
"""
def __init__(self, session, transport):
self.session = session
self.transport = transport
@ -71,24 +77,32 @@ class JingleContent(object):
return (self.accepted and not self.sent)
def add_remote_candidates(self, candidates):
''' Add a list of candidates to the list of remote candidates. '''
"""
Add a list of candidates to the list of remote candidates
"""
pass
def stanzaCB(self, stanza, content, error, action):
''' Called when something related to our content was sent by peer. '''
"""
Called when something related to our content was sent by peer
"""
if action in self.callbacks:
for callback in self.callbacks[action]:
callback(stanza, content, error, action)
def __transportInfoCB(self, stanza, content, error, action):
''' Got a new transport candidate. '''
"""
Got a new transport candidate
"""
candidates = self.transport.parse_transport_stanza(
content.getTag('transport'))
if candidates:
self.add_remote_candidates(candidates)
def __content(self, payload=[]):
''' Build a XML content-wrapper for our data. '''
"""
Build a XML content-wrapper for our data
"""
return xmpp.Node('content',
attrs={'name': self.name, 'creator': self.creator},
payload=payload)
@ -99,7 +113,9 @@ class JingleContent(object):
self.session.send_transport_info(content)
def __fillJingleStanza(self, stanza, content, error, action):
''' Add our things to session-initiate stanza. '''
"""
Add our things to session-initiate stanza
"""
self._fillContent(content)
self.sent = True
content.addChild(node=self.transport.make_transport())

View File

@ -10,8 +10,10 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
''' Handles Jingle RTP sessions (XEP 0167). '''
"""
Handles Jingle RTP sessions (XEP 0167)
"""
import gobject
@ -23,7 +25,9 @@ from jingle_content import contents, JingleContent
# TODO: Will that be even used?
def get_first_gst_element(elements):
''' Returns, if it exists, the first available element of the list. '''
"""
Return, if it exists, the first available element of the list
"""
for name in elements:
factory = gst.element_factory_find(name)
if factory:
@ -70,7 +74,7 @@ class JingleRTPContent(JingleContent):
self.p2psession = self.conference.new_session(self.farsight_media)
participant = self.conference.new_participant(self.session.peerjid)
#FIXME: Consider a workaround, here...
# FIXME: Consider a workaround, here...
# pidgin and telepathy-gabble don't follow the XEP, and it won't work
# due to bad controlling-mode
params = {'controlling-mode': self.session.weinitiate,# 'debug': False}
@ -85,14 +89,14 @@ class JingleRTPContent(JingleContent):
def add_remote_candidates(self, candidates):
JingleContent.add_remote_candidates(self, candidates)
#FIXME: connectivity should not be etablished yet
# FIXME: connectivity should not be etablished yet
# Instead, it should be etablished after session-accept!
if self.sent:
self.p2pstream.set_remote_candidates(candidates)
def batch_dtmf(self, events):
if self._dtmf_running:
raise Exception #TODO: Proper exception
raise Exception # TODO: Proper exception
self._dtmf_running = True
self._start_dtmf(events.pop(0))
gobject.timeout_add(500, self._next_dtmf, events)
@ -143,7 +147,7 @@ class JingleRTPContent(JingleContent):
elif name == 'farsight-codecs-changed':
if self.is_ready():
self.session.on_session_state_changed(self)
#TODO: description-info
# TODO: description-info
elif name == 'farsight-local-candidates-prepared':
self.candidates_ready = True
if self.is_ready():
@ -152,7 +156,7 @@ class JingleRTPContent(JingleContent):
candidate = message.structure['candidate']
self.transport.candidates.append(candidate)
if self.candidates_ready:
#FIXME: Is this case even possible?
# FIXME: Is this case even possible?
self.send_candidate(candidate)
elif name == 'farsight-component-state-changed':
state = message.structure['state']
@ -173,7 +177,7 @@ class JingleRTPContent(JingleContent):
if self.transport.remote_candidates:
self.p2pstream.set_remote_candidates(self.transport.remote_candidates)
self.transport.remote_candidates = []
#TODO: farsight.DIRECTION_BOTH only if senders='both'
# TODO: farsight.DIRECTION_BOTH only if senders='both'
self.p2pstream.set_property('direction', farsight.DIRECTION_BOTH)
self.session.content_negociated(self.media)
@ -195,7 +199,7 @@ class JingleRTPContent(JingleContent):
codecs.append(c)
if len(codecs) > 0:
#FIXME: Handle this case:
# FIXME: Handle this case:
# glib.GError: There was no intersection between the remote codecs and
# the local ones
self.p2pstream.set_remote_codecs(codecs)
@ -228,14 +232,15 @@ class JingleRTPContent(JingleContent):
class JingleAudio(JingleRTPContent):
''' Jingle VoIP sessions consist of audio content transported
over an ICE UDP protocol. '''
"""
Jingle VoIP sessions consist of audio content transported over an ICE UDP
protocol
"""
def __init__(self, session, transport=None):
JingleRTPContent.__init__(self, session, 'audio', transport)
self.setup_stream()
''' Things to control the gstreamer's pipeline '''
def setup_stream(self):
JingleRTPContent.setup_stream(self)
@ -283,9 +288,8 @@ class JingleVideo(JingleRTPContent):
JingleRTPContent.__init__(self, session, 'video', transport)
self.setup_stream()
''' Things to control the gstreamer's pipeline '''
def setup_stream(self):
#TODO: Everything is not working properly:
# TODO: Everything is not working properly:
# sometimes, one window won't show up,
# sometimes it'll freeze...
JingleRTPContent.setup_stream(self)

View File

@ -10,7 +10,10 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
''' Handles Jingle sessions (XEP 0166). '''
"""
Handles Jingle sessions (XEP 0166)
"""
#TODO:
# * Have JingleContent here
@ -29,25 +32,38 @@ import xmpp
from jingle_transport import get_jingle_transport
from jingle_content import get_jingle_content
#FIXME: Move it to JingleSession.States?
# FIXME: Move it to JingleSession.States?
class JingleStates(object):
''' States in which jingle session may exist. '''
"""
States in which jingle session may exist
"""
ended = 0
pending = 1
active = 2
class OutOfOrder(Exception):
''' Exception that should be raised when an action is received when in the wrong state. '''
"""
Exception that should be raised when an action is received when in the wrong
state
"""
class TieBreak(Exception):
''' Exception that should be raised in case of a tie, when we overrule the other action. '''
"""
Exception that should be raised in case of a tie, when we overrule the other
action
"""
class JingleSession(object):
''' This represents one jingle session. '''
"""
This represents one jingle session
"""
def __init__(self, con, weinitiate, jid, sid=None):
''' con -- connection object,
weinitiate -- boolean, are we the initiator?
jid - jid of the other entity'''
"""
con -- connection object,
weinitiate -- boolean, are we the initiator?
jid - jid of the other entity
"""
self.contents = {} # negotiated contents
self.connection = con # connection to use
# our full jid
@ -97,15 +113,16 @@ class JingleSession(object):
'iq-error': [self.__errorCB],
}
''' Interaction with user '''
def approve_session(self):
''' Called when user accepts session in UI (when we aren't the initiator).
'''
"""
Called when user accepts session in UI (when we aren't the initiator)
"""
self.accept_session()
def decline_session(self):
''' Called when user declines session in UI (when we aren't the initiator)
'''
"""
Called when user declines session in UI (when we aren't the initiator)
"""
reason = xmpp.Node('reason')
reason.addChild('decline')
self._session_terminate(reason)
@ -125,7 +142,9 @@ class JingleSession(object):
self.on_session_state_changed()
def end_session(self):
''' Called when user stops or cancel session in UI. '''
"""
Called when user stops or cancel session in UI
"""
reason = xmpp.Node('reason')
if self.state == JingleStates.active:
reason.addChild('success')
@ -133,8 +152,6 @@ class JingleSession(object):
reason.addChild('cancel')
self._session_terminate(reason)
''' Middle-level functions to manage contents. Handle local content
cache and send change notifications. '''
def get_content(self, media=None):
if media is None:
return None
@ -144,9 +161,12 @@ class JingleSession(object):
return content
def add_content(self, name, content, creator='we'):
''' Add new content to session. If the session is active,
this will send proper stanza to update session.
Creator must be one of ('we', 'peer', 'initiator', 'responder')'''
"""
Add new content to session. If the session is active, this will send
proper stanza to update session
Creator must be one of ('we', 'peer', 'initiator', 'responder')
"""
assert creator in ('we', 'peer', 'initiator', 'responder')
if (creator == 'we' and self.weinitiate) or (creator == 'peer' and \
@ -164,7 +184,9 @@ class JingleSession(object):
content.accepted = True
def remove_content(self, creator, name):
''' We do not need this now '''
"""
We do not need this now
"""
#TODO:
if (creator, name) in self.contents:
content = self.contents[(creator, name)]
@ -175,7 +197,9 @@ class JingleSession(object):
self.end_session()
def modify_content(self, creator, name, *someother):
''' We do not need this now '''
"""
We do not need this now
"""
pass
def on_session_state_changed(self, content=None):
@ -203,19 +227,23 @@ class JingleSession(object):
self.__content_accept(content)
def is_ready(self):
''' Returns True when all codecs and candidates are ready
(for all contents). '''
"""
Return True when all codecs and candidates are ready (for all contents)
"""
return (all((content.is_ready() for content in self.contents.itervalues()))
and self.accepted)
''' Middle-level function to do stanza exchange. '''
def accept_session(self):
''' Mark the session as accepted. '''
"""
Mark the session as accepted
"""
self.accepted = True
self.on_session_state_changed()
def start_session(self):
''' Mark the session as ready to be started. '''
"""
Mark the session as ready to be started
"""
self.accepted = True
self.on_session_state_changed()
@ -234,11 +262,12 @@ class JingleSession(object):
jingle.addChild(node=content)
self.connection.connection.send(stanza)
''' Session callbacks. '''
def stanzaCB(self, stanza):
''' A callback for ConnectionJingle. It gets stanza, then
tries to send it to all internally registered callbacks.
First one to raise xmpp.NodeProcessed breaks function.'''
"""
A callback for ConnectionJingle. It gets stanza, then tries to send it to
all internally registered callbacks. First one to raise
xmpp.NodeProcessed breaks function
"""
jingle = stanza.getTag('jingle')
error = stanza.getTag('error')
if error:
@ -250,7 +279,7 @@ class JingleSession(object):
if action not in self.callbacks:
self.__send_error(stanza, 'bad_request')
return
#FIXME: If we aren't initiated and it's not a session-initiate...
# FIXME: If we aren't initiated and it's not a session-initiate...
if action != 'session-initiate' and self.state == JingleStates.ended:
self.__send_error(stanza, 'item-not-found', 'unknown-session')
return
@ -268,16 +297,18 @@ class JingleSession(object):
except TieBreak:
self.__send_error(stanza, 'conflict', 'tiebreak')
except OutOfOrder:
self.__send_error(stanza, 'unexpected-request', 'out-of-order')#FIXME
# FIXME
self.__send_error(stanza, 'unexpected-request', 'out-of-order')
def __defaultCB(self, stanza, jingle, error, action):
''' Default callback for action stanzas -- simple ack
and stop processing. '''
"""
Default callback for action stanzas -- simple ack and stop processing
"""
response = stanza.buildReply('result')
self.connection.connection.send(response)
def __errorCB(self, stanza, jingle, error, action):
#FIXME
# FIXME
text = error.getTagData('text')
jingle_error = None
xmpp_error = None
@ -287,7 +318,7 @@ class JingleSession(object):
elif child.getNamespace() == xmpp.NS_STANZAS:
xmpp_error = child.getName()
self.__dispatch_error(xmpp_error, jingle_error, text)
#FIXME: Not sure when we would want to do that...
# FIXME: Not sure when we would want to do that...
if xmpp_error == 'item-not-found':
self.connection.delete_jingle_session(self.peerjid, self.sid)
@ -298,9 +329,9 @@ class JingleSession(object):
if (creator, name) in self.contents:
transport_ns = content.getTag('transport').getNamespace()
if transport_ns == xmpp.JINGLE_ICE_UDP:
#FIXME: We don't manage anything else than ICE-UDP now...
#What was the previous transport?!?
#Anyway, content's transport is not modifiable yet
# FIXME: We don't manage anything else than ICE-UDP now...
# What was the previous transport?!?
# Anyway, content's transport is not modifiable yet
pass
else:
stanza, jingle = self.__make_jingle('transport-reject')
@ -310,8 +341,8 @@ class JingleSession(object):
self.connection.connection.send(stanza)
raise xmpp.NodeProcessed
else:
#FIXME: This ressource is unknown to us, what should we do?
#For now, reject the transport
# FIXME: This ressource is unknown to us, what should we do?
# For now, reject the transport
stanza, jingle = self.__make_jingle('transport-reject')
c = jingle.setTag('content', attrs={'creator': creator,
'name': name})
@ -320,7 +351,7 @@ class JingleSession(object):
raise xmpp.NodeProcessed
def __sessionInfoCB(self, stanza, jingle, error, action):
#TODO: ringing, active, (un)hold, (un)mute
# TODO: ringing, active, (un)hold, (un)mute
payload = jingle.getPayload()
if len(payload) > 0:
self.__send_error(stanza, 'feature-not-implemented', 'unsupported-info')
@ -332,7 +363,7 @@ class JingleSession(object):
name = content['name']
if (creator, name) in self.contents:
content = self.contents[(creator, name)]
#TODO: this will fail if content is not an RTP content
# TODO: this will fail if content is not an RTP content
self.connection.dispatch('JINGLE_DISCONNECTED',
(self.peerjid, self.sid, content.media, 'removed'))
content.destroy()
@ -342,17 +373,21 @@ class JingleSession(object):
self._session_terminate(reason)
def __sessionAcceptCB(self, stanza, jingle, error, action):
if self.state != JingleStates.pending: #FIXME
# FIXME
if self.state != JingleStates.pending:
raise OutOfOrder
self.state = JingleStates.active
def __contentAcceptCB(self, stanza, jingle, error, action):
''' Called when we get content-accept stanza or equivalent one
(like session-accept).'''
"""
Called when we get content-accept stanza or equivalent one (like
session-accept)
"""
# check which contents are accepted
for content in jingle.iterTags('content'):
creator = content['creator']
name = content['name']#TODO...
# TODO
name = content['name']
def __contentAddCB(self, stanza, jingle, error, action):
if self.state == JingleStates.ended:
@ -363,7 +398,7 @@ class JingleSession(object):
rejected_contents = parse_result[3]
for name, creator in rejected_contents:
#TODO:
# TODO
content = JingleContent()
self.add_content(name, content, creator)
self.__content_reject(content)
@ -373,10 +408,10 @@ class JingleSession(object):
contents))
def __sessionInitiateCB(self, stanza, jingle, error, action):
''' We got a jingle session request from other entity,
therefore we are the receiver... Unpack the data,
inform the user. '''
"""
We got a jingle session request from other entity, therefore we are the
receiver... Unpack the data, inform the user
"""
if self.state != JingleStates.ended:
raise OutOfOrder
@ -417,7 +452,9 @@ class JingleSession(object):
contents))
def __broadcastCB(self, stanza, jingle, error, action):
''' Broadcast the stanza contents to proper content handlers. '''
"""
Broadcast the stanza contents to proper content handlers
"""
for content in jingle.iterTags('content'):
name = content['name']
creator = content['creator']
@ -437,11 +474,12 @@ class JingleSession(object):
(self.peerjid, self.sid, None, text))
def __broadcastAllCB(self, stanza, jingle, error, action):
''' Broadcast the stanza to all content handlers. '''
"""
Broadcast the stanza to all content handlers
"""
for content in self.contents.itervalues():
content.stanzaCB(stanza, None, error, action)
''' Internal methods. '''
def __parse_contents(self, jingle):
#TODO: Needs some reworking
contents = []
@ -492,8 +530,6 @@ class JingleSession(object):
break
return (reason, text)
''' Methods that make/send proper pieces of XML. They check if the session
is in appropriate state. '''
def __make_jingle(self, action):
stanza = xmpp.Iq(typ='set', to=xmpp.JID(self.peerjid))
attrs = {'action': action,
@ -516,14 +552,17 @@ class JingleSession(object):
self.__dispatch_error(error, jingle_error, text)
def __append_content(self, jingle, content):
''' Append <content/> element to <jingle/> element,
with (full=True) or without (full=False) <content/>
children. '''
"""
Append <content/> element to <jingle/> element, with (full=True) or
without (full=False) <content/> children
"""
jingle.addChild('content',
attrs={'name': content.name, 'creator': content.creator})
def __append_contents(self, jingle):
''' Append all <content/> elements to <jingle/>.'''
"""
Append all <content/> elements to <jingle/>
"""
# TODO: integrate with __appendContent?
# TODO: parameters 'name', 'content'?
for content in self.contents.values():
@ -571,7 +610,7 @@ class JingleSession(object):
(self.peerjid, self.sid, None, text))
def __content_add(self, content):
#TODO: test
# TODO: test
assert self.state != JingleStates.ended
stanza, jingle = self.__make_jingle('content-add')
self.__append_content(jingle, content)
@ -579,7 +618,7 @@ class JingleSession(object):
self.connection.connection.send(stanza)
def __content_accept(self, content):
#TODO: test
# TODO: test
assert self.state != JingleStates.ended
stanza, jingle = self.__make_jingle('content-accept')
self.__append_content(jingle, content)
@ -591,7 +630,7 @@ class JingleSession(object):
stanza, jingle = self.__make_jingle('content-reject')
self.__append_content(jingle, content)
self.connection.connection.send(stanza)
#TODO: this will fail if content is not an RTP content
# TODO: this will fail if content is not an RTP content
self.connection.dispatch('JINGLE_DISCONNECTED',
(self.peerjid, self.sid, content.media, 'rejected'))
@ -603,7 +642,7 @@ class JingleSession(object):
stanza, jingle = self.__make_jingle('content-remove')
self.__append_content(jingle, content)
self.connection.connection.send(stanza)
#TODO: this will fail if content is not an RTP content
# TODO: this will fail if content is not an RTP content
self.connection.dispatch('JINGLE_DISCONNECTED',
(self.peerjid, self.sid, content.media, 'removed'))

View File

@ -10,7 +10,10 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
''' Handles Jingle Transports (currently only ICE-UDP). '''
"""
Handles Jingle Transports (currently only ICE-UDP)
"""
import xmpp
@ -25,13 +28,18 @@ def get_jingle_transport(node):
class TransportType(object):
''' Possible types of a JingleTransport '''
"""
Possible types of a JingleTransport
"""
datagram = 1
streaming = 2
class JingleTransport(object):
''' An abstraction of a transport in Jingle sessions. '''
"""
An abstraction of a transport in Jingle sessions
"""
def __init__(self, type_):
self.type = type_
self.candidates = []
@ -42,19 +50,25 @@ class JingleTransport(object):
yield self.make_candidate(candidate)
def make_candidate(self, candidate):
''' Build a candidate stanza for the given candidate. '''
"""
Build a candidate stanza for the given candidate
"""
pass
def make_transport(self, candidates=None):
''' Build a transport stanza with the given candidates (or
self.candidates if candidates is None). '''
"""
Build a transport stanza with the given candidates (or self.candidates if
candidates is None)
"""
if not candidates:
candidates = self._iter_candidates()
transport = xmpp.Node('transport', payload=candidates)
return transport
def parse_transport_stanza(self, transport):
''' Returns the list of transport candidates from a transport stanza. '''
"""
Return the list of transport candidates from a transport stanza
"""
return []
@ -132,4 +146,3 @@ class JingleTransportICEUDP(JingleTransport):
return candidates
transports[xmpp.NS_JINGLE_ICE_UDP] = JingleTransportICEUDP

View File

@ -25,7 +25,9 @@ import subprocess
def kwallet_available():
"""Return True if kwalletcli can be run, False otherwise."""
"""
Return True if kwalletcli can be run, False otherwise
"""
try:
p = subprocess.Popen(["kwalletcli", "-qV"])
except Exception:
@ -37,7 +39,8 @@ def kwallet_available():
def kwallet_get(folder, entry):
"""Retrieve a passphrase from the KDE Wallet via kwalletcli.
"""
Retrieve a passphrase from the KDE Wallet via kwalletcli
Arguments:
folder: The top-level category to use (normally the programme name)
@ -45,7 +48,6 @@ def kwallet_get(folder, entry):
Returns the passphrase as unicode, False if it cannot be found,
or None if an error occured.
"""
p = subprocess.Popen(["kwalletcli", "-q", "-f", folder.encode('utf-8'),
"-e", entry.encode('utf-8')], stdout=subprocess.PIPE)
@ -60,7 +62,8 @@ def kwallet_get(folder, entry):
def kwallet_put(folder, entry, passphrase):
"""Store a passphrase into the KDE Wallet via kwalletcli.
"""
Store a passphrase into the KDE Wallet via kwalletcli
Arguments:
folder: The top-level category to use (normally the programme name)
@ -68,7 +71,6 @@ def kwallet_put(folder, entry, passphrase):
passphrase: The value to store
Returns True on success, False otherwise.
"""
p = subprocess.Popen(["kwalletcli", "-q", "-f", folder.encode('utf-8'),
"-e", entry.encode('utf-8'), "-P"], stdin=subprocess.PIPE)

View File

@ -86,8 +86,9 @@ def popen_nt_friendly(command):
return Popen(command, cwd=gettempdir(), stdout=PIPE)
def check_for_latex_support():
'''check is latex is available and if it can create a picture.'''
"""
Check if latex is available and if it can create a picture
"""
try:
filename = latex_to_image("test")
if filename:

View File

@ -24,7 +24,9 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
''' This module allows to access the on-disk database of logs. '''
"""
This module allows to access the on-disk database of logs
"""
import os
import sys
@ -150,7 +152,9 @@ class Logger:
self.get_jids_already_in_db()
def simple_commit(self, sql_to_commit):
'''helper to commit'''
"""
Helper to commit
"""
self.cur.execute(sql_to_commit)
try:
self.con.commit()
@ -177,14 +181,14 @@ class Logger:
return self.jids_already_in
def jid_is_from_pm(self, jid):
'''if jid is gajim@conf/nkour it's likely a pm one, how we know
gajim@conf is not a normal guy and nkour is not his resource?
we ask if gajim@conf is already in jids (with type room jid)
this fails if user disables logging for room and only enables for
pm (so higly unlikely) and if we fail we do not go chaos
(user will see the first pm as if it was message in room's public chat)
and after that all okay'''
"""
If jid is gajim@conf/nkour it's likely a pm one, how we know gajim@conf
is not a normal guy and nkour is not his resource? we ask if gajim@conf
is already in jids (with type room jid) this fails if user disables
logging for room and only enables for pm (so higly unlikely) and if we
fail we do not go chaos (user will see the first pm as if it was message
in room's public chat) and after that all okay
"""
if jid.find('/') > -1:
possible_room_jid = jid.split('/', 1)[0]
return self.jid_is_room_jid(possible_room_jid)
@ -202,13 +206,14 @@ class Logger:
return True
def get_jid_id(self, jid, typestr=None):
'''jids table has jid and jid_id
logs table has log_id, jid_id, contact_name, time, kind, show, message
so to ask logs we need jid_id that matches our jid in jids table
this method wants jid and returns the jid_id for later sql-ing on logs
typestr can be 'ROOM' or anything else depending on the type of JID
and is only needed to be specified when the JID is new in DB
'''
"""
jids table has jid and jid_id logs table has log_id, jid_id,
contact_name, time, kind, show, message so to ask logs we need jid_id
that matches our jid in jids table this method wants jid and returns the
jid_id for later sql-ing on logs typestr can be 'ROOM' or anything else
depending on the type of JID and is only needed to be specified when the
JID is new in DB
"""
if jid.find('/') != -1: # if it has a /
jid_is_from_pm = self.jid_is_from_pm(jid)
if not jid_is_from_pm: # it's normal jid with resource
@ -238,7 +243,9 @@ class Logger:
return jid_id
def convert_human_values_to_db_api_values(self, kind, show):
'''coverts from string style to constant ints for db'''
"""
Convert from string style to constant ints for db
"""
if kind == 'status':
kind_col = constants.KIND_STATUS
elif kind == 'gcstatus':
@ -277,7 +284,9 @@ class Logger:
return kind_col, show_col
def convert_human_transport_type_to_db_api_values(self, type_):
'''converts from string style to constant ints for db'''
"""
Convert from string style to constant ints for db
"""
if type_ == 'aim':
return constants.TYPE_AIM
if type_ == 'gadu-gadu':
@ -309,7 +318,9 @@ class Logger:
return None
def convert_api_values_to_human_transport_type(self, type_id):
'''converts from constant ints for db to string style'''
"""
Convert from constant ints for db to string style
"""
if type_id == constants.TYPE_AIM:
return 'aim'
if type_id == constants.TYPE_GG:
@ -340,7 +351,9 @@ class Logger:
return 'mrim'
def convert_human_subscription_values_to_db_api_values(self, sub):
'''converts from string style to constant ints for db'''
"""
Convert from string style to constant ints for db
"""
if sub == 'none':
return constants.SUBSCRIPTION_NONE
if sub == 'to':
@ -351,7 +364,9 @@ class Logger:
return constants.SUBSCRIPTION_BOTH
def convert_db_api_values_to_human_subscription_values(self, sub):
'''converts from constant ints for db to string style'''
"""
Convert from constant ints for db to string style
"""
if sub == constants.SUBSCRIPTION_NONE:
return 'none'
if sub == constants.SUBSCRIPTION_TO:
@ -382,30 +397,40 @@ class Logger:
return message_id
def insert_unread_events(self, message_id, jid_id):
''' add unread message with id: message_id'''
"""
Add unread message with id: message_id
"""
sql = 'INSERT INTO unread_messages VALUES (%d, %d, 0)' % (message_id,
jid_id)
self.simple_commit(sql)
def set_read_messages(self, message_ids):
''' mark all messages with ids in message_ids as read'''
"""
Mark all messages with ids in message_ids as read
"""
ids = ','.join([str(i) for i in message_ids])
sql = 'DELETE FROM unread_messages WHERE message_id IN (%s)' % ids
self.simple_commit(sql)
def set_shown_unread_msgs(self, msg_id):
''' mark unread message as shown un GUI '''
"""
Mark unread message as shown un GUI
"""
sql = 'UPDATE unread_messages SET shown = 1 where message_id = %s' % \
msg_id
self.simple_commit(sql)
def reset_shown_unread_messages(self):
''' Set shown field to False in unread_messages table '''
"""
Set shown field to False in unread_messages table
"""
sql = 'UPDATE unread_messages SET shown = 0'
self.simple_commit(sql)
def get_unread_msgs(self):
''' get all unread messages '''
"""
Get all unread messages
"""
all_messages = []
try:
self.cur.execute(
@ -435,15 +460,18 @@ class Logger:
return all_messages
def write(self, kind, jid, message=None, show=None, tim=None, subject=None):
'''write a row (status, gcstatus, message etc) to logs database
kind can be status, gcstatus, gc_msg, (we only recv for those 3),
single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
we cannot know if it is pm or normal chat message, we try to guess
see jid_is_from_pm()
"""
Write a row (status, gcstatus, message etc) to logs database
we analyze jid and store it as follows:
jids.jid text column will hold JID if TC-related, room_jid if GC-related,
ROOM_JID/nick if pm-related.'''
kind can be status, gcstatus, gc_msg, (we only recv for those 3),
single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent we cannot
know if it is pm or normal chat message, we try to guess see
jid_is_from_pm()
We analyze jid and store it as follows:
jids.jid text column will hold JID if TC-related, room_jid if GC-related,
ROOM_JID/nick if pm-related.
"""
if self.jids_already_in == []: # only happens if we just created the db
self.open_db()
@ -516,12 +544,14 @@ class Logger:
return self.commit_to_db(values, write_unread)
def get_last_conversation_lines(self, jid, restore_how_many_rows,
pending_how_many, timeout, account):
'''accepts how many rows to restore and when to time them out (in minutes)
(mark them as too old) and number of messages that are in queue
and are already logged but pending to be viewed,
returns a list of tupples containg time, kind, message,
list with empty tupple if nothing found to meet our demands'''
pending_how_many, timeout, account):
"""
Accept how many rows to restore and when to time them out (in minutes)
(mark them as too old) and number of messages that are in queue and are
already logged but pending to be viewed, returns a list of tupples
containg time, kind, message, list with empty tupple if nothing found to
meet our demands
"""
try:
self.get_jid_id(jid)
except exceptions.PysqliteOperationalError, e:
@ -561,9 +591,12 @@ class Logger:
return start_of_day
def get_conversation_for_date(self, jid, year, month, day, account):
'''returns contact_name, time, kind, show, message, subject
for each row in a list of tupples,
returns list with empty tupple if we found nothing to meet our demands'''
"""
Return contact_name, time, kind, show, message, subject
For each row in a list of tupples, returns list with empty tupple if we
found nothing to meet our demands
"""
try:
self.get_jid_id(jid)
except exceptions.PysqliteOperationalError, e:
@ -586,9 +619,12 @@ class Logger:
return results
def get_search_results_for_query(self, jid, query, account):
'''returns contact_name, time, kind, show, message
for each row in a list of tupples,
returns list with empty tupple if we found nothing to meet our demands'''
"""
Returns contact_name, time, kind, show, message
For each row in a list of tupples, returns list with empty tupple if we
found nothing to meet our demands
"""
try:
self.get_jid_id(jid)
except exceptions.PysqliteOperationalError, e:
@ -615,7 +651,9 @@ class Logger:
return results
def get_days_with_logs(self, jid, year, month, max_day, account):
'''returns the list of days that have logs (not status messages)'''
"""
Return the list of days that have logs (not status messages)
"""
try:
self.get_jid_id(jid)
except exceptions.PysqliteOperationalError, e:
@ -650,8 +688,10 @@ class Logger:
return days_with_logs
def get_last_date_that_has_logs(self, jid, account=None, is_room=False):
'''returns last time (in seconds since EPOCH) for which
we had logs (excluding statuses)'''
"""
Return last time (in seconds since EPOCH) for which we had logs
(excluding statuses)
"""
where_sql = ''
if not is_room:
where_sql = self._build_contact_where(account, jid)
@ -676,8 +716,10 @@ class Logger:
return result
def get_room_last_message_time(self, jid):
'''returns FASTLY last time (in seconds since EPOCH) for which
we had logs for that room from rooms_last_message_time table'''
"""
Return FASTLY last time (in seconds since EPOCH) for which we had logs
for that room from rooms_last_message_time table
"""
try:
jid_id = self.get_jid_id(jid, 'ROOM')
except exceptions.PysqliteOperationalError, e:
@ -697,8 +739,10 @@ class Logger:
return result
def set_room_last_message_time(self, jid, time):
'''set last time (in seconds since EPOCH) for which
we had logs for that room in rooms_last_message_time table'''
"""
Set last time (in seconds since EPOCH) for which we had logs for that
room in rooms_last_message_time table
"""
jid_id = self.get_jid_id(jid, 'ROOM')
# jid_id is unique in this table, create or update :
sql = 'REPLACE INTO rooms_last_message_time VALUES (%d, %d)' % \
@ -706,8 +750,9 @@ class Logger:
self.simple_commit(sql)
def _build_contact_where(self, account, jid):
'''build the where clause for a jid, including metacontacts
jid(s) if any'''
"""
Build the where clause for a jid, including metacontacts jid(s) if any
"""
where_sql = ''
# will return empty list if jid is not associated with
# any metacontacts
@ -727,7 +772,9 @@ class Logger:
return where_sql
def save_transport_type(self, jid, type_):
'''save the type of the transport in DB'''
"""
Save the type of the transport in DB
"""
type_id = self.convert_human_transport_type_to_db_api_values(type_)
if not type_id:
# unknown type
@ -747,7 +794,9 @@ class Logger:
self.simple_commit(sql)
def get_transports_type(self):
'''return all the type of the transports in DB'''
"""
Return all the type of the transports in DB
"""
self.cur.execute(
'SELECT * from transports_cache')
results = self.cur.fetchall()
@ -767,11 +816,13 @@ class Logger:
# (2)
# GzipFile needs a file-like object, StringIO emulates file for plain strings
def iter_caps_data(self):
''' Iterate over caps cache data stored in the database.
"""
Iterate over caps cache data stored in the database
The iterator values are pairs of (node, ver, ext, identities, features):
identities == {'category':'foo', 'type':'bar', 'name':'boo'},
features being a list of feature namespaces. '''
features being a list of feature namespaces.
"""
# get data from table
# the data field contains binary object (gzipped data), this is a hack
# to get that data without trying to convert it to unicode
@ -854,16 +905,21 @@ class Logger:
self.simple_commit(sql)
def clean_caps_table(self):
'''Remove caps which was not seen for 3 months'''
"""
Remove caps which was not seen for 3 months
"""
sql = '''DELETE FROM caps_cache WHERE last_seen < %d''' % \
int(time.time() - 3*30*24*3600)
self.simple_commit(sql)
def replace_roster(self, account_name, roster_version, roster):
''' Replace current roster in DB by a new one.
accout_name is the name of the account to change
roster_version is the version of the new roster
roster is the new version '''
"""
Replace current roster in DB by a new one
accout_name is the name of the account to change.
roster_version is the version of the new roster.
roster is the new version.
"""
# First we must reset roster_version value to ensure that the server
# sends back all the roster at the next connexion if the replacement
# didn't work properly.
@ -887,7 +943,9 @@ class Logger:
roster_version)
def del_contact(self, account_jid, jid):
''' Remove jid from account_jid roster. '''
"""
Remove jid from account_jid roster
"""
try:
account_jid_id = self.get_jid_id(account_jid)
jid_id = self.get_jid_id(jid)
@ -902,7 +960,9 @@ class Logger:
self.con.commit()
def add_or_update_contact(self, account_jid, jid, name, sub, ask, groups):
''' Add or update a contact from account_jid roster. '''
"""
Add or update a contact from account_jid roster
"""
if sub == 'remove':
self.del_contact(account_jid, jid)
return
@ -933,7 +993,9 @@ class Logger:
self.con.commit()
def get_roster(self, account_jid):
''' Return the accound_jid roster in NonBlockingRoster format. '''
"""
Return the accound_jid roster in NonBlockingRoster format
"""
data = {}
account_jid_id = self.get_jid_id(account_jid)
@ -972,7 +1034,9 @@ class Logger:
return data
def remove_roster(self, account_jid):
''' Remove all entry from account_jid roster. '''
"""
Remove all entry from account_jid roster
"""
account_jid_id = self.get_jid_id(account_jid)
self.cur.execute('DELETE FROM roster_entry WHERE account_jid_id=?',

View File

@ -23,7 +23,7 @@ import i18n
def parseLogLevel(arg):
"""
eiter numeric value or level name from logging module
Eiter numeric value or level name from logging module
"""
if arg.isdigit():
return int(arg)
@ -98,7 +98,7 @@ def colorize(text, color):
class FancyFormatter(logging.Formatter):
"""
A Eye-candy formatter with colors
An eye-candy formatter with colors
"""
colors_mapping = {
'DEBUG': colors.BLUE,
@ -134,7 +134,7 @@ class FancyFormatter(logging.Formatter):
def init(use_color=False):
"""
initialize the logging system
Iinitialize the logging system
"""
consoleloghandler = logging.StreamHandler()
consoleloghandler.setFormatter(

View File

@ -228,7 +228,9 @@ class OptionsParser:
caps.capscache.initialize_from_db()
def assert_unread_msgs_table_exists(self):
'''create table unread_messages if there is no such table'''
"""
Create table unread_messages if there is no such table
"""
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
@ -346,8 +348,10 @@ class OptionsParser:
gajim.config.set('version', '0.10.1.2')
def update_config_to_01013(self):
'''create table transports_cache if there is no such table'''
#FIXME see #2812
"""
Create table transports_cache if there is no such table
"""
# FIXME see #2812
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
@ -369,9 +373,11 @@ class OptionsParser:
gajim.config.set('version', '0.10.1.3')
def update_config_to_01014(self):
'''apply indeces to the logs database'''
"""
Apply indeces to the logs database
"""
print _('migrating logs database to indices')
#FIXME see #2812
# FIXME see #2812
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
@ -393,7 +399,9 @@ class OptionsParser:
gajim.config.set('version', '0.10.1.4')
def update_config_to_01015(self):
'''clean show values in logs database'''
"""
Clean show values in logs database
"""
#FIXME see #2812
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
@ -412,8 +420,10 @@ class OptionsParser:
gajim.config.set('version', '0.10.1.5')
def update_config_to_01016(self):
'''#2494 : Now we play gc_received_message sound even if
notify_on_all_muc_messages is false. Keep precedent behaviour.'''
"""
#2494 : Now we play gc_received_message sound even if
notify_on_all_muc_messages is false. Keep precedent behaviour
"""
if 'notify_on_all_muc_messages' in self.old_values and \
self.old_values['notify_on_all_muc_messages'] == 'False' and \
gajim.config.get_per('soundevents', 'muc_message_received', 'enabled'):
@ -422,36 +432,45 @@ class OptionsParser:
gajim.config.set('version', '0.10.1.6')
def update_config_to_01017(self):
'''trayicon_notification_on_new_messages ->
trayicon_notification_on_events '''
"""
trayicon_notification_on_new_messages -> trayicon_notification_on_events
"""
if 'trayicon_notification_on_new_messages' in self.old_values:
gajim.config.set('trayicon_notification_on_events',
self.old_values['trayicon_notification_on_new_messages'])
gajim.config.set('version', '0.10.1.7')
def update_config_to_01018(self):
'''chat_state_notifications -> outgoing_chat_state_notifications'''
"""
chat_state_notifications -> outgoing_chat_state_notifications
"""
if 'chat_state_notifications' in self.old_values:
gajim.config.set('outgoing_chat_state_notifications',
self.old_values['chat_state_notifications'])
gajim.config.set('version', '0.10.1.8')
def update_config_to_01101(self):
'''fill time_stamp from before_time and after_time'''
"""
Fill time_stamp from before_time and after_time
"""
if 'before_time' in self.old_values:
gajim.config.set('time_stamp', '%s%%X%s ' % (
self.old_values['before_time'], self.old_values['after_time']))
gajim.config.set('version', '0.11.0.1')
def update_config_to_01102(self):
'''fill time_stamp from before_time and after_time'''
"""
Fill time_stamp from before_time and after_time
"""
if 'ft_override_host_to_send' in self.old_values:
gajim.config.set('ft_add_hosts_to_send',
self.old_values['ft_override_host_to_send'])
gajim.config.set('version', '0.11.0.2')
def update_config_to_01111(self):
'''always_hide_chatbuttons -> compact_view'''
"""
Always_hide_chatbuttons -> compact_view
"""
if 'always_hide_groupchat_buttons' in self.old_values and \
'always_hide_chat_buttons' in self.old_values:
gajim.config.set('compact_view', self.old_values['always_hide_groupchat_buttons'] and \
@ -459,7 +478,9 @@ class OptionsParser:
gajim.config.set('version', '0.11.1.1')
def update_config_to_01112(self):
'''gtk+ theme is renamed to default'''
"""
GTK+ theme is renamed to default
"""
if 'roster_theme' in self.old_values and \
self.old_values['roster_theme'] == 'gtk+':
gajim.config.set('roster_theme', _('default'))
@ -568,7 +589,9 @@ class OptionsParser:
gajim.config.set('version', '0.11.4.1')
def update_config_to_01142(self):
'''next_message_received sound event is splittedin 2 events'''
"""
next_message_received sound event is splittedin 2 events
"""
gajim.config.add_per('soundevents', 'next_message_received_focused')
gajim.config.add_per('soundevents', 'next_message_received_unfocused')
if gajim.config.get_per('soundevents', 'next_message_received'):
@ -681,7 +704,9 @@ class OptionsParser:
gajim.config.set('version', '0.12.1.4')
def update_config_to_01215(self):
'''Remove hardcoded ../data/sounds from config'''
"""
Remove hardcoded ../data/sounds from config
"""
dirs = ('../data', gajim.gajimpaths.root, gajim.DATA_DIR)
for evt in gajim.config.get_per('soundevents'):
path = gajim.config.get_per('soundevents', evt ,'path')

View File

@ -206,64 +206,64 @@ import gtkgui_helpers
class AbstractPEP(object):
type = ''
namespace = ''
@classmethod
def get_tag_as_PEP(cls, jid, account, event_tag):
items = event_tag.getTag('items', {'node': cls.namespace})
if items:
log.debug("Received PEP 'user %s' from %s" % (cls.type, jid))
log.debug("Received PEP 'user %s' from %s" % (cls.type, jid))
return cls(jid, account, items)
else:
return None
return None
def __init__(self, jid, account, items):
self._pep_specific_data, self._retracted = self._extract_info(items)
self._update_contacts(jid, account)
if jid == gajim.get_jid_from_account(account):
self._update_account(account)
def _extract_info(self, items):
'''To be implemented by subclasses'''
raise NotImplementedError
def _update_contacts(self, jid, account):
for contact in gajim.contacts.get_contacts(account, jid):
def _update_contacts(self, jid, account):
for contact in gajim.contacts.get_contacts(account, jid):
if self._retracted:
if self.type in contact.pep:
del contact.pep[self.type]
else:
contact.pep[self.type] = self
def _update_account(self, account):
acc = gajim.connections[account]
def _update_account(self, account):
acc = gajim.connections[account]
if self._retracted:
if self.type in acc.pep:
del acc.pep[self.type]
else:
acc.pep[self.type] = self
def asPixbufIcon(self):
'''SHOULD be implemented by subclasses'''
return None
def asMarkupText(self):
'''SHOULD be implemented by subclasses'''
return ''
class UserMoodPEP(AbstractPEP):
'''XEP-0107: User Mood'''
type = 'mood'
namespace = xmpp.NS_MOOD
def _extract_info(self, items):
mood_dict = {}
for item in items.getTags('item'):
mood_tag = item.getTag('mood')
if mood_tag:
@ -273,22 +273,22 @@ class UserMoodPEP(AbstractPEP):
mood_dict['text'] = child.getData()
else:
mood_dict['mood'] = name
retracted = items.getTag('retract') or not 'mood' in mood_dict
retracted = items.getTag('retract') or not 'mood' in mood_dict
return (mood_dict, retracted)
def asPixbufIcon(self):
assert not self._retracted
received_mood = self._pep_specific_data['mood']
mood = received_mood if received_mood in MOODS else 'unknown'
pixbuf = gtkgui_helpers.load_mood_icon(mood).get_pixbuf()
return pixbuf
def asMarkupText(self):
assert not self._retracted
untranslated_mood = self._pep_specific_data['mood']
mood = self._translate_mood(untranslated_mood)
markuptext = '<b>%s</b>' % gobject.markup_escape_text(mood)
markuptext = '<b>%s</b>' % gobject.markup_escape_text(mood)
if 'text' in self._pep_specific_data:
text = self._pep_specific_data['text']
markuptext += ' (%s)' % gobject.markup_escape_text(text)
@ -303,13 +303,13 @@ class UserMoodPEP(AbstractPEP):
class UserTunePEP(AbstractPEP):
'''XEP-0118: User Tune'''
type = 'tune'
namespace = xmpp.NS_TUNE
def _extract_info(self, items):
def _extract_info(self, items):
tune_dict = {}
for item in items.getTags('item'):
tune_tag = item.getTag('tune')
if tune_tag:
@ -318,23 +318,23 @@ class UserTunePEP(AbstractPEP):
data = child.getData().strip()
if child.getName() in TUNE_DATA:
tune_dict[name] = data
retracted = items.getTag('retract') or not ('artist' in tune_dict or
retracted = items.getTag('retract') or not ('artist' in tune_dict or
'title' in tune_dict)
return (tune_dict, retracted)
def asPixbufIcon(self):
import os
path = os.path.join(gajim.DATA_DIR, 'emoticons', 'static', 'music.png')
return gtk.gdk.pixbuf_new_from_file(path)
def asMarkupText(self):
assert not self._retracted
tune = self._pep_specific_data
artist = tune.get('artist', _('Unknown Artist'))
artist = gobject.markup_escape_text(artist)
title = tune.get('title', _('Unknown Title'))
title = gobject.markup_escape_text(title)
@ -345,17 +345,17 @@ class UserTunePEP(AbstractPEP):
'from <i>%(source)s</i>') % {'title': title,
'artist': artist, 'source': source}
return tune_string
class UserActivityPEP(AbstractPEP):
'''XEP-0108: User Activity'''
type = 'activity'
namespace = xmpp.NS_ACTIVITY
def _extract_info(self, items):
activity_dict = {}
for item in items.getTags('item'):
activity_tag = item.getTag('activity')
if activity_tag:
@ -369,28 +369,28 @@ class UserActivityPEP(AbstractPEP):
for subactivity in child.getChildren():
subactivity_name = subactivity.getName().strip()
activity_dict['subactivity'] = subactivity_name
retracted = items.getTag('retract') or not 'activity' in activity_dict
return (activity_dict, retracted)
def asPixbufIcon(self):
assert not self._retracted
pep = self._pep_specific_data
activity = pep['activity']
has_known_activity = activity in ACTIVITIES
has_known_subactivity = (has_known_activity and ('subactivity' in pep)
and (pep['subactivity'] in ACTIVITIES[activity]))
if has_known_activity:
if has_known_subactivity:
subactivity = pep['subactivity']
return gtkgui_helpers.load_activity_icon(activity, subactivity).get_pixbuf()
else:
return gtkgui_helpers.load_activity_icon(activity).get_pixbuf()
else:
else:
return gtkgui_helpers.load_activity_icon('unknown').get_pixbuf()
def asMarkupText(self):
assert not self._retracted
pep = self._pep_specific_data
@ -403,45 +403,45 @@ class UserActivityPEP(AbstractPEP):
if subactivity in ACTIVITIES[activity]:
subactivity = ACTIVITIES[activity][subactivity]
activity = ACTIVITIES[activity]['category']
markuptext = '<b>' + gobject.markup_escape_text(activity)
if subactivity:
markuptext += ': ' + gobject.markup_escape_text(subactivity)
markuptext += '</b>'
if text:
markuptext += ' (%s)' % gobject.markup_escape_text(text)
return markuptext
return markuptext
class UserNicknamePEP(AbstractPEP):
'''XEP-0172: User Nickname'''
type = 'nickname'
namespace = xmpp.NS_NICK
def _extract_info(self, items):
def _extract_info(self, items):
nick = ''
for item in items.getTags('item'):
child = item.getTag('nick')
if child:
nick = child.getData()
break
retracted = items.getTag('retract') or not nick
return (nick, retracted)
return (nick, retracted)
def _update_contacts(self, jid, account):
nick = '' if self._retracted else self._pep_specific_data
for contact in gajim.contacts.get_contacts(account, jid):
contact.contact_name = nick
def _update_account(self, account):
if self._retracted:
gajim.nicks[account] = gajim.config.get_per('accounts', account, 'name')
else:
gajim.nicks[account] = self._pep_specific_data
SUPPORTED_PERSONAL_USER_EVENTS = [UserMoodPEP, UserTunePEP, UserActivityPEP,
UserNicknamePEP]
@ -451,7 +451,7 @@ class ConnectionPEP(object):
self._account = account
self._dispatcher = dispatcher
self._pubsub_connection = pubsub_connection
def _pubsubEventCB(self, xmpp_dispatcher, msg):
''' Called when we receive <message /> with pubsub event. '''
if not msg.getTag('event'):
@ -459,7 +459,7 @@ class ConnectionPEP(object):
if msg.getTag('error'):
log.debug('PubsubEventCB received error stanza. Ignoring')
raise xmpp.NodeProcessed
jid = helpers.get_full_jid_from_iq(msg)
event_tag = msg.getTag('event')
@ -467,7 +467,7 @@ class ConnectionPEP(object):
pep = pep_class.get_tag_as_PEP(jid, self._account, event_tag)
if pep:
self._dispatcher.dispatch('PEP_RECEIVED', (jid, pep.type))
items = event_tag.getTag('items')
if items:
for item in items.getTags('item'):
@ -477,9 +477,9 @@ class ConnectionPEP(object):
# but to be sure...
self._dispatcher.dispatch('ATOM_ENTRY',
(atom.OldEntry(node=entry),))
raise xmpp.NodeProcessed
def send_activity(self, activity, subactivity=None, message=None):
if not self.pep_supported:
return
@ -492,7 +492,7 @@ class ConnectionPEP(object):
i = item.addChild('text')
i.addData(message)
self._pubsub_connection.send_pb_publish('', xmpp.NS_ACTIVITY, item, '0')
def retract_activity(self):
if not self.pep_supported:
return
@ -510,13 +510,13 @@ class ConnectionPEP(object):
i = item.addChild('text')
i.addData(message)
self._pubsub_connection.send_pb_publish('', xmpp.NS_MOOD, item, '0')
def retract_mood(self):
if not self.pep_supported:
return
self.send_mood(None)
self._pubsub_connection.send_pb_retract('', xmpp.NS_MOOD, '0')
def send_tune(self, artist='', title='', source='', track=0, length=0,
items=None):
if not self.pep_supported:

View File

@ -41,10 +41,13 @@ S_FINISHED = 4
CONNECT_TIMEOUT = 20
class Proxy65Manager:
''' keep records for file transfer proxies. Each time account
establishes a connection to its server call proxy65manger.resolve(proxy)
for every proxy that is convigured within the account. The class takes
care to resolve and test each proxy only once.'''
"""
Keep records for file transfer proxies. Each time account establishes a
connection to its server call proxy65manger.resolve(proxy) for every proxy
that is convigured within the account. The class takes care to resolve and
test each proxy only once
"""
def __init__(self, idlequeue):
# dict {proxy: proxy properties}
self.idlequeue = idlequeue
@ -53,7 +56,9 @@ class Proxy65Manager:
self.default_proxies = {}
def resolve(self, proxy, connection, sender_jid, default=None):
''' start '''
"""
Start
"""
if proxy in self.proxies:
resolver = self.proxies[proxy]
else:
@ -102,7 +107,9 @@ class Proxy65Manager:
class ProxyResolver:
def resolve_result(self, host, port, jid):
''' test if host has a real proxy65 listening on port '''
"""
Test if host has a real proxy65 listening on port
"""
self.host = str(host)
self.port = int(port)
self.jid = unicode(jid)
@ -175,19 +182,25 @@ class ProxyResolver:
self.try_next_connection()
def try_next_connection(self):
''' try to resolve proxy with the next possible connection '''
"""
Try to resolve proxy with the next possible connection
"""
if self.connections:
connection = self.connections.pop(0)
self.start_resolve(connection)
def add_connection(self, connection):
''' add a new connection in case the first fails '''
"""
Add a new connection in case the first fails
"""
self.connections.append(connection)
if self.state == S_INITIAL:
self.start_resolve(connection)
def start_resolve(self, connection):
''' request network address from proxy '''
"""
Request network address from proxy
"""
self.state = S_STARTED
self.active_connection = connection
iq = common.xmpp.Protocol(name='iq', to=self.proxy, typ='get')
@ -209,10 +222,16 @@ class ProxyResolver:
self.sender_jid = sender_jid
class HostTester(Socks5, IdleObject):
''' fake proxy tester. '''
"""
Fake proxy tester
"""
def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure):
''' try to establish and auth to proxy at (host, port)
call on_success, or on_failure according to the result'''
"""
Try to establish and auth to proxy at (host, port)
Calls on_success, or on_failure according to the result.
"""
self.host = host
self.port = port
self.jid = jid
@ -226,7 +245,9 @@ class HostTester(Socks5, IdleObject):
self.sid = sid
def connect(self):
''' create the socket and plug it to the idlequeue '''
"""
Create the socket and plug it to the idlequeue
"""
if self.host is None:
self.on_failure()
return None
@ -320,10 +341,16 @@ class HostTester(Socks5, IdleObject):
return
class ReceiverTester(Socks5, IdleObject):
''' fake proxy tester. '''
"""
Fake proxy tester
"""
def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure):
''' try to establish and auth to proxy at (host, port)
call on_success, or on_failure according to the result'''
"""
Try to establish and auth to proxy at (host, port)
Call on_success, or on_failure according to the result.
"""
self.host = host
self.port = port
self.jid = jid
@ -337,7 +364,9 @@ class ReceiverTester(Socks5, IdleObject):
self.sid = sid
def connect(self):
''' create the socket and plug it to the idlequeue '''
"""
Create the socket and plug it to the idlequeue
"""
if self.host is None:
self.on_failure()
return None

View File

@ -67,7 +67,9 @@ class ConnectionPubSub:
self.__callbacks[id_]=(cb, args, kwargs)
def send_pb_publish(self, jid, node, item, id_, options=None):
'''Publish item to a node.'''
"""
Publish item to a node
"""
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('set', to=jid)
@ -80,20 +82,24 @@ class ConnectionPubSub:
self.connection.send(query)
def send_pb_retrieve(self, jid, node, cb=None, *args, **kwargs):
'''Get items from a node'''
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('get', to=jid)
r = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
r = r.addChild('items', {'node': node})
def send_pb_retrieve(self, jid, node, cb=None, *args, **kwargs):
"""
Get items from a node
"""
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('get', to=jid)
r = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
r = r.addChild('items', {'node': node})
id_ = self.connection.send(query)
if cb:
self.__callbacks[id_]=(cb, args, kwargs)
def send_pb_retract(self, jid, node, id_):
'''Delete item from a node'''
"""
Delete item from a node
"""
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('set', to=jid)
@ -104,7 +110,9 @@ class ConnectionPubSub:
self.connection.send(query)
def send_pb_delete(self, jid, node):
'''Deletes node.'''
"""
Delete node
"""
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('set', to=jid)
@ -122,7 +130,9 @@ class ConnectionPubSub:
'node': node})
def send_pb_create(self, jid, node, configure = False, configure_form = None):
'''Creates new node.'''
"""
Create a new node
"""
if not self.connection or self.connected < 2:
return
query = xmpp.Iq('set', to=jid)

View File

@ -88,11 +88,12 @@ class CommonResolver():
# FIXME: API usage is not consistent! This one requires that process is called
class LibAsyncNSResolver(CommonResolver):
'''
"""
Asynchronous resolver using libasyncns-python. process() method has to be
called in order to proceed the pending requests.
Based on patch submitted by Damien Thebault.
'''
called in order to proceed the pending requests. Based on patch submitted by
Damien Thebault.
"""
def __init__(self):
self.asyncns = libasyncns.Asyncns()
CommonResolver.__init__(self)
@ -146,20 +147,22 @@ class LibAsyncNSResolver(CommonResolver):
class NSLookupResolver(CommonResolver):
'''
"""
Asynchronous DNS resolver calling nslookup. Processing of pending requests
is invoked from idlequeue which is watching file descriptor of pipe of stdout
of nslookup process.
'''
is invoked from idlequeue which is watching file descriptor of pipe of
stdout of nslookup process.
"""
def __init__(self, idlequeue):
self.idlequeue = idlequeue
self.process = False
CommonResolver.__init__(self)
def parse_srv_result(self, fqdn, result):
''' parse the output of nslookup command and return list of
properties: 'host', 'port','weight', 'priority' corresponding to the found
srv hosts '''
"""
Parse the output of nslookup command and return list of properties:
'host', 'port','weight', 'priority' corresponding to the found srv hosts
"""
if os.name == 'nt':
return self._parse_srv_result_nt(fqdn, result)
elif os.name == 'posix':
@ -260,7 +263,9 @@ class NSLookupResolver(CommonResolver):
CommonResolver._on_ready(self, host, type, result_list)
def start_resolve(self, host, type):
''' spawn new nslookup process and start waiting for results '''
"""
Spawn new nslookup process and start waiting for results
"""
ns = NsLookup(self._on_ready, host, type)
ns.set_idlequeue(self.idlequeue)
ns.commandtimeout = 10

View File

@ -33,17 +33,19 @@ except ImportError:
return None
else:
def pos_int_validator(text):
"""Validates that text can be evaluated as a positive integer."""
"""
Validates that text can be evaluated as a positive integer
"""
result = int(text)
if result < 0:
raise ValueError("Error: value '%(text)s' "
"must be a positive integer")
return result
def generate_uri_role( role_name, aliases,
anchor_text, base_url,
interpret_url, validator):
'''Creates and register a uri based "interpreted role".
def generate_uri_role( role_name, aliases, anchor_text, base_url,
interpret_url, validator):
"""
Create and register a uri based "interpreted role"
Those are similar to the RFC, and PEP ones, and take
role_name:
@ -58,7 +60,7 @@ else:
this, modulo the validated text, will be added to it
validator:
should return the validated text, or raise ValueError
'''
"""
def uri_reference_role(role, rawtext, text, lineno, inliner,
options={}, content=[]):
try:
@ -94,15 +96,15 @@ else:
pos_int_validator)
class HTMLGenerator:
'''Really simple HTMLGenerator starting from publish_parts.
"""
Really simple HTMLGenerator starting from publish_parts
It reuses the docutils.core.Publisher class, which means it is *not*
threadsafe.
'''
def __init__(self,
settings_spec=None,
settings_overrides=dict(report_level=5, halt_level=5),
config_section='general'):
"""
def __init__(self, settings_spec=None,
settings_overrides=dict(report_level=5, halt_level=5),
config_section='general'):
self.pub = Publisher(reader=None, parser=None, writer=None,
settings=None,
source_class=io.StringInput,
@ -124,13 +126,12 @@ else:
config_section)
def create_xhtml(self, text,
destination=None,
destination_path=None,
enable_exit_status=None):
''' Create xhtml for a fragment of IM dialog.
We can use the source_name to store info about
the message.'''
def create_xhtml(self, text, destination=None, destination_path=None,
enable_exit_status=None):
"""
Create xhtml for a fragment of IM dialog. We can use the source_name
to store info about the message
"""
self.pub.set_source(text, None)
self.pub.set_destination(destination, destination_path)
output = self.pub.publish(enable_exit_status=enable_exit_status)

View File

@ -66,7 +66,9 @@ class SleepyWindows:
return idleDelta
def poll(self):
'''checks to see if we should change state'''
"""
Check to see if we should change state
"""
if not SUPPORTED:
return False
@ -113,7 +115,9 @@ class SleepyUnix:
return idle.getIdleSec()
def poll(self):
'''checks to see if we should change state'''
"""
Check to see if we should change state
"""
if not SUPPORTED:
return False

View File

@ -52,9 +52,12 @@ READ_TIMEOUT = 180
SEND_TIMEOUT = 180
class SocksQueue:
''' queue for all file requests objects '''
"""
Queue for all file requests objects
"""
def __init__(self, idlequeue, complete_transfer_cb=None,
progress_transfer_cb=None, error_cb=None):
progress_transfer_cb=None, error_cb=None):
self.connected = 0
self.readers = {}
self.files_props = {}
@ -72,9 +75,10 @@ class SocksQueue:
self.on_failure = None
def start_listener(self, port, sha_str, sha_handler, sid):
''' start waiting for incomming connections on (host, port)
and do a socks5 authentication using sid for generated sha
'''
"""
Start waiting for incomming connections on (host, port) and do a socks5
authentication using sid for generated SHA
"""
self.sha_handlers[sha_str] = (sha_handler, sid)
if self.listener is None:
self.listener = Socks5Listener(self.idlequeue, port)
@ -121,8 +125,10 @@ class SocksQueue:
streamhost['idx'] = receiver.queue_idx
def _socket_connected(self, streamhost, file_props):
''' called when there is a host connected to one of the
senders's streamhosts. Stop othere attempts for connections '''
"""
Called when there is a host connected to one of the senders's
streamhosts. Stop othere attempts for connections
"""
for host in file_props['streamhosts']:
if host != streamhost and 'idx' in host:
if host['state'] == 1:
@ -137,10 +143,11 @@ class SocksQueue:
host['state'] = -2
def reconnect_receiver(self, receiver, streamhost):
''' Check the state of all streamhosts and if all has failed, then
emit connection failure cb. If there are some which are still
not connected try to establish connection to one of them.
'''
"""
Check the state of all streamhosts and if all has failed, then emit
connection failure cb. If there are some which are still not connected
try to establish connection to one of them
"""
self.idlequeue.remove_timeout(receiver.fd)
self.idlequeue.unplug_idle(receiver.fd)
file_props = receiver.file_props
@ -173,7 +180,9 @@ class SocksQueue:
self.process_result(-1, receiver)
def _connection_refused(self, streamhost, file_props, idx):
''' cb, called when we loose connection during transfer'''
"""
Called when we loose connection during transfer
"""
if file_props is None:
return
streamhost['state'] = -1
@ -189,7 +198,9 @@ class SocksQueue:
del(file_props['failure_cb'])
def add_receiver(self, account, sock5_receiver):
''' add new file request '''
"""
Add new file request
"""
self.readers[self.idx] = sock5_receiver
sock5_receiver.queue_idx = self.idx
sock5_receiver.queue = self
@ -259,9 +270,10 @@ class SocksQueue:
sender.file_props = file_props
def add_file_props(self, account, file_props):
''' file_prop to the dict of current file_props.
It is identified by account name and sid
'''
"""
File_prop to the dict of current file_props. It is identified by account
name and sid
"""
if file_props is None or ('sid' in file_props) is False:
return
_id = file_props['sid']
@ -279,7 +291,9 @@ class SocksQueue:
self.connected = 0
def get_file_props(self, account, sid):
''' get fil_prop by account name and session id '''
"""
Get fil_prop by account name and session id
"""
if account in self.files_props:
fl_props = self.files_props[account]
if sid in fl_props:
@ -294,11 +308,12 @@ class SocksQueue:
self.connected += 1
def process_result(self, result, actor):
''' Take appropriate actions upon the result:
[ 0, - 1 ] complete/end transfer
[ > 0 ] send progress message
[ None ] do nothing
'''
"""
Take appropriate actions upon the result:
[ 0, - 1 ] complete/end transfer
[ > 0 ] send progress message
[ None ] do nothing
"""
if result is None:
return
if result in (0, -1) and self.complete_transfer_cb is not None:
@ -310,8 +325,10 @@ class SocksQueue:
self.progress_transfer_cb(actor.account, actor.file_props)
def remove_receiver(self, idx, do_disconnect=True):
''' Remove reciver from the list and decrease
the number of active connections with 1'''
"""
Remove reciver from the list and decrease the number of active
connections with 1
"""
if idx != -1:
if idx in self.readers:
reader = self.readers[idx]
@ -325,8 +342,10 @@ class SocksQueue:
del(self.readers[idx])
def remove_sender(self, idx, do_disconnect=True):
''' Remove sender from the list of senders and decrease the
number of active connections with 1'''
"""
Remove sender from the list of senders and decrease the number of active
connections with 1
"""
if idx != -1:
if idx in self.senders:
if do_disconnect:
@ -386,9 +405,10 @@ class Socks5:
self.file = None
def get_fd(self):
''' Test if file is already open and return its fd,
or just open the file and return the fd.
'''
"""
Test if file is already open and return its fd, or just open the file and
return the fd
"""
if 'fd' in self.file_props:
fd = self.file_props['fd']
else:
@ -413,8 +433,10 @@ class Socks5:
pass
def receive(self):
''' Reads small chunks of data.
Calls owner's disconnected() method if appropriate.'''
"""
Read small chunks of data. Call owner's disconnected() method if
appropriate
"""
received = ''
try:
add = self._recv(64)
@ -426,7 +448,9 @@ class Socks5:
return add
def send_raw(self,raw_data):
''' Writes raw outgoing data. '''
"""
Write raw outgoing data
"""
try:
self._send(raw_data)
except Exception:
@ -483,7 +507,9 @@ class Socks5:
return -1
def get_file_contents(self, timeout):
''' read file contents from socket and write them to file '''
"""
Read file contents from socket and write them to file
"""
if self.file_props is None or ('file-name' in self.file_props) is False:
self.file_props['error'] = -2
return None
@ -557,7 +583,9 @@ class Socks5:
return None
def disconnect(self):
''' Closes open descriptors and remover socket descr. from idleque '''
"""
Close open descriptors and remover socket descr. from idleque
"""
# be sure that we don't leave open file
self.close_file()
self.idlequeue.remove_timeout(self.fd)
@ -573,13 +601,15 @@ class Socks5:
self.state = -1
def _get_auth_buff(self):
''' Message, that we support 1 one auth mechanism:
the 'no auth' mechanism. '''
"""
Message, that we support 1 one auth mechanism: the 'no auth' mechanism
"""
return struct.pack('!BBB', 0x05, 0x01, 0x00)
def _parse_auth_buff(self, buff):
''' Parse the initial message and create a list of auth
mechanisms '''
"""
Parse the initial message and create a list of auth mechanisms
"""
auth_mechanisms = []
try:
num_auth = struct.unpack('!xB', buff[:2])[0]
@ -591,9 +621,9 @@ class Socks5:
return auth_mechanisms
def _get_auth_response(self):
''' socks version(5), number of extra auth methods (we send
0x00 - no auth
) '''
"""
Socks version(5), number of extra auth methods (we send 0x00 - no auth)
"""
return struct.pack('!BB', 0x05, 0x00)
def _get_connect_buff(self):
@ -604,8 +634,10 @@ class Socks5:
return buff
def _get_request_buff(self, msg, command = 0x01):
''' Connect request by domain name,
sid sha, instead of domain name (jep 0096) '''
"""
Connect request by domain name, sid sha, instead of domain name (jep
0096)
"""
buff = struct.pack('!BBBBB%dsBB' % len(msg),
0x05, command, 0x00, 0x03, len(msg), msg, 0, 0)
return buff
@ -634,7 +666,9 @@ class Socks5:
return (req_type, host, port)
def read_connect(self):
''' connect responce: version, auth method '''
"""
Connect response: version, auth method
"""
buff = self._recv()
try:
version, method = struct.unpack('!BB', buff)
@ -652,7 +686,9 @@ class Socks5:
self.idlequeue.plug_idle(self, True, False)
def _get_sha1_auth(self):
''' get sha of sid + Initiator jid + Target jid '''
"""
Get sha of sid + Initiator jid + Target jid
"""
if 'is_a_proxy' in self.file_props:
del(self.file_props['is_a_proxy'])
return hashlib.sha1('%s%s%s' % (self.sid,
@ -662,9 +698,12 @@ class Socks5:
hexdigest()
class Socks5Sender(Socks5, IdleObject):
''' class for sending file to socket over socks5 '''
"""
Class for sending file to socket over socks5
"""
def __init__(self, idlequeue, sock_hash, parent, _sock, host=None,
port=None):
port=None):
self.queue_idx = sock_hash
self.queue = parent
Socks5.__init__(self, idlequeue, host, port, None, None, None)
@ -745,7 +784,9 @@ class Socks5Sender(Socks5, IdleObject):
self.disconnect()
def send_file(self):
''' start sending the file over verified connection '''
"""
Start sending the file over verified connection
"""
if self.file_props['started']:
return
self.file_props['error'] = 0
@ -766,7 +807,9 @@ class Socks5Sender(Socks5, IdleObject):
return self.write_next() # initial for nl byte
def main(self):
''' initial requests for verifying the connection '''
"""
Initial requests for verifying the connection
"""
if self.state == 1: # initial read
buff = self.receive()
if not self.connected:
@ -785,7 +828,9 @@ class Socks5Sender(Socks5, IdleObject):
return None
def disconnect(self, cb=True):
''' Closes the socket. '''
"""
Close the socket
"""
# close connection and remove us from the queue
Socks5.disconnect(self)
if self.file_props is not None:
@ -796,10 +841,12 @@ class Socks5Sender(Socks5, IdleObject):
class Socks5Listener(IdleObject):
def __init__(self, idlequeue, port):
''' handle all incomming connections on (0.0.0.0, port)
"""
Handle all incomming connections on (0.0.0.0, port)
This class implements IdleObject, but we will expect
only pollin events though
'''
"""
self.port = port
self.ais = socket.getaddrinfo(None, port, socket.AF_UNSPEC,
socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_PASSIVE)
@ -843,16 +890,22 @@ class Socks5Listener(IdleObject):
self.started = True
def pollend(self):
''' called when we stop listening on (host, port) '''
"""
Called when we stop listening on (host, port)
"""
self.disconnect()
def pollin(self):
''' accept a new incomming connection and notify queue'''
"""
Accept a new incomming connection and notify queue
"""
sock = self.accept_conn()
self.queue.on_connection_accepted(sock)
def disconnect(self):
''' free all resources, we are not listening anymore '''
"""
Free all resources, we are not listening anymore
"""
self.idlequeue.remove_timeout(self.fd)
self.idlequeue.unplug_idle(self.fd)
self.fd = -1
@ -864,7 +917,9 @@ class Socks5Listener(IdleObject):
pass
def accept_conn(self):
''' accepts a new incomming connection '''
"""
Accept a new incomming connection
"""
_sock = self._serv.accept()
_sock[0].setblocking(False)
return _sock
@ -909,7 +964,9 @@ class Socks5Receiver(Socks5, IdleObject):
self.queue.reconnect_receiver(self, self.streamhost)
def connect(self):
''' create the socket and plug it to the idlequeue '''
"""
Create the socket and plug it to the idlequeue
"""
if self.ais is None:
return None
@ -1018,7 +1075,9 @@ class Socks5Receiver(Socks5, IdleObject):
return 1 # we are connected
def main(self, timeout=0):
''' begin negotiation. on success 'address' != 0 '''
"""
Begin negotiation. on success 'address' != 0
"""
result = 1
buff = self.receive()
if buff == '':
@ -1087,7 +1146,9 @@ class Socks5Receiver(Socks5, IdleObject):
return None
def disconnect(self, cb=True):
''' Closes the socket. Remove self from queue if cb is True'''
"""
Close the socket. Remove self from queue if cb is True
"""
# close connection
Socks5.disconnect(self)
if cb is True:

View File

@ -84,10 +84,11 @@ class StanzaSession(object):
return to
def remove_events(self, types):
'''
Remove events associated with this session from the queue.
returns True if any events were removed (unlike events.py remove_events)
'''
"""
Remove events associated with this session from the queue
Returns True if any events were removed (unlike events.py remove_events)
"""
any_removed = False
for j in (self.jid, self.jid.getStripped()):
@ -140,10 +141,10 @@ class StanzaSession(object):
self.cancelled_negotiation()
def cancelled_negotiation(self):
'''
"""
A negotiation has been cancelled, so reset this session to its default
state.
'''
state
"""
if self.control:
self.control.on_cancel_session_negotiation()
@ -175,7 +176,7 @@ class StanzaSession(object):
class EncryptedStanzaSession(StanzaSession):
'''
"""
An encrypted stanza negotiation has several states. They arerepresented as
the following values in the 'status' attribute of the session object:
@ -198,7 +199,8 @@ class EncryptedStanzaSession(StanzaSession):
The transition between these states is handled in gajim.py's
handle_session_negotiation method.
'''
"""
def __init__(self, conn, jid, thread_id, type_='chat'):
StanzaSession.__init__(self, conn, jid, thread_id, type_='chat')
@ -228,9 +230,9 @@ class EncryptedStanzaSession(StanzaSession):
return True
def set_kc_s(self, value):
'''
keep the encrypter updated with my latest cipher key
'''
"""
Keep the encrypter updated with my latest cipher key
"""
self._kc_s = value
self.encrypter = self.cipher.new(self._kc_s, self.cipher.MODE_CTR,
counter=self.encryptcounter)
@ -239,9 +241,9 @@ class EncryptedStanzaSession(StanzaSession):
return self._kc_s
def set_kc_o(self, value):
'''
keep the decrypter updated with the other party's latest cipher key
'''
"""
Keep the decrypter updated with the other party's latest cipher key
"""
self._kc_o = value
self.decrypter = self.cipher.new(self._kc_o, self.cipher.MODE_CTR,
counter=self.decryptcounter)
@ -335,7 +337,9 @@ class EncryptedStanzaSession(StanzaSession):
return self.encrypter.encrypt(padded)
def decrypt_stanza(self, stanza):
''' delete the unencrypted explanation body, if it exists '''
"""
Delete the unencrypted explanation body, if it exists
"""
orig_body = stanza.getTag('body')
if orig_body:
stanza.delChild(orig_body)
@ -584,7 +588,9 @@ class EncryptedStanzaSession(StanzaSession):
self.send(request)
def verify_options_bob(self, form):
''' 4.3 esession response (bob) '''
"""
4.3 esession response (bob)
"""
negotiated = {'recv_pubkey': None, 'send_pubkey': None}
not_acceptable = []
ask_user = {}
@ -653,7 +659,9 @@ class EncryptedStanzaSession(StanzaSession):
return (negotiated, not_acceptable, ask_user)
def respond_e2e_bob(self, form, negotiated, not_acceptable):
''' 4.3 esession response (bob) '''
"""
4.3 esession response (bob)
"""
response = xmpp.Message()
feature = response.NT.feature
feature.setNamespace(xmpp.NS_FEATURE)
@ -728,7 +736,9 @@ class EncryptedStanzaSession(StanzaSession):
self.send(response)
def verify_options_alice(self, form):
''' 'Alice Accepts' '''
"""
'Alice Accepts'
"""
negotiated = {}
ask_user = {}
not_acceptable = []
@ -756,11 +766,13 @@ class EncryptedStanzaSession(StanzaSession):
return (negotiated, not_acceptable, ask_user)
def accept_e2e_alice(self, form, negotiated):
''' 'Alice Accepts', continued '''
"""
'Alice Accepts', continued
"""
self.encryptable_stanzas = ['message']
self.sas_algs = 'sas28x5'
self.cipher = AES
self.hash_alg = sha256
self.hash_alg = sha256
self.compression = None
self.negotiated = negotiated
@ -828,7 +840,9 @@ class EncryptedStanzaSession(StanzaSession):
self.status = 'identified-alice'
def accept_e2e_bob(self, form):
''' 4.5 esession accept (bob) '''
"""
4.5 esession accept (bob)
"""
response = xmpp.Message()
init = response.NT.init
@ -948,11 +962,11 @@ class EncryptedStanzaSession(StanzaSession):
self.control.print_esession_details()
def do_retained_secret(self, k, old_srs):
'''
"""
Calculate the new retained secret. determine if the user needs to check
the remote party's identity. Set up callbacks for when the identity has
been verified.
'''
been verified
"""
new_srs = self.hmac(k, 'New Retained Secret')
self.srs = new_srs
@ -1017,12 +1031,12 @@ class EncryptedStanzaSession(StanzaSession):
self.enable_encryption = False
def fail_bad_negotiation(self, reason, fields=None):
'''
Sends an error and cancels everything.
"""
Send an error and cancels everything
If fields is None, the remote party has given us a bad cryptographic
value of some kind. Otherwise, list the fields we haven't implemented
'''
value of some kind. Otherwise, list the fields we haven't implemented.
"""
err = xmpp.Error(xmpp.Message(), xmpp.ERR_FEATURE_NOT_IMPLEMENTED)
err.T.error.T.text.setData(reason)