Some refactoring

Put disco and presence handlers in configurable Handler classes

darcs-hash:20070708140132-86b55-48a41b751c68fb60620fe883f38b7c3104fdf796.gz
This commit is contained in:
David Rousselie
2007-07-08 16:01:32 +02:00
parent a9534ee40f
commit 7507f3b6ab
17 changed files with 1233 additions and 999 deletions

View File

@@ -1,11 +1,16 @@
"""Jabber related classes"""
__revision__ = ""
import jcl.model.account as account
from jcl.model.account import Account
class Handler(object):
"""handling class"""
def __init__(self, component):
"""Default Handler constructor"""
self.component = component
def filter(self, stanza, lang_class):
"""
Filter account to be processed by the handler
@@ -21,13 +26,41 @@ class Handler(object):
"""
return []
class DiscoHandler(object):
"""Handle disco get items requests"""
def filter(self, node, info_query):
"""Filter requests to be handled"""
return False
def handle(self, node, info_query, lang_class, disco_items, data):
"""Handle disco get items request"""
def root_filter(self, stanza, lang_class, node=None):
"""Filter stanza sent to root node"""
to_jid = stanza.get_to()
if to_jid.resource is None and to_jid.node is None and node is None:
return True
else:
return None
def account_type_filter(self, stanza, lang_class, node=None):
"""Filter stanzas sent to account type node"""
to_jid = stanza.get_to()
account_type = to_jid.resource
if account_type is not None and to_jid.node is None:
return account_type
else:
return None
def account_filter(self, stanza, lang_class, node=None):
"""Filter stanzas sent to account jid"""
name = stanza.get_to().node
return name
def get_account_filter(self, stanza, lang_class, node=None):
"""Filter stanzas sent to account jid, only if account exists"""
name = stanza.get_to().node
if name is not None:
return account.get_account(name,
stanza.get_from().bare())
else:
return None
def get_accounts_root_filter(self, stanza, lang_class, node=None):
"""Filter stanza sent to root node"""
to_jid = stanza.get_to()
if to_jid.resource is None and to_jid.node is None and node is None:
return account.get_accounts(stanza.get_from().bare())
else:
return None

View File

@@ -27,7 +27,8 @@ from pyxmpp.jabber.dataforms import Form, Field
import jcl
from jcl.lang import Lang
from jcl.jabber import DiscoHandler
from jcl.jabber.disco import DiscoHandler, RootDiscoGetInfoHandler
import jcl.model as model
from jcl.model.account import Account
COMMAND_NS = "http://jabber.org/protocol/commands"
@@ -146,47 +147,60 @@ class JCLCommandManager(CommandManager):
field_type="fixed",
label="Account name")) # TODO: add to Lang
bare_from_jid = unicode(info_query.get_from().bare())
self.account_manager.db_connect()
model.db_connect()
accounts = Account.select(Account.q.user_jid == bare_from_jid)
for _account in accounts:
fields = [Field(name="name",
field_type="fixed",
value=_account.name)]
result_form.add_item(fields)
self.account_manager.db_disconnect()
model.db_disconnect()
result_form.as_xml(command_node)
return [response]
class CommandRootDiscoGetInfoHandler(RootDiscoGetInfoHandler):
def handle(self, info_query, lang_class, node, disco_obj, data):
"""Add command feature to DiscoInfo"""
disco_infos = RootDiscoGetInfoHandler.handle(self, info_query,
lang_class, node,
disco_obj, data)
disco_infos[0].add_feature(COMMAND_NS)
return disco_infos
class CommandDiscoGetInfoHandler(DiscoHandler):
"""Handle Ad-Hoc command disco get info requests"""
def filter(self, node, info_query):
def filter(self, info_query, lang_class, node):
"""
Filter requests to be handled. Only known commands
"""
return (node in command_manager.commands)
def handle(self, disco_info, node, info_query, data, lang_class):
def handle(self, info_query, lang_class, node, disco_obj, data):
"""
Return infos for given command
"""
if not disco_info:
disco_info = DiscoInfo()
return command_manager.get_command_info(disco_info, node, lang_class)
if not disco_obj:
disco_obj = DiscoInfo()
return [command_manager.get_command_info(disco_info=disco_obj,
command_name=node,
lang_class=lang_class)]
class CommandDiscoGetItemsHandler(DiscoHandler):
"""Handle Ad-Hoc command disco get items requests"""
def filter(self, node, info_query):
def filter(self, info_query, lang_class, node):
"""
Filter requests to be handled.
"""
return (node == 'http://jabber.org/protocol/commands')
def handle(self, disco_items, node, info_query, data, lang_class):
def handle(self, info_query, lang_class, node, disco_obj, data):
"""
"""
if not disco_items:
disco_items = DiscoItems()
return command_manager.list_commands(disco_items, lang_class)
if not disco_obj:
disco_obj = DiscoItems()
return [command_manager.list_commands(disco_items=disco_obj,
lang_class=lang_class)]

View File

