summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2011-10-19 13:22:42 +0100
committerJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2011-10-19 13:22:42 +0100
commit7423834758dda2093a6e8e675ab4078c5f87ffcd (patch)
tree0a1ecc7aa3767daec030024da9011c79ef865e1f
parent7f981d42521913a3f7a715cd043cbf7fba5009b0 (diff)
downloadpykolab-7423834758dda2093a6e8e675ab4078c5f87ffcd.tar.gz
Restructure the command-line interface so that it can be extended easier, and particular commands can be shipped in seperate packages
-rw-r--r--pykolab/cli/__init__.py622
-rw-r--r--pykolab/cli/cmd_create_mailbox.py43
-rw-r--r--pykolab/cli/cmd_delete_mailbox.py53
-rw-r--r--pykolab/cli/cmd_export_mailbox.py125
-rw-r--r--pykolab/cli/cmd_list_deleted_mailboxes.py44
-rw-r--r--pykolab/cli/cmd_list_domains.py54
-rw-r--r--pykolab/cli/cmd_list_mailboxes.py63
-rw-r--r--pykolab/cli/cmd_sync.py60
-rw-r--r--pykolab/cli/cmd_undelete_mailbox.py48
-rw-r--r--pykolab/cli/commands.py192
-rw-r--r--pykolab/cli/telemetry/__init__.py0
-rw-r--r--pykolab/cli/telemetry/cmd_examine_command_issue.py126
-rw-r--r--pykolab/cli/telemetry/cmd_examine_session.py144
-rw-r--r--pykolab/cli/telemetry/cmd_expire_sessions.py39
-rw-r--r--pykolab/cli/telemetry/cmd_list_sessions.py66
15 files changed, 1067 insertions, 612 deletions
diff --git a/pykolab/cli/__init__.py b/pykolab/cli/__init__.py
index 65c60c8..98075c9 100644
--- a/pykolab/cli/__init__.py
+++ b/pykolab/cli/__init__.py
@@ -43,621 +43,19 @@ imap = pykolab.imap
class Cli(object):
def __init__(self):
- domain_group = conf.add_cli_parser_option_group(_("CLI Options"))
+ import commands
+ commands.__init__()
- domain_group.add_option( '--review',
- dest = "review",
- action = "store_true",
- default = False,
- help = _("Review LDIF before committed"))
+ to_execute = []
- conf.finalize_conf()
+ arg_num = 1
+ for arg in sys.argv[1:]:
+ arg_num += 1
+ if not arg.startswith('-') and len(sys.argv) > arg_num:
+ if commands.commands.has_key(sys.argv[arg_num].replace('-','_')):
+ to_execute.append(sys.argv[arg_num].replace('-','_'))
- try:
- action = conf.cli_args.pop(0)
- except IndexError, e:
- self.no_command()
-
- action_function = action.replace('-','_')
- action_components = action.split('-')
-
- if hasattr(self, "action_%s" %(action)):
- exec("self.action_%s()" %(action))
- elif hasattr(self, "action_%s" %(action_function)):
- log.info(_("TODO: self.check_%s()") %(action_function))
- exec("self.action_%s()" %(action_function))
- else:
- try:
- action_domain = action_components.pop()
- action_action = action_components.pop()
- exec("from pykolab.cli import action_%s" %(action_domain))
- if hasattr("action_%s" %(action_domain), "%s" %(action_action)):
- exec(
- "result = action_%s.%s(%r)" %(
- action_domain,
- action_action,
- conf.cli_args
- )
- )
-
- except IndexError, e:
- self.no_command()
- except ImportError, e:
- pass
-
- self.print_usage()
-
- def no_command(self):
- print >> sys.stderr, _("No command given, see --help for details")
- sys.exit(1)
-
- ##
- ## Alias (shorthand) commands
- ##
-
- def action_cm(self):
- """
- Alias for action_create_mailbox
- """
-
- self.action_create_mailbox()
-
- def action_dm(self):
- """
- Alias for action_delete_mailbox
- """
-
- self.action_delete_mailbox()
-
- def action_lm(self):
- """
- Alias for action_list_mailbox
- """
-
- self.action_list_mailbox()
-
- ##
- ## Actual commands
- ##
-
- def action_add_domain(self):
- log.info(
- _("TODO: Figure out where the domain should actually be added.")
- )
-
- domainname = conf.cli_args.pop(0)
-
- log.info(_("Adding domain %s") %(domainname))
-
- # The dn of our new entry/object
- log.info(_("TODO: Make the format for a new domain configurable."))
- dn = "associateddomain=%s,cn=kolab,cn=config" %(domainname)
-
- # A dict to help build the "body" of the object
- log.info(_("TODO: Make what a domain looks like configurable."))
- attrs = {}
- attrs['objectclass'] = [
- 'top',
- 'domainrelatedobject',
- 'organization',
- 'inetdomain'
- ]
- attrs['associatedDomain'] = ['%s' %(domainname)]
- domainname_components = domainname.split('.')
- attrs['inetDomainBaseDN'] = [
- 'dc=%s,dc=%s' %(
- domainname_components[0],
- domainname_components[1]
- )
- ]
-
- # TODO: Prompt for organization name/description. For now, use domain
- # name.
- attrs['o'] = ['%s' %(domainname)]
-
- go_ahead = True
-
- if conf.cli_keywords.review:
- ldif_writer = ldif.LDIFWriter(sys.stdout)
- ldif_writer.unparse(dn,attrs)
- if not utils.ask_confirmation(
- _("Please ACK or NACK the above LDIF:"),
- default="y",
- all_inclusive_no=True
- ):
-
- go_ahead = False
-
- if go_ahead:
- # Convert our dict to nice syntax for the add-function using
- # modlist-module
- _ldif = addModlist(attrs)
-
- # TODO: Use auth
- # Now build an ldap connection and execute the motherf.
- ldap_con = ldap.initialize(conf.get('ldap', 'uri'))
- ldap_con.bind_s(
- conf.get('ldap', 'bind_dn'),
- conf.get('ldap', 'bind_pw')
- )
-
- # The try/except should actually be in check_add_domain
- try:
- # Do the actual synchronous add-operation to the ldapserver
- ldap_con.add_s(dn,_ldif)
- except ldap.ALREADY_EXISTS, e:
- log.error(_("Domain %s already exists.") %(domainname))
-
- # Its nice to the server to disconnect and free resources when done
- ldap_con.unbind_s()
-
- def action_add_group(self):
- print >> sys.stderr, _("Not yet implemented.")
- sys.exit(1)
-
- def action_add_user(self):
- print >> sys.stderr, _("Not yet implemented.")
- sys.exit(1)
-
- def action_create_mailbox(self):
- mailbox = conf.cli_args.pop(0)
-
- imap.connect()
- imap.cm(mailbox)
-
- def action_delete_domain(self):
- domainname = conf.cli_args.pop(0)
-
- log.info(_("Deleting domain %s") %(domainname))
-
- dn = "associateddomain=%s,cn=kolab,cn=config" %(domainname)
-
- # TODO: Use auth
- ldap_con = ldap.initialize(conf.get('ldap', 'uri'))
- ldap_con.bind_s(
- conf.get('ldap', 'bind_dn'),
- conf.get('ldap', 'bind_pw')
- )
-
- # The try/except should actually be in check_del_domain()
- try:
- # Do the actual synchronous add-operation to the ldapserver
- ldap_con.delete_s(dn)
- except ldap.NO_SUCH_OBJECT, e:
- log.error(_("No domain %s exists.") %(domainname))
-
- # Its nice to the server to disconnect and free resources when done
- ldap_con.unbind_s()
-
- def action_delete_group(self):
- print >> sys.stderr, _("Not yet implemented.")
- sys.exit(1)
-
- def action_delete_mailbox(self):
- """
- Delete mailbox
- """
-
- target_folder = None
-
- try:
- delete_folder = conf.cli_args.pop(0)
- except IndexError, e:
- print >> sys.stderr, _("No mailbox specified")
- sys.exit(1)
-
- imap.connect()
- imap.dm(delete_folder)
-
- def action_delete_user(self):
- print >> sys.stderr, _("Not yet implemented.")
- sys.exit(1)
-
- def action_export_mailbox(self):
- import os
- import subprocess
-
- user = conf.cli_args.pop(0)
-
- # TODO: /etc/imapd.conf is not the definitive location for the
- # imapd.conf configuration file.
- partition_proc = subprocess.Popen(
- ['grep', '^partition', '/etc/imapd.conf'],
- stdout=subprocess.PIPE
- )
-
- partitions = [
- x.split(':')[1].strip()
- for x in partition_proc.communicate()[0].split('\n')
- if len(x.split(':')) > 1
- ]
-
- # TODO: ctl_mboxlist is not necessarily in this location.
- ctl_mboxlist_args = [ '/usr/lib/cyrus-imapd/ctl_mboxlist', '-d' ]
- ctl_mboxlist = subprocess.Popen(
- ctl_mboxlist_args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
- )
-
- mboxlist_proc = subprocess.Popen(
- ['grep', '-E', '\s*%s\s*.*i.*p.*' %(user)],
- stdin=ctl_mboxlist.stdout,
- stdout=subprocess.PIPE
- )
-
- ctl_mboxlist.stdout.close()
-
- # TODO: Handle errors from ctl_mboxlist process (stderr)
- mboxlist_output = mboxlist_proc.communicate()[0]
-
- zipper_args = [ 'zip', '-r', '%s.zip' %(user) ]
- directories = []
-
- for mbox_internal in mboxlist_output.split('\n'):
- if len(mbox_internal.split('\t')[0].split('!')) > 1:
- domain = mbox_internal.split('\t')[0].split('!')[0]
- mailbox = '/'.join(
- mbox_internal.split(
- '\t'
- )[0].split(
- '!'
- )[1].split(
- '.'
- )[1:]
- )
-
- for partition in partitions:
- mbox_dir = '%s/domain/%s/%s/%s/user/%s/' %(
- partition,
- domain[0],
- domain,
- user[0],
- mailbox
- )
-
- if os.path.isdir(mbox_dir):
- directories.append(mbox_dir)
-
- else:
- log.debug(
- _('%s is not a directory') %(mbox_dir),
- level=5
- )
-
- if not len(directories) == 0:
- zipper_output = subprocess.Popen(
- zipper_args + directories,
- stdout=subprocess.PIPE
- ).communicate()[0]
-
- print >> sys.stderr, _("ZIP file at %s.zip") %(user)
- else:
- print >> sys.stderr, _("No directories found for user %s") %(user)
- sys.exit(1)
-
- def action_list_deleted(self):
- """
- List deleted mailboxes
- """
- imap.connect()
- folders = imap.lm("DELETED/*")
- print "Deleted folders:"
- for folder in folders:
- print folder
-
- def action_list_domains(self):
- auth.connect()
-
- # Create the authentication object.
- # TODO: Binds with superuser credentials!
- domains = auth.list_domains()
-
- # TODO: Take a hint in --quiet, and otherwise print out a nice table
- # with headers and such.
- for domain,domain_aliases in domains:
- if len(domain_aliases) > 0:
- print _("Primary domain: %s - Secondary domain(s): %s") %(
- domain,
- ', '.join(domain_aliases)
- )
- else:
- print _("Primary domain: %s") %(domain)
-
- def action_list_mailbox(self):
- """
- List mailboxes
- """
- try:
- searches = [ conf.cli_args.pop(0) ]
- except IndexError, e:
- #searches = [ 'DELETED/*', 'shared/*', 'user/*' ]
- searches = [ '' ]
-
- imap.connect()
-
- folders = []
-
- for search in searches:
- folders.extend(imap.lm(search))
-
- for folder in folders:
- print folder
-
- def action_sync(self):
- log.debug(_("Listing domains..."), level=5)
- start_time = time.time()
- domains = auth.list_domains()
- end_time = time.time()
- log.debug(
- _("Found %d domains in %d seconds") %(
- len(domains),
- (end_time-start_time)
- ),
- level=8
- )
-
- all_folders = []
-
- for primary_domain,secondary_domains in domains:
- log.debug(_("Running for domain %s") %(primary_domain), level=8)
- auth.connect(primary_domain)
- start_time = time.time()
- auth.synchronize(primary_domain, secondary_domains)
- end_time = time.time()
-
- log.info(_("Synchronizing users for %s took %d seconds")
- %(primary_domain, (end_time-start_time))
- )
-
- def action_telemetry_examine_command_issue_id(self):
- from pykolab import telemetry
-
- db = telemetry.init_db()
-
- try:
- wanted = conf.cli_args.pop(0)
- except:
- log.error(_("Unspecified command issue identifier"))
- sys.exit(1)
-
- command_issue = db.query(
- telemetry.TelemetryCommandIssue
- ).filter_by(
- id=wanted
- ).first()
-
- if command_issue == None:
- log.error(_("Invalid command issue identifier"))
- sys.exit(1)
-
- session = db.query(
- telemetry.TelemetrySession
- ).filter_by(
- id=command_issue.session_id
- ).first()
-
- if session == None:
- log.error(_("Invalid session identifier"))
- sys.exit(1)
-
- user = db.query(
- telemetry.TelemetryUser
- ).filter_by(
- id=session.user_id
- ).first()
-
- server = db.query(
- telemetry.TelemetryServer
- ).filter_by(
- id=session.server_id
- ).first()
-
- print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
-
- command_issues = db.query(
- telemetry.TelemetryCommandIssue
- ).filter_by(
- session_id=session.id
- )
-
- for _command_issue in command_issues:
- command = db.query(
- telemetry.TelemetryCommand
- ).filter_by(
- id=_command_issue.command_id
- ).first()
-
- command_arg = db.query(
- telemetry.TelemetryCommandArg
- ).filter_by(
- id=_command_issue.command_arg_id
- ).first()
-
- if command_issue.id == _command_issue.id:
- print "========="
-
- print "Client(%d): %s %s %s" %(
- _command_issue.id,
- _command_issue.command_tag,
- command.command,
- command_arg.command_arg
- )
-
- server_responses = db.query(
- telemetry.TelemetryServerResponse
- ).filter_by(
- command_issue_id=_command_issue.id
- )
-
- for server_response in server_responses:
- server_response_lines = server_response.response.split('\n');
-
- for server_response_line in server_response_lines:
- print "Server(%d): %s" %(
- server_response.id,
- server_response_line
- )
-
- if command_issue.id == _command_issue.id:
- print "========="
-
- def action_telemetry_examine_session(self, session_id=None):
- from pykolab import telemetry
-
- db = telemetry.init_db()
-
- wanted = False
-
- if session_id == None:
- try:
- wanted = conf.cli_args.pop(0)
- except:
- log.error(_("Unspecified session identifier"))
- sys.exit(1)
-
- if not wanted:
- wanted = session_id
-
- session_wanted = None
-
- try:
- _wanted = (int)(wanted)
- session_wanted = _wanted
- except:
- user_wanted = wanted
-
- if not session_wanted == None:
- session = db.query(
- telemetry.TelemetrySession
- ).filter_by(
- id=session_wanted
- ).first()
-
- if session == None:
- log.error(_("Invalid session identifier"))
- sys.exit(1)
-
- user = db.query(
- telemetry.TelemetryUser
- ).filter_by(
- id=session.user_id
- ).first()
-
- server = db.query(
- telemetry.TelemetryServer
- ).filter_by(
- id=session.server_id
- ).first()
-
- else:
- user = db.query(
- telemetry.TelemetryUser
- ).filter_by(
- sasl_username=user_wanted
- ).first()
-
- sessions = db.query(
- telemetry.TelemetrySession
- ).filter_by(
- user_id=user.id
- ).order_by(
- telemetry.telemetry_session_table.c.start
- )
-
- for session in sessions:
- self.action_telemetry_examine_session(session_id=session.id)
-
- return
-
- print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
-
- command_issues = db.query(
- telemetry.TelemetryCommandIssue
- ).filter_by(
- session_id=session.id
- )
-
- for command_issue in command_issues:
- command = db.query(
- telemetry.TelemetryCommand
- ).filter_by(
- id=command_issue.command_id
- ).first()
-
- command_arg = db.query(
- telemetry.TelemetryCommandArg
- ).filter_by(
- id=command_issue.command_arg_id
- ).first()
-
- print "Client(%d): %s %s %s" %(
- command_issue.id,
- command_issue.command_tag,
- command.command,
- command_arg.command_arg
- )
-
- server_responses = db.query(
- telemetry.TelemetryServerResponse
- ).filter_by(
- command_issue_id=command_issue.id
- )
-
- for server_response in server_responses:
- server_response_lines = server_response.response.split('\n');
- for server_response_line in server_response_lines:
- print "Server(%d): %s" %(
- server_response.id,
- server_response_line
- )
-
- def action_telemetry_expire_sessions(self):
- from pykolab import telemetry
- telemetry.expire_sessions()
-
- def action_telemetry_list_sessions(self):
- from pykolab import telemetry
-
- db = telemetry.init_db()
-
- sessions = db.query(
- telemetry.TelemetrySession
- ).order_by(
- telemetry.telemetry_session_table.c.start
- )
-
- for session in sessions:
- user = db.query(
- telemetry.TelemetryUser
- ).filter_by(
- id=session.user_id
- ).first()
-
- print _("Session for user %s started at %s with ID %s") %(
- user.sasl_username,
- session.start,
- session.id
- )
-
- def action_undelete_mailbox(self):
- """
- Undelete mailbox
- """
-
- target_folder = None
-
- undelete_folder = conf.cli_args.pop(0)
- if len(conf.cli_args) > 0:
- target_folder = conf.cli_args.pop(0)
-
- imap.connect()
- imap.undelete(undelete_folder, target_folder)
+ commands.execute('_'.join(to_execute))
def run(self):
pass
-
- def print_usage(self):
- print >> sys.stderr, _("Actions") + ":"
- print >> sys.stderr, "add-domain <domainname>"
- print >> sys.stderr, "list-domains"
diff --git a/pykolab/cli/cmd_create_mailbox.py b/pykolab/cli/cmd_create_mailbox.py
new file mode 100644
index 0000000..5e0fb80
--- /dev/null
+++ b/pykolab/cli/cmd_create_mailbox.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('create_mailbox', execute, description=description(), aliases='cm')
+
+def description():
+ return """Create a mailbox or sub-folder of an existing mailbox."""
+
+def execute(*args, **kw):
+ mailbox = conf.cli_args.pop(0)
+
+ imap.connect()
+ imap.cm(mailbox)
+
diff --git a/pykolab/cli/cmd_delete_mailbox.py b/pykolab/cli/cmd_delete_mailbox.py
new file mode 100644
index 0000000..e1bd11f
--- /dev/null
+++ b/pykolab/cli/cmd_delete_mailbox.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('delete_mailbox', execute, description=description(), aliases=['dm'])
+
+def description():
+ return """Delete a mailbox or sub-folder. Note that the mailbox or folder is removed recursively."""
+
+def execute(*args, **kw):
+ """
+ Delete mailbox
+ """
+
+ try:
+ delete_folder = conf.cli_args.pop(0)
+ except IndexError, e:
+ print >> sys.stderr, _("No mailbox specified")
+ sys.exit(1)
+
+ imap.connect()
+ delete_folders = imap.lm(delete_folder)
+ for delete_folder in delete_folders:
+ imap.delete_mailfolder(delete_folder)
+
diff --git a/pykolab/cli/cmd_export_mailbox.py b/pykolab/cli/cmd_export_mailbox.py
new file mode 100644
index 0000000..eaca347
--- /dev/null
+++ b/pykolab/cli/cmd_export_mailbox.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('export_mailbox', execute)
+
+def cli_options():
+ my_option_group = conf.add_cli_parser_option_group(_("CLI Options"))
+ my_option_group.add_option( '--all',
+ dest = "all",
+ action = "store_true",
+ default = False,
+ help = _("All folders this user has access to"))
+
+def execute(*args, **kw):
+ import os
+ import subprocess
+
+ user = conf.cli_args.pop(0)
+
+ # TODO: /etc/imapd.conf is not the definitive location for the
+ # imapd.conf configuration file.
+ partition_proc = subprocess.Popen(
+ ['grep', '^partition', '/etc/imapd.conf'],
+ stdout=subprocess.PIPE
+ )
+
+ partitions = [
+ x.split(':')[1].strip()
+ for x in partition_proc.communicate()[0].split('\n')
+ if len(x.split(':')) > 1
+ ]
+
+ # TODO: ctl_mboxlist is not necessarily in this location.
+ ctl_mboxlist_args = [ '/usr/lib/cyrus-imapd/ctl_mboxlist', '-d' ]
+ ctl_mboxlist = subprocess.Popen(
+ ctl_mboxlist_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE
+ )
+
+ mboxlist_proc = subprocess.Popen(
+ ['grep', '-E', '\s*%s\s*.*i.*p.*' %(user)],
+ stdin=ctl_mboxlist.stdout,
+ stdout=subprocess.PIPE
+ )
+
+ ctl_mboxlist.stdout.close()
+
+ # TODO: Handle errors from ctl_mboxlist process (stderr)
+ mboxlist_output = mboxlist_proc.communicate()[0]
+
+ zipper_args = [ 'zip', '-r', '%s.zip' %(user) ]
+ directories = []
+
+ for mbox_internal in mboxlist_output.split('\n'):
+ if len(mbox_internal.split('\t')[0].split('!')) > 1:
+ domain = mbox_internal.split('\t')[0].split('!')[0]
+ mailbox = '/'.join(
+ mbox_internal.split(
+ '\t'
+ )[0].split(
+ '!'
+ )[1].split(
+ '.'
+ )[1:]
+ )
+
+ for partition in partitions:
+ mbox_dir = '%s/domain/%s/%s/%s/user/%s/' %(
+ partition,
+ domain[0],
+ domain,
+ user[0],
+ mailbox
+ )
+
+ if os.path.isdir(mbox_dir):
+ directories.append(mbox_dir)
+
+ else:
+ log.debug(
+ _('%s is not a directory') %(mbox_dir),
+ level=5
+ )
+
+ if not len(directories) == 0:
+ zipper_output = subprocess.Popen(
+ zipper_args + directories,
+ stdout=subprocess.PIPE
+ ).communicate()[0]
+
+ print >> sys.stderr, _("ZIP file at %s.zip") %(user)
+ else:
+ print >> sys.stderr, _("No directories found for user %s") %(user)
+ sys.exit(1)
+
diff --git a/pykolab/cli/cmd_list_deleted_mailboxes.py b/pykolab/cli/cmd_list_deleted_mailboxes.py
new file mode 100644
index 0000000..3ca6991
--- /dev/null
+++ b/pykolab/cli/cmd_list_deleted_mailboxes.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('list_deleted_mailboxes', execute)
+
+def execute(*args, **kw):
+ """
+ List deleted mailboxes
+ """
+ imap.connect()
+ folders = imap.lm("DELETED/*")
+ print "Deleted folders:"
+ for folder in folders:
+ print folder
+
diff --git a/pykolab/cli/cmd_list_domains.py b/pykolab/cli/cmd_list_domains.py
new file mode 100644
index 0000000..7018445
--- /dev/null
+++ b/pykolab/cli/cmd_list_domains.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('list_domains', execute, description="List Kolab domains.")
+
+def execute(*args, **kw):
+ auth.connect()
+
+ # Create the authentication object.
+ # TODO: Binds with superuser credentials!
+ domains = auth.list_domains()
+
+ print "%-39s %-40s" %("Primary Domain Name Space","Secondary Domain Name Space(s)")
+
+ # TODO: Take a hint in --quiet, and otherwise print out a nice table
+ # with headers and such.
+ for domain,domain_aliases in domains:
+ if len(domain_aliases) > 0:
+ print _("%-39s %-40s") %(
+ domain,
+ ', '.join(domain_aliases)
+ )
+ else:
+ print _("%-39s") %(domain)
+
diff --git a/pykolab/cli/cmd_list_mailboxes.py b/pykolab/cli/cmd_list_mailboxes.py
new file mode 100644
index 0000000..f6f6e10
--- /dev/null
+++ b/pykolab/cli/cmd_list_mailboxes.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('list_mailboxes', execute, description="List mailboxes.\n" + \
+ "%-28s" %('') + \
+ "Use wildcards '*' and '%' for more control.\n")
+
+def cli_options():
+ my_option_group = conf.add_cli_parser_option_group(_("CLI Options"))
+ my_option_group.add_option( '--raw',
+ dest = "raw",
+ action = "store_true",
+ default = False,
+ help = _("Display raw UTF-7 folder names"))
+
+def execute(*args, **kw):
+ """
+ List mailboxes
+ """
+ try:
+ searches = [ conf.cli_args.pop(1) ]
+ except IndexError, e:
+ #searches = [ 'DELETED/*', 'shared/*', 'user/*' ]
+ searches = [ '' ]
+
+ imap.connect()
+
+ folders = []
+
+ for search in searches:
+ folders.extend(imap.lm(search))
+
+ for folder in folders:
+ print folder
diff --git a/pykolab/cli/cmd_sync.py b/pykolab/cli/cmd_sync.py
new file mode 100644
index 0000000..ebb9cf3
--- /dev/null
+++ b/pykolab/cli/cmd_sync.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('sync', execute, description="Synchronize Kolab Users with IMAP.")
+
+def execute(*args, **kw):
+ log.debug(_("Listing domains..."), level=5)
+ start_time = time.time()
+ domains = auth.list_domains()
+ end_time = time.time()
+ log.debug(
+ _("Found %d domains in %d seconds") %(
+ len(domains),
+ (end_time-start_time)
+ ),
+ level=8
+ )
+
+ all_folders = []
+
+ for primary_domain,secondary_domains in domains:
+ log.debug(_("Running for domain %s") %(primary_domain), level=8)
+ auth.connect(primary_domain)
+ start_time = time.time()
+ auth.synchronize(primary_domain, secondary_domains)
+ end_time = time.time()
+
+ log.info(_("Synchronizing users for %s took %d seconds")
+ %(primary_domain, (end_time-start_time))
+ )
+
diff --git a/pykolab/cli/cmd_undelete_mailbox.py b/pykolab/cli/cmd_undelete_mailbox.py
new file mode 100644
index 0000000..e4dec3a
--- /dev/null
+++ b/pykolab/cli/cmd_undelete_mailbox.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('undelete_mailbox', execute, description="Recover mailboxes previously deleted.")
+
+def execute(*args, **kw):
+ """
+ Undelete mailbox
+ """
+
+ target_folder = None
+
+ undelete_folder = conf.cli_args.pop(0)
+ if len(conf.cli_args) > 0:
+ target_folder = conf.cli_args.pop(0)
+
+ imap.connect()
+ imap.undelete_mailfolder(undelete_folder, target_folder)
+
diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
new file mode 100644
index 0000000..2173ce0
--- /dev/null
+++ b/pykolab/cli/commands.py
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 sys
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+commands = {}
+command_groups = {}
+
+def __init__():
+ # We only want the base path
+ commands_base_path = os.path.dirname(__file__)
+
+ for commands_path, dirnames, filenames in os.walk(commands_base_path):
+ if not commands_path == commands_base_path:
+ continue
+
+ for filename in filenames:
+ if filename.startswith('cmd_') and filename.endswith('.py'):
+ module_name = filename.replace('.py','')
+ cmd_name = module_name.replace('cmd_', '')
+ #print "exec(\"from %s import __init__ as %s_register\"" %(module_name,cmd_name)
+ exec("from %s import __init__ as %s_register" %(module_name,cmd_name))
+ exec("%s_register()" %(cmd_name))
+
+ for dirname in dirnames:
+ register_group(commands_path, dirname)
+
+ register('help', list_commands)
+
+ register('list_users', not_yet_implemented, description="Not yet implemented")
+ register('add_user', not_yet_implemented, description="Not yet implemented")
+ register('delete_user', not_yet_implemented, description="Not yet implemented")
+
+ register('list_groups', not_yet_implemented, description="Not yet implemented")
+ register('add_group', not_yet_implemented, description="Not yet implemented")
+ register('delete_group', not_yet_implemented, description="Not yet implemented")
+
+ register('add_domain', not_yet_implemented, description="Not yet implemented")
+ register('delete_domain', not_yet_implemented, description="Not yet implemented")
+
+def list_commands(*args, **kw):
+ """
+ List commands
+ """
+
+ __commands = {}
+
+ for command in commands.keys():
+ if isinstance(command, tuple):
+ command_group, command = command
+ __commands[command_group] = {
+ command: commands[(command_group,command)]
+ }
+ else:
+ __commands[command] = commands[command]
+
+ _commands = __commands.keys()
+ _commands.sort()
+
+ for _command in _commands:
+ if __commands[_command].has_key('function'):
+ # This is a top-level command
+ if not __commands[_command]['description'] == None:
+ print "%-25s - %s" %(_command.replace('_','-'),__commands[_command]['description'])
+ else:
+ print "%-25s" %(_command.replace('_','-'))
+
+ for _command in _commands:
+ if not __commands[_command].has_key('function'):
+ # This is a nested command
+ print "\n" + _("Command Group: %s") %(_command) + "\n"
+ ___commands = __commands[_command].keys()
+ ___commands.sort()
+ for __command in ___commands:
+ if not __commands[_command][__command]['description'] == None:
+ print "%-4s%-21s - %s" %('',__command.replace('_','-'),__commands[_command][__command]['description'])
+ else:
+ print "%-4s%-21s" %('',__command.replace('_','-'))
+
+def execute(cmd_name, *args, **kw):
+ if not commands.has_key(cmd_name):
+ log.error(_("No such command."))
+ sys.exit(1)
+
+ if not commands[cmd_name].has_key('function') and \
+ not commands[cmd_name].has_key('group'):
+ log.error(_("No such command."))
+ sys.exit(1)
+
+ if commands[cmd_name].has_key('group'):
+ group = commands[cmd_name]['group']
+ command_name = commands[cmd_name]['cmd_name']
+ try:
+ exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" %(group,command_name,group,command_name))
+ exec("%s_%s_cli_options()" %(group,command_name))
+ except ImportError, e:
+ pass
+
+ else:
+ try:
+ exec("from cmd_%s import cli_options as %s_cli_options" %(cmd_name,cmd_name))
+ exec("%s_cli_options()" %(cmd_name))
+ except ImportError, e:
+ pass
+
+ conf.finalize_conf()
+ _cmd_name = conf.cli_args.pop(0)
+ commands[cmd_name]['function'](conf.cli_args, kw)
+
+def register_group(dirname, module):
+ commands_base_path = os.path.join(os.path.dirname(__file__), module)
+
+ commands[module] = {}
+
+ for commands_path, dirnames, filenames in os.walk(commands_base_path):
+ if not commands_path == commands_base_path:
+ continue
+
+ for filename in filenames:
+ if filename.startswith('cmd_') and filename.endswith('.py'):
+ module_name = filename.replace('.py','')
+ cmd_name = module_name.replace('cmd_', '')
+ #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" %(module,module_name,module,cmd_name)
+ exec("from %s.%s import __init__ as %s_%s_register" %(module,module_name,module,cmd_name))
+ exec("%s_%s_register()" %(module,cmd_name))
+
+def register(cmd_name, func, group=None, description=None, aliases=[]):
+ if not group == None:
+ command = "%s_%s" %(group,cmd_name)
+ else:
+ command = cmd_name
+
+ if isinstance(aliases, basestring):
+ aliases = [aliases]
+
+ if commands.has_key(command):
+ log.fatal(_("Command '%s' already registered") %(command))
+ sys.exit(1)
+
+ if callable(func):
+ if group == None:
+ commands[cmd_name] = {
+ 'function': func,
+ 'description': description
+ }
+ else:
+ commands[group][cmd_name] = {
+ 'function': func,
+ 'description': description
+ }
+
+ commands[command] = commands[group][cmd_name]
+ commands[command]['group'] = group
+ commands[command]['cmd_name'] = cmd_name
+
+ for alias in aliases:
+ commands[alias] = {
+ 'function': func,
+ 'description': _("Alias for %s") %(cmd_name)
+ }
+
+##
+## Commands not yet implemented
+##
+
+def not_yet_implemented(*args, **kw):
+ print _("Not yet implemented")
+ sys.exit(1) \ No newline at end of file
diff --git a/pykolab/cli/telemetry/__init__.py b/pykolab/cli/telemetry/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pykolab/cli/telemetry/__init__.py
diff --git a/pykolab/cli/telemetry/cmd_examine_command_issue.py b/pykolab/cli/telemetry/cmd_examine_command_issue.py
new file mode 100644
index 0000000..cceb5fe
--- /dev/null
+++ b/pykolab/cli/telemetry/cmd_examine_command_issue.py
@@ -0,0 +1,126 @@
+
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+from pykolab import telemetry
+from pykolab.cli import commands
+
+def __init__():
+ commands.register('examine_command_issue', execute, group='telemetry', description="Examine a particular telemetry command issue.")
+
+def execute(*args, **kw):
+ db = telemetry.init_db()
+
+ try:
+ wanted = conf.cli_args.pop(0)
+ except:
+ log.error(_("Unspecified command issue identifier"))
+ sys.exit(1)
+
+ command_issue = db.query(
+ telemetry.TelemetryCommandIssue
+ ).filter_by(
+ id=wanted
+ ).first()
+
+ if command_issue == None:
+ log.error(_("Invalid command issue identifier"))
+ sys.exit(1)
+
+ session = db.query(
+ telemetry.TelemetrySession
+ ).filter_by(
+ id=command_issue.session_id
+ ).first()
+
+ if session == None:
+ log.error(_("Invalid session identifier"))
+ sys.exit(1)
+
+ user = db.query(
+ telemetry.TelemetryUser
+ ).filter_by(
+ id=session.user_id
+ ).first()
+
+ server = db.query(
+ telemetry.TelemetryServer
+ ).filter_by(
+ id=session.server_id
+ ).first()
+
+ print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
+
+ command_issues = db.query(
+ telemetry.TelemetryCommandIssue
+ ).filter_by(
+ session_id=session.id
+ )
+
+ for _command_issue in command_issues:
+ command = db.query(
+ telemetry.TelemetryCommand
+ ).filter_by(
+ id=_command_issue.command_id
+ ).first()
+
+ command_arg = db.query(
+ telemetry.TelemetryCommandArg
+ ).filter_by(
+ id=_command_issue.command_arg_id
+ ).first()
+
+ if command_issue.id == _command_issue.id:
+ print "========="
+
+ print "Client(%d): %s %s %s" %(
+ _command_issue.id,
+ _command_issue.command_tag,
+ command.command,
+ command_arg.command_arg
+ )
+
+ server_responses = db.query(
+ telemetry.TelemetryServerResponse
+ ).filter_by(
+ command_issue_id=_command_issue.id
+ )
+
+ for server_response in server_responses:
+ server_response_lines = server_response.response.split('\n');
+
+ for server_response_line in server_response_lines:
+ print "Server(%d): %s" %(
+ server_response.id,
+ server_response_line
+ )
+
+ if command_issue.id == _command_issue.id:
+ print "========="
+
diff --git a/pykolab/cli/telemetry/cmd_examine_session.py b/pykolab/cli/telemetry/cmd_examine_session.py
new file mode 100644
index 0000000..f36c0a9
--- /dev/null
+++ b/pykolab/cli/telemetry/cmd_examine_session.py
@@ -0,0 +1,144 @@
+
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+from pykolab import telemetry
+from pykolab.cli import commands
+
+def __init__():
+ commands.register('examine_session', execute, group='telemetry', description="Examine a Telemetry session.")
+
+def execute(*args, **kw):
+ db = telemetry.init_db()
+
+ wanted = False
+
+ if session_id == None:
+ try:
+ wanted = conf.cli_args.pop(0)
+ except:
+ log.error(_("Unspecified session identifier"))
+ sys.exit(1)
+
+ if not wanted:
+ wanted = session_id
+
+ session_wanted = None
+
+ try:
+ _wanted = (int)(wanted)
+ session_wanted = _wanted
+ except:
+ user_wanted = wanted
+
+ if not session_wanted == None:
+ session = db.query(
+ telemetry.TelemetrySession
+ ).filter_by(
+ id=session_wanted
+ ).first()
+
+ if session == None:
+ log.error(_("Invalid session identifier"))
+ sys.exit(1)
+
+ user = db.query(
+ telemetry.TelemetryUser
+ ).filter_by(
+ id=session.user_id
+ ).first()
+
+ server = db.query(
+ telemetry.TelemetryServer
+ ).filter_by(
+ id=session.server_id
+ ).first()
+
+ else:
+ user = db.query(
+ telemetry.TelemetryUser
+ ).filter_by(
+ sasl_username=user_wanted
+ ).first()
+
+ sessions = db.query(
+ telemetry.TelemetrySession
+ ).filter_by(
+ user_id=user.id
+ ).order_by(
+ telemetry.telemetry_session_table.c.start
+ )
+
+ for session in sessions:
+ self.action_telemetry_examine_session(session_id=session.id)
+
+ return
+
+ print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
+
+ command_issues = db.query(
+ telemetry.TelemetryCommandIssue
+ ).filter_by(
+ session_id=session.id
+ )
+
+ for command_issue in command_issues:
+ command = db.query(
+ telemetry.TelemetryCommand
+ ).filter_by(
+ id=command_issue.command_id
+ ).first()
+
+ command_arg = db.query(
+ telemetry.TelemetryCommandArg
+ ).filter_by(
+ id=command_issue.command_arg_id
+ ).first()
+
+ print "Client(%d): %s %s %s" %(
+ command_issue.id,
+ command_issue.command_tag,
+ command.command,
+ command_arg.command_arg
+ )
+
+ server_responses = db.query(
+ telemetry.TelemetryServerResponse
+ ).filter_by(
+ command_issue_id=command_issue.id
+ )
+
+ for server_response in server_responses:
+ server_response_lines = server_response.response.split('\n');
+ for server_response_line in server_response_lines:
+ print "Server(%d): %s" %(
+ server_response.id,
+ server_response_line
+ )
+
diff --git a/pykolab/cli/telemetry/cmd_expire_sessions.py b/pykolab/cli/telemetry/cmd_expire_sessions.py
new file mode 100644
index 0000000..2da1d3f
--- /dev/null
+++ b/pykolab/cli/telemetry/cmd_expire_sessions.py
@@ -0,0 +1,39 @@
+
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+from pykolab import telemetry
+from pykolab.cli import commands
+
+def __init__():
+ commands.register('expire_sessions', execute, group='telemetry', description="Expire Telemetry sessions.")
+
+def execute(*args, **kw):
+ telemetry.expire_sessions()
+
diff --git a/pykolab/cli/telemetry/cmd_list_sessions.py b/pykolab/cli/telemetry/cmd_list_sessions.py
new file mode 100644
index 0000000..d2c5293
--- /dev/null
+++ b/pykolab/cli/telemetry/cmd_list_sessions.py
@@ -0,0 +1,66 @@
+
+# -*- coding: utf-8 -*-
+# Copyright 2010-2011 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# 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; version 3 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 Library 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 pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+from pykolab import telemetry
+from pykolab.cli import commands
+
+def __init__():
+ commands.register('list_sessions', execute, group='telemetry', description="List IMAP sessions using Telemetry.")
+
+def cli_options():
+ my_option_group = conf.add_cli_parser_option_group(_("List Options"))
+ my_option_group.add_option( '--since',
+ dest = "since",
+ action = "store",
+ default = 0,
+ help = _("Display sessions since ..."))
+
+def execute(*args, **kw):
+ db = telemetry.init_db()
+
+ sessions = db.query(
+ telemetry.TelemetrySession
+ ).order_by(
+ telemetry.telemetry_session_table.c.start
+ )
+
+ for session in sessions:
+ user = db.query(
+ telemetry.TelemetryUser
+ ).filter_by(
+ id=session.user_id
+ ).first()
+
+ print _("Session for user %s started at %s with ID %s") %(
+ user.sasl_username,
+ session.start,
+ session.id
+ )
+