first import

first import between version 0.1.3 and 0.2

darcs-hash:20051127110300-684f5-0ed50cd0e86df9195cec2c1df070fdf24a6faeb5.gz
This commit is contained in:
dax
2005-11-27 12:03:00 +01:00
commit 9fa2df5563
27 changed files with 4351 additions and 0 deletions

0
jabber/__init__.py Normal file
View File

868
jabber/component.py Normal file
View File

@@ -0,0 +1,868 @@
##
## 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 logging
import sys
import anydbm
import os
import mailconnection
from mailconnection import *
from x import *
from storage import *
import 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, config):
Component.__init__(self, \
JID(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")), \
disco_category = "gateway", \
disco_type = "headline")
self.__logger = logging.getLogger("jabber.Component")
self.__shutdown = 0
# TODO : delete signals not known by Windows
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGPIPE, self.signal_handler)
signal.signal(signal.SIGHUP, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGALRM, self.time_handler)
self.__interval = int(config.get_content("config/check_interval"))
self.__config = config
# self.__registered = {}
try:
self.__storage = globals()[config.get_content("config/storage") + "Storage"]()
except:
print >>sys.stderr, "Cannot find " \
+ config.get_content("config/storage") + "Storage class"
exit(1)
self.__spool_dir = config.get_content("config/spooldir") + "/" + \
config.get_content("config/jabber/service")
self.__storage.spool_dir = self.__spool_dir
self.__storage.nb_pk_fields = 2
self.__reg_form = None
self.__reg_form_init = None
# dump registered accounts (save) at least every hour
self.__count = 60 / self.__interval
def __del__(self):
logging.shutdown()
""" Register Form creator """
def get_reg_form(self):
if self.__reg_form == None:
self.__reg_form = X()
self.__reg_form.xmlns = "jabber:x:data"
self.__reg_form.title = "Jabber Mail connection registration"
self.__reg_form.instructions = "Enter anything below"
self.__reg_form.type = "form"
self.__reg_form.add_field(type = "text-single", \
label = "Connection name", \
var = "name")
self.__reg_form.add_field(type = "text-single", \
label = "Login", \
var = "login")
self.__reg_form.add_field(type = "text-private", \
label = "Password", \
var = "password")
self.__reg_form.add_field(type = "text-single", \
label = "Host", \
var = "host")
self.__reg_form.add_field(type = "text-single", \
label = "Port", \
var = "port")
field = self.__reg_form.add_field(type = "list-single", \
label = "Mailbox 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")
self.__reg_form.add_field(type = "text-single", \
label = "Mailbox (IMAP)", \
var = "mailbox", \
value = "INBOX")
field = self.__reg_form.add_field(type = "list-single", \
label = "Action when state is 'Free For Chat'", \
var = "ffc_action", \
value = str(mailconnection.RETRIEVE))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form.add_field(type = "list-single", \
label = "Action when state is 'Online'", \
var = "online_action", \
value = str(mailconnection.RETRIEVE))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form.add_field(type = "list-single", \
label = "Action when state is 'Away'", \
var = "away_action", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form.add_field(type = "list-single", \
label = "Action when state is 'Extended Away'", \
var = "ea_action", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form.add_field(type = "list-single", \
label = "Action when state is 'Offline'", \
var = "offline_action", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
# default interval in config file
self.__reg_form.add_field(type = "text-single", \
label = "Mail check interval (in minutes)", \
var = "interval", \
value = "5")
return self.__reg_form
""" Register Form modifier for existing accounts """
def get_reg_form_init(self, jid, name):
if not self.__storage.has_key((jid, name)):
return None
account = self.__storage[(jid, name)]
if self.__reg_form_init == None:
self.__reg_form_init = X()
self.__reg_form_init.xmlns = "jabber:x:data"
self.__reg_form_init.title = "Jabber mail connection Modifier"
self.__reg_form_init.instructions = "Modifier for connection " + \
name
self.__reg_form_init.type = "form"
self.__reg_form_init.add_field(type = "fixed", \
label = "Connection name", \
var = "name", \
value = name)
self.__reg_form_init.add_field(type = "text-single", \
label = "Login", \
var = "login", \
value = account.login)
self.__reg_form_init.add_field(type = "text-private", \
label = "Password", \
var = "password", \
value = account.password)
self.__reg_form_init.add_field(type = "text-single", \
label = "Host", \
var = "host", \
value = account.host)
self.__reg_form_init.add_field(type = "text-single", \
label = "Port", \
var = "port", \
value = str(account.port))
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Mailbox type", \
var = "type", \
value = account.get_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")
self.__reg_form_init.add_field(type = "text-single", \
label = "Mailbox (IMAP)", \
var = "mailbox")
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Action when state is 'Free For Chat'", \
var = "ffc_action", \
value = str(account.ffc_action))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Action when state is 'Online'", \
var = "online_action", \
value = str(account.online_action))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Action when state is 'Away'", \
var = "away_action", \
value = str(account.away_action))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Action when state is 'Extended Away'", \
var = "ea_action", \
value = str(account.ea_action))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
field = self.__reg_form_init.add_field(type = "list-single", \
label = "Action when state is 'Offline'", \
var = "offline_action", \
value = str(account.offline_action))
field.add_option(label = "Do nothing", \
value = str(mailconnection.DO_NOTHING))
field.add_option(label = "Send mail digest", \
value = str(mailconnection.DIGEST))
field.add_option(label = "Retrieve mail", \
value = str(mailconnection.RETRIEVE))
self.__reg_form_init.add_field(type = "text-single", \
label = "Mail check interval (in minutes)", \
var = "interval", \
value = str(account.interval))
else:
self.__reg_form_init.fields["login"].value = account.login
self.__reg_form_init.fields["password"].value = account.password
self.__reg_form_init.fields["host"].value = account.host
self.__reg_form_init.fields["port"].value = str(account.port)
self.__reg_form_init.fields["type"].value = account.get_type()
self.__reg_form_init.fields["ffc_action"].value = str(account.ffc_action)
self.__reg_form_init.fields["online_action"].value = str(account.online_action)
self.__reg_form_init.fields["away_action"].value = str(account.away_action)
self.__reg_form_init.fields["ea_action"].value = str(account.ea_action)
self.__reg_form_init.fields["offline_action"].value = str(account.offline_action)
self.__reg_form_init.fields["interval"].value = str(account.interval)
if account.get_type()[0:4] == "imap":
self.__reg_form_init.fields["mailbox"].value = account.mailbox
else:
self.__reg_form_init.fields["mailbox"].value = "INBOX"
return self.__reg_form_init
""" Looping method """
def run(self, timeout):
self.connect()
# Set check mail timer
threading.Timer(self.__interval * 60, 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,))
# for jid in self.__storage.keys(()):
# p = Presence(from_jid = str(self.jid), to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
# for name in self.__registered[jid].keys():
# if self.__storage[(jid, name)].status != "offline":
# p = Presence(from_jid = name + "@" + str(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, signum, frame):
self.__logger.debug("Signal %i received, checking mail..." % (signum,))
self.check_all_mail()
self.__logger.debug("Resetting alarm signal")
threading.Timer(self.__interval * 60, self.time_handler)
if self.__count == 0:
self.__logger.debug("Dumping registered accounts Database")
self.__storage.sync()
self.__count = 60 / self.__interval
else:
self.__count -= 1
""" Component authentication handler """
def authenticated(self):
self.__logger.debug("AUTHENTICATED")
Component.authenticated(self)
# for jid in self.__registered.keys():
# p = Presence(from_jid = str(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):
print "*** 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, "Jabber Mail Component", "headline", "mail")
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")
base_from_jid = str(iq.get_from().bare())
di = DiscoItems()
if not node and self.__registered.has_key(base_from_jid):
for name in self.__registered[base_from_jid].keys():
account = self.__registered[base_from_jid][name]
str_name = account.get_type() + " connection " + name
if account.get_type()[0:4] == "imap":
str_name += " (" + account.mailbox + ")"
DiscoItem(di, JID(name + "@" + str(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", "Jabber Mail Component")
q.newTextChild(q.ns(), "version", "0.1")
self.stream.send(iq)
return 1
""" Send back register form to user """
def get_register(self, iq):
self.__logger.debug("GET_REGISTER")
base_from_jid = str(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(base_from_jid, to.node).attach_xml(q)
else:
self.get_reg_form().attach_xml(q)
self.stream.send(iq)
return 1
""" Handle user registration response """
def set_register(self, iq):
self.__logger.debug("SET_REGISTER")
to = iq.get_to()
from_jid = iq.get_from()
base_from_jid = str(from_jid.bare())
remove = iq.xpath_eval("r:query/r:remove", \
{"r" : "jabber:iq:register"})
if remove:
if self.__registered.has_key(base_from_jid):
for name in self.__registered[base_from_jid].keys():
p = Presence(from_jid = name + "@" + str(self.jid), \
to_jid = from_jid, \
stanza_type = "unsubscribe")
self.stream.send(p)
p = Presence(from_jid = name + "@" + str(self.jid), \
to_jid = from_jid, \
stanza_type = "unsubscribed")
self.stream.send(p)
del self.__registered[base_from_jid]
# self.__storage.
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""
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("ffc_action") and x.fields["ffc_action"].value != "":
ffc_action = int(x.fields["ffc_action"].value)
else:
ffc_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("ea_action") and x.fields["ea_action"].value != "":
ea_action = int(x.fields["ea_action"].value)
else:
ea_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
self.__logger.debug(u"New Account: %s, %s, %s, %s, %s, %s, %s %i %i %i %i %i %i" \
% (name, login, password, host, str(port), \
mailbox, type, ffc_action, online_action, away_action, \
ea_action, offline_action, interval))
iq = iq.make_result_response()
self.stream.send(iq)
if not self.__registered.has_key(base_from_jid):
self.__registered[base_from_jid] = {}
p = Presence(from_jid = self.jid, to_jid = from_jid.bare(), \
stanza_type="subscribe")
self.stream.send(p)
## Update account
if port != None:
socket = host + ":" + str(port)
else:
socket = host
if self.__registered[base_from_jid].has_key(name):
m = Message(from_jid = self.jid, to_jid = from_jid, \
stanza_type = "message", \
body = u"Updated %s connection '%s': Registered with "\
"username '%s' and password '%s' on '%s'" \
% (type, name, login, password, socket))
self.stream.send(m)
else:
m = Message(from_jid = self.jid, to_jid = from_jid, \
stanza_type = "message", \
body = u"New %s connection '%s': Registered with " \
"username '%s' and password '%s' on '%s'" \
% (type, name, login, password, socket))
self.stream.send(m)
p = Presence(from_jid = name + "@" + str(self.jid), \
to_jid = from_jid.bare(), \
stanza_type="subscribe")
self.stream.send(p)
self.__registered[base_from_jid][name] = \
mailconnection_factory.get_new_mail_connection(type)
self.__registered[base_from_jid][name].login = login
self.__registered[base_from_jid][name].password = password
self.__registered[base_from_jid][name].host = host
self.__registered[base_from_jid][name].ffc_action = ffc_action
self.__registered[base_from_jid][name].online_action = online_action
self.__registered[base_from_jid][name].away_action = away_action
self.__registered[base_from_jid][name].ea_action = ea_action
self.__registered[base_from_jid][name].offline_action = offline_action
if port:
self.__registered[base_from_jid][name].port = port
if interval:
self.__registered[base_from_jid][name].interval = interval
if type[0:4] == "imap":
self.__registered[base_from_jid][name].mailbox = mailbox
self.__storage.add([base_from_jid, name], self.__registered[base_from_jid][name])
return 1
""" Handle presence availability """
def presence_available(self, stanza):
self.__logger.debug("PRESENCE_AVAILABLE")
from_jid = stanza.get_from()
base_from_jid = str(from_jid.bare())
name = stanza.get_to().node
show = stanza.get_show()
self.__logger.debug("SHOW : " + str(show))
if self.__registered.has_key(base_from_jid):
if not name:
p = Presence(from_jid = self.jid, \
to_jid = from_jid, \
status = \
str(len(self.__registered[base_from_jid])) \
+ " accounts registered.", \
show = show, \
stanza_type = "available")
self.stream.send(p)
for name in self.__registered[base_from_jid].keys():
account = self.__registered[base_from_jid][name]
# Make available to receive mail only when online
account.status = "offline" # TODO get real status available = (not show)
p = Presence(from_jid = name + "@" + \
str(self.jid), \
to_jid = from_jid, \
status = account.get_status(), \
show = show, \
stanza_type = "available")
self.stream.send(p)
elif self.__registered[base_from_jid].has_key(name):
account = self.__registered[base_from_jid][name]
# Make available to receive mail only when online
account.status = "offline" # TODO get real status = (not show)
p = Presence(from_jid = name + "@" + \
str(self.jid), \
to_jid = from_jid, \
status = account.get_status(), \
show = show, \
stanza_type = "available")
self.stream.send(p)
return 1
""" handle presence unavailability """
def presence_unavailable(self, stanza):
self.__logger.debug("PRESENCE_UNAVAILABLE")
from_jid = stanza.get_from()
base_from_jid = str(from_jid.bare())
if stanza.get_to() == str(self.jid) \
and self.__registered.has_key(base_from_jid):
for name in self.__registered[base_from_jid].keys():
self.__registered[base_from_jid][name].status = "offline" # TODO get real status
p = Presence(from_jid = name + "@" + str(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 = str(from_jid.bare())
if self.__registered.has_key(base_from_jid) \
and self.__registered[base_from_jid].has_key(name):
account = self.__registered[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(), \
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 = str(from_jid.bare())
if self.__registered.has_key(base_from_jid) \
and self.__registered[base_from_jid].has_key(name):
del self.__registered[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())
name = message.get_to().node
base_from_jid = str(message.get_from().bare())
if name and self.__registered.has_key(base_from_jid):
body = message.get_body()
cmd = body.split(' ')
if cmd[0] == "check":
self.check_mail(base_from_jid, name)
elif cmd[0] == "dump":
body = ""
for jid in self.__registered.keys():
for name in self.__registered[jid].keys():
body += name + " for user " + jid
msg = Message(from_jid = self.jid, to_jid = base_from_jid, \
stanza_type = "message", \
body = body)
self.stream.send(msg)
return 1
# """ Store registered sessions """
# def store_registered(self):
# self.__logger.debug("STORE_REGISTERED")
# try:
# if not os.path.isdir(self.__spool_dir):
# os.makedirs(self.__spool_dir)
# str_registered = anydbm.open(self.__spool_dir + "/registered.db", \
# 'n')
# self.__logger.debug("Saving registered sessions")
# for jid in self.__registered.keys():
# for name in self.__registered[jid].keys():
# self.__logger.debug("\t" + jid + ", _" + name + "_")
# str_registered[jid + '#' + name] = \
# str(self.__storage[(jid, name)])
# str_registered.close()
# except Exception, e:
# print >>sys.stderr, "Cannot save to registered.db : "
# print >>sys.stderr, e
# """ Load previously registered sessions """
# def load_registered(self):
# self.__logger.debug("LOAD_REGISTERED")
# try:
# if not os.path.isdir(self.__spool_dir):
# os.makedirs(self.__spool_dir)
# str_registered = anydbm.open(self.__spool_dir + "/registered.db", \
# 'c')
# self.__logger.debug("Loading previously registered sessions")
# for key in str_registered.keys():
# jid, name = key.split('#')
# if not self.__registered.has_key(jid):
# self.__registered[jid] = {}
# self.__storage[(jid, name)] = \
# mailconnection_factory.str_to_mail_connection(str_registered[key])
# # self.__storage[(jid, name)].name = name
# self.__logger.debug("Loaded data for %s on %s :" % (jid, name))
# self.__logger.debug("\t %s" % (self.__storage[(jid, name)]))
# str_registered.close()
# except Exception, e:
# print >>sys.stderr, "Cannot load registered.db : "
# print >>sys.stderr, e
""" Check mail account """
def check_mail(self, jid, name):
self.__logger.debug("CHECK_MAIL")
account = self.__storage[(jid, name)]
action = account.action
if action != "nothing":
try:
self.__logger.debug("Checking " \
+ name)
self.__logger.debug("\t" + account.login \
+ "@" + account.host)
account.connect()
mail_list = account.get_mail_list()
if not mail_list or mail_list[0] == '':
num = 0
else:
num = len(mail_list)
# unseen mails checked by external client
if num < account.lastcheck:
account.lastcheck = 0
if action == "retrieve":
while account.lastcheck < num:
body = account.get_mail(int(mail_list[account.lastcheck]))
mesg = Message(from_jid = name + "@" + \
str(self.jid), \
to_jid = jid, \
stanza_type = "message", \
body = body)
self.stream.send(mesg)
account.lastcheck += 1
else:
body = ""
while account.lastcheck < num:
body += \
account.get_mail_summary(int(mail_list[account.lastcheck])) \
+ "\n----------------------------------\n"
account.lastcheck += 1
if body != "":
mesg = Message(from_jid = name + "@" + \
str(self.jid), \
to_jid = jid, \
stanza_type = "headline", \
body = body)
self.stream.send(mesg)
account.disconnect()
except Exception,e:
self.__logger.debug("Error while checking mail : %s" \
% (e))
""" check mail handler """
def check_all_mail(self):
self.__logger.debug("CHECK_ALL_MAIL")
for jid in self.__registered.keys():
for name in self.__registered[jid].keys():
self.check_mail(jid, name)

47
jabber/config.py Normal file
View 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 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()

373
jabber/mailconnection.py Normal file
View File

@@ -0,0 +1,373 @@
##
## 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 email
import email.Header
import poplib
import imaplib
import socket
IMAP4_TIMEOUT = 10
POP3_TIMEOUT = 10
DO_NOTHING = 0
DIGEST = 1
RETRIEVE = 2
## 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"""
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.host = host
self.port = port
self.ssl = ssl
self.lastcheck = 0
self.status = "offline"
self.connection = None
self.ffc_action = RETRIEVE
self.online_action = RETRIEVE
self.away_action = RETRIEVE
self.ea_action = RETRIEVE
self.offline_action = DO_NOTHING
def __eq__(self, other):
return self.get_type() == other.get_type() \
and self.login == other.login \
and self.password == other.password \
and self.host == other.host \
and self.port == other.port \
and self.ssl == other.ssl \
and self.ffc_action == other.ffc_action \
and self.online_action == other.online_action \
and self.away_action == other.away_action \
and self.ea_action == other.ea_action \
and self.offline_action == other.offline_action
def __str__(self):
return self.get_type() + "#" + self.login + "#" + self.password + "#" \
+ self.host + "#" + str(self.port) + "#" + str(self.ffc_action) + "#" \
+ str(self.online_action) + "#" + str(self.away_action) + "#" + \
str(self.ea_action) + "#" + str(self.offline_action)
def get_decoded_part(self, part):
content_charset = part.get_content_charset()
if content_charset:
return part.get_payload(decode=True).decode(content_charset)
else:
return part.get_payload(decode=True)
def format_message(self, email_msg, include_body = True):
from_decoded = email.Header.decode_header(email_msg["From"])
result = u"From : "
for i in range(len(from_decoded)):
if from_decoded[i][1]:
result += from_decoded[i][0].decode(from_decoded[i][1])
else:
result += from_decoded[i][0]
result += "\n"
subject_decoded = email.Header.decode_header(email_msg["Subject"])
result += u"Subject : "
for i in range(len(subject_decoded)):
if subject_decoded[i][1]:
result += subject_decoded[i][0].decode(subject_decoded[i][1])
else:
result += subject_decoded[i][0]
result += "\n\n"
if include_body:
action = {
"text/plain" : lambda part: self.get_decoded_part(part),
"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) + '\n'
return result
def format_message_summary(self, email_msg):
return self.format_message(email_msg, False)
def get_type(self):
return "UNKNOWN"
def get_status(self):
return self.get_type() + "://" + self.login + "@" + self.host + ":" + \
str(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_action(self):
mapping = {"online": self.online_action,
"ffc": self.ffc_action,
"away": self.away_action,
"ea": self.ea_action,
"offline": self.offline_action}
if mapping.has_key(self.status):
return mapping[self.status]
return "nothing"
action = property(get_action)
class IMAPConnection(MailConnection):
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):
print >>sys.stderr, "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):
print >>sys.stderr, "Disconnecting from IMAP server " \
+ self.host
self.connection.logout()
def get_mail_list(self):
print >>sys.stderr, "Getting mail list"
typ, data = self.connection.select(self.mailbox)
typ, data = self.connection.search(None, 'UNSEEN')
if typ == 'OK':
return data[0].split(' ')
return None
def get_mail(self, index):
print >>sys.stderr, "Getting mail " + str(index)
typ, data = self.connection.select(self.mailbox)
typ, data = self.connection.fetch(index, '(RFC822)')
self.connection.store(index, "FLAGS", "UNSEEN")
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):
print >>sys.stderr, "Getting mail summary " + str(index)
typ, data = self.connection.select(self.mailbox)
typ, data = self.connection.fetch(index, '(RFC822)')
self.connection.store(index, "FLAGS", "UNSEEN")
if typ == 'OK':
return self.format_message_summary(email.message_from_string(data[0][1]))
return u"Error while fetching mail " + str(index)
class POP3Connection(MailConnection):
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)
def get_type(self):
if self.ssl:
return "pop3s"
return "pop3"
def connect(self):
print >>sys.stderr, "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):
print >>sys.stderr, "Disconnecting from POP3 server " \
+ self.host
self.connection.quit()
def get_mail_list(self):
print >>sys.stderr, "Getting mail list"
count, size = self.connection.stat()
return [str(i) for i in range(1, count + 1)]
def get_mail(self, index):
print >>sys.stderr, "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):
print >>sys.stderr, "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)

View File

@@ -0,0 +1,108 @@
##
## mailconnection_factory.py
## Login : <adro8400@claralinux>
## Started on Fri May 20 10:41:46 2005 adro8400
## $Id: mailconnection_factory.py,v 1.2 2005/09/18 20:24:07 dax Exp $
##
## Copyright (C) 2005 adro8400
## 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
##
from mailconnection import IMAPConnection, POP3Connection
""" 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'"""
def get_new_mail_connection(type):
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"
""" 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#True'
:Types:
- 'connection_string': string
:return: MailConnection of given type found in string parameter
:returntype: 'MailConnection'"""
def str_to_mail_connection(connection_string):
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()
host = arg_list.pop()
port = int(arg_list.pop())
ffc_action = int(arg_list.pop())
online_action = int(arg_list.pop())
away_action = int(arg_list.pop())
ea_action = int(arg_list.pop())
offline_action = int(arg_list.pop())
result = None
if type == "imap":
mailbox = arg_list.pop()
result = IMAPConnection(login = login, \
password = password, \
host = host, \
ssl = False, \
port = port, \
mailbox = mailbox)
elif type == "imaps":
mailbox = arg_list.pop()
result = IMAPConnection(login = login, \
password = password, \
host = host, \
port = port, \
ssl = True, \
mailbox = mailbox)
elif type == "pop3":
result = POP3Connection(login = login, \
password = password, \
host = host, \
port = port, \
ssl = False)
elif type == "pop3s":
result = POP3Connection(login = login, \
password = password, \
host = host, \
port = port, \
ssl = True)
if result is None:
raise Exception, "Connection type \"" + type + "\" unknown"
result.ffc_action = ffc_action
result.online_action = online_action
result.away_action = away_action
result.ea_action = ea_action
result.offline_action = offline_action
return result

180
jabber/storage.py Normal file
View File

@@ -0,0 +1,180 @@
##
## storage.py
## Login : <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 mailconnection_factory
from UserDict import UserDict
class Storage(UserDict):
def __init__(self, nb_pk_fields = 1, spool_dir = "."):
UserDict.__init__(self)
self._spool_dir = ""
self.set_spool_dir(spool_dir)
self.nb_pk_fields = nb_pk_fields
self.file = self._spool_dir + "/registered.db"
# return hash of hash (jid and name)
def load(self):
pass
def sync(self):
pass
def store(self, nb_pk_fields, registered, pk):
pass
def add(self, key_list, obj):
pass
def remove(self, key_list):
pass
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)
class DBMStorage(Storage):
def __init__(self, nb_pk_fields = 1, spool_dir = "."):
# print "DBM INIT"
Storage.__init__(self, nb_pk_fields, spool_dir)
self.__str_registered = anydbm.open(self.file, \
'c')
def __del__(self):
# print "DBM STOP"
self.__str_registered.close()
def load(self):
# print "DBM LOAD"
result = {}
try:
for pk in self.__str_registered.keys():
pk_list = pk.split('#')
obj = result
key = None
while pk_list:
key = pk_list.pop(0)
if pk_list:
if not obj.has_key(key):
obj[key] = {}
obj = obj[key]
obj[key] = mailconnection_factory.str_to_mail_connection(self.__str_registered[pk])
except Exception, e:
print >>sys.stderr, "Cannot load registered.db : "
print >>sys.stderr, e
return result
def sync(self):
# print "DBM SYNC"
self.__str_registered.close()
self.__str_registered = anydbm.open(self.file, \
'c')
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, registered):
# print "DBM STORE"
try:
self.__store(self.nb_pk_fields, registered, "")
# Force file synchronisation
self.sync()
except Exception, e:
print >>sys.stderr, "Cannot save to registered.db : "
print >>sys.stderr, e
def __setitem__(self, pk_tuple, obj):
print "Adding " + "#".join(pk_tuple) + " = " + str(obj)
self.__str_registered["#".join(pk_tuple)] = str(obj)
self.sync()
def __getitem__(self, pk_tuple):
print "Getting " + "#".join(pk_tuple)
if len(pk_tuple) == self.nb_pk_fields:
return mailconnection_factory.str_to_mail_connection(self.__str_registered["#".join(pk_tuple)])
else:
partial_key = "#".join(pk_tuple)
regexp = re.compile(partial_key)
return [mailconnection_factory.str_to_mail_connection(self.__str_registered[key])
for key in self.__str_registered.keys()
if regexp.search(key)]
def __delitem__(self, pk_tuple):
print "Deleting " + "#".join(pk_tuple)
del self.__str_registered["#".join(pk_tuple)]
self.sync()
def has_key(self, pk_tuple):
return self.__str_registered.has_key("#".join(pk_tuple))
def keys(self, pk_tuple = None):
if pk_tuple is None:
return [tuple(key.split("#")) for key in self.__str_registered.keys()]
else:
level = len(pk_tuple)
partial_key = "#".join(pk_tuple)
regexp = re.compile("^" + partial_key)
result = {}
for key in self.__str_registered.keys():
if regexp.search(key):
result[key.split("#")[level]] = None
return result.keys()
class SQLiteStorage(Storage):
def __init__(self, nb_pk_fields = 1, spool_dir = "."):
pass
def load(self):
pass
def sync(self):
pass
def store(self, nb_pk_fields, registered, pk):
pass
def add(self, key_list, obj):
pass
def remove(self, key_list):
pass

129
jabber/x.py Normal file
View 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