@@ -40,7 +40,6 @@ from Queue import Queue
from sqlobject.inheritance import InheritableSQLObject
from sqlobject.sqlbuilder import AND
from sqlobject.dbconnection import connectionForURI
import pyxmpp.error as error
from pyxmpp.jid import JID
@@ -53,10 +52,19 @@ from pyxmpp.jabber.dataforms import Form, Field, Option
import jcl
from jcl.error import FieldError
from jcl.jabber import Handler
from jcl.jabber.disco import AccountDiscoGetInfoHandler, \
AccountTypeDiscoGetInfoHandler, RootDiscoGetItemsHandler, \
AccountTypeDiscoGetItemsHandler
from jcl.jabber.message import PasswordMessageHandler
import jcl.jabber.command as command
from jcl.jabber.command import CommandDiscoGetItemsHandler, \
CommandDiscoGetInfoHandler, CommandManager, JCLCommandManager
CommandDiscoGetInfoHandler, CommandManager, JCLCommandManager, \
CommandRootDiscoGetInfoHandler
from jcl.jabber.presence import AccountPresenceAvailableHandler, \
RootPresenceAvailableHandler, AccountPresenceUnavailableHandler, \
RootPresenceUnavailableHandler, AccountPresenceSubscribeHandler, \
RootPresenceSubscribeHandler, AccountPresenceUnsubscribeHandler
import jcl.model as model
from jcl.model import account
from jcl.model.account import Account, LegacyJID
from jcl.lang import Lang
@@ -67,10 +75,12 @@ VERSION = "0.1"
# JCL implementation
###############################################################################
class JCLComponent(Component, object):
"""Implement default JCL component behavior:
"""
Implement default JCL component behavior:
- Jabber register process (add, delete, update accounts)
- Jabber presence handling
- passwork request at login
- Service Administration (XEP-0133)
"""
timeout = 1
@@ -80,7 +90,6 @@ class JCLComponent(Component, object):
secret,
server,
port,
db_connection_str,
disco_category="headline",
disco_type="x-unknown",
lang=Lang()):
@@ -94,21 +103,28 @@ class JCLComponent(Component, object):
# default values
self.name = lang.get_default_lang_class().component_name
self.spool_dir = "."
self.db_connection_str = db_connection_str
self.version = VERSION
self.time_unit = 60
self.queue = Queue(100)
self.account_manager = AccountManager(self)
self.msg_handlers = []
self.subscribe_handlers = []
self.unsubscribe_handlers = []
self.available_handlers = []
self.unavailable_handlers = []
self.presence_subscribe_handlers = [[AccountPresenceSubscribeHandler(self),
RootPresenceSubscribeHandler(self)]]
self.presence_unsubscribe_handlers = [[AccountPresenceUnsubscribeHandler(self)]]
self.presence_available_handlers = [[AccountPresenceAvailableHandler(self),
RootPresenceAvailableHandler(self)]]
self.presence_unavailable_handlers = [[AccountPresenceUnavailableHandler(self),
RootPresenceUnavailableHandler(self)]]
command.command_manager = JCLCommandManager()
command.command_manager.component = self
command.command_manager.account_manager = self.account_manager
self.disco_get_items_handlers = [CommandDiscoGetItemsHandler()]
self.disco_get_info_handlers = [CommandDiscoGetInfoHandler()]
self.disco_get_items_handlers = [[RootDiscoGetItemsHandler(self),
AccountTypeDiscoGetItemsHandler(self)],
[CommandDiscoGetItemsHandler(self)]]
self.disco_get_info_handlers = [[CommandRootDiscoGetInfoHandler(self),
AccountDiscoGetInfoHandler(self),
AccountTypeDiscoGetInfoHandler(self)],
[CommandDiscoGetInfoHandler(self)]]
self.__logger = logging.getLogger("jcl.jabber.JCLComponent")
self.lang = lang
@@ -119,7 +135,8 @@ class JCLComponent(Component, object):
signal.signal(signal.SIGTERM, self.signal_handler)
def run(self):
"""Main loop
"""
Main loop
Connect to Jabber server
Start timer thread
Call Component main loop
@@ -149,27 +166,12 @@ class JCLComponent(Component, object):
self.disconnect()
self.__logger.debug("Exitting normally")
#################
# SQlite connections are not multi-threaded
# Utils workaround methods
#################
def db_connect(self):
"""Create a new connection to the DataBase (SQLObject use connection
pool) associated to the current thread"""
account.hub.threadConnection = \
connectionForURI(self.db_connection_str)
# account.hub.threadConnection.debug = True
def db_disconnect(self):
"""Delete connection associated to the current thread"""
del account.hub.threadConnection
###########################################################################
# Handlers
###########################################################################
def time_handler(self):
"""Timer thread handler
"""
Timer thread handler
"""
self.__logger.info("Timer thread started...")
try:
@@ -179,13 +181,17 @@ class JCLComponent(Component, object):
self.wait_event.wait(self.time_unit)
self.handle_tick()
self.__logger.debug("Resetting alarm signal")
##time.sleep(self.time_unit)
except Exception, exception:
type, value, stack = sys.exc_info()
self.__logger.error("Error in timer thread\n%s\n%s"
% (exception, "".join(traceback.format_exception
(type, value, stack, 5))))
self.queue.put(exception)
self.__logger.info("Timer thread terminated...")
def authenticated(self):
"""Override authenticated Component event handler
"""
Override authenticated Component event handler
Register event handlers
Probe for every accounts registered
"""
@@ -227,7 +233,7 @@ class JCLComponent(Component, object):
self.handle_message)
self.send_stanzas(self.account_manager.probe_all_accounts_presence())
self.msg_handlers += [PasswordMessageHandler()]
self.msg_handlers += [[PasswordMessageHandler(self)]]
def signal_handler(self, signum, frame):
"""Stop method handler
@@ -277,32 +283,45 @@ class JCLComponent(Component, object):
self.send_stanzas(result)
return result
def apply_registered_behavior(self, handlers, stanza, apply_all=True):
def apply_registered_behavior(self, handlers, stanza,
apply_filter_func=None,
apply_handle_func=None):
"""Execute handler if their filter method does not return None"""
result = []
self.db_connect()
lang = self.lang.get_lang_class_from_node(stanza.get_node())
for handler in handlers:
try:
self.__logger.debug("Applying filter " + repr(handler))
data = handler.filter(stanza, lang)
if data:
self.__logger.debug("Applying handler " + repr(handler))
result += handler.handle(stanza, lang, data)
if not apply_all:
break
except Exception, e:
type, value, stack = sys.exc_info()
self.__logger.error("Error with handler " + str(handler) +
" with " + str(stanza) + "\n%s\n%s"
% (e, "".join(traceback.format_exception
(type, value, stack, 5))))
result += [Message(from_jid=stanza.get_to(),
to_jid=stanza.get_from(),
stanza_type="error",
subject=lang.error_subject,
body=lang.error_body % (e.message))]
self.db_disconnect()
lang_class = self.lang.get_lang_class_from_node(stanza.get_node())
for handler_group in handlers:
for handler in handler_group:
try:
self.__logger.debug("Applying filter " + repr(handler))
if apply_filter_func is not None:
data = apply_filter_func(handler.filter, stanza, lang_class)
else:
data = handler.filter(stanza, lang_class)
if data is not None and data != False:
self.__logger.debug("Applying handler " + repr(handler))
if apply_handle_func is not None:
handler_result = apply_handle_func(handler.handle,
stanza,
lang_class,
data,
result)
else:
handler_result = handler.handle(stanza, lang_class,
data)
if handler_result is not None:
result += handler_result
break
except Exception, e:
type, value, stack = sys.exc_info()
self.__logger.error("Error with handler " + str(handler) +
" with " + str(stanza) + "\n%s\n%s"
% (e, "".join(traceback.format_exception
(type, value, stack, 5))))
result += [Message(from_jid=stanza.get_to(),
to_jid=stanza.get_from(),
stanza_type="error",
subject=lang_class.error_subject,
body=lang_class.error_body % (e.message))]
self.send_stanzas(result)
return result
@@ -337,50 +356,29 @@ class JCLComponent(Component, object):
return 1
def disco_get_info(self, node, info_query):
"""Discovery get info handler
"""
result = self.apply_behavior(\
info_query,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_disco_get_info(),
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_type_disco_get_info(),
lambda name, from_jid, account_type, lang_class: \
self.account_manager.root_disco_get_info(\
node,
self.name,
self.disco_identity.category,
self.disco_identity.type))
if result is None:
lang_class = self.lang.get_lang_class_from_node(info_query.get_node())
for disco_filter in self.disco_get_info_handlers:
data = disco_filter.filter(node, info_query)
if data:
result = disco_filter.handle(result, node, info_query,
data, lang_class)
Discovery get info handler
"""
result = self.apply_registered_behavior(\
self.disco_get_info_handlers,
info_query,
lambda filter_func, stanza, lang_class: \
filter_func(stanza, lang_class, node),
lambda handle_func, stanza, lang_class, data, result: \
handle_func(stanza, lang_class, node, result, data))
return result
def disco_get_items(self, node, info_query):
"""Discovery get nested nodes handler
"""
result = self.apply_behavior(\
Discovery get nested nodes handler
"""
result = self.apply_registered_behavior(\
self.disco_get_items_handlers,
info_query,
lambda name, from_jid, account_type, lang_class: \
None,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_type_disco_get_items(from_jid,
account_type),
lambda name, from_jid, account_type, lang_class: \
self.account_manager.root_disco_get_items(node,
from_jid,
lang_class))
if result is None:
lang_class = self.lang.get_lang_class_from_node(info_query.get_node())
for disco_filter in self.disco_get_items_handlers:
data = disco_filter.filter(node, info_query)
if data:
result = disco_filter.handle(result, node, info_query,
data, lang_class)
lambda filter_func, stanza, lang_class: \
filter_func(stanza, lang_class, node),
lambda handle_func, stanza, lang_class, data, result: \
handle_func(stanza, lang_class, node, result, data))
return result
def handle_get_version(self, info_query):
@@ -474,22 +472,7 @@ class JCLComponent(Component, object):
if presence sent to the component ('if not name'), presence is sent to
all accounts for current user. Otherwise, send presence from current account.
"""
result = self.apply_registered_behavior(self.available_handlers, stanza)
if result == []:
result = self.apply_behavior(\
stanza,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_handle_presence_available(name,
from_jid,
lang_class,
stanza.get_show()),
lambda name, from_jid, account_type, lang_class: \
[],
lambda name, from_jid, account_type, lang_class: \
self.account_manager.root_handle_presence_available(from_jid,
lang_class,
stanza.get_show()),
send_result=True)
result = self.apply_registered_behavior(self.presence_available_handlers, stanza)
return result
@@ -497,38 +480,16 @@ class JCLComponent(Component, object):
"""Handle presence unavailability
"""
self.__logger.debug("PRESENCE_UNAVAILABLE")
result = self.apply_registered_behavior(self.unavailable_handlers, stanza)
if result == []:
result = self.apply_behavior(\
stanza,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_handle_presence_unavailable(name,
from_jid),
lambda name, from_jid, account_type, lang_class: \
[],
lambda name, from_jid, account_type, lang_class: \
self.account_manager.root_handle_presence_unavailable(from_jid),
send_result=True)
result = self.apply_registered_behavior(self.presence_unavailable_handlers,
stanza)
return result
def handle_presence_subscribe(self, stanza):
"""Handle subscribe presence from user
"""
self.__logger.debug("PRESENCE_SUBSCRIBE")
result = self.apply_registered_behavior(self.subscribe_handlers, stanza)
if result == []:
result = self.apply_behavior(\
stanza,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_handle_presence_subscribe(name,
from_jid,
stanza),
lambda name, from_jid, account_type, lang_class: \
[],
lambda name, from_jid, account_type, lang_class: \
self.account_manager.root_handle_presence_subscribe(from_jid,
stanza),
send_result=True)
result = self.apply_registered_behavior(self.presence_subscribe_handlers,
stanza)
return result
def handle_presence_subscribed(self, stanza):
@@ -541,18 +502,8 @@ class JCLComponent(Component, object):
"""Handle unsubscribe presence from user
"""
self.__logger.debug("PRESENCE_UNSUBSCRIBE")
result = self.apply_registered_behavior(self.unsubscribe_handlers, stanza)
if result == []:
result = self.apply_behavior(\
stanza,
lambda name, from_jid, account_type, lang_class: \
self.account_manager.account_handle_presence_unsubscribe(name,
from_jid),
lambda name, from_jid, account_type, lang_class: \
[],
lambda name, from_jid, account_type, lang_class: \
[],
send_result=True)
result = self.apply_registered_behavior(self.presence_unsubscribe_handlers,
stanza)
return result
def handle_presence_unsubscribed(self, stanza):
@@ -570,7 +521,7 @@ class JCLComponent(Component, object):
Handle password response message
"""
self.__logger.debug("MESSAGE: " + message.get_body())
self.apply_registered_behavior(self.msg_handlers, message, False)
self.apply_registered_behavior(self.msg_handlers, message)
return 1
def handle_command(self, info_query):
@@ -593,7 +544,7 @@ class JCLComponent(Component, object):
###########################################################################
# Utils
###########################################################################
def send_error_to_account(self, _account, exception):
def send_error(self, _account, exception):
""" """
self.send_stanzas(self.account_manager.send_error_from_account(_account, exception))
type, value, stack = sys.exc_info()
@@ -643,72 +594,6 @@ class AccountManager(object):
account_classes = property(_get_account_classes, _set_account_classes)
###### disco_get_info handlers ######
def account_disco_get_info(self):
"""Implement discovery get_info on an account node"""
self.__logger.debug("account_disco_get_info")
disco_info = DiscoInfo()
disco_info.add_feature("jabber:iq:register")
return disco_info
def account_type_disco_get_info(self):
"""Implement discovery get_info on an account type node"""
self.__logger.debug("account_type_disco_get_info")
return self.account_disco_get_info()
def root_disco_get_info(self, node, name, category, type):
"""Implement discovery get_info on main component JID"""
self.__logger.debug("root_disco_get_info")
if not node:
disco_info = DiscoInfo()
disco_info.add_feature("jabber:iq:version")
disco_info.add_feature(command.COMMAND_NS)
if not self.has_multiple_account_type:
disco_info.add_feature("jabber:iq:register")
DiscoIdentity(disco_info, name,
category,
type)
return disco_info
else:
return None
###### disco_get_items handlers ######
def account_type_disco_get_items(self, from_jid, account_type):
"""Discovery get_items on an account type node"""
self.__logger.debug("Listing account for " + account_type)
account_class = self._get_account_class(account_type + "Account")
if account_class is not None:
return self._list_accounts(account_class,
from_jid.bare(),
account_type=account_type)
else:
self.__logger.error("Error: " + account_class.__name__
+ " class not in account_classes")
return None
def root_disco_get_items(self, node, from_jid, lang_class):
"""Discovery get_items on root node"""
if node is not None:
return None
disco_items = None
if self.has_multiple_account_type: # list accounts with only one type declared
disco_items = DiscoItems()
for account_type in self.account_types:
type_label_attr = "type_" + account_type.lower() + "_name"
if hasattr(lang_class, type_label_attr):
type_label = getattr(lang_class, type_label_attr)
else:
type_label = account_type
DiscoItem(disco_items,
JID(unicode(self.component.jid) + "/" +
account_type),
account_type,
type_label)
else:
disco_items = self._list_accounts(self.account_classes[0],
from_jid.bare())
return disco_items
###### get_register handlers ######
def account_get_register(self, info_query,
name,
@@ -718,19 +603,19 @@ class AccountManager(object):
"""Handle get_register on an account.
Return a preinitialized form"""
info_query = info_query.make_result_response()
account_class = self._get_account_class(account_type + "Account")
self.db_connect()
account_class = self.get_account_class(account_type + "Account")
model.db_connect()
accounts = account_class.select(\
AND(account_class.q.name == name,
account_class.q.user_jid == unicode(from_jid.bare())))
if accounts is not None:
query = info_query.new_query("jabber:iq:register")
_account = accounts[0]
self.db_disconnect()
model.db_disconnect()
self.get_reg_form_init(lang_class,
_account).as_xml(query)
else:
self.db_disconnect()
model.db_disconnect()
return [info_query]
def _account_type_get_register(self, info_query, account_class, lang_class):
@@ -748,7 +633,7 @@ class AccountManager(object):
"""Handle get_register on an account_type node"""
return self._account_type_get_register(\
info_query,
self._get_account_class(account_type + "Account"),
self.get_account_class(account_type + "Account"),
lang_class)
def root_get_register(self, info_query, lang_class):
@@ -762,7 +647,7 @@ class AccountManager(object):
def remove_all_accounts(self, user_jid):
"""Unsubscribe all accounts associated to 'user_jid' then delete
those accounts from the DataBase"""
self.db_connect()
model.db_connect()
result = []
for _account in Account.select(Account.q.user_jid == unicode(user_jid)):
self.__logger.debug("Deleting " + _account.name
@@ -781,7 +666,7 @@ class AccountManager(object):
result.append(Presence(from_jid=self.component.jid,
to_jid=user_jid,
stanza_type="unsubscribed"))
self.db_disconnect()
model.db_disconnect()
return result
def _populate_account(self, _account, lang_class, x_data,
@@ -791,7 +676,7 @@ class AccountManager(object):
result = []
from_jid = info_query.get_from()
bare_from_jid = unicode(from_jid.bare())
self.db_connect()
model.db_connect()
try:
for (field, field_type, field_options, field_post_func,
field_default_func) in _account.get_register_fields():
@@ -816,7 +701,7 @@ class AccountManager(object):
lang_class.mandatory_field % (field))
text.setNs(text.newNs(error.STANZA_ERROR_NS, None))
result.append(iq_error)
self.db_disconnect()
model.db_disconnect()
return result
result.append(info_query.make_result_response())
@@ -840,7 +725,7 @@ class AccountManager(object):
to_jid=_account.user_jid,
subject=_account.get_update_message_subject(lang_class),
body=_account.get_update_message_body(lang_class)))
self.db_disconnect()
model.db_disconnect()
return result
def account_set_register(self, name, from_jid, lang_class,
@@ -848,13 +733,13 @@ class AccountManager(object):
"""Update account"""
self.__logger.debug("Updating account " + name)
bare_from_jid = from_jid.bare()
self.db_connect()
model.db_connect()
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == unicode(bare_from_jid)))
accounts_count = accounts.count()
_account = list(accounts)[0]
self.db_disconnect()
model.db_disconnect()
if accounts_count > 1:
# Just print a warning, only the first account will be use
self.__logger.error("There might not exist 2 accounts for " +
@@ -874,7 +759,7 @@ class AccountManager(object):
x_data,
info_query):
"""Create new account from account_class"""
self.db_connect()
model.db_connect()
bare_from_jid = from_jid.bare()
_account = account_class(user_jid=unicode(bare_from_jid),
name=name,
@@ -882,7 +767,7 @@ class AccountManager(object):
all_accounts = Account.select(\
Account.q.user_jid == unicode(bare_from_jid))
first_account = (all_accounts.count() > 0)
self.db_disconnect()
model.db_disconnect()
return self._populate_account(_account, lang_class, x_data,
info_query, True, first_account)
@@ -895,7 +780,7 @@ class AccountManager(object):
"""Create new typed account"""
return self._account_type_set_register(\
name, from_jid,
self._get_account_class(account_type + "Account"), lang_class,
self.get_account_class(account_type + "Account"), lang_class,
x_data, info_query)
def root_set_register(self, name, from_jid, lang_class,
@@ -911,39 +796,12 @@ class AccountManager(object):
###### presence generic handlers ######
def account_handle_presence(self, name, from_jid, presence_func):
"""Handle presence sent to an account JID"""
result = []
self.db_connect()
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == unicode(from_jid.bare())))
if accounts.count() > 0:
result.extend(presence_func(accounts[0]))
self.db_disconnect()
return result
def root_handle_presence(self, from_jid, presence_func, root_presence_func):
"""handle presence sent to component JID"""
result = []
self.db_connect()
accounts = Account.select(\
Account.q.user_jid == unicode(from_jid.bare()))
accounts_length = 0
for _account in accounts:
accounts_length += 1
result.extend(presence_func(_account))
self.db_disconnect()
if (accounts_length > 0):
result.extend(root_presence_func(accounts_length))
return result
def send_presence_all(self, presence):
"""Send presence to all account. Optimized to use only one sql
request"""
current_user_jid = None
result = []
self.db_connect()
model.db_connect()
# Explicit reference to account table (clauseTables) to use
# "user_jid" column with Account subclasses
for _account in \
@@ -951,146 +809,50 @@ class AccountManager(object):
orderBy="user_jid"):
if current_user_jid != _account.user_jid:
current_user_jid = _account.user_jid
result.extend(self._send_presence(self.component.jid,
_account.user_jid,
presence))
result.extend(getattr(self, "_send_presence_" +
result.extend(self.send_presence(self.component.jid,
_account.user_jid,
presence))
result.extend(getattr(self, "send_presence_" +
presence)(_account))
self.db_disconnect()
model.db_disconnect()
return result
###### presence_available handlers ######
def account_handle_presence_available(self, name, from_jid, lang_class, show):
"""Handle presence \"available\" sent to an account JID"""
self.__logger.debug("Account handle presence available")
return self.account_handle_presence(\
name, from_jid,
lambda _account: \
self._send_presence_available(_account,
show,
lang_class))
def root_handle_presence_available(self, from_jid, lang_class, show):
"""Handle presence \"available\" sent to component JID"""
self.__logger.debug("Root handle presence available")
return self.root_handle_presence(\
from_jid,
lambda _account: \
self._send_presence_available(_account,
show,
lang_class),
lambda nb_accounts: \
self._send_root_presence(from_jid, "available", show,
str(nb_accounts) +
lang_class.message_status))
###### presence_unavailable handlers ######
def account_handle_presence_unavailable(self, name, from_jid):
"""Handle presence \"unavailable\" sent to an account JID"""
self.__logger.debug("Account handle presence available")
return self.account_handle_presence(\
name, from_jid,
lambda _account: \
self._send_presence_unavailable(_account))
def root_handle_presence_unavailable(self, from_jid):
"""Handle presence \"unavailable\" sent to component JID"""
self.__logger.debug("Root handle presence available")
return self.root_handle_presence(\
from_jid,
lambda _account: \
self._send_presence_unavailable(_account),
lambda nb_accounts: \
self._send_root_presence(from_jid, "unavailable"))
###### presence_subscribe handlers ######
def account_handle_presence_subscribe(self, name, from_jid, stanza):
"""Handle \"subscribe\" iq sent to an account JID"""
if self._has_account(from_jid, name):
return [stanza.make_accept_response()]
else:
self.__logger.debug("Account '" + str(name) + "' for user '" +
unicode(from_jid.bare()) + "' was not found. " +
"Refusing subscription")
return []
def root_handle_presence_subscribe(self, from_jid, stanza):
"""Handle \"subscribe\" iq sent to component JID"""
if self._has_account(from_jid):
return [stanza.make_accept_response()]
else:
self.__logger.debug("User '" +
unicode(from_jid.bare()) +
"' doesn't have any account. " +
"Refusing subscription")
return []
###### presence_unsubscribe handler (only apply to account) ######
def account_handle_presence_unsubscribe(self, name, from_jid):
"""Handle \"unsubscribe\" iq sent to account JID"""
result = []
self.db_connect()
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == unicode(from_jid.bare())))
for _account in accounts:
result.append(Presence(from_jid=_account.jid,
to_jid=from_jid,
stanza_type="unsubscribe"))
result.append(Presence(from_jid=_account.jid,
to_jid=from_jid,
stanza_type="unsubscribed"))
_account.destroySelf()
self.db_disconnect()
return result
def probe_all_accounts_presence(self):
"""Send presence probe to all registered accounts"""
return self.send_presence_all("probe")
###### Utils methods ######
def _has_account(self, from_jid, name=None):
"""Check if user with \"from_jid\" JID has an account.
Check if an account named \"name\" exist if \"name\" given."""
self.db_connect()
if name is None:
accounts = Account.select(\
Account.q.user_jid == unicode(from_jid.bare()))
else:
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == unicode(from_jid.bare())))
result = (accounts is not None \
and accounts.count() > 0)
self.db_disconnect()
return result
def _list_accounts(self, _account_class, bare_from_jid,
account_type=""):
def list_accounts(self, bare_from_jid, account_class=None,
account_type=""):
"""List accounts in disco_items for given _account_class and user jid"""
if account_class is None:
account_class = self.account_classes[0]
if account_type is not None and account_type != "":
resource = "/" + account_type
account_type = account_type + "/"
else:
resource = ""
self.db_connect()
accounts = _account_class.select(_account_class.q.user_jid == \
unicode(bare_from_jid))
model.db_connect()
accounts = account_class.select(account_class.q.user_jid == \
unicode(bare_from_jid))
if accounts.count() == 0:
return None
disco_items = DiscoItems()
return
for _account in accounts:
self.__logger.debug(str(_account))
DiscoItem(disco_items,
JID(unicode(_account.jid) + resource),
account_type + _account.name,
_account.long_name)
self.db_disconnect()
return disco_items
yield (_account, resource, account_type)
model.db_disconnect()
def _get_account_class(self, account_class_name):
def list_account_types(self, lang_class):
"""List account supported types"""
for account_type in self.account_types:
type_label_attr = "type_" + account_type.lower() + "_name"
if hasattr(lang_class, type_label_attr):
type_label = getattr(lang_class, type_label_attr)
else:
type_label = account_type
yield (account_type, type_label)
def get_account_class(self, account_class_name):
"""Return account class definition from declared classes in
account_classes from its class name"""
self.__logger.debug("Looking for " + account_class_name)
@@ -1101,19 +863,9 @@ class AccountManager(object):
self.__logger.debug(account_class_name + " not found")
return None
def db_connect(self):
"""Create a new connection to the DataBase (SQLObject use connection
pool) associated to the current thread"""
account.hub.threadConnection = \
connectionForURI(self.component.db_connection_str) # TODO : move db_connection_str to AccountManager
# account.hub.threadConnection.debug = True
def db_disconnect(self):
"""Delete connection associated to the current thread"""
del account.hub.threadConnection
def get_reg_form(self, lang_class, _account_class, bare_from_jid):
"""Return register form based on language and account class
"""
Return register form based on language and account class
"""
reg_form = Form(title=lang_class.register_title,
instructions=lang_class.register_instructions)
@@ -1123,7 +875,7 @@ class AccountManager(object):
name="name",
required=True)
self.db_connect()
model.db_connect()
for (field_name,
field_type,
field_options,
@@ -1158,11 +910,12 @@ class AccountManager(object):
except:
self.__logger.debug("Setting field " + field_name + " required")
field.required = True
self.db_disconnect()
model.db_disconnect()
return reg_form
def get_reg_form_init(self, lang_class, _account):
"""Return register form for an existing account (update)
"""
Return register form for an existing account (update)
"""
reg_form = self.get_reg_form(lang_class, _account.__class__,
_account.user_jid)
@@ -1177,31 +930,34 @@ class AccountManager(object):
"""Compose account jid from account name"""
return name + u"@" + unicode(self.component.jid)
def _send_presence_probe(self, _account):
def send_presence_probe(self, _account):
"""Send presence probe to account's user"""
return [Presence(from_jid=_account.jid,
to_jid=_account.user_jid,
stanza_type="probe")]
def _send_presence_unavailable(self, _account):
def send_presence_unavailable(self, _account):
"""Send unavailable presence to account's user"""
model.db_connect()
_account.status = account.OFFLINE
return [Presence(from_jid=_account.jid,
to_jid=_account.user_jid,
stanza_type="unavailable")]
def _send_root_presence(self, to_jid, presence_type,
show=None, status=None):
result = self._send_presence(self.component.jid, to_jid,
presence_type, show=show,
status=status)
result.extend(self._send_root_presence_legacy(to_jid,
presence_type,
show=show,
status=status))
result = [Presence(from_jid=_account.jid,
to_jid=_account.user_jid,
stanza_type="unavailable")]
model.db_disconnect()
return result
def _send_presence(self, from_jid, to_jid, presence_type, status=None, show=None):
def send_root_presence(self, to_jid, presence_type,
show=None, status=None):
result = self.send_presence(self.component.jid, to_jid,
presence_type, show=show,
status=status)
result.extend(self.send_root_presence_legacy(to_jid,
presence_type,
show=show,
status=status))
return result
def send_presence(self, from_jid, to_jid, presence_type, status=None, show=None):
"""Send presence stanza"""
return [Presence(from_jid=from_jid,
to_jid=to_jid,
@@ -1209,10 +965,11 @@ class AccountManager(object):
show=show,
stanza_type=presence_type)]
def _send_presence_available(self, _account, show, lang_class):
def send_presence_available(self, _account, show, lang_class):
"""Send available presence to account's user and ask for password
if necessary"""
result = []
model.db_connect()
_account.default_lang_class = lang_class
old_status = _account.status
if show is None:
@@ -1225,28 +982,24 @@ class AccountManager(object):
show=show,
stanza_type="available"))
if hasattr(_account, 'store_password') \
and hasattr(_account, 'password') \
and _account.store_password == False \
and old_status == account.OFFLINE \
and _account.password == None :
and hasattr(_account, 'password') \
and _account.store_password == False \
and old_status == account.OFFLINE \
and _account.password == None :
result.extend(self.ask_password(_account, lang_class))
model.db_disconnect()
return result
def _send_root_presence_legacy(self, to_jid, presence_type,
def send_root_presence_legacy(self, to_jid, presence_type,
status=None, show=None):
"""Send presence from legacy JID"""
result = []
self.db_connect()
legacy_jids = LegacyJID.select(\
AND(LegacyJID.q.accountID == Account.q.id,
Account.q.user_jid == unicode(to_jid.bare())))
for legacy_jid in legacy_jids:
for legacy_jid in account.get_legacy_jids(unicode(to_jid.bare())):
result.append(Presence(from_jid=legacy_jid.jid,
to_jid=to_jid,
show=show,
status=status,
stanza_type=presence_type))
self.db_disconnect()
return result
def ask_password(self, _account, lang_class):
@@ -1254,8 +1007,8 @@ class AccountManager(object):
"""
result = []
if hasattr(_account, 'waiting_password_reply') \
and not _account.waiting_password_reply \
and _account.status != account.OFFLINE:
and not _account.waiting_password_reply \
and _account.status != account.OFFLINE:
_account.waiting_password_reply = True
result.append(Message(from_jid=_account.jid,
to_jid=_account.user_jid,
@@ -1265,6 +1018,20 @@ class AccountManager(object):
(_account.name)))
return result
def set_password(self, _account, from_jid, password, lang_class):
"""
Set password to given account
"""
model.db_connect()
_account.password = password
_account.waiting_password_reply = False
result = [Message(from_jid=_account.jid,
to_jid=from_jid,
subject=lang_class.password_saved_for_session,
body=lang_class.password_saved_for_session)]
model.db_disconnect()
return result
def send_error_from_account(self, _account, exception):
"""Send an error message only one time until _account.in_error
has been reset to False"""

149
src/jcl/jabber/disco.py Normal file
View File

@@ -0,0 +1,149 @@
##
## disco.py
## Login : David Rousselie <dax@happycoders.org>
## Started on Wed Jun 27 22:27:25 2007 David Rousselie
## $Id$
##
## Copyright (C) 2007 David Rousselie
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
import logging
from pyxmpp.jid import JID
from pyxmpp.jabber.disco import DiscoInfo, DiscoItems, DiscoItem, DiscoIdentity
import jcl.jabber as jabber
class DiscoHandler(object):
"""Handle disco get items requests"""
def __init__(self, component):
self.component = component
def filter(self, stanza, lang_class, node):
"""Filter requests to be handled"""
return False
def handle(self, stanza, lang_class, node, disco_obj, data):
"""Handle disco get items request"""
return None
class RootDiscoGetInfoHandler(DiscoHandler):
filter = jabber.root_filter
def __init__(self, component):
DiscoHandler.__init__(self, component)
self.__logger = logging.getLogger("jcl.jabber.RootDiscoGetInfoHandler")
def handle(self, stanza, lang_class, node, disco_obj, data):
"""Implement discovery get_info on main component JID"""
self.__logger.debug("root_disco_get_info")
disco_info = DiscoInfo()
disco_info.add_feature("jabber:iq:version")
if not self.component.account_manager.has_multiple_account_type:
disco_info.add_feature("jabber:iq:register")
DiscoIdentity(disco_info, self.component.name,
self.component.disco_identity.category,
self.component.disco_identity.type)
return [disco_info]
class AccountDiscoGetInfoHandler(DiscoHandler):
filter = jabber.account_filter
def __init__(self, component):
DiscoHandler.__init__(self, component)
self.__logger = logging.getLogger("jcl.jabber.AccountDiscoGetInfoHandler")
def handle(self, stanza, lang_class, node, disco_obj, data):
"""Implement discovery get_info on an account node"""
self.__logger.debug("account_disco_get_info")
disco_info = DiscoInfo()
disco_info.add_feature("jabber:iq:register")
return [disco_info]
class AccountTypeDiscoGetInfoHandler(AccountDiscoGetInfoHandler):
filter = jabber.account_type_filter
def __init__(self, component):
AccountDiscoGetInfoHandler.__init__(self, component)
self.__logger = logging.getLogger("jcl.jabber.AccountTypeDiscoGetInfoHandler")
class RootDiscoGetItemsHandler(DiscoHandler):
filter = jabber.root_filter
def __init__(self, component):
DiscoHandler.__init__(self, component)
self.__logger = logging.getLogger("jcl.jabber.RootDiscoGetItemsHandler")
def handle(self, stanza, lang_class, node, disco_obj, data):
"""Discovery get_items on root node"""
from_jid = stanza.get_from()
if node is not None:
return None
disco_items = None
if self.component.account_manager.has_multiple_account_type: # list accounts with only one type declared
disco_items = DiscoItems()
for (account_type, type_label) in \
self.component.account_manager.list_account_types(lang_class):
DiscoItem(disco_items,
JID(unicode(self.component.jid) + "/" +
account_type),
account_type,
type_label)
else:
disco_items = DiscoItems()
for (_account, resource, account_type) in \
self.component.account_manager.list_accounts(from_jid.bare()):
DiscoItem(disco_items,
JID(unicode(_account.jid) + resource),
account_type + _account.name,
_account.long_name)
return [disco_items]
class AccountTypeDiscoGetItemsHandler(DiscoHandler):
filter = jabber.account_type_filter
def __init__(self, component):
DiscoHandler.__init__(self, component)
self.__logger = logging.getLogger("jcl.jabber.AccountTypeDiscoGetItemsHandler")
def handle(self, stanza, lang_class, node, disco_obj, data):
"""Discovery get_items on an account type node"""
account_type = data
from_jid = stanza.get_from()
self.__logger.debug("Listing account for " + account_type)
account_class = self.component.account_manager.get_account_class(account_type + "Account")
if account_class is not None:
disco_items = DiscoItems()
for (_account, resource, account_type) in \
self.component.account_manager.list_accounts(from_jid.bare(),
account_class,
account_type=account_type):
DiscoItem(disco_items,
JID(unicode(_account.jid) + resource),
account_type + _account.name,
_account.long_name)
return [disco_items]
else:
self.__logger.error("Error: " + account_class.__name__
+ " class not in account_classes")
return []

View File

@@ -31,6 +31,7 @@ import logging
from jcl.jabber import Handler
from jcl.jabber.component import JCLComponent
from jcl.lang import Lang
import jcl.model as model
from jcl.model.account import Account
from pyxmpp.message import Message
@@ -48,14 +49,12 @@ class FeederComponent(JCLComponent):
secret,
server,
port,
db_connection_str,
lang = Lang()):
JCLComponent.__init__(self,
jid,
secret,
server,
port,
db_connection_str,
lang=lang)
# Define default feeder and sender, can be override
self.handler = FeederHandler(Feeder(self), Sender(self))
@@ -65,12 +64,12 @@ class FeederComponent(JCLComponent):
def handle_tick(self):
"""Implement main feed/send behavior"""
self.db_connect()
model.db_connect()
self.handler.handle(\
None, self.lang.get_default_lang_class(),
self.handler.filter(None,
self.lang.get_default_lang_class()))
self.db_disconnect()
model.db_disconnect()

View File

@@ -22,16 +22,19 @@
import re
from sqlobject.sqlbuilder import AND
from pyxmpp.message import Message
from jcl.jabber import Handler
import jcl.model.account as account
from jcl.model.account import Account
class PasswordMessageHandler(Handler):
"""Handle password message"""
def __init__(self):
def __init__(self, component):
"""handler constructor"""
Handler.__init__(self, component)
self.password_regexp = re.compile("\[PASSWORD\]")
def filter(self, stanza, lang_class):
@@ -39,23 +42,14 @@ class PasswordMessageHandler(Handler):
Return the uniq account associated with a name and user JID.
DB connection might already be opened.
"""
name = stanza.get_to().node
bare_from_jid = unicode(stanza.get_from().bare())
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == bare_from_jid))
if accounts.count() > 1:
print >>sys.stderr, "Account " + name + " for user " + \
bare_from_jid + " must be uniq"
elif accounts.count() == 0:
return None
_account = accounts[0]
_account = account.get_account(stanza.get_to().node,
stanza.get_from().bare())
if hasattr(_account, 'password') \
and hasattr(_account, 'waiting_password_reply') \
and (getattr(_account, 'waiting_password_reply') == True) \
and self.password_regexp.search(stanza.get_subject()) \
is not None:
return accounts
and hasattr(_account, 'waiting_password_reply') \
and (getattr(_account, 'waiting_password_reply') == True) \
and self.password_regexp.search(stanza.get_subject()) \
is not None:
return _account
else:
return None
@@ -63,10 +57,6 @@ class PasswordMessageHandler(Handler):
"""
Receive password in stanza (must be a Message) for given account.
"""
_account = data[0]
_account.password = stanza.get_body()
_account.waiting_password_reply = False
return [Message(from_jid=_account.jid,
to_jid=stanza.get_from(),
subject=lang_class.password_saved_for_session,
body=lang_class.password_saved_for_session)]
return self.component.account_manager.set_password(data, stanza.get_from(),
stanza.get_body(),
lang_class)

