package refactoring
- reorganize classes - make it run even when pysqlite2 is not installed - some tests to complete mailconnection_factory coverage darcs-hash:20060724214007-86b55-9b38308b8f645c2067c7b200f17532da62ec825c.gz
This commit is contained in:
0
src/jmc/__init__.py
Normal file
0
src/jmc/__init__.py
Normal file
0
src/jmc/email/__init__.py
Normal file
0
src/jmc/email/__init__.py
Normal file
479
src/jmc/email/mailconnection.py
Normal file
479
src/jmc/email/mailconnection.py
Normal file
@@ -0,0 +1,479 @@
|
||||
##
|
||||
## mailconnection.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri Jan 7 11:06:42 2005
|
||||
## $Id: mailconnection.py,v 1.11 2005/09/18 20:24:07 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 sys
|
||||
import logging
|
||||
import email
|
||||
import email.Header
|
||||
import traceback
|
||||
|
||||
import poplib
|
||||
import imaplib
|
||||
import socket
|
||||
|
||||
from jmc.utils.lang import Lang
|
||||
|
||||
IMAP4_TIMEOUT = 10
|
||||
POP3_TIMEOUT = 10
|
||||
|
||||
DO_NOTHING = 0
|
||||
DIGEST = 1
|
||||
RETRIEVE = 2
|
||||
default_encoding = "iso-8859-1"
|
||||
|
||||
## All MY* classes are implemented to add a timeout (settimeout)
|
||||
## while connecting
|
||||
class MYIMAP4(imaplib.IMAP4):
|
||||
def open(self, host = '', port = imaplib.IMAP4_PORT):
|
||||
"""Setup connection to remote server on "host:port"
|
||||
(default: localhost:standard IMAP4 port).
|
||||
This connection will be used by the routines:
|
||||
read, readline, send, shutdown.
|
||||
"""
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.settimeout(IMAP4_TIMEOUT)
|
||||
self.sock.connect((host, port))
|
||||
self.sock.settimeout(None)
|
||||
self.file = self.sock.makefile('rb')
|
||||
|
||||
class MYIMAP4_SSL(imaplib.IMAP4_SSL):
|
||||
def open(self, host = '', port = imaplib.IMAP4_SSL_PORT):
|
||||
"""Setup connection to remote server on "host:port".
|
||||
(default: localhost:standard IMAP4 SSL port).
|
||||
This connection will be used by the routines:
|
||||
read, readline, send, shutdown.
|
||||
"""
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.settimeout(IMAP4_TIMEOUT)
|
||||
self.sock.connect((host, port))
|
||||
self.sock.settimeout(None)
|
||||
self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
|
||||
|
||||
class MYPOP3(poplib.POP3):
|
||||
def __init__(self, host, port = poplib.POP3_PORT):
|
||||
self.host = host
|
||||
self.port = port
|
||||
msg = "getaddrinfo returns an empty list"
|
||||
self.sock = None
|
||||
for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
try:
|
||||
self.sock = socket.socket(af, socktype, proto)
|
||||
self.sock.settimeout(POP3_TIMEOUT)
|
||||
self.sock.connect(sa)
|
||||
self.sock.settimeout(None)
|
||||
except socket.error, msg:
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
if not self.sock:
|
||||
raise socket.error, msg
|
||||
self.file = self.sock.makefile('rb')
|
||||
self._debugging = 0
|
||||
self.welcome = self._getresp()
|
||||
|
||||
class MYPOP3_SSL(poplib.POP3_SSL):
|
||||
def __init__(self, host, port = poplib.POP3_SSL_PORT, keyfile = None, certfile = None):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.keyfile = keyfile
|
||||
self.certfile = certfile
|
||||
self.buffer = ""
|
||||
msg = "getaddrinfo returns an empty list"
|
||||
self.sock = None
|
||||
for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
try:
|
||||
self.sock = socket.socket(af, socktype, proto)
|
||||
self.sock.settimeout(POP3_TIMEOUT)
|
||||
self.sock.connect(sa)
|
||||
self.sock.settimeout(None)
|
||||
except socket.error, msg:
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
if not self.sock:
|
||||
raise socket.error, msg
|
||||
self.file = self.sock.makefile('rb')
|
||||
self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
|
||||
self._debugging = 0
|
||||
self.welcome = self._getresp()
|
||||
|
||||
class MailConnection(object):
|
||||
""" Wrapper to mail connection and action.
|
||||
Abstract class, do not represent real mail connection type"""
|
||||
|
||||
_logger = logging.getLogger("jmc.MailConnection")
|
||||
|
||||
def __init__(self, login = "", password = "", host = "", \
|
||||
port = 110, ssl = False):
|
||||
""" Initialize MailConnection object for common parameters of all
|
||||
connections types
|
||||
|
||||
:Parameters:
|
||||
- 'login': login used to connect mail server
|
||||
- 'password': password associated with 'login' to connect mail server
|
||||
- 'host': mail server hostname
|
||||
- 'port': mail server port
|
||||
- 'ssl': activate ssl to connect server
|
||||
|
||||
:Types:
|
||||
- 'login': string
|
||||
- 'password': string
|
||||
- 'host': string
|
||||
- 'port': int
|
||||
- 'ssl': boolean"""
|
||||
self.login = login
|
||||
self.password = password
|
||||
self.store_password = True
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.ssl = ssl
|
||||
self.status = "offline"
|
||||
self.connection = None
|
||||
self.chat_action = RETRIEVE
|
||||
self.online_action = RETRIEVE
|
||||
self.away_action = RETRIEVE
|
||||
self.xa_action = RETRIEVE
|
||||
self.dnd_action = RETRIEVE
|
||||
self.offline_action = DO_NOTHING
|
||||
self.interval = 5
|
||||
self.lastcheck = 0
|
||||
self.default_lang_class = Lang.en
|
||||
self.waiting_password_reply = False
|
||||
self.in_error = False
|
||||
self.live_email_only = False
|
||||
self.first_check = True
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.get_type() == other.get_type() \
|
||||
and self.login == other.login \
|
||||
and (not self.store_password or self.password == other.password) \
|
||||
and self.store_password == other.store_password \
|
||||
and self.host == other.host \
|
||||
and self.port == other.port \
|
||||
and self.ssl == other.ssl \
|
||||
and self.chat_action == other.chat_action \
|
||||
and self.online_action == other.online_action \
|
||||
and self.away_action == other.away_action \
|
||||
and self.xa_action == other.xa_action \
|
||||
and self.dnd_action == other.dnd_action \
|
||||
and self.offline_action == other.offline_action \
|
||||
and self.interval == other.interval \
|
||||
and self.live_email_only == other.live_email_only
|
||||
|
||||
def __str__(self):
|
||||
return self.get_type() + "#" + self.login + "#" + \
|
||||
(self.store_password and self.password or "/\\") + "#" \
|
||||
+ self.host + "#" + str(self.port) + "#" + str(self.chat_action) + "#" \
|
||||
+ str(self.online_action) + "#" + str(self.away_action) + "#" + \
|
||||
str(self.xa_action) + "#" + str(self.dnd_action) + "#" + \
|
||||
str(self.offline_action) + "#" + str(self.interval) + "#" + str(self.live_email_only)
|
||||
|
||||
def get_decoded_part(self, part, charset_hint):
|
||||
content_charset = part.get_content_charset()
|
||||
result = u""
|
||||
try:
|
||||
if content_charset:
|
||||
result = unicode(part.get_payload(decode=True).decode(content_charset))
|
||||
else:
|
||||
result = unicode(part.get_payload(decode=True))
|
||||
except Exception, e:
|
||||
try:
|
||||
result = unicode(part.get_payload(decode=True).decode("iso-8859-1"))
|
||||
except Exception, e:
|
||||
try:
|
||||
result = unicode(part.get_payload(decode=True).decode(default_encoding))
|
||||
except Exception, e:
|
||||
if charset_hint is not None:
|
||||
try:
|
||||
result = unicode(part.get_payload(decode=True).decode(charset_hint))
|
||||
except Exception, e:
|
||||
type, value, stack = sys.exc_info()
|
||||
print >>sys.stderr, "".join(traceback.format_exception
|
||||
(type, value, stack, 5))
|
||||
|
||||
return result
|
||||
|
||||
def format_message(self, email_msg, include_body = True):
|
||||
from_decoded = email.Header.decode_header(email_msg["From"])
|
||||
charset_hint = None
|
||||
email_from = u""
|
||||
result = u"From : "
|
||||
for i in range(len(from_decoded)):
|
||||
try:
|
||||
if from_decoded[i][1]:
|
||||
charset_hint = from_decoded[i][1]
|
||||
email_from += unicode(from_decoded[i][0].decode(from_decoded[i][1]))
|
||||
else:
|
||||
email_from += unicode(from_decoded[i][0])
|
||||
except Exception,e:
|
||||
try:
|
||||
email_from += unicode(from_decoded[i][0].decode("iso-8859-1"))
|
||||
except Exception, e:
|
||||
try:
|
||||
email_from += unicode(from_decoded[i][0].decode(default_encoding))
|
||||
except Exception, e:
|
||||
type, value, stack = sys.exc_info()
|
||||
print >>sys.stderr, "".join(traceback.format_exception
|
||||
(type, value, stack, 5))
|
||||
result += email_from + u"\n"
|
||||
|
||||
subject_decoded = email.Header.decode_header(email_msg["Subject"])
|
||||
result += u"Subject : "
|
||||
for i in range(len(subject_decoded)):
|
||||
try:
|
||||
if subject_decoded[i][1]:
|
||||
charset_hint = subject_decoded[i][1]
|
||||
result += unicode(subject_decoded[i][0].decode(subject_decoded[i][1]))
|
||||
else:
|
||||
result += unicode(subject_decoded[i][0])
|
||||
except Exception,e:
|
||||
try:
|
||||
result += unicode(subject_decoded[i][0].decode("iso-8859-1"))
|
||||
except Exception, e:
|
||||
try:
|
||||
result += unicode(subject_decoded[i][0].decode(default_encoding))
|
||||
except Exception, e:
|
||||
if charset_hint is not None:
|
||||
try:
|
||||
result += unicode(subject_decoded[i][0].decode(charset_hint))
|
||||
except Exception, e:
|
||||
type, value, stack = sys.exc_info()
|
||||
print >>sys.stderr, "".join(traceback.format_exception
|
||||
(type, value, stack, 5))
|
||||
|
||||
result += u"\n\n"
|
||||
|
||||
if include_body:
|
||||
action = {
|
||||
"text/plain" : lambda part: self.get_decoded_part(part, charset_hint),
|
||||
"text/html" : lambda part: "\n<<<HTML part skipped>>>\n"
|
||||
}
|
||||
for part in email_msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
if action.has_key(content_type):
|
||||
result += action[content_type](part) + u'\n'
|
||||
return (result, email_from)
|
||||
|
||||
def format_message_summary(self, email_msg):
|
||||
return self.format_message(email_msg, False)
|
||||
|
||||
def get_status_msg(self):
|
||||
return self.get_type() + "://" + self.login + "@" + self.host + ":" + \
|
||||
unicode(self.port)
|
||||
|
||||
def connect(self):
|
||||
pass
|
||||
|
||||
def disconnect(self):
|
||||
pass
|
||||
|
||||
def get_mail_list(self):
|
||||
return 0
|
||||
|
||||
def get_mail(self, index):
|
||||
return None
|
||||
|
||||
def get_mail_summary(self, index):
|
||||
return None
|
||||
|
||||
def get_next_mail_index(self, mail_list):
|
||||
pass
|
||||
|
||||
# Does not modify server state but just internal JMC state
|
||||
def mark_all_as_read(self):
|
||||
pass
|
||||
|
||||
def get_action(self):
|
||||
mapping = {"online": self.online_action,
|
||||
"chat": self.chat_action,
|
||||
"away": self.away_action,
|
||||
"xa": self.xa_action,
|
||||
"dnd": self.dnd_action,
|
||||
"offline": self.offline_action}
|
||||
if mapping.has_key(self.status):
|
||||
return mapping[self.status]
|
||||
return DO_NOTHING
|
||||
|
||||
action = property(get_action)
|
||||
|
||||
class IMAPConnection(MailConnection):
|
||||
_logger = logging.getLogger("jmc.IMAPConnection")
|
||||
|
||||
def __init__(self, login = "", password = "", host = "", \
|
||||
port = None, ssl = False, mailbox = "INBOX"):
|
||||
if not port:
|
||||
if ssl:
|
||||
port = 993
|
||||
else:
|
||||
port = 143
|
||||
MailConnection.__init__(self, login, password, host, port, ssl)
|
||||
self.mailbox = mailbox
|
||||
|
||||
def __eq__(self, other):
|
||||
return MailConnection.__eq__(self, other) \
|
||||
and self.mailbox == other.mailbox
|
||||
|
||||
def __str__(self):
|
||||
return MailConnection.__str__(self) + "#" + self.mailbox
|
||||
|
||||
def get_type(self):
|
||||
if self.ssl:
|
||||
return "imaps"
|
||||
return "imap"
|
||||
|
||||
def get_status(self):
|
||||
return MailConnection.get_status(self) + "/" + self.mailbox
|
||||
|
||||
def connect(self):
|
||||
IMAPConnection._logger.debug("Connecting to IMAP server " \
|
||||
+ self.login + "@" + self.host + ":" + str(self.port) \
|
||||
+ " (" + self.mailbox + "). SSL=" \
|
||||
+ str(self.ssl))
|
||||
if self.ssl:
|
||||
self.connection = MYIMAP4_SSL(self.host, self.port)
|
||||
else:
|
||||
self.connection = MYIMAP4(self.host, self.port)
|
||||
self.connection.login(self.login, self.password)
|
||||
|
||||
def disconnect(self):
|
||||
IMAPConnection._logger.debug("Disconnecting from IMAP server " \
|
||||
+ self.host)
|
||||
self.connection.logout()
|
||||
|
||||
def get_mail_list(self):
|
||||
IMAPConnection._logger.debug("Getting mail list")
|
||||
typ, data = self.connection.select(self.mailbox)
|
||||
typ, data = self.connection.search(None, 'RECENT')
|
||||
if typ == 'OK':
|
||||
return data[0].split(' ')
|
||||
return None
|
||||
|
||||
def get_mail(self, index):
|
||||
IMAPConnection._logger.debug("Getting mail " + str(index))
|
||||
typ, data = self.connection.select(self.mailbox, True)
|
||||
typ, data = self.connection.fetch(index, '(RFC822)')
|
||||
if typ == 'OK':
|
||||
return self.format_message(email.message_from_string(data[0][1]))
|
||||
return u"Error while fetching mail " + str(index)
|
||||
|
||||
def get_mail_summary(self, index):
|
||||
IMAPConnection._logger.debug("Getting mail summary " + str(index))
|
||||
typ, data = self.connection.select(self.mailbox, True)
|
||||
typ, data = self.connection.fetch(index, '(RFC822)')
|
||||
if typ == 'OK':
|
||||
return self.format_message_summary(email.message_from_string(data[0][1]))
|
||||
return u"Error while fetching mail " + str(index)
|
||||
|
||||
def get_next_mail_index(self, mail_list):
|
||||
if not mail_list or mail_list[0] == '':
|
||||
return None
|
||||
return mail_list.pop(0)
|
||||
|
||||
def mark_all_as_read(self):
|
||||
self.get_mail_list()
|
||||
|
||||
type = property(get_type)
|
||||
|
||||
class POP3Connection(MailConnection):
|
||||
_logger = logging.getLogger("jmc.POP3Connection")
|
||||
|
||||
def __init__(self, login = "", password = "", host = "", \
|
||||
port = None, ssl = False):
|
||||
if not port:
|
||||
if ssl:
|
||||
port = 995
|
||||
else:
|
||||
port = 110
|
||||
MailConnection.__init__(self, login, password, host, port, ssl)
|
||||
self.__nb_mail = 0
|
||||
self.__lastmail = 0
|
||||
|
||||
def get_type(self):
|
||||
if self.ssl:
|
||||
return "pop3s"
|
||||
return "pop3"
|
||||
|
||||
def connect(self):
|
||||
POP3Connection._logger.debug("Connecting to POP3 server " \
|
||||
+ self.login + "@" + self.host + ":" + str(self.port)\
|
||||
+ ". SSL=" + str(self.ssl))
|
||||
if self.ssl:
|
||||
self.connection = MYPOP3_SSL(self.host, self.port)
|
||||
else:
|
||||
self.connection = MYPOP3(self.host, self.port)
|
||||
try:
|
||||
self.connection.apop(self.login, self.password)
|
||||
except:
|
||||
self.connection.user(self.login)
|
||||
self.connection.pass_(self.password)
|
||||
|
||||
|
||||
def disconnect(self):
|
||||
POP3Connection._logger.debug("Disconnecting from POP3 server " \
|
||||
+ self.host)
|
||||
self.connection.quit()
|
||||
|
||||
def get_mail_list(self):
|
||||
POP3Connection._logger.debug("Getting mail list")
|
||||
count, size = self.connection.stat()
|
||||
self.__nb_mail = count
|
||||
return [str(i) for i in range(1, count + 1)]
|
||||
|
||||
def get_mail(self, index):
|
||||
POP3Connection._logger.debug("Getting mail " + str(index))
|
||||
ret, data, size = self.connection.retr(index)
|
||||
if ret[0:3] == '+OK':
|
||||
return self.format_message(email.message_from_string('\n'.join(data)))
|
||||
return u"Error while fetching mail " + str(index)
|
||||
|
||||
def get_mail_summary(self, index):
|
||||
POP3Connection._logger.debug("Getting mail summary " + str(index))
|
||||
ret, data, size = self.connection.retr(index)
|
||||
if ret[0:3] == '+OK':
|
||||
return self.format_message_summary(email.message_from_string('\n'.join(data)))
|
||||
return u"Error while fetching mail " + str(index)
|
||||
|
||||
def get_next_mail_index(self, mail_list):
|
||||
if self.__nb_mail == self.__lastmail:
|
||||
return None
|
||||
if self.__nb_mail < self.__lastmail:
|
||||
self.__lastmail = 0
|
||||
result = int(mail_list[self.__lastmail])
|
||||
self.__lastmail += 1
|
||||
return result
|
||||
|
||||
def mark_all_as_read(self):
|
||||
self.get_mail_list()
|
||||
self.__lastmail = self.__nb_mail
|
||||
|
||||
type = property(get_type)
|
||||
142
src/jmc/email/mailconnection_factory.py
Normal file
142
src/jmc/email/mailconnection_factory.py
Normal file
@@ -0,0 +1,142 @@
|
||||
##
|
||||
## mailconnection_factory.py
|
||||
## Login : David Rousselie <david.rousselie@happycoders.org>
|
||||
## Started on Fri May 20 10:41:46 2005 David Rousselie
|
||||
## $Id: mailconnection_factory.py,v 1.2 2005/09/18 20:24:07 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 jmc.email.mailconnection as mailconnection
|
||||
from jmc.email.mailconnection import IMAPConnection, POP3Connection
|
||||
|
||||
def get_new_mail_connection(type):
|
||||
""" Static method to return an empty MailConnection object of given type
|
||||
:Parameters:
|
||||
- 'type': type of connection to return : 'imap', 'imaps', 'pop3', 'pop3s'
|
||||
|
||||
:return: MailConnection of given type in parameter, None if unknown type
|
||||
|
||||
:returntype: 'MailConnection'
|
||||
"""
|
||||
if type == "imap":
|
||||
return IMAPConnection()
|
||||
elif type == "imaps":
|
||||
return IMAPConnection(ssl = True)
|
||||
elif type == "pop3":
|
||||
return POP3Connection()
|
||||
elif type == "pop3s":
|
||||
return POP3Connection(ssl = True)
|
||||
raise Exception, "Connection type \"" + type + "\" unknown"
|
||||
|
||||
def str_to_mail_connection(connection_string):
|
||||
""" Static methode to create a MailConnection object filled from string
|
||||
|
||||
:Parameters:
|
||||
- 'connection_string': string containing MailConnection parameters separated
|
||||
by '#'. ex: 'pop3#login#password#host#110#chat_action#online_action#away_action#xa_action#dnd_action#offline_action#check_interval#liv_email_only(#Mailbox)'
|
||||
|
||||
:Types:
|
||||
- 'connection_string': string
|
||||
|
||||
:return: MailConnection of given type found in string parameter
|
||||
|
||||
:returntype: 'MailConnection'
|
||||
"""
|
||||
arg_list = connection_string.split("#")
|
||||
# optionals values must be the at the beginning of the list to pop them
|
||||
# last
|
||||
arg_list.reverse()
|
||||
type = arg_list.pop()
|
||||
login = arg_list.pop()
|
||||
password = arg_list.pop()
|
||||
if password == "/\\":
|
||||
password = None
|
||||
store_password = False
|
||||
else:
|
||||
store_password = True
|
||||
host = arg_list.pop()
|
||||
port = int(arg_list.pop())
|
||||
chat_action = None
|
||||
online_action = None
|
||||
away_action = None
|
||||
xa_action = None
|
||||
dnd_action = None
|
||||
offline_action = None
|
||||
interval = None
|
||||
live_email_only = False
|
||||
result = None
|
||||
if type[0:4] == "imap":
|
||||
if len(arg_list) == 9:
|
||||
chat_action = int(arg_list.pop())
|
||||
online_action = int(arg_list.pop())
|
||||
away_action = int(arg_list.pop())
|
||||
xa_action = int(arg_list.pop())
|
||||
dnd_action = int(arg_list.pop())
|
||||
offline_action = int(arg_list.pop())
|
||||
interval = int(arg_list.pop())
|
||||
live_email_only = (arg_list.pop().lower() == "true")
|
||||
else:
|
||||
retrieve = bool(arg_list.pop() == "True")
|
||||
if retrieve:
|
||||
chat_action = online_action = away_action = xa_action = dnd_action = mailconnection.RETRIEVE
|
||||
else:
|
||||
chat_action = online_action = away_action = xa_action = dnd_action = mailconnection.DIGEST
|
||||
offline_action = mailconnection.DO_NOTHING
|
||||
mailbox = arg_list.pop()
|
||||
result = IMAPConnection(login = login, \
|
||||
password = password, \
|
||||
host = host, \
|
||||
ssl = (len(type) == 5), \
|
||||
port = port, \
|
||||
mailbox = mailbox)
|
||||
elif type[0:4] == "pop3":
|
||||
if len(arg_list) == 8:
|
||||
chat_action = int(arg_list.pop())
|
||||
online_action = int(arg_list.pop())
|
||||
away_action = int(arg_list.pop())
|
||||
xa_action = int(arg_list.pop())
|
||||
dnd_action = int(arg_list.pop())
|
||||
offline_action = int(arg_list.pop())
|
||||
interval = int(arg_list.pop())
|
||||
live_email_only = (arg_list.pop().lower() == "true")
|
||||
else:
|
||||
retrieve = bool(arg_list.pop() == "True")
|
||||
if retrieve:
|
||||
chat_action = online_action = away_action = xa_action = dnd_action = mailconnection.RETRIEVE
|
||||
else:
|
||||
chat_action = online_action = away_action = xa_action = dnd_action = mailconnection.DIGEST
|
||||
offline_action = mailconnection.DO_NOTHING
|
||||
result = POP3Connection(login = login, \
|
||||
password = password, \
|
||||
host = host, \
|
||||
port = port, \
|
||||
ssl = (len(type) == 5))
|
||||
if result is None:
|
||||
raise Exception, "Connection type \"" + type + "\" unknown"
|
||||
result.store_password = store_password
|
||||
result.chat_action = chat_action
|
||||
result.online_action = online_action
|
||||
result.away_action = away_action
|
||||
result.xa_action = xa_action
|
||||
result.dnd_action = dnd_action
|
||||
result.offline_action = offline_action
|
||||
if interval is not None:
|
||||
result.interval = interval
|
||||
result.live_email_only = live_email_only
|
||||
return result
|
||||
|
||||
|
||||
0
src/jmc/jabber/__init__.py
Normal file
0
src/jmc/jabber/__init__.py
Normal file
940
src/jmc/jabber/component.py
Normal file
940
src/jmc/jabber/component.py
Normal file
@@ -0,0 +1,940 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
##
|
||||
## component.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri Jan 7 11:06:42 2005
|
||||
## $Id: component.py,v 1.12 2005/09/18 20:24:07 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 re
|
||||
import signal
|
||||
import threading
|
||||
import thread
|
||||
import logging
|
||||
import sys
|
||||
import anydbm
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from jmc.email.mailconnection import *
|
||||
from jmc.jabber.x import *
|
||||
from jmc.utils.storage import *
|
||||
from jmc.utils.lang import Lang
|
||||
import jmc.email.mailconnection_factory
|
||||
|
||||
import pyxmpp.jabberd
|
||||
from pyxmpp.presence import Presence
|
||||
from pyxmpp.message import Message
|
||||
from pyxmpp.streambase import StreamError, FatalStreamError
|
||||
from pyxmpp.jid import JID
|
||||
from pyxmpp.jabber.disco import DiscoItems, DiscoItem, DiscoInfo, DiscoIdentity
|
||||
from pyxmpp.jabberd.component import Component
|
||||
|
||||
class ComponentFatalError(RuntimeError):
|
||||
pass
|
||||
|
||||
class MailComponent(Component):
|
||||
def __init__(self,
|
||||
jid,
|
||||
secret,
|
||||
server,
|
||||
port,
|
||||
default_lang,
|
||||
check_interval,
|
||||
spool_dir,
|
||||
storage,
|
||||
name):
|
||||
Component.__init__(self, \
|
||||
JID(jid), \
|
||||
secret, \
|
||||
server, \
|
||||
port, \
|
||||
disco_category = "gateway", \
|
||||
disco_type = "headline")
|
||||
self.__logger = logging.getLogger("jmc.jabber.Component")
|
||||
self.__shutdown = 0
|
||||
self.__lang = Lang(default_lang)
|
||||
self.__name = name
|
||||
|
||||
signal.signal(signal.SIGINT, self.signal_handler)
|
||||
signal.signal(signal.SIGTERM, self.signal_handler)
|
||||
|
||||
self.__interval = check_interval
|
||||
spool_dir += "/" + jid
|
||||
try:
|
||||
self.__storage = globals()[storage \
|
||||
+ "Storage"](2, spool_dir = spool_dir)
|
||||
except:
|
||||
print >>sys.stderr, "Cannot find " \
|
||||
+ storage + "Storage class"
|
||||
sys.exit(1)
|
||||
# dump registered accounts (save) every hour
|
||||
self.__count = 60
|
||||
self.running = False
|
||||
|
||||
def __del__(self):
|
||||
logging.shutdown()
|
||||
|
||||
""" Register Form creator """
|
||||
def get_reg_form(self, lang_class):
|
||||
reg_form = X()
|
||||
reg_form.xmlns = "jabber:x:data"
|
||||
reg_form.title = lang_class.register_title
|
||||
reg_form.instructions = lang_class.register_instructions
|
||||
reg_form.type = "form"
|
||||
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_name, \
|
||||
var = "name")
|
||||
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_login, \
|
||||
var = "login")
|
||||
|
||||
reg_form.add_field(type = "text-private", \
|
||||
label = lang_class.account_password, \
|
||||
var = "password")
|
||||
|
||||
reg_form.add_field(type = "boolean", \
|
||||
label = lang_class.account_password_store, \
|
||||
var = "store_password",
|
||||
value = "1")
|
||||
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_host, \
|
||||
var = "host")
|
||||
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_port, \
|
||||
var = "port")
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_type, \
|
||||
var = "type")
|
||||
field.add_option(label = "POP3", \
|
||||
value = "pop3")
|
||||
field.add_option(label = "POP3S", \
|
||||
value = "pop3s")
|
||||
field.add_option(label = "IMAP", \
|
||||
value = "imap")
|
||||
field.add_option(label = "IMAPS", \
|
||||
value = "imaps")
|
||||
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_mailbox, \
|
||||
var = "mailbox", \
|
||||
value = "INBOX")
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_ffc_action, \
|
||||
var = "chat_action", \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_online_action, \
|
||||
var = "online_action", \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_away_action, \
|
||||
var = "away_action", \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_xa_action, \
|
||||
var = "xa_action", \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_dnd_action, \
|
||||
var = "dnd_action", \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form.add_field(type = "list-single", \
|
||||
label = lang_class.account_offline_action, \
|
||||
var = "offline_action", \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
# default interval in config file
|
||||
reg_form.add_field(type = "text-single", \
|
||||
label = lang_class.account_check_interval, \
|
||||
var = "interval", \
|
||||
value = unicode(self.__interval))
|
||||
|
||||
reg_form.add_field(type = "boolean", \
|
||||
label = lang_class.account_live_email_only, \
|
||||
var = "live_email_only")
|
||||
|
||||
return reg_form
|
||||
|
||||
""" Register Form modifier for existing accounts """
|
||||
def get_reg_form_init(self, lang_class, jid, name):
|
||||
if not self.__storage.has_key((jid, name)):
|
||||
return None
|
||||
account = self.__storage[(jid, name)]
|
||||
reg_form_init = X()
|
||||
reg_form_init.xmlns = "jabber:x:data"
|
||||
reg_form_init.title = lang_class.update_title
|
||||
reg_form_init.instructions = lang_class.update_instructions % \
|
||||
(name,)
|
||||
reg_form_init.type = "form"
|
||||
|
||||
reg_form_init.add_field(type = "hidden", \
|
||||
label = lang_class.account_name, \
|
||||
var = "name", \
|
||||
value = name)
|
||||
|
||||
reg_form_init.add_field(type = "text-single", \
|
||||
label = lang_class.account_login, \
|
||||
var = "login", \
|
||||
value = account.login)
|
||||
|
||||
reg_form_init.add_field(type = "text-private", \
|
||||
label = lang_class.account_password, \
|
||||
var = "password", \
|
||||
value = account.password)
|
||||
|
||||
reg_form_init.add_field(type = "boolean", \
|
||||
label = lang_class.account_password_store, \
|
||||
var = "store_password", \
|
||||
value = str(account.store_password).lower())
|
||||
|
||||
reg_form_init.add_field(type = "text-single", \
|
||||
label = lang_class.account_host, \
|
||||
var = "host", \
|
||||
value = account.host)
|
||||
|
||||
reg_form_init.add_field(type = "text-single", \
|
||||
label = lang_class.account_port, \
|
||||
var = "port", \
|
||||
value = unicode(account.port))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_type, \
|
||||
var = "type", \
|
||||
value = account.get_type())
|
||||
if account.get_type()[0:4] == "imap":
|
||||
field.add_option(label = "IMAP", \
|
||||
value = "imap")
|
||||
field.add_option(label = "IMAPS", \
|
||||
value = "imaps")
|
||||
field = reg_form_init.add_field(type = "text-single", \
|
||||
label = lang_class.account_mailbox, \
|
||||
var = "mailbox")
|
||||
field.value = account.mailbox
|
||||
else:
|
||||
field.add_option(label = "POP3", \
|
||||
value = "pop3")
|
||||
field.add_option(label = "POP3S", \
|
||||
value = "pop3s")
|
||||
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_ffc_action, \
|
||||
var = "chat_action", \
|
||||
value = str(account.chat_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_online_action, \
|
||||
var = "online_action", \
|
||||
value = str(account.online_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_away_action, \
|
||||
var = "away_action", \
|
||||
value = str(account.away_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_xa_action, \
|
||||
var = "xa_action", \
|
||||
value = str(account.xa_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_dnd_action, \
|
||||
var = "dnd_action", \
|
||||
value = str(account.dnd_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
field = reg_form_init.add_field(type = "list-single", \
|
||||
label = lang_class.account_offline_action, \
|
||||
var = "offline_action", \
|
||||
value = str(account.offline_action))
|
||||
field.add_option(label = lang_class.action_nothing, \
|
||||
value = str(mailconnection.DO_NOTHING))
|
||||
field.add_option(label = lang_class.action_digest, \
|
||||
value = str(mailconnection.DIGEST))
|
||||
field.add_option(label = lang_class.action_retrieve, \
|
||||
value = str(mailconnection.RETRIEVE))
|
||||
|
||||
reg_form_init.add_field(type = "text-single", \
|
||||
label = lang_class.account_check_interval, \
|
||||
var = "interval", \
|
||||
value = str(account.interval))
|
||||
|
||||
reg_form_init.add_field(type = "boolean", \
|
||||
label = lang_class.account_live_email_only, \
|
||||
var = "live_email_only", \
|
||||
value = str(account.live_email_only).lower())
|
||||
|
||||
return reg_form_init
|
||||
|
||||
""" Looping method """
|
||||
def run(self, timeout):
|
||||
self.connect()
|
||||
self.running = True
|
||||
thread.start_new_thread(self.time_handler, ())
|
||||
try:
|
||||
while (not self.__shutdown and self.stream
|
||||
and not self.stream.eof and self.stream.socket is not None):
|
||||
try:
|
||||
self.stream.loop_iter(timeout)
|
||||
except (KeyboardInterrupt, SystemExit, FatalStreamError, \
|
||||
StreamError):
|
||||
raise
|
||||
except:
|
||||
self.__logger.exception("Exception cought:")
|
||||
finally:
|
||||
## TODO : for jid in self.__storage.keys(())
|
||||
## for name in self.__storage.keys((jid,))
|
||||
self.running = False
|
||||
if self.stream:
|
||||
for jid in self.__storage.keys(()):
|
||||
p = Presence(from_jid = unicode(self.jid), to_jid = jid, \
|
||||
stanza_type = "unavailable")
|
||||
self.stream.send(p)
|
||||
for jid, name in self.__storage.keys():
|
||||
if self.__storage[(jid, name)].status != "offline":
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = jid, \
|
||||
stanza_type = "unavailable")
|
||||
self.stream.send(p)
|
||||
threads = threading.enumerate()
|
||||
for th in threads:
|
||||
try:
|
||||
th.join(10 * timeout)
|
||||
except:
|
||||
pass
|
||||
for th in threads:
|
||||
try:
|
||||
th.join(timeout)
|
||||
except:
|
||||
pass
|
||||
self.disconnect()
|
||||
del self.__storage
|
||||
self.__logger.debug("Exitting normally")
|
||||
|
||||
""" Stop method handler """
|
||||
def signal_handler(self, signum, frame):
|
||||
self.__logger.debug("Signal %i received, shutting down..." % (signum,))
|
||||
self.__shutdown = 1
|
||||
|
||||
""" SIGALRM signal handler """
|
||||
def time_handler(self):
|
||||
self.__logger.debug("Check mail thread started...")
|
||||
while self.running:
|
||||
self.check_all_mail()
|
||||
self.__logger.debug("Resetting alarm signal")
|
||||
if self.__count == 0:
|
||||
self.__logger.debug("Dumping registered accounts Database")
|
||||
self.__storage.sync()
|
||||
self.__count = 60
|
||||
else:
|
||||
self.__count -= 1
|
||||
time.sleep(60)
|
||||
|
||||
""" Component authentication handler """
|
||||
def authenticated(self):
|
||||
self.__logger.debug("AUTHENTICATED")
|
||||
Component.authenticated(self)
|
||||
for jid in self.__storage.keys(()):
|
||||
p = Presence(from_jid = unicode(self.jid), \
|
||||
to_jid = jid, stanza_type = "probe")
|
||||
self.stream.send(p)
|
||||
for jid, name in self.__storage.keys():
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = jid, stanza_type = "probe")
|
||||
self.stream.send(p)
|
||||
|
||||
self.stream.set_iq_get_handler("query", "jabber:iq:version", \
|
||||
self.get_version)
|
||||
self.stream.set_iq_get_handler("query", "jabber:iq:register", \
|
||||
self.get_register)
|
||||
self.stream.set_iq_set_handler("query", "jabber:iq:register", \
|
||||
self.set_register)
|
||||
|
||||
self.stream.set_presence_handler("available", \
|
||||
self.presence_available)
|
||||
|
||||
self.stream.set_presence_handler("probe", \
|
||||
self.presence_available)
|
||||
|
||||
self.stream.set_presence_handler("unavailable", \
|
||||
self.presence_unavailable)
|
||||
|
||||
self.stream.set_presence_handler("unsubscribe", \
|
||||
self.presence_unsubscribe)
|
||||
self.stream.set_presence_handler("unsubscribed", \
|
||||
self.presence_unsubscribed)
|
||||
self.stream.set_presence_handler("subscribe", \
|
||||
self.presence_subscribe)
|
||||
self.stream.set_presence_handler("subscribed", \
|
||||
self.presence_subscribed)
|
||||
|
||||
self.stream.set_message_handler("normal", \
|
||||
self.message)
|
||||
|
||||
def stream_state_changed(self,state,arg):
|
||||
self.__logger.debug("*** State changed: %s %r ***" % (state,arg))
|
||||
|
||||
""" Discovery get info handler """
|
||||
def disco_get_info(self, node, iq):
|
||||
self.__logger.debug("DISCO_GET_INFO")
|
||||
di = DiscoInfo()
|
||||
if node is None:
|
||||
di.add_feature("jabber:iq:version")
|
||||
di.add_feature("jabber:iq:register")
|
||||
DiscoIdentity(di, self.__name, "headline", "newmail")
|
||||
else:
|
||||
di.add_feature("jabber:iq:register")
|
||||
return di
|
||||
|
||||
""" Discovery get nested nodes handler """
|
||||
def disco_get_items(self, node, iq):
|
||||
self.__logger.debug("DISCO_GET_ITEMS")
|
||||
lang_class = self.__lang.get_lang_class_from_node(iq.get_node())
|
||||
base_from_jid = unicode(iq.get_from().bare())
|
||||
di = DiscoItems()
|
||||
if not node:
|
||||
for name in self.__storage.keys((base_from_jid,)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
str_name = lang_class.connection_label % (account.get_type().upper(), name)
|
||||
if account.get_type()[0:4] == "imap":
|
||||
str_name += " (" + account.mailbox + ")"
|
||||
DiscoItem(di, JID(name + "@" + unicode(self.jid)), \
|
||||
name, str_name)
|
||||
return di
|
||||
|
||||
""" Get Version handler """
|
||||
def get_version(self, iq):
|
||||
self.__logger.debug("GET_VERSION")
|
||||
iq = iq.make_result_response()
|
||||
q = iq.new_query("jabber:iq:version")
|
||||
q.newTextChild(q.ns(), "name", self.__name)
|
||||
q.newTextChild(q.ns(), "version", "0.2.1")
|
||||
self.stream.send(iq)
|
||||
return 1
|
||||
|
||||
""" Send back register form to user """
|
||||
def get_register(self, iq):
|
||||
self.__logger.debug("GET_REGISTER")
|
||||
lang_class = self.__lang.get_lang_class_from_node(iq.get_node())
|
||||
base_from_jid = unicode(iq.get_from().bare())
|
||||
to = iq.get_to()
|
||||
iq = iq.make_result_response()
|
||||
q = iq.new_query("jabber:iq:register")
|
||||
if to and to != self.jid:
|
||||
self.get_reg_form_init(lang_class,
|
||||
base_from_jid,
|
||||
to.node).attach_xml(q)
|
||||
else:
|
||||
self.get_reg_form(lang_class).attach_xml(q)
|
||||
self.stream.send(iq)
|
||||
return 1
|
||||
|
||||
""" Handle user registration response """
|
||||
def set_register(self, iq):
|
||||
self.__logger.debug("SET_REGISTER")
|
||||
lang_class = self.__lang.get_lang_class_from_node(iq.get_node())
|
||||
to = iq.get_to()
|
||||
from_jid = iq.get_from()
|
||||
base_from_jid = unicode(from_jid.bare())
|
||||
remove = iq.xpath_eval("r:query/r:remove", \
|
||||
{"r" : "jabber:iq:register"})
|
||||
if remove:
|
||||
for name in self.__storage.keys((base_from_jid,)):
|
||||
self.__logger.debug("Deleting " + name + " for " + base_from_jid)
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = from_jid, \
|
||||
stanza_type = "unsubscribe")
|
||||
self.stream.send(p)
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = from_jid, \
|
||||
stanza_type = "unsubscribed")
|
||||
self.stream.send(p)
|
||||
del self.__storage[(base_from_jid, name)]
|
||||
p = Presence(from_jid = self.jid, to_jid = from_jid, \
|
||||
stanza_type = "unsubscribe")
|
||||
self.stream.send(p)
|
||||
p = Presence(from_jid = self.jid, to_jid = from_jid, \
|
||||
stanza_type = "unsubscribed")
|
||||
self.stream.send(p)
|
||||
return 1
|
||||
|
||||
query = iq.get_query()
|
||||
x = X()
|
||||
x.from_xml(query.children)
|
||||
|
||||
if x.fields.has_key("name"):
|
||||
name = x.fields["name"].value.lower()
|
||||
else:
|
||||
name = u""
|
||||
|
||||
if x.fields.has_key("login"):
|
||||
login = x.fields["login"].value
|
||||
else:
|
||||
login = u""
|
||||
|
||||
if x.fields.has_key("password"):
|
||||
password = x.fields["password"].value
|
||||
else:
|
||||
password = u""
|
||||
|
||||
store_password = x.fields.has_key("store_password") \
|
||||
and (x.fields["store_password"].value == "1")
|
||||
|
||||
if x.fields.has_key("host"):
|
||||
host = x.fields["host"].value
|
||||
else:
|
||||
host = u""
|
||||
|
||||
if x.fields.has_key("mailbox"):
|
||||
mailbox = x.fields["mailbox"].value
|
||||
else:
|
||||
mailbox = u""
|
||||
|
||||
if x.fields.has_key("type"):
|
||||
type = x.fields["type"].value
|
||||
else:
|
||||
type = u"pop3"
|
||||
|
||||
if x.fields.has_key("port") and x.fields["port"].value != "":
|
||||
port = int(x.fields["port"].value)
|
||||
else:
|
||||
port = None
|
||||
|
||||
if x.fields.has_key("chat_action") and x.fields["chat_action"].value != "":
|
||||
chat_action = int(x.fields["chat_action"].value)
|
||||
else:
|
||||
chat_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("online_action") and x.fields["online_action"].value != "":
|
||||
online_action = int(x.fields["online_action"].value)
|
||||
else:
|
||||
online_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("away_action") and x.fields["away_action"].value != "":
|
||||
away_action = int(x.fields["away_action"].value)
|
||||
else:
|
||||
away_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("xa_action") and x.fields["xa_action"].value != "":
|
||||
xa_action = int(x.fields["xa_action"].value)
|
||||
else:
|
||||
xa_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("dnd_action") and x.fields["dnd_action"].value != "":
|
||||
dnd_action = int(x.fields["dnd_action"].value)
|
||||
else:
|
||||
dnd_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("offline_action") and x.fields["offline_action"].value != "":
|
||||
offline_action = int(x.fields["offline_action"].value)
|
||||
else:
|
||||
offline_action = mailconnection.DO_NOTHING
|
||||
|
||||
if x.fields.has_key("interval") and x.fields["interval"].value != "":
|
||||
interval = int(x.fields["interval"].value)
|
||||
else:
|
||||
interval = None
|
||||
|
||||
live_email_only = x.fields.has_key("live_email_only") \
|
||||
and (x.fields["live_email_only"].value == "1")
|
||||
|
||||
self.__logger.debug(u"New Account: %s, %s, %s, %s, %s, %s, %s, %s %i %i %i %i %i %i %i %s" \
|
||||
% (name, login, password, str(store_password), host, str(port), \
|
||||
mailbox, type, chat_action, online_action, away_action, \
|
||||
xa_action, dnd_action, offline_action, interval, str(live_email_only)))
|
||||
|
||||
iq = iq.make_result_response()
|
||||
self.stream.send(iq)
|
||||
|
||||
if not self.__storage.has_key((base_from_jid,)):
|
||||
p = Presence(from_jid = self.jid, to_jid = base_from_jid, \
|
||||
stanza_type="subscribe")
|
||||
self.stream.send(p)
|
||||
|
||||
## Update account
|
||||
if port != None:
|
||||
socket = host + ":" + str(port)
|
||||
else:
|
||||
socket = host
|
||||
if self.__storage.has_key((base_from_jid, name)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
m = Message(from_jid = self.jid, to_jid = from_jid, \
|
||||
stanza_type = "normal", \
|
||||
subject = lang_class.update_account_message_subject \
|
||||
% (type, name), \
|
||||
body = lang_class.update_account_message_body \
|
||||
% (login, password, socket))
|
||||
self.stream.send(m)
|
||||
else:
|
||||
account = mailconnection_factory.get_new_mail_connection(type)
|
||||
m = Message(from_jid = self.jid, to_jid = from_jid, \
|
||||
stanza_type = "normal", \
|
||||
subject = lang_class.new_account_message_subject \
|
||||
% (type, name), \
|
||||
body = lang_class.new_account_message_body \
|
||||
% (login, password, socket))
|
||||
self.stream.send(m)
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = base_from_jid, \
|
||||
stanza_type="subscribe")
|
||||
self.stream.send(p)
|
||||
account.login = login
|
||||
account.password = password
|
||||
account.store_password = store_password
|
||||
account.host = host
|
||||
account.chat_action = chat_action
|
||||
account.online_action = online_action
|
||||
account.away_action = away_action
|
||||
account.xa_action = xa_action
|
||||
account.dnd_action = dnd_action
|
||||
account.offline_action = offline_action
|
||||
account.interval = interval
|
||||
account.live_email_only = live_email_only
|
||||
|
||||
if port:
|
||||
account.port = port
|
||||
|
||||
if type[0:4] == "imap":
|
||||
account.mailbox = mailbox
|
||||
self.__storage[(base_from_jid, name)] = account
|
||||
|
||||
return 1
|
||||
|
||||
def __send_presence_available(self, name, to_account, to_jid, show, lang_class):
|
||||
to_account.default_lang_class = lang_class
|
||||
to_account.first_check = True
|
||||
old_status = to_account.status
|
||||
# Make available to receive mail only when online
|
||||
if show is None:
|
||||
to_account.status = "online" # TODO get real status = (not show)
|
||||
else:
|
||||
to_account.status = show
|
||||
p = Presence(from_jid = name + "@" + \
|
||||
unicode(self.jid), \
|
||||
to_jid = to_jid, \
|
||||
status = to_account.get_status_msg(), \
|
||||
show = show, \
|
||||
stanza_type = "available")
|
||||
self.stream.send(p)
|
||||
if to_account.store_password == False \
|
||||
and old_status == "offline":
|
||||
self.__ask_password(name, to_jid, lang_class, to_account)
|
||||
|
||||
""" Handle presence availability """
|
||||
def presence_available(self, stanza):
|
||||
self.__logger.debug("PRESENCE_AVAILABLE")
|
||||
from_jid = stanza.get_from()
|
||||
base_from_jid = unicode(from_jid.bare())
|
||||
name = stanza.get_to().node
|
||||
lang_class = self.__lang.get_lang_class_from_node(stanza.get_node())
|
||||
show = stanza.get_show()
|
||||
self.__logger.debug("SHOW : " + str(show))
|
||||
if name:
|
||||
self.__logger.debug("TO : " + name + " " + base_from_jid)
|
||||
if not name and self.__storage.has_key((base_from_jid,)):
|
||||
p = Presence(from_jid = self.jid, \
|
||||
to_jid = from_jid, \
|
||||
status = \
|
||||
str(len(self.__storage.keys((base_from_jid,)))) \
|
||||
+ " accounts registered.", \
|
||||
show = show, \
|
||||
stanza_type = "available")
|
||||
self.stream.send(p)
|
||||
for name in self.__storage.keys((base_from_jid,)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
self.__send_presence_available(name, account, from_jid, show, lang_class)
|
||||
elif self.__storage.has_key((base_from_jid, name)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
self.__send_presence_available(name, account, from_jid, show, lang_class)
|
||||
return 1
|
||||
|
||||
def __ask_password(self, name, from_jid, lang_class, account):
|
||||
if not account.waiting_password_reply \
|
||||
and account.status != "offline":
|
||||
account.waiting_password_reply = True
|
||||
msg = Message(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = from_jid, \
|
||||
stanza_type = "normal", \
|
||||
subject = u"[PASSWORD] " + lang_class.ask_password_subject, \
|
||||
body = lang_class.ask_password_body % \
|
||||
(account.host, account.login))
|
||||
self.stream.send(msg)
|
||||
|
||||
""" handle presence unavailability """
|
||||
def presence_unavailable(self, stanza):
|
||||
self.__logger.debug("PRESENCE_UNAVAILABLE")
|
||||
from_jid = stanza.get_from()
|
||||
base_from_jid = unicode(from_jid.bare())
|
||||
if stanza.get_to() == unicode(self.jid):
|
||||
for name in self.__storage.keys((base_from_jid,)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
account.status = "offline"
|
||||
account.waiting_password_reply = False
|
||||
if account.store_password == False:
|
||||
self.__logger.debug("Forgetting password")
|
||||
account.password = None
|
||||
p = Presence(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = from_jid, \
|
||||
stanza_type = "unavailable")
|
||||
self.stream.send(p)
|
||||
|
||||
p = Presence(from_jid = stanza.get_to(), to_jid = from_jid, \
|
||||
stanza_type = "unavailable")
|
||||
self.stream.send(p)
|
||||
return 1
|
||||
|
||||
""" handle subscribe presence from user """
|
||||
def presence_subscribe(self, stanza):
|
||||
self.__logger.debug("PRESENCE_SUBSCRIBE")
|
||||
p = stanza.make_accept_response()
|
||||
self.stream.send(p)
|
||||
return 1
|
||||
|
||||
""" handle subscribed presence from user """
|
||||
def presence_subscribed(self, stanza):
|
||||
self.__logger.debug("PRESENCE_SUBSCRIBED")
|
||||
name = stanza.get_to().node
|
||||
from_jid = stanza.get_from()
|
||||
base_from_jid = unicode(from_jid.bare())
|
||||
if name is not None and self.__storage.has_key((base_from_jid, name)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
account.status = "online" # TODO retrieve real status
|
||||
p = Presence(from_jid = stanza.get_to(), to_jid = from_jid, \
|
||||
status = account.get_status_msg(), \
|
||||
stanza_type = "available")
|
||||
self.stream.send(p)
|
||||
return 1
|
||||
|
||||
""" handle unsubscribe presence from user """
|
||||
def presence_unsubscribe(self, stanza):
|
||||
self.__logger.debug("PRESENCE_UNSUBSCRIBE")
|
||||
name = stanza.get_to().node
|
||||
from_jid = stanza.get_from()
|
||||
base_from_jid = unicode(from_jid.bare())
|
||||
if name is not None and self.__storage.has_key((base_from_jid, name)):
|
||||
del self.__storage[(base_from_jid, name)]
|
||||
p = Presence(from_jid = stanza.get_to(), to_jid = from_jid, \
|
||||
stanza_type = "unsubscribe")
|
||||
self.stream.send(p)
|
||||
p = stanza.make_accept_response()
|
||||
self.stream.send(p)
|
||||
return 1
|
||||
|
||||
""" handle unsubscribed presence from user """
|
||||
def presence_unsubscribed(self, stanza):
|
||||
self.__logger.debug("PRESENCE_UNSUBSCRIBED")
|
||||
p = Presence(from_jid = stanza.get_to(), to_jid = stanza.get_from(), \
|
||||
stanza_type = "unavailable")
|
||||
self.stream.send(p)
|
||||
self.__storage.sync()
|
||||
return 1
|
||||
|
||||
""" Handle new message """
|
||||
def message(self, message):
|
||||
self.__logger.debug("MESSAGE: " + message.get_body())
|
||||
lang_class = self.__lang.get_lang_class_from_node(message.get_node())
|
||||
name = message.get_to().node
|
||||
base_from_jid = unicode(message.get_from().bare())
|
||||
if re.compile("\[PASSWORD\]").search(message.get_subject()) is not None \
|
||||
and self.__storage.has_key((base_from_jid, name)):
|
||||
account = self.__storage[(base_from_jid, name)]
|
||||
account.password = message.get_body()
|
||||
account.waiting_password_reply = False
|
||||
msg = Message(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = message.get_from(), \
|
||||
stanza_type = "normal", \
|
||||
subject = lang_class.password_saved_for_session, \
|
||||
body = lang_class.password_saved_for_session)
|
||||
self.stream.send(msg)
|
||||
return 1
|
||||
|
||||
""" Check mail account """
|
||||
def check_mail(self, jid, name):
|
||||
self.__logger.debug("\nCHECK_MAIL " + unicode(jid) + " " + name)
|
||||
account = self.__storage[(jid, name)]
|
||||
action = account.action
|
||||
|
||||
if action != mailconnection.DO_NOTHING:
|
||||
try:
|
||||
if account.password is None:
|
||||
self.__ask_password(name, jid, account.default_lang_class, account)
|
||||
return
|
||||
self.__logger.debug("Checking " + name)
|
||||
self.__logger.debug("\t" + account.login \
|
||||
+ "@" + account.host)
|
||||
account.connect()
|
||||
mail_list = account.get_mail_list()
|
||||
if action == mailconnection.RETRIEVE:
|
||||
mail_index = account.get_next_mail_index(mail_list)
|
||||
while mail_index is not None:
|
||||
(body, email_from) = account.get_mail(mail_index)
|
||||
mesg = Message(from_jid = name + "@" + \
|
||||
unicode(self.jid), \
|
||||
to_jid = jid, \
|
||||
stanza_type = "normal", \
|
||||
subject = account.default_lang_class.new_mail_subject % (email_from), \
|
||||
body = body)
|
||||
self.stream.send(mesg)
|
||||
mail_index = account.get_next_mail_index(mail_list)
|
||||
else:
|
||||
body = ""
|
||||
new_mail_count = 0
|
||||
mail_index = account.get_next_mail_index(mail_list)
|
||||
while mail_index:
|
||||
(tmp_body, from_email) = \
|
||||
account.get_mail_summary(mail_index)
|
||||
body += tmp_body + "\n----------------------------------\n"
|
||||
mail_index = account.get_next_mail_index(mail_list)
|
||||
new_mail_count += 1
|
||||
if body != "":
|
||||
mesg = Message(from_jid = name + "@" + \
|
||||
unicode(self.jid), \
|
||||
to_jid = jid, \
|
||||
stanza_type = "headline", \
|
||||
subject = account.default_lang_class.new_digest_subject % (new_mail_count), \
|
||||
body = body)
|
||||
self.stream.send(mesg)
|
||||
account.disconnect()
|
||||
account.in_error = False
|
||||
self.__logger.debug("\nCHECK_MAIL ends " + unicode(jid) + " " + name)
|
||||
except Exception,e:
|
||||
if account.in_error == False:
|
||||
account.in_error = True
|
||||
msg = Message(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = jid, \
|
||||
stanza_type = "error", \
|
||||
subject = account.default_lang_class.check_error_subject, \
|
||||
body = account.default_lang_class.check_error_body \
|
||||
% (e))
|
||||
self.stream.send(msg)
|
||||
type, value, stack = sys.exc_info()
|
||||
self.__logger.debug("Error while checking mail : %s\n%s" \
|
||||
% (e, "".join(traceback.format_exception
|
||||
(type, value, stack, 5))))
|
||||
|
||||
""" check mail handler """
|
||||
def check_all_mail(self):
|
||||
self.__logger.debug("CHECK_ALL_MAIL")
|
||||
for jid, name in self.__storage.keys():
|
||||
account = self.__storage[(jid, name)]
|
||||
if account.first_check and account.live_email_only:
|
||||
account.first_check = False
|
||||
if account.password is None:
|
||||
self.__ask_password(name, jid, account.default_lang_class, account)
|
||||
return
|
||||
try:
|
||||
account.connect()
|
||||
account.mark_all_as_read()
|
||||
account.disconnect()
|
||||
account.in_error = False
|
||||
except Exception,e:
|
||||
if account.in_error == False:
|
||||
account.in_error = True
|
||||
msg = Message(from_jid = name + "@" + unicode(self.jid), \
|
||||
to_jid = jid, \
|
||||
stanza_type = "error", \
|
||||
subject = account.default_lang_class.check_error_subject, \
|
||||
body = account.default_lang_class.check_error_body \
|
||||
% (e))
|
||||
self.stream.send(msg)
|
||||
type, value, stack = sys.exc_info()
|
||||
self.__logger.debug("Error while first checking mail : %s\n%s" \
|
||||
% (e, "".join(traceback.format_exception
|
||||
(type, value, stack, 5))))
|
||||
account.lastcheck += 1
|
||||
if account.lastcheck == account.interval:
|
||||
account.lastcheck = 0
|
||||
self.check_mail(jid, name)
|
||||
129
src/jmc/jabber/x.py
Normal file
129
src/jmc/jabber/x.py
Normal file
@@ -0,0 +1,129 @@
|
||||
##
|
||||
## x.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri Jan 7 11:06:42 2005
|
||||
## $Id: x.py,v 1.3 2005/09/18 20:24:07 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 sys
|
||||
from pyxmpp.stanza import common_doc
|
||||
|
||||
class Option(object):
|
||||
def __init__(self, label, value):
|
||||
self.__label = label
|
||||
self.__value = value
|
||||
|
||||
def get_xml(self, parent):
|
||||
if parent is None:
|
||||
option = common_doc.newChild(None, "option", None)
|
||||
else:
|
||||
option = parent.newChild(None, "option", None)
|
||||
option.setProp("label", self.__label)
|
||||
option.newChild(None, "value", self.__value)
|
||||
return option
|
||||
|
||||
class Field(object):
|
||||
def __init__(self, type, label, var, value):
|
||||
self.__type = type
|
||||
self.__label = label
|
||||
self.__var = var
|
||||
self.value = value
|
||||
self.__options = []
|
||||
|
||||
def add_option(self, label, value):
|
||||
option = Option(label, value)
|
||||
self.__options.append(option)
|
||||
return option
|
||||
|
||||
def get_xml(self, parent):
|
||||
if parent is None:
|
||||
raise Exception, "parent field should not be None"
|
||||
else:
|
||||
field = parent.newChild(None, "field", None)
|
||||
field.setProp("type", self.__type)
|
||||
if not self.__label is None:
|
||||
field.setProp("label", self.__label)
|
||||
if not self.__var is None:
|
||||
field.setProp("var", self.__var)
|
||||
if self.value:
|
||||
field.newChild(None, "value", self.value)
|
||||
for option in self.__options:
|
||||
option.get_xml(field)
|
||||
return field
|
||||
|
||||
class X(object):
|
||||
def __init__(self):
|
||||
self.fields = {}
|
||||
self.fields_tab = []
|
||||
self.title = None
|
||||
self.instructions = None
|
||||
self.type = None
|
||||
self.xmlns = None
|
||||
|
||||
def add_field(self, type = "fixed", label = None, var = None, value = ""):
|
||||
field = Field(type, label, var, value)
|
||||
self.fields[var] = field
|
||||
# fields_tab exist to keep added fields order
|
||||
self.fields_tab.append(field)
|
||||
return field
|
||||
|
||||
def attach_xml(self, iq):
|
||||
node = iq.newChild(None, "x", None)
|
||||
_ns = node.newNs(self.xmlns, None)
|
||||
node.setNs(_ns)
|
||||
if not self.title is None:
|
||||
node.newTextChild(None, "title", self.title)
|
||||
if not self.instructions is None:
|
||||
node.newTextChild(None, "instructions", self.instructions)
|
||||
for field in self.fields_tab:
|
||||
field.get_xml(node)
|
||||
return node
|
||||
|
||||
def from_xml(self, node):
|
||||
## TODO : test node type and ns and clean that loop !!!!
|
||||
while node and node.type != "element":
|
||||
node = node.next
|
||||
child = node.children
|
||||
while child:
|
||||
## TODO : test child type (element) and ns (jabber:x:data)
|
||||
if child.type == "element" and child.name == "field":
|
||||
if child.hasProp("type"):
|
||||
type = child.prop("type")
|
||||
else:
|
||||
type = ""
|
||||
|
||||
if child.hasProp("label"):
|
||||
label = child.prop("label")
|
||||
else:
|
||||
label = ""
|
||||
|
||||
if child.hasProp("var"):
|
||||
var = child.prop("var")
|
||||
else:
|
||||
var = ""
|
||||
|
||||
xval = child.children
|
||||
while xval and xval.name != "value":
|
||||
xval = xval.next
|
||||
if xval:
|
||||
value = xval.getContent()
|
||||
else:
|
||||
value = ""
|
||||
field = Field(type, label, var, value)
|
||||
self.fields[var] = field
|
||||
child = child.next
|
||||
91
src/jmc/jmc.py
Executable file
91
src/jmc/jmc.py
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/python -u
|
||||
##
|
||||
## Jabber Mail Component
|
||||
## jmc.py
|
||||
## Login : David Rousselie <david.rousselie@happycoders.org>
|
||||
## Started on Fri Jan 7 11:06:42 2005
|
||||
## $Id: jmc.py,v 1.3 2005/07/11 20:39:31 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 sys
|
||||
import os.path
|
||||
import logging
|
||||
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
del sys.setdefaultencoding
|
||||
|
||||
from jmc import mailconnection
|
||||
from jmc.component import MailComponent, ComponentFatalError
|
||||
from jmc.config import Config
|
||||
|
||||
def main(config_file = "jmc.xml", isDebug = 0):
|
||||
try:
|
||||
logger = logging.getLogger()
|
||||
logger.addHandler(logging.StreamHandler())
|
||||
if isDebug > 0:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
try:
|
||||
logger.debug("Loading config file " + config_file)
|
||||
config = Config(config_file)
|
||||
except:
|
||||
print >>sys.stderr, "Couldn't load config file:", \
|
||||
str(sys.exc_value)
|
||||
sys.exit(1)
|
||||
|
||||
pidfile = open(config.get_content("config/pidfile"), "w")
|
||||
pidfile.write(str(os.getpid()))
|
||||
pidfile.close()
|
||||
mailconnection.default_encoding = config.get_content("config/mail_default_encoding")
|
||||
print "creating component..."
|
||||
mailcomp = MailComponent(config.get_content("config/jabber/service"), \
|
||||
config.get_content("config/jabber/secret"), \
|
||||
config.get_content("config/jabber/server"), \
|
||||
int(config.get_content("config/jabber/port")), \
|
||||
config.get_content("config/jabber/language"), \
|
||||
int(config.get_content("config/check_interval")), \
|
||||
config.get_content("config/spooldir"), \
|
||||
config.get_content("config/storage"), \
|
||||
config.get_content("config/jabber/vCard/FN"))
|
||||
|
||||
print "starting..."
|
||||
mailcomp.run(1)
|
||||
except ComponentFatalError,e:
|
||||
print e
|
||||
print "Aborting."
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
var_option = 0
|
||||
file_num = 0
|
||||
index = 0
|
||||
debug_level = 0
|
||||
for opt in sys.argv:
|
||||
if var_option == 0 and len(opt) == 2 and opt == "-c":
|
||||
var_option += 1
|
||||
elif (var_option & 1) == 1 and len(opt) > 0:
|
||||
var_option += 1
|
||||
file_num = index
|
||||
if len(opt) == 2 and opt == "-D":
|
||||
debug_level = 1
|
||||
index += 1
|
||||
if (var_option & 2) == 2:
|
||||
main(sys.argv[file_num], debug_level)
|
||||
else:
|
||||
main("/etc/jabber/jmc.xml", debug_level)
|
||||
|
||||
0
src/jmc/utils/__init__.py
Normal file
0
src/jmc/utils/__init__.py
Normal file
47
src/jmc/utils/config.py
Normal file
47
src/jmc/utils/config.py
Normal file
@@ -0,0 +1,47 @@
|
||||
##
|
||||
## config.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri Jan 7 11:06:42 2005
|
||||
## $Id: config.py,v 1.2 2005/03/13 11:39:36 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005
|
||||
## 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 libxml2
|
||||
import os
|
||||
|
||||
from pyxmpp.jid import JID
|
||||
from jmc.jabber.component import ComponentFatalError
|
||||
|
||||
class Config:
|
||||
def __init__(self, config_file):
|
||||
self.doc = None
|
||||
self.config_file = config_file
|
||||
# libxml2.initializeCatalog()
|
||||
# libxml2.loadCatalog(os.path.join(data_dir, "catalog.xml"))
|
||||
parser = libxml2.createFileParserCtxt(config_file)
|
||||
# parser.validate(1)
|
||||
parser.parseDocument()
|
||||
if not parser.isValid():
|
||||
raise ComponentFatalError, "Invalid configuration"
|
||||
self.doc = parser.doc()
|
||||
|
||||
def get_content(self, xpath):
|
||||
return self.doc.xpathEval(xpath)[0].getContent()
|
||||
|
||||
def __del__(self):
|
||||
if self.doc:
|
||||
self.doc.freeDoc()
|
||||
210
src/jmc/utils/lang.py
Normal file
210
src/jmc/utils/lang.py
Normal file
@@ -0,0 +1,210 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##
|
||||
## lang.py
|
||||
## Login : David Rousselie <david.rousselie@happycoders.org>
|
||||
## Started on Sat Jan 28 16:37:11 2006 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2006 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
|
||||
##
|
||||
|
||||
|
||||
class Lang:
|
||||
def __init__(self, default_lang = "en"):
|
||||
self.default_lang = default_lang
|
||||
|
||||
def get_lang_from_node(self, node):
|
||||
lang = node.getLang()
|
||||
if lang is None:
|
||||
print "Using default lang " + self.default_lang
|
||||
lang = self.default_lang
|
||||
return lang
|
||||
|
||||
def get_lang_class(self, lang):
|
||||
return getattr(Lang, lang)
|
||||
|
||||
def get_lang_class_from_node(self, node):
|
||||
return self.get_lang_class(self.get_lang_from_node(node))
|
||||
|
||||
class en:
|
||||
register_title = u"Jabber Mail connection registration"
|
||||
register_instructions = u"Enter connection parameters"
|
||||
account_name = u"Connection name"
|
||||
account_login = u"Login"
|
||||
account_password = u"Password"
|
||||
account_password_store = u"Store password on Jabber server?"
|
||||
account_host = u"Host"
|
||||
account_port = u"Port"
|
||||
account_type = u"Mail server type"
|
||||
account_mailbox = u"Mailbox path (IMAP)"
|
||||
account_ffc_action = u"Action when state is 'Free For Chat'"
|
||||
account_online_action = u"Action when state is 'Online'"
|
||||
account_away_action = u"Action when state is 'Away'"
|
||||
account_xa_action = u"Action when state is 'Not Available'"
|
||||
account_dnd_action = u"Action when state is 'Do not Disturb'"
|
||||
account_offline_action = u"Action when state is 'Offline'"
|
||||
account_check_interval = u"Mail check interval (in minutes)"
|
||||
account_live_email_only = u"Reports only emails received while connected to Jabber"
|
||||
action_nothing = u"Do nothing"
|
||||
action_retrieve = u"Retrieve mail"
|
||||
action_digest = u"Send mail digest"
|
||||
update_title = u"Jabber mail connection update"
|
||||
update_instructions = u"Modifying connection '%s'"
|
||||
connection_label = u"%s connection '%s'"
|
||||
update_account_message_subject = u"Updated %s connection '%s'"
|
||||
update_account_message_body = u"Registered with username '%s' and " \
|
||||
"password '%s' on '%s'"
|
||||
new_account_message_subject = u"New %s connection '%s' created"
|
||||
new_account_message_body = u"Registered with " \
|
||||
"username '%s' and password '%s' on '%s'"
|
||||
ask_password_subject = u"Password request"
|
||||
ask_password_body = u"Reply to this message with the password " \
|
||||
"for the following account: \n" \
|
||||
"\thost = %s\n" \
|
||||
"\tlogin = %s\n"
|
||||
password_saved_for_session = u"Password will be kept during your Jabber session"
|
||||
check_error_subject = u"Error while checking emails."
|
||||
check_error_body = u"An error appears while checking emails:\n\t%s"
|
||||
new_mail_subject = u"New email from %s"
|
||||
new_digest_subject = u"%i new email(s)"
|
||||
|
||||
class fr:
|
||||
register_title = u"Enregistrement d'une nouvelle connexion à un serveur email."
|
||||
register_instructions = u"Entrer les paramètres de connexion"
|
||||
account_name = u"Nom de la connexion"
|
||||
account_login = u"Nom d'utilisateur"
|
||||
account_password = u"Mot de passe"
|
||||
account_password_store = u"Sauvegarder le mot de passe sur le serveur Jabber ?"
|
||||
account_host = u"Adresse du serveur email"
|
||||
account_port = u"Port du serveur email"
|
||||
account_type = u"Type du serveur email"
|
||||
account_mailbox = u"Chemin de la boîte email (IMAP)"
|
||||
account_ffc_action = u"Action lorsque l'état est 'Free For Chat'"
|
||||
account_online_action = u"Action lorsque l'état est 'Online'"
|
||||
account_away_action = u"Action lorsque l'état est 'Away'"
|
||||
account_xa_action = u"Action lorsque l'état est 'Not Available'"
|
||||
account_dnd_action = u"Action lorsque l'état est 'Do not Disturb'"
|
||||
account_offline_action = u"Action lorsque l'état est 'Offline'"
|
||||
account_check_interval = u"Interval de vérification de nouveaux emails (en minutes)"
|
||||
account_live_email_only = u"Vérifier les nouveaux emails seulement " \
|
||||
"lorsqu'une session Jabber est ouverte"
|
||||
action_nothing = u"Ne rien faire"
|
||||
action_retrieve = u"Récupérer l'email"
|
||||
action_digest = u"Envoyer un résumé"
|
||||
update_title = u"Mise à jour du compte JMC"
|
||||
update_instructions = u"Modification de la connexion '%s'"
|
||||
connection_label = u"Connexion %s '%s'"
|
||||
update_account_message_subject = u"La connexion %s '%s' a été mise à jour"
|
||||
update_account_message_body = u"Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'"
|
||||
new_account_message_subject = u"La connexion %s '%s' a été créée"
|
||||
new_account_message_body = u"Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'"
|
||||
ask_password_subject = u"Demande de mot de passe"
|
||||
ask_password_body = u"Répondre à ce message avec le mot de passe du " \
|
||||
"compte suivant : \n" \
|
||||
"\thost = %s\n" \
|
||||
"\tlogin = %s\n"
|
||||
password_saved_for_session = u"Le mot de passe sera garder tout au " \
|
||||
"long de la session Jabber."
|
||||
check_error_subject = u"Erreur lors de la vérification des emails."
|
||||
check_error_body = u"Une erreur est survenue lors de la vérification " \
|
||||
"des emails :\n\t%s"
|
||||
new_mail_subject = u"Nouvel email de %s"
|
||||
new_digest_subject = u"%i nouveau(x) email(s)"
|
||||
|
||||
class nl:
|
||||
register_title = u"Registratie van verbindingen voor Jabber Mail"
|
||||
register_instructions = u"Instellingen voor verbinding"
|
||||
account_name = u"Accountnaam"
|
||||
account_login = u"Gebruikersnaam"
|
||||
account_password = u"Wachtwoord"
|
||||
account_password_store = u"Wachtwoord opslaan op Jabber-server?"
|
||||
account_host = u"Server"
|
||||
account_port = u"Poort"
|
||||
account_type = u"Soort account"
|
||||
account_mailbox = u"Pad naar mailbox (IMAP)"
|
||||
account_ffc_action = u"Actie bij aanwezigheid 'Chat'"
|
||||
account_online_action = u"Actie bij aanwezigheid 'Beschikbaar'"
|
||||
account_away_action = u"Actie bij aanwezigheid 'Afwezig'"
|
||||
account_xa_action = u"Actie bij aanwezigheid 'Langdurig afwezig'"
|
||||
account_dnd_action = u"Actie bij aanwezigheid 'Niet storen'"
|
||||
account_offline_action = u"Actie bij aanwezigheid 'Niet beschikbaar'"
|
||||
account_check_interval = u"Controle-interval (in minuten)"
|
||||
account_live_email_only = u"Enkel controleren op e-mails als er een" \
|
||||
"verbinding is met Jabber"
|
||||
action_nothing = u"Niets doen"
|
||||
action_retrieve = u"E-mail ophalen"
|
||||
action_digest = u"Samenvatting verzenden"
|
||||
update_title = u"Bijwerken van JMC"
|
||||
update_instructions = u"Verbinding '%s' aanpassen"
|
||||
connection_label = u"%s verbinding '%s'"
|
||||
update_account_message_subject = u"Verbinding %s '%s' werd bijgewerkt"
|
||||
update_account_message_body = u"Geregistreerd met gebruikersnaam '%s'"\
|
||||
"en wachtwoord '%s' op '%s'"
|
||||
new_account_message_subject = u"Nieuwe %s verbinding '%s' aangemaakt"
|
||||
new_account_message_body = u"Geregistreerd met " \
|
||||
"gebruikersnaam '%s' en wachtwoord '%s' op '%s'"
|
||||
ask_password_subject = u"Wachtwoordaanvraag"
|
||||
ask_password_body = u"Antwoord dit bericht met het volgende wachtwoord" \
|
||||
"voor de volgende account: \n" \
|
||||
"\thost = %s\n" \
|
||||
"\tlogin = %s\n"
|
||||
password_saved_for_session = u"Het wachtwoord zal worden bewaard tijdens uw Jabber-sessie"
|
||||
check_error_subject = u"Fout tijdens controle op e-mails."
|
||||
check_error_body = u"Fout tijdens controle op e-mails:\n\t%s"
|
||||
new_mail_subject = u"Nieuwe e-mail van %s"
|
||||
new_digest_subject = u"%i nieuwe e-mail(s)"
|
||||
|
||||
class es:
|
||||
register_title = u"Registro de nueva cuenta de email"
|
||||
register_instructions = u"Inserta los datos para la nueva cuenta"
|
||||
account_name = u"Nombre para la cuenta"
|
||||
account_login = u"Usuario (login)"
|
||||
account_password = u"Contraseña"
|
||||
account_password_store = u"¿Guardar la contraseña en el servidor Jabber?"
|
||||
account_host = u"Host"
|
||||
account_port = u"Puerto"
|
||||
account_type = u"Tipo de servidor Mail"
|
||||
account_mailbox = u"Ruta del mailbox (solo para IMAP)"
|
||||
account_ffc_action = u"Acción para cuando tu estado sea 'Listopara hablar'"
|
||||
account_online_action = u"Acción para cuando tu estado sea 'Conectado'"
|
||||
account_away_action = u"Acción para cuando tu estado sea 'Ausente'"
|
||||
account_xa_action = u"Acción para cuando tu estado sea 'No disponible'"
|
||||
account_dnd_action = u"Acción para cuando tu estado sea 'No molestar'"
|
||||
account_offline_action = u"Acción para cuando tu estado sea 'Desconectado'"
|
||||
account_check_interval = u"Intervalo para comprobar emails nuevos (en minutos)"
|
||||
account_live_email_only = u"Avisarme de emails nuevos solo cuando esté conectado"
|
||||
action_nothing = u"No hacer nada"
|
||||
action_retrieve = u"Mostrarme el email"
|
||||
action_digest = u"Enviar resúmen"
|
||||
update_title = u"Actualización de cuenta de email"
|
||||
update_instructions = u"Modifica los datos de la cuenta '%s'"
|
||||
connection_label = u"%s conexión '%s'"
|
||||
update_account_message_subject = u"Actualizada %s conexión '%s'"
|
||||
update_account_message_body = u"Registrado con el usuario '%s' y " \
|
||||
"contraseña '%s' en '%s'"
|
||||
new_account_message_subject = u"Nueva %s conexión '%s' creada"
|
||||
new_account_message_body = u"Registrado con " \
|
||||
"usuario '%s' y contraseña '%s' en '%s'"
|
||||
ask_password_subject = u"Petición de contraseña"
|
||||
ask_password_body = u"Para avisarte de emails nuevos, contesta a este mensaje con la contraseña " \
|
||||
"de la cuenta: \n" \
|
||||
"\tHost = %s\n" \
|
||||
"\tUsuario = %s\n"
|
||||
password_saved_for_session = u"La contraseña será guardada para esta sesión únicamente."
|
||||
check_error_subject = u"Error al revisar los emails."
|
||||
check_error_body = u"Un error apareció al revisar los emails:\n\t%s"
|
||||
new_mail_subject = u"Nuevo email en %s"
|
||||
new_digest_subject = u"%i email(s) nuevo(s)"
|
||||
33
src/jmc/utils/release.py
Normal file
33
src/jmc/utils/release.py
Normal file
@@ -0,0 +1,33 @@
|
||||
##
|
||||
## release.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Mon Jul 24 22:37:00 2006 dax
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2006 dax
|
||||
## 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
|
||||
##
|
||||
|
||||
version = "0.2.2"
|
||||
author = "David Rousselie"
|
||||
email = "dax@happycoders.org"
|
||||
license = "GPL"
|
||||
long_description = """Jabber Mail Component
|
||||
|
||||
JMC is a jabber service to check email from POP3 and IMAP4 server and retrieve
|
||||
them or just a notification of new emails. Jabber users can register multiple
|
||||
email accounts.
|
||||
|
||||
"""
|
||||
297
src/jmc/utils/storage.py
Normal file
297
src/jmc/utils/storage.py
Normal file
@@ -0,0 +1,297 @@
|
||||
##
|
||||
## storage.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Wed Jul 20 20:26:53 2005 dax
|
||||
## $Id: storage.py,v 1.1 2005/09/18 20:24:07 dax Exp $
|
||||
##
|
||||
## Copyright (C) 2005 dax
|
||||
## 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 os
|
||||
import re
|
||||
import os.path
|
||||
import sys
|
||||
import anydbm
|
||||
import logging
|
||||
from UserDict import UserDict
|
||||
|
||||
import jmc.email.mailconnection_factory as mailconnection_factory
|
||||
|
||||
|
||||
class Storage(UserDict):
|
||||
def __init__(self, nb_pk_fields = 1, spool_dir = ".", db_file = None):
|
||||
UserDict.__init__(self)
|
||||
self.nb_pk_fields = nb_pk_fields
|
||||
if db_file is None:
|
||||
self._spool_dir = ""
|
||||
self.set_spool_dir(spool_dir)
|
||||
self.file = self._spool_dir + "/registered.db"
|
||||
else:
|
||||
spool_dir = os.path.dirname(db_file) or "."
|
||||
self.set_spool_dir(spool_dir)
|
||||
self.file = db_file
|
||||
self._registered = self.load()
|
||||
|
||||
def __setitem__(self, pk_tuple, obj):
|
||||
# print "Adding " + "#".join(map(str, pk_tuple)) + " = " + str(obj)
|
||||
self._registered[str("#".join(map(str, pk_tuple)))] = obj
|
||||
|
||||
def __getitem__(self, pk_tuple):
|
||||
# print "Getting " + "#".join(map(str, pk_tuple))
|
||||
if len(pk_tuple) == self.nb_pk_fields:
|
||||
return self._registered[str("#".join(map(str, pk_tuple)))]
|
||||
else:
|
||||
partial_key = str("#".join(map(str, pk_tuple)))
|
||||
regexp = re.compile(partial_key)
|
||||
return [self._registered[key]
|
||||
for key in self._registered.keys()
|
||||
if regexp.search(key)]
|
||||
|
||||
def __delitem__(self, pk_tuple):
|
||||
#print "Deleting " + "#".join(map(str, pk_tuple))
|
||||
del self._registered[str("#".join(map(str, pk_tuple)))]
|
||||
|
||||
def get_spool_dir(self):
|
||||
return self._spool_dir
|
||||
|
||||
def set_spool_dir(self, spool_dir):
|
||||
self._spool_dir = spool_dir
|
||||
if not os.path.isdir(self._spool_dir):
|
||||
os.makedirs(self._spool_dir)
|
||||
|
||||
spool_dir = property(get_spool_dir, set_spool_dir)
|
||||
|
||||
def has_key(self, pk_tuple):
|
||||
if len(pk_tuple) == self.nb_pk_fields:
|
||||
return self._registered.has_key(str("#".join(map(str, pk_tuple))))
|
||||
else:
|
||||
partial_key = str("#".join(map(str, pk_tuple)))
|
||||
regexp = re.compile("^" + partial_key)
|
||||
for key in self._registered.keys():
|
||||
if regexp.search(key):
|
||||
return True
|
||||
return False
|
||||
|
||||
def keys(self, pk_tuple = None):
|
||||
if pk_tuple is None:
|
||||
return [tuple(key.split("#")) for key in self._registered.keys()]
|
||||
else:
|
||||
level = len(pk_tuple)
|
||||
partial_key = str("#".join(map(str, pk_tuple)))
|
||||
regexp = re.compile("^" + partial_key)
|
||||
result = {}
|
||||
for key in self._registered.keys():
|
||||
if regexp.search(key):
|
||||
result[key.split("#")[level]] = None
|
||||
return result.keys()
|
||||
|
||||
def dump(self):
|
||||
for pk in self._registered.keys():
|
||||
print pk + " = " + str(self._registered[pk])
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
class DBMStorage(Storage):
|
||||
_logger = logging.getLogger("jmc.utils.DBMStorage")
|
||||
|
||||
def __init__(self, nb_pk_fields = 1, spool_dir = ".", db_file = None):
|
||||
# print "DBM INIT"
|
||||
Storage.__init__(self, nb_pk_fields, spool_dir, db_file)
|
||||
|
||||
def __del__(self):
|
||||
# print "DBM STOP"
|
||||
self.sync()
|
||||
|
||||
def load(self):
|
||||
str_registered = anydbm.open(self.file, \
|
||||
'c')
|
||||
result = {}
|
||||
try:
|
||||
for pk in str_registered.keys():
|
||||
result[pk] = mailconnection_factory.str_to_mail_connection(str_registered[pk])
|
||||
except Exception, e:
|
||||
print >>sys.stderr, "Cannot load registered.db : "
|
||||
print >>sys.stderr, e
|
||||
str_registered.close()
|
||||
return result
|
||||
|
||||
def sync(self):
|
||||
#print "DBM SYNC"
|
||||
self.store()
|
||||
|
||||
def __store(self, nb_pk_fields, registered, pk):
|
||||
if nb_pk_fields > 0:
|
||||
for key in registered.keys():
|
||||
if pk:
|
||||
self.__store(nb_pk_fields - 1, \
|
||||
registered[key], pk + "#" + key)
|
||||
else:
|
||||
self.__store(nb_pk_fields - 1, \
|
||||
registered[key], key)
|
||||
else:
|
||||
self.__str_registered[pk] = str(registered)
|
||||
# print "STORING : " + pk + " = " + str(registered)
|
||||
|
||||
def store(self):
|
||||
# print "DBM STORE"
|
||||
try:
|
||||
str_registered = anydbm.open(self.file, \
|
||||
'n')
|
||||
for pk in self._registered.keys():
|
||||
str_registered[pk] = str(self._registered[pk])
|
||||
except Exception, e:
|
||||
print >>sys.stderr, "Cannot save to registered.db : "
|
||||
print >>sys.stderr, e
|
||||
str_registered.close()
|
||||
|
||||
def __setitem__(self, pk_tuple, obj):
|
||||
Storage.__setitem__(self, pk_tuple, obj)
|
||||
self.sync()
|
||||
|
||||
def __delitem__(self, pk_tuple):
|
||||
Storage.__delitem__(self, pk_tuple)
|
||||
self.sync()
|
||||
|
||||
# Do not fail if pysqlite is not installed
|
||||
try:
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
|
||||
class SQLiteStorage(Storage):
|
||||
_logger = logging.getLogger("jmc.utils.SQLiteStorage")
|
||||
|
||||
def __init__(self, nb_pk_fields = 1, spool_dir = ".", db_file = None):
|
||||
self.__connection = None
|
||||
Storage.__init__(self, nb_pk_fields, spool_dir, db_file)
|
||||
|
||||
def create(self):
|
||||
SQLiteStorage._logger.debug("creating new Table")
|
||||
cursor = self.__connection.cursor()
|
||||
cursor.execute("""
|
||||
create table account(
|
||||
jid STRING,
|
||||
name STRING,
|
||||
type STRING,
|
||||
login STRING,
|
||||
password STRING,
|
||||
host STRING,
|
||||
port INTEGER,
|
||||
chat_action INTEGER,
|
||||
online_action INTEGER,
|
||||
away_action INTEGER,
|
||||
xa_action INTEGER,
|
||||
dnd_action INTEGER,
|
||||
offline_action INTEGER,
|
||||
interval INTEGER,
|
||||
live_email_only BOOLEAN,
|
||||
mailbox STRING,
|
||||
PRIMARY KEY(jid, name)
|
||||
)
|
||||
""")
|
||||
self.__connection.commit()
|
||||
cursor.close()
|
||||
|
||||
def __del__(self):
|
||||
self.__connection.close()
|
||||
|
||||
def sync(self):
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
if not os.path.exists(self.file):
|
||||
self.__connection = sqlite.connect(self.file)
|
||||
self.create()
|
||||
else:
|
||||
self.__connection = sqlite.connect(self.file)
|
||||
cursor = self.__connection.cursor()
|
||||
cursor.execute("""select * from account""")
|
||||
result = {}
|
||||
for row in cursor.fetchall():
|
||||
# print "Creating new " + row[self.nb_pk_fields] + " connection."
|
||||
account_type = row[self.nb_pk_fields]
|
||||
account = result["#".join(row[0:self.nb_pk_fields])] = mailconnection_factory.get_new_mail_connection(account_type)
|
||||
account.login = row[self.nb_pk_fields + 1]
|
||||
account.password = row[self.nb_pk_fields + 2]
|
||||
if account.password is None:
|
||||
account.store_password = False
|
||||
else:
|
||||
account.store_password = True
|
||||
account.host = row[self.nb_pk_fields + 3]
|
||||
account.port = int(row[self.nb_pk_fields + 4])
|
||||
account.chat_action = int(row[self.nb_pk_fields + 5])
|
||||
account.online_action = int(row[self.nb_pk_fields + 6])
|
||||
account.away_action = int(row[self.nb_pk_fields + 7])
|
||||
account.xa_action = int(row[self.nb_pk_fields + 8])
|
||||
account.dnd_action = int(row[self.nb_pk_fields + 9])
|
||||
account.offline_action = int(row[self.nb_pk_fields + 10])
|
||||
account.interval = int(row[self.nb_pk_fields + 11])
|
||||
account.live_email_only = (row[self.nb_pk_fields + 12] == 1)
|
||||
if account_type[0:4] == "imap":
|
||||
account.mailbox = row[self.nb_pk_fields + 13]
|
||||
# for field_index in range(self.nb_pk_fields + 1, len(row)):
|
||||
# print "\tSetting " + str(cursor.description[field_index][0]) + \
|
||||
# " to " + str(row[field_index])
|
||||
# setattr(account,
|
||||
# cursor.description[field_index][0],
|
||||
# row[field_index])
|
||||
cursor.close()
|
||||
return result
|
||||
|
||||
def __setitem__(self, pk_tuple, obj):
|
||||
Storage.__setitem__(self, pk_tuple, obj)
|
||||
cursor = self.__connection.cursor()
|
||||
mailbox = None
|
||||
password = None
|
||||
if obj.type[0:4] == "imap":
|
||||
mailbox = obj.mailbox
|
||||
if obj.store_password == True:
|
||||
password = obj.password
|
||||
cursor.execute("""
|
||||
insert or replace into account values
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(pk_tuple[0],
|
||||
pk_tuple[1],
|
||||
obj.type,
|
||||
obj.login,
|
||||
password,
|
||||
obj.host,
|
||||
obj.port,
|
||||
obj.chat_action,
|
||||
obj.online_action,
|
||||
obj.away_action,
|
||||
obj.xa_action,
|
||||
obj.dnd_action,
|
||||
obj.offline_action,
|
||||
obj.interval,
|
||||
obj.live_email_only,
|
||||
mailbox))
|
||||
self.__connection.commit()
|
||||
cursor.close()
|
||||
|
||||
def __delitem__(self, pk_tuple):
|
||||
Storage.__delitem__(self, pk_tuple)
|
||||
cursor = self.__connection.cursor()
|
||||
cursor.execute("""
|
||||
delete from account where jid = ? and name = ?
|
||||
""",
|
||||
(pk_tuple[0],
|
||||
pk_tuple[1]))
|
||||
self.__connection.commit()
|
||||
cursor.close()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
73
src/utils/backend_converter.py
Normal file
73
src/utils/backend_converter.py
Normal file
@@ -0,0 +1,73 @@
|
||||
##
|
||||
## jmc_backend_converter.py
|
||||
## Login : David Rousselie <david.rousselie@happycoders.org>
|
||||
## Started on Sun Jan 29 18:46:29 2006 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2006 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 sys
|
||||
sys.path.insert(0, "..")
|
||||
import types
|
||||
import jabber.storage
|
||||
import os.path
|
||||
import re
|
||||
|
||||
if len(sys.argv) != 5:
|
||||
print >>sys.stderr, "Usage: " + sys.argv[0] + " from_type from_db_file to_type to_db_file"
|
||||
print >>sys.stderr, "Supported DB type are :"
|
||||
for var in [aclass
|
||||
for aclass in dir(jabber.storage)
|
||||
if type(getattr(jabber.storage, aclass)) == types.ClassType \
|
||||
and re.compile(".+Storage$").match(aclass) is not None]:
|
||||
print >>sys.stderr, "\t" + var
|
||||
sys.exit(1)
|
||||
|
||||
from_storage_class = sys.argv[1]
|
||||
from_file = sys.argv[2]
|
||||
to_storage_class = sys.argv[3]
|
||||
to_file = sys.argv[4]
|
||||
|
||||
if not os.path.exists(from_file):
|
||||
print >>sys.stderr, from_file + " does not exist."
|
||||
sys.exit(1)
|
||||
|
||||
from jabber.storage import *
|
||||
|
||||
from_storage = None
|
||||
to_storage = None
|
||||
try:
|
||||
from_storage = globals()[from_storage_class + "Storage"](2, db_file = from_file)
|
||||
except Exception,e:
|
||||
print >>sys.stderr, e
|
||||
print >>sys.stderr, "Cannot find " + from_storage_class + "Storage class"
|
||||
sys.exit(1)
|
||||
try:
|
||||
to_storage = globals()[to_storage_class + "Storage"](2, db_file = to_file)
|
||||
except Exception,e:
|
||||
print >>sys.stderr, e
|
||||
print >>sys.stderr, "Cannot find " + to_storage_class + "Storage class"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
for jid, name in from_storage.keys():
|
||||
print "Converting " + jid + "/" + name + " from " + from_storage_class + \
|
||||
" to " + to_storage_class + "."
|
||||
to_storage[(jid, name)] = from_storage[(jid, name)]
|
||||
|
||||
to_storage.sync()
|
||||
|
||||
58
src/utils/backend_dump.py
Normal file
58
src/utils/backend_dump.py
Normal file
@@ -0,0 +1,58 @@
|
||||
##
|
||||
## dump.py
|
||||
## Login : David Rousselie <david.rousselie@happycoders.org>
|
||||
## Started on Mon Jan 30 21:43:38 2006 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2006
|
||||
## 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 sys
|
||||
sys.path.insert(0, "..")
|
||||
import types
|
||||
import jabber.storage
|
||||
import os.path
|
||||
import re
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print >>sys.stderr, "Usage: " + sys.argv[0] + " db_type db_file"
|
||||
print >>sys.stderr, "Supported DB type are :"
|
||||
for var in [aclass
|
||||
for aclass in dir(jabber.storage)
|
||||
if type(getattr(jabber.storage, aclass)) == types.ClassType \
|
||||
and re.compile(".+Storage$").match(aclass) is not None]:
|
||||
print >>sys.stderr, "\t" + var
|
||||
sys.exit(1)
|
||||
|
||||
from_storage_class = sys.argv[1]
|
||||
from_file = sys.argv[2]
|
||||
|
||||
if not os.path.exists(from_file):
|
||||
print >>sys.stderr, from_file + " does not exist."
|
||||
sys.exit(1)
|
||||
|
||||
from jabber.storage import *
|
||||
|
||||
try:
|
||||
from_storage = globals()[from_storage_class + "Storage"](2, db_file = from_file)
|
||||
except Exception,e:
|
||||
print >>sys.stderr, e
|
||||
print >>sys.stderr, "Cannot find " + from_storage_class + "Storage class"
|
||||
sys.exit(1)
|
||||
|
||||
for jid, name in from_storage.keys():
|
||||
print jid + "/" + name + " from " + from_storage_class + " = " + str(from_storage[(jid, name)])
|
||||
Reference in New Issue
Block a user