Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dax/jmc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--run_tests.py2
-rw-r--r--src/jmc/jabber/component.py98
-rw-r--r--src/jmc/jabber/tests/component.py206
-rw-r--r--src/jmc/model/account.py61
-rw-r--r--src/jmc/model/tests/account.py9
-rw-r--r--src/jmc/runner.py3
-rw-r--r--src/jmc/tests/runner.py3
7 files changed, 365 insertions, 17 deletions
diff --git a/run_tests.py b/run_tests.py
index edd7d95..29e2f65 100644
--- a/run_tests.py
+++ b/run_tests.py
@@ -44,7 +44,7 @@ def suite():
if __name__ == '__main__':
logger = logging.getLogger()
logger.addHandler(logging.StreamHandler())
- logger.setLevel(logging.INFO)
+ logger.setLevel(logging.CRITICAL)
coverage.erase()
coverage.start()
diff --git a/src/jmc/jabber/component.py b/src/jmc/jabber/component.py
index fd66f06..504abdd 100644
--- a/src/jmc/jabber/component.py
+++ b/src/jmc/jabber/component.py
@@ -1,4 +1,4 @@
-# -*- coding: UTF-8 -*-
+# -*- coding: utf-8 -*-
##
## component.py
## Login : David Rousselie <dax@happycoders.org>
@@ -22,13 +22,18 @@
##
import logging
+import re
+import sys
+
+from sqlobject import *
from pyxmpp.message import Message
-from jcl.model.account import PresenceAccount
+from jcl.model.account import Account, PresenceAccount
+from jcl.jabber.component import Handler, DefaultSubscribeHandler, DefaultUnsubscribeHandler, DefaultPresenceHandler
from jcl.jabber.feeder import FeederComponent, Feeder, MessageSender, HeadlineSender
-from jmc.model.account import MailAccount, IMAPAccount, POP3Account
+from jmc.model.account import MailAccount, IMAPAccount, POP3Account, SMTPAccount
from jmc.lang import Lang
class MailComponent(FeederComponent):
@@ -53,7 +58,16 @@ class MailComponent(FeederComponent):
lang = lang)
self.feeder = MailFeeder(self)
self.sender = MailSender(self)
- self.account_manager.account_classes = (IMAPAccount, POP3Account)
+ self.account_manager.account_classes = (IMAPAccount, POP3Account, SMTPAccount)
+
+ def authenticated(self):
+ """Register message handlers"""
+ FeederComponent.authenticated(self)
+ self.msg_handlers += [SendMailMessageHandler(), RootSendMailMessageHandler()]
+ self.subscribe_handlers += [MailSubscribeHandler()]
+ self.unsubscribe_handlers += [MailUnsubscribeHandler()]
+ self.available_handlers += [DefaultPresenceHandler()]
+ self.unavailable_handlers += [DefaultPresenceHandler()]
class MailFeeder(Feeder):
"""Email check"""
@@ -159,4 +173,80 @@ class MailSender(MessageSender, HeadlineSender):
MessageSender.send(self, to_account, subject, body)
elif to_account.action == MailAccount.DIGEST:
HeadlineSender.send(self, to_account, subject, body)
+
+class MailHandler(Handler):
+ """Define filter for email address in JID"""
+
+ def __init__(self):
+ Handler.__init__(self)
+ self.dest_jid_regexp = re.compile(".*%.*")
+
+ def filter(self, stanza):
+ """Return empty array if JID match '.*%.*@componentJID'"""
+ if self.dest_jid_regexp.match(stanza.get_to().node):
+ bare_from_jid = unicode(stanza.get_from().bare())
+ accounts = Account.select(Account.q.user_jid == bare_from_jid)
+ if accounts.count() == 0:
+ raise Exception()
+ else:
+ default_account = accounts.newClause(SMTPAccount.q.default_account == True)
+ if default_account.count() > 0:
+ return default_account
+ else:
+ return accounts
+ return None
+
+class SendMailMessageHandler(MailHandler):
+ def __init__(self):
+ MailHandler.__init__(self)
+ self.__logger = logging.getLogger("jmc.jabber.component.SendMailMessageHandler")
+
+ def handle(self, message, lang, accounts):
+ to_email = replace(message.get_to().node, '%', '@', 1)
+ accounts[0].send_email(to_email, message.get_subject(), message.get_body())
+
+class RootSendMailMessageHandler(SendMailMessageHandler):
+ def __init__(self):
+ SendMailMessageHandler.__init__(self)
+ self.__logger = logging.getLogger("jmc.jabber.component.RootSendMailMessageHandler")
+
+ def filter(self, message):
+ name = message.get_to().node
+ bare_from_jid = unicode(message.get_from().bare())
+ accounts = Account.select(\
+ AND(Account.q.name == name, \
+ Account.q.user_jid == bare_from_jid))
+ if accounts.count() != 1:
+ self.__logger.error("Account " + name + " for user " + bare_from_jid + " must be uniq")
+ return accounts
+
+ def handle(self, message, lang, accounts):
+ # TODO : parse "headers", or advanced addressing
+ to_email = ""
+ accounts[0].send_email(to_email, message.get_subject(), message.get_body())
+
+class MailSubscribeHandler(DefaultSubscribeHandler, MailHandler):
+ """Use DefaultSubscribeHandler handle method and MailHandler filter"""
+
+ def __init__(self):
+ DefaultSubscribeHandler.__init__(self)
+ MailHandler.__init__(self)
+
+ def filter(self, stanza):
+ return MailHandler.filter(self, stanza)
+
+ def handle(self, stanza, lang, accounts):
+ return DefaultSubscribeHandler.handle(self, stanza, lang, accounts)
+
+class MailUnsubscribeHandler(DefaultUnsubscribeHandler, MailHandler):
+ """Use DefaultUnsubscribeHandler handle method and MailHandler filter"""
+
+ def __init__(self):
+ DefaultUnsubscribeHandler.__init__(self)
+ MailHandler.__init__(self)
+ def filter(self, stanza):
+ return MailHandler.filter(self, stanza)
+
+ def handle(self, stanza, lang, accounts):
+ return DefaultUnsubscribeHandler.handle(self, stanza, lang, accounts)
diff --git a/src/jmc/jabber/tests/component.py b/src/jmc/jabber/tests/component.py
index 1c47536..d435c2f 100644
--- a/src/jmc/jabber/tests/component.py
+++ b/src/jmc/jabber/tests/component.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
##
## test_component.py
## Login : <dax@happycoders.org>
@@ -27,17 +28,21 @@ import sys
from sqlobject import *
from sqlobject.dbconnection import TheURIOpener
+from pyxmpp.presence import Presence
+from pyxmpp.message import Message
+
from jcl.model import account
from jcl.model.account import Account, PresenceAccount
+from jcl.jabber.tests.component import DefaultSubscribeHandler_TestCase, DefaultUnsubscribeHandler_TestCase
-from jmc.model.account import MailAccount, IMAPAccount, POP3Account
-from jmc.jabber.component import MailComponent
+from jmc.model.account import MailAccount, IMAPAccount, POP3Account, SMTPAccount
+from jmc.jabber.component import MailComponent, SendMailMessageHandler, RootSendMailMessageHandler, MailHandler, MailSubscribeHandler, MailUnsubscribeHandler
if sys.platform == "win32":
- DB_PATH = "/c|/temp/test.db"
+ DB_PATH = "/c|/temp/jmc_test.db"
else:
- DB_PATH = "/tmp/test.db"
+ DB_PATH = "/tmp/jmc_test.db"
DB_URL = DB_PATH# + "?debug=1&debugThreading=1"
class MockStream(object):
@@ -148,6 +153,7 @@ class MailComponent_TestCase(unittest.TestCase):
MailAccount.createTable(ifNotExists = True)
IMAPAccount.createTable(ifNotExists = True)
POP3Account.createTable(ifNotExists = True)
+ SMTPAccount.createTable(ifNotExists = True)
MockIMAPAccount.createTable(ifNotExists = True)
MockPOP3Account.createTable(ifNotExists = True)
del account.hub.threadConnection
@@ -156,6 +162,7 @@ class MailComponent_TestCase(unittest.TestCase):
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
MockPOP3Account.dropTable(ifExists = True)
MockIMAPAccount.dropTable(ifExists = True)
+ SMTPAccount.dropTable(ifExists = True)
POP3Account.dropTable(ifExists = True)
IMAPAccount.dropTable(ifExists = True)
MailAccount.dropTable(ifExists = True)
@@ -502,9 +509,196 @@ class MailComponent_TestCase(unittest.TestCase):
self.assertTrue(account11.has_connected)
self.assertTrue(account11.marked_all_as_read)
del account.hub.threadConnection
-
+
+class SendMailMessageHandler_TestCase(unittest.TestCase):
+ def setUp(self):
+ self.handler = SendMailMessageHandler()
+
+ def test_handle(self):
+ # TODO
+ pass
+
+class RootSendMailMessageHandler_TestCase(unittest.TestCase):
+ def setUp(self):
+ self.handler = RootSendMailMessageHandler()
+ if os.path.exists(DB_PATH):
+ os.unlink(DB_PATH)
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ Account.createTable(ifNotExists = True)
+ SMTPAccount.createTable(ifNotExists = True)
+ del account.hub.threadConnection
+
+ def tearDown(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ SMTPAccount.dropTable(ifExists = True)
+ Account.dropTable(ifExists = True)
+ del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
+ account.hub.threadConnection.close()
+ del account.hub.threadConnection
+ if os.path.exists(DB_PATH):
+ os.unlink(DB_PATH)
+
+ def test_filter(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(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", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertEquals(accounts.count(), 1)
+ del account.hub.threadConnection
+
+ def test_filter_wrong_dest(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user1@test.com", \
+ to_jid = "user2%test.com@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertEquals(accounts.count(), 0)
+ del account.hub.threadConnection
+
+ def test_filter_wrong_user(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user2@test.com", \
+ to_jid = "account11@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertEquals(accounts.count(), 0)
+ del account.hub.threadConnection
+
+class MailHandler_TestCase(unittest.TestCase):
+ def setUp(self):
+ self.handler = MailHandler()
+ if os.path.exists(DB_PATH):
+ os.unlink(DB_PATH)
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ Account.createTable(ifNotExists = True)
+ SMTPAccount.createTable(ifNotExists = True)
+ del account.hub.threadConnection
+
+ def tearDown(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ SMTPAccount.dropTable(ifExists = True)
+ Account.dropTable(ifExists = True)
+ del TheURIOpener.cachedURIs['sqlite://' + DB_URL]
+ account.hub.threadConnection.close()
+ del account.hub.threadConnection
+ if os.path.exists(DB_PATH):
+ os.unlink(DB_PATH)
+
+ def test_filter(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account11.default_account = True
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user1@test.com", \
+ to_jid = "user2%test.com@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertNotEquals(accounts, None)
+ self.assertEquals(accounts.count(), 1)
+ self.assertEquals(accounts[0].name, "account11")
+ del account.hub.threadConnection
+
+ def test_filter_no_default(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user1@test.com", \
+ to_jid = "user2%test.com@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertNotEquals(accounts, None)
+ self.assertEquals(accounts.count(), 2)
+ self.assertEquals(accounts[0].name, "account11")
+ del account.hub.threadConnection
+
+ def test_filter_wrong_dest(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user1@test.com", \
+ to_jid = "user2test.com@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ accounts = self.handler.filter(message)
+ self.assertEquals(accounts, None)
+ del account.hub.threadConnection
+
+ def test_filter_wrong_account(self):
+ account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
+ account11 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account11", \
+ jid = "account11@jcl.test.com")
+ account12 = SMTPAccount(user_jid = "user1@test.com", \
+ name = "account12", \
+ jid = "account12@jcl.test.com")
+ message = Message(from_jid = "user3@test.com", \
+ to_jid = "user2%test.com@jcl.test.com", \
+ stanza_type = "normal", \
+ body = "message")
+ try:
+ accounts = self.handler.filter(message)
+ except Exception, e:
+ self.assertNotEquals(e, None)
+ return
+ finally:
+ del account.hub.threadConnection
+ self.fail("No exception catched")
+
+class MailSubscribeHandler_TestCase(DefaultSubscribeHandler_TestCase, MailHandler_TestCase):
+ def setUp(self):
+ MailHandler_TestCase.setUp(self)
+ self.handler = MailSubscribeHandler()
+
+class MailUnsubscribeHandler_TestCase(DefaultUnsubscribeHandler_TestCase, MailHandler_TestCase):
+ def setUp(self):
+ MailHandler_TestCase.setUp(self)
+ self.handler = MailUnsubscribeHandler()
+
def suite():
- return unittest.makeSuite(MailComponent_TestCase, 'test')
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(MailComponent_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(SendMailMessageHandler_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(RootSendMailMessageHandler_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(MailHandler_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(MailUnsubscribeHandler_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(MailSubscribeHandler_TestCase, 'test'))
+ return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')
diff --git a/src/jmc/model/account.py b/src/jmc/model/account.py
index 247755c..65bb99a 100644
--- a/src/jmc/model/account.py
+++ b/src/jmc/model/account.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
##
## account.py
## Login : <dax@happycoders.org>
@@ -158,7 +159,7 @@ class MailAccount(PresenceAccount):
self.__logger = logging.getLogger("jmc.model.account.MailAccount")
self.connection = None
self.connected = False
- self.default_lang_class = Lang.en # TODO: use String
+ self.default_lang_class = Lang.en
def _get_register_fields(cls, real_class = None):
"""See Account._get_register_fields
@@ -338,7 +339,7 @@ class MailAccount(PresenceAccount):
raise NotImplementedError
class IMAPAccount(MailAccount):
- mailbox = StringCol(default = "INBOX") # TODO : set default INBOX in reg_form (use get_register_fields last field ?)
+ mailbox = StringCol(default = "INBOX")
def _get_register_fields(cls, real_class = None):
"""See Account._get_register_fields
@@ -515,3 +516,59 @@ class POP3Account(MailAccount):
self.get_mail_list()
self.lastmail = self.nb_mail
+
+class SMTPAccount(Account):
+ """Send email account"""
+
+ login = StringCol(default = "")
+ password = StringCol(default = None)
+ host = StringCol(default = "localhost")
+ port = IntCol(default = 110)
+ ssl = BoolCol(default = False)
+ store_password = BoolCol(default = True)
+ waiting_password_reply = BoolCol(default = False)
+ default_from = StringCol(default = "nobody@localhost")
+ default_account = BoolCol(default = False)
+
+ def _init(self, *args, **kw):
+ """SMTPAccount init
+ Initialize class attributes"""
+ Account._init(self, *args, **kw)
+ self.__logger = logging.getLogger("jmc.model.account.SMTPAccount")
+
+ def _get_register_fields(cls, real_class = None):
+ """See Account._get_register_fields
+ """
+ def password_post_func(password, default_func):
+ if password is None or password == "":
+ return None
+ return password
+
+ if real_class is None:
+ real_class = cls
+ return Account.get_register_fields(real_class) + \
+ [("login", "text-single", None, \
+ lambda field_value, default_func: account.mandatory_field(field_value), \
+ lambda : ""), \
+ ("password", "text-private", None, password_post_func, \
+ lambda : ""), \
+ ("host", "text-single", None, \
+ lambda field_value, default_func: account.mandatory_field(field_value), \
+ lambda : ""), \
+ ("port", "text-single", None, \
+ account.int_post_func, \
+ lambda : real_class.get_default_port()), \
+ ("ssl", "boolean", None, \
+ account.default_post_func, \
+ lambda : False), \
+ ("default_from", "text-single", None, \
+ lambda field_value, default_func: account.mandatory_field(field_value), \
+ lambda : ""), \
+ ("store_password", "boolean", None, \
+ account.default_post_func, \
+ lambda : True)]
+
+ get_register_fields = classmethod(_get_register_fields)
+
+ def send_email(self, to_email, subject, body):
+ pass
diff --git a/src/jmc/model/tests/account.py b/src/jmc/model/tests/account.py
index 64f77cc..fa5e96c 100644
--- a/src/jmc/model/tests/account.py
+++ b/src/jmc/model/tests/account.py
@@ -31,9 +31,9 @@ from sqlobject.dbconnection import TheURIOpener
from jcl.model import account
from jcl.model.account import Account, PresenceAccount
-from jmc.model.account import MailAccount, POP3Account, IMAPAccount
+from jmc.model.account import MailAccount, POP3Account, IMAPAccount, SMTPAccount
-from jcl.model.tests.account import PresenceAccount_TestCase
+from jcl.model.tests.account import Account_TestCase, PresenceAccount_TestCase
from jmc.model.tests import email_generator, server
if sys.platform == "win32":
@@ -388,12 +388,17 @@ class IMAPAccount_TestCase(unittest.TestCase):
register_fields = IMAPAccount.get_register_fields()
self.assertEquals(len(register_fields), 16)
+class SMTPAccount_TestCase(Account_TestCase):
+ def test_get_register_fields(self):
+ register_fields = SMTPAccount.get_register_fields()
+ self.assertEquals(len(register_fields), 7)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(MailAccount_TestCase, 'test'))
suite.addTest(unittest.makeSuite(POP3Account_TestCase, 'test'))
suite.addTest(unittest.makeSuite(IMAPAccount_TestCase, 'test'))
+ suite.addTest(unittest.makeSuite(SMTPAccount_TestCase, 'test'))
return suite
if __name__ == '__main__':
diff --git a/src/jmc/runner.py b/src/jmc/runner.py
index c103e9f..9d418e1 100644
--- a/src/jmc/runner.py
+++ b/src/jmc/runner.py
@@ -22,7 +22,7 @@
from jcl.runner import JCLRunner
-from jmc.model.account import MailAccount, IMAPAccount, POP3Account
+from jmc.model.account import MailAccount, IMAPAccount, POP3Account, SMTPAccount
from jmc.jabber.component import MailComponent
from jmc.lang import Lang
@@ -48,6 +48,7 @@ class JMCRunner(JCLRunner):
MailAccount.createTable(ifNotExists = True)
IMAPAccount.createTable(ifNotExists = True)
POP3Account.createTable(ifNotExists = True)
+ SMTPAccount.createTable(ifNotExists = True)
def run(self):
def run_func():
diff --git a/src/jmc/tests/runner.py b/src/jmc/tests/runner.py
index 6f818c4..9ae0c3e 100644
--- a/src/jmc/tests/runner.py
+++ b/src/jmc/tests/runner.py
@@ -33,7 +33,7 @@ from jcl.model.account import Account, PresenceAccount
import jmc
from jmc.runner import JMCRunner
-from jmc.model.account import MailAccount, IMAPAccount, POP3Account
+from jmc.model.account import MailAccount, IMAPAccount, POP3Account, SMTPAccount
if sys.platform == "win32":
DB_PATH = "/c|/temp/test.db"
@@ -136,6 +136,7 @@ class JMCRunner_TestCase(JCLRunner_TestCase):
MailAccount.dropTable()
IMAPAccount.dropTable()
POP3Account.dropTable()
+ SMTPAccount.dropTable()
del account.hub.threadConnection
os.unlink(DB_PATH)
self.assertFalse(os.access("/tmp/jmc.pid", os.F_OK))