View File

@@ -24,17 +24,19 @@
from pyxmpp.presence import Presence
from jcl.jabber import Handler
import jcl.jabber as jabber
import jcl.model as model
class DefaultPresenceHandler(Handler):
"""Handle presence"""
def handle(self, presence, lang_class, data):
def handle(self, stanza, lang_class, data):
"""Return same presence as receive one"""
to_jid = presence.get_to()
from_jid = presence.get_from()
presence.set_to(from_jid)
presence.set_from(to_jid)
return [presence]
to_jid = stanza.get_to()
from_jid = stanza.get_from()
stanza.set_to(from_jid)
stanza.set_from(to_jid)
return [stanza]
class DefaultSubscribeHandler(Handler):
"""Return default response to subscribe queries"""
@@ -64,3 +66,94 @@ class DefaultUnsubscribeHandler(Handler):
stanza_type="unsubscribed"))
return result
class AccountPresenceHandler(Handler):
filter = jabber.get_account_filter
def handle(self, stanza, lang_class, data):
"""Handle presence sent to an account JID"""
result = []
_account = data
result.extend(self.get_account_presence(stanza, lang_class, _account))
return result
class AccountPresenceAvailableHandler(AccountPresenceHandler):
def get_account_presence(self, stanza, lang_class, _account):
return self.component.account_manager.send_presence_available(_account,
stanza.get_show(),
lang_class)
class RootPresenceHandler(Handler):
filter = jabber.get_accounts_root_filter
def handle(self, stanza, lang_class, data):
"""handle presence sent to component JID"""
result = []
accounts_length = 0
accounts = data
for _account in accounts:
accounts_length += 1
result.extend(self.get_account_presence(stanza, lang_class, _account))
if accounts_length > 0:
result.extend(self.get_root_presence(stanza, lang_class, accounts_length))
return result
class RootPresenceAvailableHandler(RootPresenceHandler, AccountPresenceAvailableHandler):
def get_root_presence(self, stanza, lang_class, nb_accounts):
return self.component.account_manager.send_root_presence(stanza.get_from(),
"available",
stanza.get_show(),
str(nb_accounts) +
lang_class.message_status)
class AccountPresenceUnavailableHandler(AccountPresenceHandler):
def get_account_presence(self, stanza, lang_class, _account):
return self.component.account_manager.send_presence_unavailable(_account)
class RootPresenceUnavailableHandler(RootPresenceHandler, AccountPresenceUnavailableHandler):
def get_root_presence(self, stanza, lang_class, nb_accounts):
return self.component.account_manager.send_root_presence(stanza.get_from(),
"unavailable")
class AccountPresenceSubscribeHandler(Handler):
""""""
filter = jabber.get_account_filter
def handle(self, stanza, lang_class, data):
"""Handle \"subscribe\" iq sent to an account JID"""
return [stanza.make_accept_response()]
class RootPresenceSubscribeHandler(AccountPresenceSubscribeHandler):
""""""
filter = jabber.get_accounts_root_filter
def handle(self, stanza, lang_class, data):
"""Handle \"subscribe\" iq sent to component JID"""
if list(data) != []:
return AccountPresenceSubscribeHandler.handle(self, stanza,
lang_class, None)
else:
return None
class AccountPresenceUnsubscribeHandler(Handler):
""""""
filter = jabber.get_account_filter
def handle(self, stanza, lang_class, data):
"""Handle \"unsubscribe\" iq sent to account JID"""
result = []
from_jid = stanza.get_from()
_account = data
model.db_connect()
result.append(Presence(from_jid=_account.jid,
to_jid=from_jid,
stanza_type="unsubscribe"))
result.append(Presence(from_jid=_account.jid,
to_jid=from_jid,
stanza_type="unsubscribed"))
_account.destroySelf()
model.db_disconnect()
return result

