Pylint checking

darcs-hash:20061001204010-86b55-2b2b3997794d11e2257effc502563ef32eac4560.gz
This commit is contained in:
David Rousselie
2006-10-01 22:40:10 +02:00
parent 12b0308572
commit 3e0cbdcfb6
8 changed files with 563 additions and 347 deletions

3
TODO
View File

@@ -0,0 +1,3 @@
* pylint sources
* make tests for every methods
* merge all necessary features from jmc to jcl

View File

@@ -0,0 +1 @@
__revision__ = "$Id: __init__.py dax $"

View File

@@ -21,13 +21,26 @@
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
"""JCL base component
"""
__revision__ = ""
import thread
import threading
import time
import logging import logging
import signal import signal
import re
from pyxmpp.jid import JID from pyxmpp.jid import JID
from pyxmpp.jabberd.component import Component from pyxmpp.jabberd.component import Component
from pyxmpp.jabber.disco import DiscoInfo, DiscoItems
from pyxmpp.message import Message
from pyxmpp.presence import Presence from pyxmpp.presence import Presence
from pyxmpp.streambase import StreamError, FatalStreamError
from jcl.jabber.x import X
from jcl.model.account import Account from jcl.model.account import Account
VERSION = "0.1" VERSION = "0.1"
@@ -35,58 +48,128 @@ VERSION = "0.1"
############################################################################### ###############################################################################
# JCL implementation # JCL implementation
############################################################################### ###############################################################################
class JCLComponent(Component): class JCLComponent(Component):
"""Implement default JCL component behavior:
- regular interval behavior
- Jabber register process (add, delete, update accounts)
- Jabber presence handling
- passwork request at login
"""
timeout = 1
def __init__(self, def __init__(self,
jid, jid,
secret, secret,
server, server,
port, port,
name = "Jabber Component Library generic component",
disco_category = "gateway", disco_category = "gateway",
disco_type = "headline", disco_type = "headline"):
spool_dir = ".",
check_interval = 1,
account_class = Account):
Component.__init__(self, \ Component.__init__(self, \
JID(jid), \ JID(jid), \
secret, \ secret, \
server, \
port, \ port, \
disco_category, \ disco_category, \
disco_type) disco_type)
# default values
self.name = "Jabber Component Library generic component"
self.spool_dir = "."
self.__account_class = None
self.account_class = Account
self.version = VERSION
self.accounts = []
self.disco_info.add_feature("jabber:iq:version")
self.disco_info.add_feature("jabber:iq:register")
self.__logger = logging.getLogger("jcl.jabber.JCLComponent") self.__logger = logging.getLogger("jcl.jabber.JCLComponent")
# TODO : self.__lang = Lang(default_lang) # TODO : self.__lang = Lang(default_lang)
self.__name = name self.__lang = None
self.__disco_category = disco_category
self.__disco_type = disco_type
self.__interval = check_interval
self.running = False self.running = False
self.__shutdown = 0
signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler) signal.signal(signal.SIGTERM, self.signal_handler)
spool_dir += "/" + jid
def set_account_class(self, account_class):
self.__account_class = account_class self.__account_class = account_class
self.__account_class.createTable(ifNotExists = True) self.__account_class.createTable(ifNotExists = True)
self.version = VERSION
def get_account_class(self):
return self.__account_class
account_class = property(get_account_class, set_account_class)
def run(self):
"""Main loop
Connect to Jabber server
Start timer thread
Call Component main loop
Clean up when shutting down JCLcomponent
"""
self.spool_dir += "/" + str(self.jid)
self.running = True
self.connect()
thread.start_new_thread(self.time_handler, ())
try:
while (self.running and self.stream
and not self.stream.eof and self.stream.socket is not None):
try:
self.stream.loop_iter(JCLComponent.timeout)
except (KeyboardInterrupt, SystemExit, FatalStreamError, \
StreamError):
raise
except:
self.__logger.exception("Exception cought:")
finally:
if self.stream:
# TODO : send unavailble from transport and all account to users
pass
# for jid in self.__storage.keys(()):
# p = Presence(from_jid = unicode(self.jid), to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
# for jid, name in self.__storage.keys():
# if self.__storage[(jid, name)].status != "offline":
# p = Presence(from_jid = name + "@" + unicode(self.jid),\
# to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
threads = threading.enumerate()
for _thread in threads:
try:
_thread.join(10 * JCLComponent.timeout)
except:
pass
for _thread in threads:
try:
_thread.join(JCLComponent.timeout)
except:
pass
self.disconnect()
# TODO : terminate SQLObject
self.__logger.debug("Exitting normally")
###########################################################################
# Handlers
###########################################################################
def time_handler(self):
"""Timer thread handler
"""
self.__logger.info("Timer thread started...")
while self.running:
self.handle_tick()
self.__logger.debug("Resetting alarm signal")
time.sleep(60)
def authenticated(self): def authenticated(self):
Component.authenticated(self) """Override authenticated Component event handler
Register event handlers
Probe for every accounts registered
"""
self.__logger.debug("AUTHENTICATED") self.__logger.debug("AUTHENTICATED")
# Send probe for transport Component.authenticated(self)
current_jid = None
for account in self.__account_class.select(orderBy = "user_jid"):
if account.user_jid != current_jid:
p = Presence(from_jid = unicode(self.jid), \
to_jid = account.user_jid, \
stanza_type = "probe")
self.stream.send(p)
current_jid = account.user_jid
p = Presence(from_jid = self.get_jid(account), \
to_jid = account.user_jid, \
stanza_type = "probe")
self.stream.send(p)
self.stream.set_iq_get_handler("query", "jabber:iq:version", \ self.stream.set_iq_get_handler("query", "jabber:iq:version", \
self.handle_get_version) self.handle_get_version)
self.stream.set_iq_get_handler("query", "jabber:iq:register", \ self.stream.set_iq_get_handler("query", "jabber:iq:register", \
@@ -114,180 +197,128 @@ class JCLComponent(Component):
self.stream.set_message_handler("normal", \ self.stream.set_message_handler("normal", \
self.handle_message) self.handle_message)
current_jid = None
for account in self.account_class.select(orderBy = "user_jid"):
if account.user_jid != current_jid:
presence = Presence(from_jid = unicode(self.jid), \
to_jid = account.user_jid, \
stanza_type = "probe")
self.stream.send(presence)
current_jid = account.user_jid
presence = Presence(from_jid = self.get_jid(account), \
to_jid = account.user_jid, \
stanza_type = "probe")
self.stream.send(presence)
def run(self):
self.connect()
self.running = True
thread.start_new_thread(self.time_handler, ())
try:
while (not self.__shutdown and self.stream
and not self.stream.eof and self.stream.socket is not None):
try:
self.stream.loop_iter(timeout)
except (KeyboardInterrupt, SystemExit, FatalStreamError, \
StreamError):
raise
except:
self.__logger.exception("Exception cought:")
finally:
self.running = False
if self.stream:
# TODO : send unavailble from transport and all account to users
pass
# for jid in self.__storage.keys(()):
# p = Presence(from_jid = unicode(self.jid), to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
# for jid, name in self.__storage.keys():
# if self.__storage[(jid, name)].status != "offline":
# p = Presence(from_jid = name + "@" + unicode(self.jid), \
# to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
threads = threading.enumerate()
for th in threads:
try:
th.join(10 * timeout)
except:
pass
for th in threads:
try:
th.join(timeout)
except:
pass
self.disconnect()
# TODO : terminate SQLObject
self.__logger.debug("Exitting normally")
def get_reg_form(self, lang_class, account_class):
pass
def get_reg_form_init(self, lang_class, account):
pass
def _ask_password(self, lang_class, account):
if not account.waiting_password_reply \
and account.status != "offline":
account.waiting_password_reply = True
msg = Message(from_jid = account.jid, \
to_jid = from_jid, \
stanza_type = "normal", \
subject = u"[PASSWORD] " + lang_class.ask_password_subject, \
body = lang_class.ask_password_body % \
(account.host, account.login))
self.stream.send(msg)
def get_jid(self, account):
return account.name + u"@" + unicode(self.jid)
## Handlers
""" Stop method handler """
def signal_handler(self, signum, frame): def signal_handler(self, signum, frame):
"""Stop method handler
"""
self.__logger.debug("Signal %i received, shutting down..." % (signum,)) self.__logger.debug("Signal %i received, shutting down..." % (signum,))
self.__shutdown = 1 self.running = False
def disco_get_info(self, node, input_query):
def stream_state_changed(self,state,arg): """Discovery get info handler
self.__logger.debug("*** State changed: %s %r ***" % (state,arg)) """
""" Discovery get info handler """
def disco_get_info(self, node, iq):
self.__logger.debug("DISCO_GET_INFO") self.__logger.debug("DISCO_GET_INFO")
di = DiscoInfo() if node is not None:
if node is None: disco_info = DiscoInfo()
di.add_feature("jabber:iq:version") disco_info.add_feature("jabber:iq:register")
di.add_feature("jabber:iq:register") return disco_info
DiscoIdentity(di, self.__name, \
self.__disco_category, \
self.__disco_type)
else: else:
di.add_feature("jabber:iq:register") return self.disco_info
return di
""" Discovery get nested nodes handler """ def disco_get_items(self, node, input_query):
def disco_get_items(self, node, iq): """Discovery get nested nodes handler
"""
self.__logger.debug("DISCO_GET_ITEMS") self.__logger.debug("DISCO_GET_ITEMS")
# lang_class = self.__lang.get_lang_class_from_node(iq.get_node()) ## TODO Lang
base_from_jid = unicode(iq.get_from().bare()) ## lang_class = self.__lang.get_lang_class_from_node(input_query.get_node())
di = DiscoItems() ## base_from_jid = unicode(input_query.get_from().bare())
disco_items = DiscoItems()
if not node: if not node:
# TODO : list accounts ## TODO : list accounts
for account in self.__accounts: for account in self.accounts:
pass self.__logger.debug(str(account))
# DiscoItem(di, JID(name + "@" + unicode(self.jid)), \ ## DiscoItem(di, JID(name + "@" + unicode(self.jid)), \
# name, str_name) ## name, str_name)
return di return disco_items
""" Get Version handler """ def handle_get_version(self, input_query):
def handle_get_version(self, iq): """Get Version handler
"""
self.__logger.debug("GET_VERSION") self.__logger.debug("GET_VERSION")
iq = iq.make_result_response() input_query = input_query.make_result_response()
q = iq.new_query("jabber:iq:version") query = input_query.new_query("jabber:iq:version")
q.newTextChild(q.ns(), "name", self.__name) query.newTextChild(query.ns(), "name", self.name)
q.newTextChild(q.ns(), "version", self.version) query.newTextChild(query.ns(), "version", self.version)
self.stream.send(iq) self.stream.send(input_query)
return 1 return 1
""" Send back register form to user """ def handle_get_register(self, input_query):
def handle_get_register(self, iq): """Send back register form to user
"""
self.__logger.debug("GET_REGISTER") self.__logger.debug("GET_REGISTER")
# lang_class = self.__lang.get_lang_class_from_node(iq.get_node()) ## TODO Lang
base_from_jid = unicode(iq.get_from().bare()) ## lang_class = self.__lang.get_lang_class_from_node(input_query.get_node())
to = iq.get_to() lang_class = None
iq = iq.make_result_response() ## base_from_jid = unicode(input_query.get_from().bare())
q = iq.new_query("jabber:iq:register") to_jid = input_query.get_to()
if to and to != self.jid: input_query = input_query.make_result_response()
query = input_query.new_query("jabber:iq:register")
if to_jid and to_jid != self.jid:
self.get_reg_form_init(lang_class, \ self.get_reg_form_init(lang_class, \
self.__accounts.select() # TODO self.accounts.select() # TODO
).attach_xml(q) ).attach_xml(query)
else: else:
self.get_reg_form(lang_class).attach_xml(q) self.get_reg_form(lang_class).attach_xml(query)
self.stream.send(iq) self.stream.send(input_query)
return 1 return 1
""" Handle user registration response """ def handle_set_register(self, input_query):
def handle_set_register(self, iq): """Handle user registration response
"""
self.__logger.debug("SET_REGISTER") self.__logger.debug("SET_REGISTER")
lang_class = self.__lang.get_lang_class_from_node(iq.get_node()) ## lang_class = \
to = iq.get_to() ## self.__lang.get_lang_class_from_node(input_query.get_node())
from_jid = iq.get_from() from_jid = input_query.get_from()
base_from_jid = unicode(from_jid.bare()) ## base_from_jid = unicode(from_jid.bare())
remove = iq.xpath_eval("r:query/r:remove", \ remove = input_query.xpath_eval("r:query/r:remove", \
{"r" : "jabber:iq:register"}) {"r" : "jabber:iq:register"})
if remove: if remove:
for name in self.__storage.keys((base_from_jid,)): # for name in self.__storage.keys((base_from_jid,)):
self.__logger.debug("Deleting " + name + " for " + base_from_jid) # self.__logger.debug("Deleting " + name \
p = Presence(from_jid = name + "@" + unicode(self.jid), \ # + " for " + base_from_jid)
to_jid = from_jid, \ # presence = Presence(from_jid = name + "@" + unicode(self.jid), \
stanza_type = "unsubscribe") # to_jid = from_jid, \
self.stream.send(p) # stanza_type = "unsubscribe")
p = Presence(from_jid = name + "@" + unicode(self.jid), \ # self.stream.send(presence)
to_jid = from_jid, \ # presence = Presence(from_jid = name + "@" + unicode(self.jid), \
stanza_type = "unsubscribed") # to_jid = from_jid, \
self.stream.send(p) # stanza_type = "unsubscribed")
del self.__storage[(base_from_jid, name)] # self.stream.send(presence)
p = Presence(from_jid = self.jid, to_jid = from_jid, \ # del self.__storage[(base_from_jid, name)]
stanza_type = "unsubscribe") presence = Presence(from_jid = self.jid, to_jid = from_jid, \
self.stream.send(p) stanza_type = "unsubscribe")
p = Presence(from_jid = self.jid, to_jid = from_jid, \ self.stream.send(presence)
stanza_type = "unsubscribed") presence = Presence(from_jid = self.jid, to_jid = from_jid, \
self.stream.send(p) stanza_type = "unsubscribed")
self.stream.send(presence)
return 1 return 1
query = iq.get_query() query = input_query.get_query()
x = X() x_data = X()
x.from_xml(query.children) x_data.from_xml(query.children)
# TODO : get info from Xdata # TODO : get info from Xdata
""" Handle presence availability """
def handle_presence_available(self, stanza): def handle_presence_available(self, stanza):
"""Handle presence availability
"""
self.__logger.debug("PRESENCE_AVAILABLE") self.__logger.debug("PRESENCE_AVAILABLE")
from_jid = stanza.get_from() from_jid = stanza.get_from()
base_from_jid = unicode(from_jid.bare()) base_from_jid = unicode(from_jid.bare())
name = stanza.get_to().node name = stanza.get_to().node
lang_class = self.__lang.get_lang_class_from_node(stanza.get_node()) ## lang_class = self.__lang.get_lang_class_from_node(stanza.get_node())
show = stanza.get_show() show = stanza.get_show()
self.__logger.debug("SHOW : " + str(show)) self.__logger.debug("SHOW : " + str(show))
if name: if name:
@@ -296,63 +327,71 @@ class JCLComponent(Component):
# else send available presence # else send available presence
return 1 return 1
""" handle presence unavailability """
def handle_presence_unavailable(self, stanza): def handle_presence_unavailable(self, stanza):
"""Handle presence unavailability
"""
self.__logger.debug("PRESENCE_UNAVAILABLE") self.__logger.debug("PRESENCE_UNAVAILABLE")
from_jid = stanza.get_from() ## from_jid = stanza.get_from()
base_from_jid = unicode(from_jid.bare()) ## base_from_jid = unicode(from_jid.bare())
# TODO : send unavailable to all user's account if target is transport # TODO : send unavailable to all user's account if target is transport
# else send unavailable back # else send unavailable back
return 1 return 1
""" handle subscribe presence from user """
def handle_presence_subscribe(self, stanza): def handle_presence_subscribe(self, stanza):
"""Handle subscribe presence from user
"""
self.__logger.debug("PRESENCE_SUBSCRIBE") self.__logger.debug("PRESENCE_SUBSCRIBE")
p = stanza.make_accept_response() presence = stanza.make_accept_response()
self.stream.send(p) self.stream.send(presence)
return 1 return 1
""" handle subscribed presence from user """
def handle_presence_subscribed(self, stanza): def handle_presence_subscribed(self, stanza):
"""Handle subscribed presence from user
"""
self.__logger.debug("PRESENCE_SUBSCRIBED") self.__logger.debug("PRESENCE_SUBSCRIBED")
name = stanza.get_to().node name = stanza.get_to().node
from_jid = stanza.get_from() ## from_jid = stanza.get_from()
base_from_jid = unicode(from_jid.bare()) ## base_from_jid = unicode(from_jid.bare())
# TODO : send presence available to subscribed user # TODO : send presence available to subscribed user
return 1 return 1
""" handle unsubscribe presence from user """
def handle_presence_unsubscribe(self, stanza): def handle_presence_unsubscribe(self, stanza):
"""Handle unsubscribe presence from user
"""
self.__logger.debug("PRESENCE_UNSUBSCRIBE") self.__logger.debug("PRESENCE_UNSUBSCRIBE")
name = stanza.get_to().node name = stanza.get_to().node
from_jid = stanza.get_from() from_jid = stanza.get_from()
base_from_jid = unicode(from_jid.bare()) ## base_from_jid = unicode(from_jid.bare())
# TODO : delete from account base # TODO : delete from account base
p = Presence(from_jid = stanza.get_to(), to_jid = from_jid, \ presence = Presence(from_jid = stanza.get_to(), to_jid = from_jid, \
stanza_type = "unsubscribe") stanza_type = "unsubscribe")
self.stream.send(p) self.stream.send(presence)
p = stanza.make_accept_response() presence = stanza.make_accept_response()
self.stream.send(p) self.stream.send(presence)
return 1 return 1
""" handle unsubscribed presence from user """
def handle_presence_unsubscribed(self, stanza): def handle_presence_unsubscribed(self, stanza):
"""Handle unsubscribed presence from user
"""
self.__logger.debug("PRESENCE_UNSUBSCRIBED") self.__logger.debug("PRESENCE_UNSUBSCRIBED")
p = Presence(from_jid = stanza.get_to(), \ presence = Presence(from_jid = stanza.get_to(), \
to_jid = stanza.get_from(), \ to_jid = stanza.get_from(), \
stanza_type = "unavailable") stanza_type = "unavailable")
self.stream.send(p) self.stream.send(presence)
return 1 return 1
""" Handle new message """
def handle_message(self, message): def handle_message(self, message):
"""Handle new message
"""
self.__logger.debug("MESSAGE: " + message.get_body()) self.__logger.debug("MESSAGE: " + message.get_body())
lang_class = self.__lang.get_lang_class_from_node(message.get_node()) lang_class = self.__lang.get_lang_class_from_node(message.get_node())
name = message.get_to().node ## name = message.get_to().node
base_from_jid = unicode(message.get_from().bare()) ## base_from_jid = unicode(message.get_from().bare())
if re.compile("\[PASSWORD\]").search(message.get_subject()) is not None: if re.compile("\[PASSWORD\]").search(message.get_subject()) \
# TODO and self.__storage.has_key((base_from_jid, name)): is not None:
# account = self.__storage[(base_from_jid, name)] ## TODO and self.__storage.has_key((base_from_jid, name)):
## account = self.__storage[(base_from_jid, name)]
account = Account()
account.password = message.get_body() account.password = message.get_body()
account.waiting_password_reply = False account.waiting_password_reply = False
msg = Message(from_jid = account.jid, \ msg = Message(from_jid = account.jid, \
@@ -363,5 +402,47 @@ class JCLComponent(Component):
self.stream.send(msg) self.stream.send(msg)
return 1 return 1
###########################################################################
# Utils
###########################################################################
def _ask_password(self, from_jid, lang_class, account):
"""Send a Jabber message to ask for account password
"""
#TODO be JMC independant
if not account.waiting_password_reply \
and account.status != "offline":
account.waiting_password_reply = True
msg = Message(from_jid = account.jid, \
to_jid = from_jid, \
stanza_type = "normal", \
subject = u"[PASSWORD] " + \
lang_class.ask_password_subject, \
body = lang_class.ask_password_body % \
(account.host, account.login))
self.stream.send(msg)
def get_jid(self, account):
"""Return account jid based on account instance and component jid
"""
return account.name + u"@" + unicode(self.jid)
###########################################################################
# Virtual methods
###########################################################################
def handle_tick(self): def handle_tick(self):
"""Virtual method
Called regularly
"""
pass
def get_reg_form(self, lang_class, account_class):
"""Virtual method
Return register form based on language and account class
"""
pass
def get_reg_form_init(self, lang_class, account):
"""Virtual method
Return register form for an existing account (update)
"""
pass pass

View File

@@ -21,50 +21,70 @@
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
"""FeederComponent with default Feeder and Sender
implementation
"""
__revision__ = "$Id: feeder.py dax $"
import logging
from jcl.jabber.component import JCLComponent from jcl.jabber.component import JCLComponent
from jcl.model.account import * from jcl.model.account import Account
class FeederComponent(JCLComponent): class FeederComponent(JCLComponent):
"""Implement a feeder sender behavior based on the
regular interval behavior of JCLComponent
feed data from given Feeder and send it to user
through the given Sender.
"""
def __init__(self, def __init__(self,
jid, jid,
secret, secret,
server, server,
port, port):
name = "Generic Feeder Component",
disco_category = "gateway",
disco_type = "headline",
spool_dir = ".",
check_interval = 1):
JCLComponent.__init__(self, \ JCLComponent.__init__(self, \
jid, \ jid, \
secret, \ secret, \
server, \ server, \
port, \ port)
name, \ self.name = "Generic Feeder Component"
disco_category, \ # Define default feeder and sender, can be override
disco_type, \ self.feeder = Feeder()
spool_dir, \ self.sender = Sender()
check_interval) self.check_interval = 1
self.__logger = logging.getLogger("jcl.jabber.JCLComponent")
def handle_tick(self): def handle_tick(self):
"""Implement main feed/send behavior
"""
for account in Account.select("*"): for account in Account.select("*"):
for message in self.__jabber_component.feeder.feed(account): for data in self.feeder.feed(account):
self.__jabber_component.sender.send(account, message) self.sender.send(account, data)
class Feeder(object): class Feeder(object):
"""Abstract feeder class
"""
def __init__(self): def __init__(self):
pass pass
def feed(self, account): def feed(self, account):
"""Feed data for given account
"""
pass pass
class Sender(object): class Sender(object):
"""Abstract sender class
"""
def __init__(self): def __init__(self):
pass pass
def send(self, to_account, message): def send(self, to_account, data):
"""Send data to given account
"""
pass pass

View File

@@ -20,110 +20,134 @@
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
import sys """X -- X data handling
"""
__revision__ = ""
from pyxmpp.stanza import common_doc from pyxmpp.stanza import common_doc
class Option(object): class Option(object):
"""Option value for list field
"""
def __init__(self, label, value): def __init__(self, label, value):
self.__label = label self.__label = label
self.__value = value self.__value = value
def get_xml(self, parent): def get_xml(self, parent):
if parent is None: """Return XML Option representation from
option = common_doc.newChild(None, "option", None) self.__label and self.__value and attach it to parent
else: """
option = parent.newChild(None, "option", None) if parent is None:
option.setProp("label", self.__label) option = common_doc.newChild(None, "option", None)
option.newChild(None, "value", self.__value) else:
return option option = parent.newChild(None, "option", None)
option.setProp("label", self.__label)
option.newChild(None, "value", self.__value)
return option
class Field(object): class Field(object):
def __init__(self, type, label, var, value): """Jabber Xdata form Field
self.__type = type """
self.__label = label def __init__(self, field_type, label, var, value):
self.__var = var self.__type = field_type
self.value = value self.__label = label
self.__options = [] self.__var = var
self.value = value
self.__options = []
def add_option(self, label, value): def add_option(self, label, value):
option = Option(label, value) """Add an Option to this field
self.__options.append(option) """
return option option = Option(label, value)
self.__options.append(option)
return option
def get_xml(self, parent): def get_xml(self, parent):
if parent is None: """Return XML Field representation
raise Exception, "parent field should not be None" and attach it to parent
else: """
field = parent.newChild(None, "field", None) if parent is None:
field.setProp("type", self.__type) raise Exception, "parent field should not be None"
if not self.__label is None: else:
field.setProp("label", self.__label) field = parent.newChild(None, "field", None)
if not self.__var is None: field.setProp("type", self.__type)
field.setProp("var", self.__var) if not self.__label is None:
if self.value: field.setProp("label", self.__label)
field.newChild(None, "value", self.value) if not self.__var is None:
for option in self.__options: field.setProp("var", self.__var)
option.get_xml(field) if self.value:
return field field.newChild(None, "value", self.value)
for option in self.__options:
option.get_xml(field)
return field
class X(object): class X(object):
"""Jabber Xdata form
"""
def __init__(self): def __init__(self):
self.fields = {} self.fields = {}
self.fields_tab = [] self.fields_tab = []
self.title = None self.title = None
self.instructions = None self.instructions = None
self.type = None self.x_type = None
self.xmlns = None self.xmlns = None
def add_field(self, type = "fixed", label = None, var = None, value = ""): def add_field(self, field_type = "fixed", label = None, var = None, value = ""):
field = Field(type, label, var, value) """Add a Field to this Xdata form
self.fields[var] = field """
# fields_tab exist to keep added fields order field = Field(field_type, label, var, value)
self.fields_tab.append(field) self.fields[var] = field
return field # fields_tab exist to keep added fields order
self.fields_tab.append(field)
return field
def attach_xml(self, iq): def attach_xml(self, iq):
node = iq.newChild(None, "x", None) """Attach this Xdata form to iq node
_ns = node.newNs(self.xmlns, None) """
node.setNs(_ns) node = iq.newChild(None, "x", None)
if not self.title is None: _ns = node.newNs(self.xmlns, None)
node.newTextChild(None, "title", self.title) node.setNs(_ns)
if not self.instructions is None: if not self.title is None:
node.newTextChild(None, "instructions", self.instructions) node.newTextChild(None, "title", self.title)
for field in self.fields_tab: if not self.instructions is None:
field.get_xml(node) node.newTextChild(None, "instructions", self.instructions)
return node for field in self.fields_tab:
field.get_xml(node)
return node
def from_xml(self, node): def from_xml(self, node):
## TODO : test node type and ns and clean that loop !!!! """Populate this X object from an XML representation
while node and node.type != "element": """
node = node.next ## TODO : test node type and ns and clean that loop !!!!
child = node.children while node and node.type != "element":
while child: node = node.next
## TODO : test child type (element) and ns (jabber:x:data) child = node.children
if child.type == "element" and child.name == "field": while child:
if child.hasProp("type"): ## TODO : test child type (element) and ns (jabber:x:data)
type = child.prop("type") if child.type == "element" and child.name == "field":
else: if child.hasProp("type"):
type = "" field_type = child.prop("type")
else:
field_type = ""
if child.hasProp("label"): if child.hasProp("label"):
label = child.prop("label") label = child.prop("label")
else: else:
label = "" label = ""
if child.hasProp("var"): if child.hasProp("var"):
var = child.prop("var") var = child.prop("var")
else: else:
var = "" var = ""
xval = child.children xval = child.children
while xval and xval.name != "value": while xval and xval.name != "value":
xval = xval.next xval = xval.next
if xval: if xval:
value = xval.getContent() value = xval.getContent()
else: else:
value = "" value = ""
field = Field(type, label, var, value) field = Field(field_type, label, var, value)
self.fields[var] = field self.fields[var] = field
child = child.next child = child.next

View File

@@ -21,12 +21,27 @@
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
# TODO delete not JCL translation """lang -- contains translations
"""
# TODO get help to generate revision
__revision__ = "$Id: lang.py dax $"
# TODO delete JMC translation
class Lang: class Lang:
"""Lang.
"""
# TODO get help on docstring
# pylint: disable-msg=W0232, R0903, C0103, C0111
def __init__(self, default_lang = "en"): def __init__(self, default_lang = "en"):
self.default_lang = default_lang self.default_lang = default_lang
def get_lang_from_node(self, node): def get_lang_from_node(self, node):
"""Extract lang contain in a XML node.
:Parameters:
- `node`: XML node.
"""
lang = node.getLang() lang = node.getLang()
if lang is None: if lang is None:
print "Using default lang " + self.default_lang print "Using default lang " + self.default_lang
@@ -34,9 +49,19 @@ class Lang:
return lang return lang
def get_lang_class(self, lang): def get_lang_class(self, lang):
return getattr(Lang, lang) """Return lang class from lang code.
:Parameters:
- `lang`: lang code.
"""
return getattr(self, lang)
def get_lang_class_from_node(self, node): def get_lang_class_from_node(self, node):
"""Return lang class from XML node.
:Parameters:
- `node`: XML node.
"""
return self.get_lang_class(self.get_lang_from_node(node)) return self.get_lang_class(self.get_lang_from_node(node))
class en: class en:
@@ -57,7 +82,8 @@ class Lang:
account_dnd_action = u"Action when state is 'Do not Disturb'" account_dnd_action = u"Action when state is 'Do not Disturb'"
account_offline_action = u"Action when state is 'Offline'" account_offline_action = u"Action when state is 'Offline'"
account_check_interval = u"Mail check interval (in minutes)" account_check_interval = u"Mail check interval (in minutes)"
account_live_email_only = u"Reports only emails received while connected to Jabber" account_live_email_only = u"Reports only emails received while " \
u"connected to Jabber"
action_nothing = u"Do nothing" action_nothing = u"Do nothing"
action_retrieve = u"Retrieve mail" action_retrieve = u"Retrieve mail"
action_digest = u"Send mail digest" action_digest = u"Send mail digest"
@@ -66,7 +92,7 @@ class Lang:
connection_label = u"%s connection '%s'" connection_label = u"%s connection '%s'"
update_account_message_subject = u"Updated %s connection '%s'" update_account_message_subject = u"Updated %s connection '%s'"
update_account_message_body = u"Registered with username '%s' and " \ update_account_message_body = u"Registered with username '%s' and " \
"password '%s' on '%s'" u"password '%s' on '%s'"
new_account_message_subject = u"New %s connection '%s' created" new_account_message_subject = u"New %s connection '%s' created"
new_account_message_body = u"Registered with " \ new_account_message_body = u"Registered with " \
"username '%s' and password '%s' on '%s'" "username '%s' and password '%s' on '%s'"
@@ -75,19 +101,22 @@ class Lang:
"for the following account: \n" \ "for the following account: \n" \
"\thost = %s\n" \ "\thost = %s\n" \
"\tlogin = %s\n" "\tlogin = %s\n"
password_saved_for_session = u"Password will be kept during your Jabber session" password_saved_for_session = u"Password will be kept during your " \
u"Jabber session"
check_error_subject = u"Error while checking emails." check_error_subject = u"Error while checking emails."
check_error_body = u"An error appears while checking emails:\n\t%s" check_error_body = u"An error appears while checking emails:\n\t%s"
new_mail_subject = u"New email from %s" new_mail_subject = u"New email from %s"
new_digest_subject = u"%i new email(s)" new_digest_subject = u"%i new email(s)"
class fr: class fr:
register_title = u"Enregistrement d'une nouvelle connexion à un serveur email." register_title = u"Enregistrement d'une nouvelle connexion à un " \
u"serveur email."
register_instructions = u"Entrer les paramètres de connexion" register_instructions = u"Entrer les paramètres de connexion"
account_name = u"Nom de la connexion" account_name = u"Nom de la connexion"
account_login = u"Nom d'utilisateur" account_login = u"Nom d'utilisateur"
account_password = u"Mot de passe" account_password = u"Mot de passe"
account_password_store = u"Sauvegarder le mot de passe sur le serveur Jabber ?" account_password_store = u"Sauvegarder le mot de passe sur le " \
u"serveur Jabber ?"
account_host = u"Adresse du serveur email" account_host = u"Adresse du serveur email"
account_port = u"Port du serveur email" account_port = u"Port du serveur email"
account_type = u"Type du serveur email" account_type = u"Type du serveur email"
@@ -98,7 +127,8 @@ class Lang:
account_xa_action = u"Action lorsque l'état est 'Not Available'" account_xa_action = u"Action lorsque l'état est 'Not Available'"
account_dnd_action = u"Action lorsque l'état est 'Do not Disturb'" account_dnd_action = u"Action lorsque l'état est 'Do not Disturb'"
account_offline_action = u"Action lorsque l'état est 'Offline'" account_offline_action = u"Action lorsque l'état est 'Offline'"
account_check_interval = u"Interval de vérification de nouveaux emails (en minutes)" account_check_interval = u"Interval de vérification de nouveaux " \
u"emails (en minutes)"
account_live_email_only = u"Vérifier les nouveaux emails seulement " \ account_live_email_only = u"Vérifier les nouveaux emails seulement " \
"lorsqu'une session Jabber est ouverte" "lorsqu'une session Jabber est ouverte"
action_nothing = u"Ne rien faire" action_nothing = u"Ne rien faire"
@@ -107,20 +137,23 @@ class Lang:
update_title = u"Mise à jour du compte JMC" update_title = u"Mise à jour du compte JMC"
update_instructions = u"Modification de la connexion '%s'" update_instructions = u"Modification de la connexion '%s'"
connection_label = u"Connexion %s '%s'" connection_label = u"Connexion %s '%s'"
update_account_message_subject = u"La connexion %s '%s' a été mise à jour" update_account_message_subject = u"La connexion %s '%s' a été mise " \
update_account_message_body = u"Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'" u"à jour"
update_account_message_body = u"Nom d'utilisateur : '%s'\nMot de " \
u"passe : '%s'\nsur : '%s'"
new_account_message_subject = u"La connexion %s '%s' a été créée" new_account_message_subject = u"La connexion %s '%s' a été créée"
new_account_message_body = u"Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'" new_account_message_body = u"Nom d'utilisateur : '%s'\nMot de passe " \
u": '%s'\nsur : '%s'"
ask_password_subject = u"Demande de mot de passe" ask_password_subject = u"Demande de mot de passe"
ask_password_body = u"Répondre à ce message avec le mot de passe du " \ ask_password_body = u"Répondre à ce message avec le mot de passe " \
"compte suivant : \n" \ u"du compte suivant : \n" \
"\thost = %s\n" \ u"\thost = %s\n" \
"\tlogin = %s\n" u"\tlogin = %s\n"
password_saved_for_session = u"Le mot de passe sera garder tout au " \ password_saved_for_session = u"Le mot de passe sera garder tout au " \
"long de la session Jabber." u"long de la session Jabber."
check_error_subject = u"Erreur lors de la vérification des emails." check_error_subject = u"Erreur lors de la vérification des emails."
check_error_body = u"Une erreur est survenue lors de la vérification " \ check_error_body = u"Une erreur est survenue lors de la " \
"des emails :\n\t%s" u"vérification des emails :\n\t%s"
new_mail_subject = u"Nouvel email de %s" new_mail_subject = u"Nouvel email de %s"
new_digest_subject = u"%i nouveau(x) email(s)" new_digest_subject = u"%i nouveau(x) email(s)"
@@ -152,16 +185,18 @@ class Lang:
connection_label = u"%s verbinding '%s'" connection_label = u"%s verbinding '%s'"
update_account_message_subject = u"Verbinding %s '%s' werd bijgewerkt" update_account_message_subject = u"Verbinding %s '%s' werd bijgewerkt"
update_account_message_body = u"Geregistreerd met gebruikersnaam '%s'"\ update_account_message_body = u"Geregistreerd met gebruikersnaam '%s'"\
"en wachtwoord '%s' op '%s'" u"en wachtwoord '%s' op '%s'"
new_account_message_subject = u"Nieuwe %s verbinding '%s' aangemaakt" new_account_message_subject = u"Nieuwe %s verbinding '%s' aangemaakt"
new_account_message_body = u"Geregistreerd met " \ new_account_message_body = u"Geregistreerd met " \
"gebruikersnaam '%s' en wachtwoord '%s' op '%s'" u"gebruikersnaam '%s' en wachtwoord " \
u"'%s' op '%s'"
ask_password_subject = u"Wachtwoordaanvraag" ask_password_subject = u"Wachtwoordaanvraag"
ask_password_body = u"Antwoord dit bericht met het volgende wachtwoord" \ ask_password_body = u"Antwoord dit bericht met het volgende " \
"voor de volgende account: \n" \ u"wachtwoord voor de volgende account: \n" \
"\thost = %s\n" \ u"\thost = %s\n" \
"\tlogin = %s\n" u"\tlogin = %s\n"
password_saved_for_session = u"Het wachtwoord zal worden bewaard tijdens uw Jabber-sessie" password_saved_for_session = u"Het wachtwoord zal worden bewaard " \
u"tijdens uw Jabber-sessie"
check_error_subject = u"Fout tijdens controle op e-mails." check_error_subject = u"Fout tijdens controle op e-mails."
check_error_body = u"Fout tijdens controle op e-mails:\n\t%s" check_error_body = u"Fout tijdens controle op e-mails:\n\t%s"
new_mail_subject = u"Nieuwe e-mail van %s" new_mail_subject = u"Nieuwe e-mail van %s"
@@ -173,19 +208,24 @@ class Lang:
account_name = u"Nombre para la cuenta" account_name = u"Nombre para la cuenta"
account_login = u"Usuario (login)" account_login = u"Usuario (login)"
account_password = u"Contraseña" account_password = u"Contraseña"
account_password_store = u"¿Guardar la contraseña en el servidor Jabber?" account_password_store = u"¿Guardar la contraseña en el servidor " \
u"Jabber?"
account_host = u"Host" account_host = u"Host"
account_port = u"Puerto" account_port = u"Puerto"
account_type = u"Tipo de servidor Mail" account_type = u"Tipo de servidor Mail"
account_mailbox = u"Ruta del mailbox (solo para IMAP)" account_mailbox = u"Ruta del mailbox (solo para IMAP)"
account_ffc_action = u"Acción para cuando tu estado sea 'Listopara hablar'" account_ffc_action = u"Acción para cuando tu estado sea " \
u"'Listopara hablar'"
account_online_action = u"Acción para cuando tu estado sea 'Conectado'" account_online_action = u"Acción para cuando tu estado sea 'Conectado'"
account_away_action = u"Acción para cuando tu estado sea 'Ausente'" account_away_action = u"Acción para cuando tu estado sea 'Ausente'"
account_xa_action = u"Acción para cuando tu estado sea 'No disponible'" account_xa_action = u"Acción para cuando tu estado sea 'No disponible'"
account_dnd_action = u"Acción para cuando tu estado sea 'No molestar'" account_dnd_action = u"Acción para cuando tu estado sea 'No molestar'"
account_offline_action = u"Acción para cuando tu estado sea 'Desconectado'" account_offline_action = u"Acción para cuando tu estado sea " \
account_check_interval = u"Intervalo para comprobar emails nuevos (en minutos)" u"'Desconectado'"
account_live_email_only = u"Avisarme de emails nuevos solo cuando esté conectado" account_check_interval = u"Intervalo para comprobar emails nuevos " \
u"(en minutos)"
account_live_email_only = u"Avisarme de emails nuevos solo cuando " \
u"esté conectado"
action_nothing = u"No hacer nada" action_nothing = u"No hacer nada"
action_retrieve = u"Mostrarme el email" action_retrieve = u"Mostrarme el email"
action_digest = u"Enviar resúmen" action_digest = u"Enviar resúmen"
@@ -193,15 +233,19 @@ class Lang:
update_instructions = u"Modifica los datos de la cuenta '%s'" update_instructions = u"Modifica los datos de la cuenta '%s'"
connection_label = u"%s conexión '%s'" connection_label = u"%s conexión '%s'"
update_account_message_subject = u"Actualizada %s conexión '%s'" update_account_message_subject = u"Actualizada %s conexión '%s'"
update_account_message_body = u"Registrado con el usuario '%s' y contraseña '%s' en '%s'" update_account_message_body = u"Registrado con el usuario '%s' y " \
u"contraseña '%s' en '%s'"
new_account_message_subject = u"Nueva %s conexión '%s' creada" new_account_message_subject = u"Nueva %s conexión '%s' creada"
new_account_message_body = u"Registrado con usuario '%s' y contraseña '%s' en '%s'" new_account_message_body = u"Registrado con usuario '%s' y " \
u"contraseña '%s' en '%s'"
ask_password_subject = u"Petición de contraseña" ask_password_subject = u"Petición de contraseña"
ask_password_body = u"Para avisarte de emails nuevos, contesta a este mensaje con la contraseña " \ ask_password_body = u"Para avisarte de emails nuevos, contesta a " \
"de la cuenta: \n" \ u"este mensaje con la contraseña " \
"\tHost = %s\n" \ u"de la cuenta: \n" \
"\tUsuario = %s\n" u"\tHost = %s\n" \
password_saved_for_session = u"La contraseña será guardada para esta sesión únicamente." u"\tUsuario = %s\n"
password_saved_for_session = u"La contraseña será guardada para " \
u"esta sesión únicamente."
check_error_subject = u"Error al revisar los emails." check_error_subject = u"Error al revisar los emails."
check_error_body = u"Un error apareció al revisar los emails:\n\t%s" check_error_body = u"Un error apareció al revisar los emails:\n\t%s"
new_mail_subject = u"Nuevo email en %s" new_mail_subject = u"Nuevo email en %s"
@@ -225,7 +269,8 @@ class Lang:
account_dnd_action = u"Akcja gdy status to 'Nie przeszkadzać'" account_dnd_action = u"Akcja gdy status to 'Nie przeszkadzać'"
account_offline_action = u"Akcja gdy status to 'Rozłączony'" account_offline_action = u"Akcja gdy status to 'Rozłączony'"
account_check_interval = u"Sprawdzaj email co (w minutach)" account_check_interval = u"Sprawdzaj email co (w minutach)"
account_live_email_only = u"Raportuj otrzymane emaile tylko\n gdy podłączony do Jabbera" account_live_email_only = u"Raportuj otrzymane emaile tylko\n gdy " \
u"podłączony do Jabbera"
action_nothing = u"Nic nie rób" action_nothing = u"Nic nie rób"
action_retrieve = u"Pobierz emaila" action_retrieve = u"Pobierz emaila"
action_digest = u"Wyślij zarys emaila" action_digest = u"Wyślij zarys emaila"
@@ -233,15 +278,20 @@ class Lang:
update_instructions = u"Modyfikacja połączenia '%s'" update_instructions = u"Modyfikacja połączenia '%s'"
connection_label = u"%s połączenie '%s'" connection_label = u"%s połączenie '%s'"
update_account_message_subject = u"Zmodyfikowane %s połączenie '%s'" update_account_message_subject = u"Zmodyfikowane %s połączenie '%s'"
update_account_message_body = u"Zarejestrowany z nazwą użytkownika '%s' i hasłem '%s' na '%s'" update_account_message_body = u"Zarejestrowany z nazwą użytkownika " \
u"'%s' i hasłem '%s' na '%s'"
new_account_message_subject = u"Nowe %s połączenie '%s' utworzone" new_account_message_subject = u"Nowe %s połączenie '%s' utworzone"
new_account_message_body = u"Zarejestrowany z nazwą użytkownika '%s' i hasłem '%s' na '%s'" new_account_message_body = u"Zarejestrowany z nazwą użytkownika " \
u"'%s' i hasłem '%s' na '%s'"
ask_password_subject = u"Żądanie hasła" ask_password_subject = u"Żądanie hasła"
ask_password_body = u"Odpowiedz na ta wiadomosc z hasłem dla podanego konta: \n" \ ask_password_body = u"Odpowiedz na ta wiadomosc z hasłem dla " \
"\tnazwa hosta = %s\n" \ u"podanego konta: \n" \
"\tnazwa uzytkownika = %s\n" u"\tnazwa hosta = %s\n" \
password_saved_for_session = u"Hasło będzie przechowywane podczas Twojej sesji Jabbera" u"\tnazwa uzytkownika = %s\n"
password_saved_for_session = u"Hasło będzie przechowywane podczas " \
u"Twojej sesji Jabbera"
check_error_subject = u"Błąd podczas sprawdzania emaili." check_error_subject = u"Błąd podczas sprawdzania emaili."
check_error_body = u"Pojawił się błąd podczas sprawdzania emaili:\n\t%s" check_error_body = u"Pojawił się błąd podczas sprawdzania " \
u"emaili:\n\t%s"
new_mail_subject = u"Nowy email od %s" new_mail_subject = u"Nowy email od %s"
new_digest_subject = u"%i nowy(ch) email(i)" new_digest_subject = u"%i nowy(ch) email(i)"

View File

@@ -26,5 +26,7 @@ from sqlobject import *
class Account(SQLObject): class Account(SQLObject):
user_jid = StringCol() user_jid = StringCol()
name = StringCol() name = StringCol()
jid = StringCol()

View File

@@ -22,6 +22,11 @@
## ##
import unittest import unittest
import thread
import threading
import time
from sqlobject import * from sqlobject import *
from jcl.jabber.component import JCLComponent from jcl.jabber.component import JCLComponent
@@ -31,6 +36,8 @@ from jcl.lang import Lang
class MockStream(object): class MockStream(object):
def __init__(self): def __init__(self):
self.sended = [] self.sended = []
self.connection_started = False
self.connection_stoped = False
def send(self, iq): def send(self, iq):
self.sended.append(iq) self.sended.append(iq)
@@ -65,6 +72,15 @@ class MockStream(object):
raise Exception("Message type unknown: " + msg_type) raise Exception("Message type unknown: " + msg_type)
if handler is None: if handler is None:
raise Exception("Handler must not be None") raise Exception("Handler must not be None")
def connect(self):
self.connection_started = True
def disconnect(self):
self.connection_stoped = True
def loop_iter(self, timeout):
time.sleep(timeout)
class JCLComponent_TestCase(unittest.TestCase): class JCLComponent_TestCase(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -80,6 +96,25 @@ class JCLComponent_TestCase(unittest.TestCase):
def test_constructor(self): def test_constructor(self):
self.assertTrue(Account._connection.tableExists("account")) self.assertTrue(Account._connection.tableExists("account"))
def test_run(self):
self.comp.stream = MockStream()
run_thread = thread.start_new_thread(self.comp.run, ())
self.assertTrue(self.comp.stream.connection_started)
self.comp.running = False
time.sleep(JCLComponent.timeout + 1)
threads = threading.enumerate()
self.assertNone(threads)
for _thread in threads:
try:
_thread.join(1)
except:
pass
self.assertTrue(self.comp.connection_stoped)
def test_run_go_offline(self):
## TODO : verify offline stanza are sent
pass
def test_authenticated_handler(self): def test_authenticated_handler(self):
self.comp.stream = MockStream() self.comp.stream = MockStream()
self.comp.authenticated() self.comp.authenticated()