View File

@@ -3,13 +3,15 @@ __revision__ = ""
import unittest
from jcl.jabber.tests import component, feeder, command
from jcl.jabber.tests import component, feeder, command, message, presence
def suite():
suite = unittest.TestSuite()
suite.addTest(component.suite())
suite.addTest(feeder.suite())
suite.addTest(command.suite())
suite.addTest(message.suite())
suite.addTest(presence.suite())
return suite
if __name__ == '__main__':

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,7 @@ from jcl.jabber.component import JCLComponent
from jcl.jabber.feeder import FeederComponent, Feeder, Sender, MessageSender, \
HeadlineSender, FeederHandler
from jcl.model.account import Account, LegacyJID
import jcl.model as model
from jcl.model import account
from jcl.model.tests.account import ExampleAccount, Example2Account
@@ -65,24 +66,24 @@ class FeederComponent_TestCase(JCLComponent_TestCase):
self.comp = FeederComponent("jcl.test.com",
"password",
"localhost",
"5347",
'sqlite://' + DB_URL)
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
"5347")
model.db_connection_str = 'sqlite://' + DB_URL
model.db_connect()
Account.createTable(ifNotExists = True)
LegacyJID.createTable(ifNotExists=True)
ExampleAccount.createTable(ifNotExists = True)
Example2Account.createTable(ifNotExists = True)
del account.hub.threadConnection
model.db_disconnect()
def tearDown(self):
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
Account.dropTable(ifExists = True)
LegacyJID.dropTable(ifExists=True)
ExampleAccount.dropTable(ifExists = True)
Example2Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
account.hub.threadConnection.close()
del account.hub.threadConnection
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
@@ -90,8 +91,8 @@ class FeederComponent_TestCase(JCLComponent_TestCase):
self.comp.time_unit = 1
self.comp.stream = MockStream()
self.comp.stream_class = MockStream
run_thread = threading.Thread(target = self.comp.run, \
name = "run_thread")
run_thread = threading.Thread(target=self.comp.run,
name="run_thread")
run_thread.start()
time.sleep(1)
self.comp.running = False
@@ -118,7 +119,7 @@ class FeederComponent_TestCase(JCLComponent_TestCase):
self.comp.stream = MockStream()
self.comp.stream_class = MockStream
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
account11 = Account(user_jid = "user1@test.com", \
name = "account11", \
jid = "account11@jcl.test.com")
@@ -190,30 +191,30 @@ class MessageSender_TestCase(unittest.TestCase):
self.comp = FeederComponent("jcl.test.com",
"password",
"localhost",
"5347",
'sqlite://' + DB_URL)
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
"5347")
model.db_connection_str = 'sqlite://' + DB_URL
model.db_connect()
Account.createTable(ifNotExists = True)
del account.hub.threadConnection
model.db_disconnect()
self.sender = MessageSender(self.comp)
self.message_type = None
def tearDown(self):
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
account.hub.threadConnection.close()
del account.hub.threadConnection
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
def test_send(self):
self.comp.stream = MockStream()
self.comp.stream_class = MockStream
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
account11 = Account(user_jid = "user1@test.com", \
name = "account11", \
jid = "account11@jcl.test.com")
model.db_connect()
account11 = Account(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
self.sender.send(account11, ("subject", "Body message"))
self.assertEquals(len(self.comp.stream.sent), 1)
message = self.comp.stream.sent[0]
@@ -222,7 +223,7 @@ class MessageSender_TestCase(unittest.TestCase):
self.assertEquals(message.get_subject(), "subject")
self.assertEquals(message.get_body(), "Body message")
self.assertEquals(message.get_type(), self.message_type)
del account.hub.threadConnection
model.db_disconnect()
class HeadlineSender_TestCase(MessageSender_TestCase):
def setUp(self):
@@ -235,24 +236,25 @@ class FeederHandler_TestCase(unittest.TestCase):
self.handler = FeederHandler(FeederMock(), SenderMock())
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connection_str = 'sqlite://' + DB_URL
model.db_connect()
Account.createTable(ifNotExists = True)
ExampleAccount.createTable(ifNotExists = True)
del account.hub.threadConnection
model.db_disconnect()
def tearDown(self):
self.handler = None
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
ExampleAccount.dropTable(ifExists = True)
Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
account.hub.threadConnection.close()
del account.hub.threadConnection
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
def test_filter(self):
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
account12 = ExampleAccount(user_jid="user2@test.com",
name="account12",
jid="account12@jcl.test.com")
@@ -264,10 +266,10 @@ class FeederHandler_TestCase(unittest.TestCase):
# accounts must be ordered by user_jid
self.assertEquals(accounts[0].name, "account11")
self.assertEquals(accounts[1].name, "account12")
del account.hub.threadConnection
model.db_disconnect()
def test_handle(self):
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
model.db_connect()
account11 = ExampleAccount(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
@@ -279,7 +281,7 @@ class FeederHandler_TestCase(unittest.TestCase):
self.assertEquals(len(sent), 2)
self.assertEquals(sent[0], (account11, ("subject", "body")))
self.assertEquals(sent[1], (account12, ("subject", "body")))
del account.hub.threadConnection
model.db_disconnect()
def suite():
suite = unittest.TestSuite()

View File

@@ -0,0 +1,161 @@
##
## message.py
## Login : David Rousselie <dax@happycoders.org>
## Started on Fri Jul 6 21:40:55 2007 David Rousselie
## $Id$
##
## Copyright (C) 2007 David Rousselie
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
import unittest
import sys
import os
from pyxmpp.message import Message
from sqlobject.dbconnection import TheURIOpener
from jcl.lang import Lang
from jcl.jabber.component import JCLComponent
from jcl.jabber.message import PasswordMessageHandler
import jcl.model.account as account
import jcl.model as model
from jcl.model.account import Account
from jcl.model.tests.account import ExampleAccount
if sys.platform == "win32":
DB_PATH = "/c|/temp/jcl_test.db"
else:
DB_PATH = "/tmp/jcl_test.db"
DB_URL = DB_PATH# + "?debug=1&debugThreading=1"
class PasswordMessageHandler_TestCase(unittest.TestCase):
def setUp(self):
self.comp = JCLComponent("jcl.test.com",
"password",
"localhost",
"5347",
'sqlite://' + DB_URL)
self.handler = PasswordMessageHandler(self.comp)
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
model.db_connection_str = 'sqlite://' + DB_URL
model.db_connect()
Account.createTable(ifNotExists = True)
ExampleAccount.createTable(ifNotExists = True)
model.db_disconnect()
def tearDown(self):
model.db_connect()
ExampleAccount.dropTable(ifExists = True)
Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
def test_filter_waiting_password(self):
model.db_connect()
account11 = ExampleAccount(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
account11.waiting_password_reply = True
account12 = ExampleAccount(user_jid="user1@test.com",
name="account12",
jid="account12@jcl.test.com")
message = Message(from_jid="user1@test.com",
to_jid="account11@jcl.test.com",
subject="[PASSWORD]",
body="secret")
_account = self.handler.filter(message, None)
self.assertEquals(_account.name, "account11")
model.db_disconnect()
def test_filter_not_waiting_password(self):
model.db_connect()
account11 = ExampleAccount(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
account11.waiting_password_reply = False
account12 = ExampleAccount(user_jid="user1@test.com",
name="account12",
jid="account12@jcl.test.com")
message = Message(from_jid="user1@test.com",
to_jid="account11@jcl.test.com",
subject="[PASSWORD]",
body="secret")
_account = self.handler.filter(message, None)
self.assertEquals(_account, None)
model.db_disconnect()
def test_filter_not_good_message(self):
model.db_connect()
account11 = ExampleAccount(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
account11.waiting_password_reply = True
account12 = ExampleAccount(user_jid="user1@test.com",
name="account12",
jid="account12@jcl.test.com")
message = Message(from_jid="user1@test.com",
to_jid="account11@jcl.test.com",
subject="[WRONG MESSAGE]",
body="secret")
_account = self.handler.filter(message, None)
self.assertEquals(_account, None)
model.db_disconnect()
def test_filter_not_password_account(self):
model.db_connect()
account11 = Account(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
account12 = Account(user_jid="user1@test.com",
name="account12",
jid="account12@jcl.test.com")
message = Message(from_jid="user1@test.com",
to_jid="account11@jcl.test.com",
subject="[PASSWORD]",
body="secret")
_account = self.handler.filter(message, None)
self.assertEquals(_account, None)
model.db_disconnect()
def test_handle(self):
model.db_connect()
account11 = ExampleAccount(user_jid="user1@test.com",
name="account11",
jid="account11@jcl.test.com")
account12 = ExampleAccount(user_jid="user1@test.com",
name="account12",
jid="account12@jcl.test.com")
message = Message(from_jid="user1@test.com",
to_jid="account11@jcl.test.com",
subject="[PASSWORD]",
body="secret")
messages = self.handler.handle(message, Lang.en, account11)
self.assertEquals(len(messages), 1)
self.assertEquals(account11.password, "secret")
model.db_disconnect()
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(PasswordMessageHandler_TestCase, 'test'))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')

View File

@@ -0,0 +1,98 @@
##
## presence.py
## Login : David Rousselie <dax@happycoders.org>
## Started on Fri Jul 6 21:45:43 2007 David Rousselie
## $Id$
##
## Copyright (C) 2007 David Rousselie
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
import unittest
from pyxmpp.presence import Presence
from jcl.jabber.presence import DefaultSubscribeHandler, \
DefaultUnsubscribeHandler, DefaultPresenceHandler
class DefaultSubscribeHandler_TestCase(unittest.TestCase):
def setUp(self):
self.handler = DefaultSubscribeHandler(None)
def test_handle(self):
presence = Presence(from_jid="user1@test.com",
to_jid="user1%test.com@jcl.test.com",
stanza_type="subscribe")
result = self.handler.handle(presence, None, [])
self.assertEquals(len(result), 2)
self.assertEquals(result[0].get_to(), "user1@test.com")
self.assertEquals(result[0].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[0].get_type(), "subscribe")
self.assertEquals(result[1].get_to(), "user1@test.com")
self.assertEquals(result[1].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[1].get_type(), "subscribed")
class DefaultUnsubscribeHandler_TestCase(unittest.TestCase):
def setUp(self):
self.handler = DefaultUnsubscribeHandler(None)
def test_handle(self):
presence = Presence(from_jid="user1@test.com",
to_jid="user1%test.com@jcl.test.com",
stanza_type="unsubscribe")
result = self.handler.handle(presence, None, [])
self.assertEquals(len(result), 2)
self.assertEquals(result[0].get_to(), "user1@test.com")
self.assertEquals(result[0].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[0].get_type(), "unsubscribe")
self.assertEquals(result[1].get_to(), "user1@test.com")
self.assertEquals(result[1].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[1].get_type(), "unsubscribed")
class DefaultPresenceHandler_TestCase(unittest.TestCase):
def setUp(self):
self.handler = DefaultPresenceHandler(None)
def test_handle_away(self):
presence = Presence(from_jid="user1@test.com",
to_jid="user1%test.com@jcl.test.com",
stanza_type="available",
show="away")
result = self.handler.handle(presence, None, [])
self.assertEquals(len(result), 1)
self.assertEquals(result[0].get_to(), "user1@test.com")
self.assertEquals(result[0].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[0].get_type(), None)
self.assertEquals(result[0].get_show(), "away")
def test_handle_offline(self):
presence = Presence(from_jid="user1@test.com",
to_jid="user1%test.com@jcl.test.com",
stanza_type="unavailable")
result = self.handler.handle(presence, None, [])
self.assertEquals(len(result), 1)
self.assertEquals(result[0].get_to(), "user1@test.com")
self.assertEquals(result[0].get_from(), "user1%test.com@jcl.test.com")
self.assertEquals(result[0].get_type(), "unavailable")
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(DefaultSubscribeHandler_TestCase, 'test'))
suite.addTest(unittest.makeSuite(DefaultUnsubscribeHandler_TestCase, 'test'))
suite.addTest(unittest.makeSuite(DefaultPresenceHandler_TestCase, 'test'))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')

View File

@@ -1,3 +1,32 @@
"""Contains data model classes"""
__revision__ = ""
from sqlobject.dbconnection import ConnectionHub
from sqlobject.dbconnection import connectionForURI
import jcl.model
db_connected = False
db_connection_str = ""
# create a hub to attach a per thread connection
hub = ConnectionHub()
def db_connect():
"""
Create a new connection to the DataBase (SQLObject use connection
pool) associated to the current thread.
"""
if not jcl.model.db_connected:
jcl.model.hub.threadConnection = \
connectionForURI(db_connection_str)
# account.hub.threadConnection.debug = True
jcl.model.db_connected = True
def db_disconnect():
"""
Delete connection associated to the current thread.
"""
if jcl.model.db_connected:
del jcl.model.hub.threadConnection
jcl.model.db_connected = False

View File

@@ -28,16 +28,16 @@ __revision__ = "$Id: account.py,v 1.3 2005/09/18 20:24:07 dax Exp $"
from sqlobject.inheritance import InheritableSQLObject
from sqlobject.col import StringCol, EnumCol, IntCol, BoolCol, ForeignKey
from sqlobject.dbconnection import ConnectionHub
from sqlobject.joins import MultipleJoin
from sqlobject.sqlbuilder import AND
from jcl.lang import Lang
from jcl.error import FieldError
import jcl.model as model
OFFLINE = "offline"
ONLINE = "online"
def default_post_func(field_value, default_func, bare_from_jid):
"""Default post process function: do nothing"""
if field_value is None or str(field_value) == "":
@@ -57,13 +57,32 @@ def mandatory_field(field_value):
raise FieldError # TODO : add translated message
return field_value
# create a hub to attach a per thread connection
hub = ConnectionHub()
def get_account(name, bare_user_jid):
result = None
model.db_connect()
accounts = Account.select(\
AND(Account.q.name == name,
Account.q.user_jid == unicode(bare_user_jid)))
if accounts.count() > 0:
result = accounts[0]
model.db_disconnect()
return result
def get_accounts(bare_user_jid):
model.db_connect()
accounts = Account.select(\
Account.q.user_jid == unicode(bare_user_jid))
if accounts.count() == 0:
model.db_disconnect()
return
for _account in accounts:
yield _account
model.db_disconnect()
class Account(InheritableSQLObject):
"""Base Account class"""
_cacheValue = False
_connection = hub
_connection = model.hub
user_jid = StringCol()
name = StringCol()
jid = StringCol()
@@ -268,8 +287,17 @@ class PresenceAccount(Account):
action = property(get_action)
def get_legacy_jids(bare_to_jid):
model.db_connect()
legacy_jids = LegacyJID.select(\
AND(LegacyJID.q.accountID == Account.q.id,
Account.q.user_jid == bare_to_jid))
for legacy_jid in legacy_jids:
yield legacy_jid
model.db_disconnect()
class LegacyJID(InheritableSQLObject):
_connection = hub
_connection = model.hub
legacy_address = StringCol()
jid = StringCol()

View File

@@ -28,6 +28,7 @@ from sqlobject import *
from sqlobject.dbconnection import TheURIOpener
from jcl.error import FieldError
import jcl.model as model
from jcl.model import account
from jcl.model.account import Account, PresenceAccount
@@ -165,13 +166,15 @@ class AccountModule_TestCase(unittest.TestCase):
class InheritableAccount_TestCase(unittest.TestCase):
def setUp(self):
self.db_url = DB_URL
model.db_connection_str = 'sqlite://' + self.db_url
def test_get_register_fields(self):
"""Check if post functions and default functions execute correctly.
"""
Check if post functions and default functions execute correctly.
To be validated this test only need to be executed without any
exception.
"""
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connect()
for (field_name,
field_type,
field_options,
@@ -184,41 +187,42 @@ class InheritableAccount_TestCase(unittest.TestCase):
except FieldError, error:
# this type of error is OK
pass
del account.hub.threadConnection
model.db_disconnect()
class Account_TestCase(InheritableAccount_TestCase):
def setUp(self):
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
self.db_url = DB_URL
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connection_str = 'sqlite://' + self.db_url
model.db_connect()
Account.createTable(ifNotExists = True)
ExampleAccount.createTable(ifNotExists = True)
del account.hub.threadConnection
model.db_disconnect()
self.account_class = Account
def tearDown(self):
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connect()
ExampleAccount.dropTable(ifExists = True)
Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + self.db_url]
account.hub.threadConnection.close()
del account.hub.threadConnection
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
def test_set_status(self):
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connect()
account11 = Account(user_jid="test1@test.com",
name="account11",
jid="account11@jcl.test.com")
account11.status = account.OFFLINE
self.assertEquals(account11.status, account.OFFLINE)
# TODO : test first_check attribute
del account.hub.threadConnection
model.db_disconnect()
def test_set_status_live_password(self):
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connect()
account11 = ExampleAccount(user_jid="test1@test.com",
name="account11",
jid="account11@jcl.test.com",
@@ -232,32 +236,33 @@ class Account_TestCase(InheritableAccount_TestCase):
self.assertEquals(account11.status, account.OFFLINE)
self.assertEquals(account11.waiting_password_reply, False)
self.assertEquals(account11.password, None)
del account.hub.threadConnection
model.db_disconnect()
class PresenceAccount_TestCase(InheritableAccount_TestCase):
def setUp(self):
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)
self.db_url = DB_URL
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connection_str = 'sqlite://' + self.db_url
model.db_connect()
Account.createTable(ifNotExists = True)
PresenceAccount.createTable(ifNotExists = True)
PresenceAccountExample.createTable(ifNotExists = True)
self.account = PresenceAccountExample(\
user_jid = "test1@test.com", \
name = "account11", \
jid = "account11@jcl.test.com")
del account.hub.threadConnection
user_jid="test1@test.com",
name="account11",
jid="account11@jcl.test.com")
model.db_disconnect()
self.account_class = PresenceAccount
def tearDown(self):
account.hub.threadConnection = connectionForURI('sqlite://' + self.db_url)
model.db_connect()
PresenceAccountExample.dropTable(ifExists = True)
PresenceAccount.dropTable(ifExists = True)
Account.dropTable(ifExists = True)
del TheURIOpener.cachedURIs['sqlite://' + self.db_url]
account.hub.threadConnection.close()
del account.hub.threadConnection
model.hub.threadConnection.close()
model.db_disconnect()
if os.path.exists(DB_PATH):
os.unlink(DB_PATH)

View File

@@ -28,6 +28,7 @@ from getopt import gnu_getopt
from sqlobject import *
import jcl.model as model
from jcl.model import account
from jcl.model.account import Account, PresenceAccount
@@ -48,35 +49,35 @@ class JCLRunner(object):
self.language = "en"
self.db_url = "sqlite:///var/spool/jabber/jcl.db"
self.pid_file = "/var/run/jabber/jcl.pid"
self.options = [("c:", "config-file=", None, \
" FILE\t\t\t\tConfiguration file to use", \
lambda arg: self.set_attr("config_file", arg)), \
("S:", "server=", "jabber", \
" SERVER_ADDRESS\t\t\tAddress of the Jabber server", \
lambda arg: self.set_attr("server", arg)), \
("P:", "port=", "jabber", \
" PORT\t\t\t\t\tPort of the Jabber server to connect the component", \
lambda arg: self.set_attr("port", int(arg))), \
("s:", "secret=", "jabber", \
" SECRET\t\t\t\tComponent password to connect to the Jabber server", \
lambda arg: self.set_attr("secret", arg)), \
("j:", "service-jid=", "jabber", \
" JID\t\t\t\tJID of the component", \
lambda arg: self.set_attr("service_jid", arg)), \
("l:", "language=", "jabber", \
" LANG\t\t\t\tDefault Language of the component", \
lambda arg: self.set_attr("language", arg)), \
("u:", "db-url=", "db", \
" URL\t\t\t\tDatabase URL", \
lambda arg: self.set_attr("db_url", arg)), \
("p:", "pid-file=", "component", \
" FILE\t\t\t\tPath of the PID file", \
lambda arg: self.set_attr("pid_file", arg)), \
("d", "debug", None, \
"\t\t\t\t\tEnable debug traces", \
lambda arg: self.set_attr("debug", True)), \
("h", "help", None, \
"\t\t\t\t\tThis help", \
self.options = [("c:", "config-file=", None,
" FILE\t\t\t\tConfiguration file to use",
lambda arg: self.set_attr("config_file", arg)),
("S:", "server=", "jabber",
" SERVER_ADDRESS\t\t\tAddress of the Jabber server",
lambda arg: self.set_attr("server", arg)),
("P:", "port=", "jabber",
" PORT\t\t\t\t\tPort of the Jabber server to connect the component",
lambda arg: self.set_attr("port", int(arg))),
("s:", "secret=", "jabber",
" SECRET\t\t\t\tComponent password to connect to the Jabber server",
lambda arg: self.set_attr("secret", arg)),
("j:", "service-jid=", "jabber",
" JID\t\t\t\tJID of the component",
lambda arg: self.set_attr("service_jid", arg)),
("l:", "language=", "jabber",
" LANG\t\t\t\tDefault Language of the component",
lambda arg: self.set_attr("language", arg)),
("u:", "db-url=", "db",
" URL\t\t\t\tDatabase URL",
lambda arg: self.set_attr("db_url", arg)),
("p:", "pid-file=", "component",
" FILE\t\t\t\tPath of the PID file",
lambda arg: self.set_attr("pid_file", arg)),
("d", "debug", None,
"\t\t\t\t\tEnable debug traces",
lambda arg: self.set_attr("debug", True)),
("h", "help", None,
"\t\t\t\t\tThis help",
lambda arg: self.print_help())]
self.logger = logging.getLogger()
self.logger.addHandler(logging.StreamHandler())
@@ -97,7 +98,7 @@ class JCLRunner(object):
def __apply_commandline_args(self, commandline_args, cleanopts):
for arg in commandline_args:
value = commandline_args[arg]
self.logger.debug("Applying argument " + arg + " = " + \
self.logger.debug("Applying argument " + arg + " = " +
value)
cleanopts[arg][1](value)
@@ -118,9 +119,9 @@ class JCLRunner(object):
if section is not None:
attr = opt.replace("-", "_")
config_property = self.config.get(section, attr)
self.logger.debug("Setting " + attr + " = " + \
config_property + \
" from configuration file " + \
self.logger.debug("Setting " + attr + " = " +
config_property +
" from configuration file " +
self.config_file)
set_func(config_property)
@@ -175,8 +176,8 @@ class JCLRunner(object):
def setup_db(self):
Account.createTable(ifNotExists = True)
PresenceAccount.createTable(ifNotExists = True)
Account.createTable(ifNotExists=True)
PresenceAccount.createTable(ifNotExists=True)
def setup_pidfile(self):
pidfile = open(self.pid_file, "w")
@@ -186,10 +187,11 @@ class JCLRunner(object):
def _run(self, run_func):
try:
self.setup_pidfile()
account.hub.threadConnection = connectionForURI(self.db_url)
model.db_connection_str = self.db_url
model.db_connect()
self.setup_db()
del account.hub.threadConnection
self.logger.debug(self.component_name + " v" + \
model.db_disconnect()
self.logger.debug(self.component_name + " v" +
self.component_version + " is starting ...")
run_func()
self.logger.debug(self.component_name + " is exiting")
@@ -199,12 +201,11 @@ class JCLRunner(object):
def run(self):
def run_func():
component = JCLComponent(jid = self.service_jid, \
secret = self.secret, \
server = self.server, \
port = self.port, \
db_connection_str = self.db_url, \
lang = Lang(self.language))
component = JCLComponent(jid=self.service_jid,
secret=self.secret,
server=self.server,
port=self.port,
lang=Lang(self.language))
component.run()
self._run(run_func)

View File

@@ -29,6 +29,7 @@ from sqlobject import *
import jcl
from jcl.runner import JCLRunner
import jcl.model as model
from jcl.model import account
from jcl.model.account import Account, PresenceAccount
@@ -125,11 +126,11 @@ class JCLRunner_TestCase(unittest.TestCase):
def do_nothing():
pass
self.runner._run(do_nothing)
account.hub.threadConnection = connectionForURI(self.runner.db_url)
model.db_connect()
# dropTable should succeed because tables should exist
Account.dropTable()
PresenceAccount.dropTable()
del account.hub.threadConnection
model.db_disconnect()
os.unlink(DB_PATH)
self.assertFalse(os.access("/tmp/jcl.pid", os.F_OK))