diff --git a/frontends/src/jp/__init__.py b/frontends/src/jp/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/frontends/src/jp/base.py b/frontends/src/jp/base.py
index 8cde080b..98f40954 100644
--- a/frontends/src/jp/base.py
+++ b/frontends/src/jp/base.py
@@ -17,24 +17,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import with_statement
from sat.core.i18n import _
-#consts
-name = u"jp"
-about = name+u""" v%s (c) Jérôme Poisson (aka Goffi) 2009, 2010, 2011, 2012, 2013, 2014
-
----
-"""+name+u""" Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (aka Goffi)
-This program comes with ABSOLUTELY NO WARRANTY;
-This is free software, and you are welcome to redistribute it
-under certain conditions.
----
-
-This software is a command line tool for jabber
-Get the latest version at http://www.goffi.org
-"""
-
global pbar_available
pbar_available = True #checked before using ProgressBar
@@ -46,35 +30,40 @@ logging.basicConfig(level=logging.DEBUG,
###
import sys
-import os
-from os.path import abspath, basename, dirname
-from argparse import ArgumentParser
-from sat.tools.jid import JID
+import locale
+import os.path
+import argparse
import gobject
+from glob import iglob
+from importlib import import_module
+from sat.tools.jid import JID
from sat_frontends.bridge.DBus import DBusBridgeFrontend
-from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
-from sat.tools.utils import clean_ustr
-import tarfile
-import tempfile
-import shutil
+from sat.core import exceptions
+import sat_frontends.jp
try:
- from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed
-except ImportError, e:
- info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar'))
- info (_('Progress bar deactivated\n--\n'))
- pbar_available=False
+ import progressbar
+except ImportError:
+ info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar'))
+ info (_('Progress bar deactivated\n--\n'))
+ progressbar=None
+
+#consts
+prog_name = u"jp"
+description = """This software is a command line tool for XMPP.
+Get the latest version at http://sat.goffi.org"""
+
+copyleft = u"""Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (aka Goffi)
+This program comes with ABSOLUTELY NO WARRANTY;
+This is free software, and you are welcome to redistribute it under certain conditions.
+"""
-#version = unicode(self.bridge.getVersion())
-version = "undefined"
-parser = ArgumentParser()
-parser.add_argument('--version', action='version', version=about % version)
-subparser = parser.add_subparsers(dest='subparser_name')
-# File managment
+def unicode_decoder(arg):
+ # Needed to have unicode strings from arguments
+ return arg.decode(locale.getpreferredencoding())
-
-class JP(object):
+class Jp(object):
"""
This class can be use to establish a connection with the
bridge. Moreover, it should manage a main loop.
@@ -83,64 +72,112 @@ class JP(object):
specify what kind of operation you want to perform.
"""
- def __init__(self, start_mainloop = False):
+ def __init__(self):
try:
- self.bridge=DBusBridgeFrontend()
- except BridgeExceptionNoService:
+ self.bridge = DBusBridgeFrontend()
+ except exceptions.BridgeExceptionNoService:
print(_(u"Can't connect to SàT backend, are you sure it's launched ?"))
sys.exit(1)
- except BridgeInitError:
+ except excpetions.BridgeInitError:
print(_(u"Can't init bridge"))
sys.exit(1)
- self._start_loop = start_mainloop
+ self.parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=description)
- def run(self):
- raise NotImplementedError
+ self._make_parents()
+ self.add_parser_options()
+ self.subparsers = self.parser.add_subparsers(title=_('Available commands'), dest='subparser_name')
+ self._auto_loop = False # when loop is used for internal reasons
+ self.need_loop = False # to set by commands when loop is needed
+ self._progress_id = None # TODO: manage several progress ids
+ self.quit_on_progress_end = True # set to False if you manage yourself exiting, or if you want the user to stop by himself
- def _run(self):
- """Call run and lauch a loop if needed"""
- print "You are connected!"
- self.run()
- if self._start_loop:
- print "Exiting loop..."
- self.loop.quit()
+ @property
+ def version(self):
+ return self.bridge.getVersion()
- def _loop_start(self):
+ @property
+ def progress_id(self):
+ return self._progress_id
+
+ @progress_id.setter
+ def progress_id(self, value):
+ self._progress_id = value
+
+ def _make_parents(self):
+ self.parents = {}
+
+ profile_parent = self.parents['profile'] = argparse.ArgumentParser(add_help=False)
+ profile_parent.add_argument("-p", "--profile", action="store", type=str, default='@DEFAULT@', help=_("Use PROFILE profile key (default: %(default)s)"))
+ profile_parent.add_argument("-c", "--connect", action="store_true", help=_("Connect the profile before doing anything else"))
+
+ progress_parent = self.parents['progress'] = argparse.ArgumentParser(add_help=False)
+ if progressbar:
+ progress_parent.add_argument("-g", "--progress", action="store_true", help=_("Show progress bar"))
+
+ def add_parser_options(self):
+ self.parser.add_argument('--version', action='version', version=("%(name)s %(version)s %(copyleft)s" % {'name': prog_name, 'version': self.version, 'copyleft': copyleft}))
+
+ def import_commands(self):
+ """ Automaticaly import commands to jp
+ looks from modules names cmd_*.py in jp path and import them
+
+ """
+ path = os.path.dirname(sat_frontends.jp.__file__)
+ modules = (os.path.splitext(module)[0] for module in map(os.path.basename, iglob(os.path.join(path, "cmd_*.py"))))
+ for module_name in modules:
+ module = import_module("sat_frontends.jp."+module_name)
+ try:
+ self.import_command_module(module)
+ except ImportError:
+ continue
+
+ def import_command_module(self, module):
+ """ Add commands from a module to jp
+ @param module: module containing commands
+
+ """
+ try:
+ for classname in module.__commands__:
+ cls = getattr(module, classname)
+ except AttributeError:
+ warning(_("Invalid module %s") % module)
+ raise ImportError
+ cls(self)
+
+
+ def run(self, args=None):
+ self.args = self.parser.parse_args(args)
+ self.args.func()
+ if self.need_loop or self._auto_loop:
+ self._start_loop()
+
+ def _start_loop(self):
self.loop = gobject.MainLoop()
try:
self.loop.run()
except KeyboardInterrupt:
info(_("User interruption: good bye"))
- def start_mainloop(self):
- self._start_loop = True
+ def stop_loop(self):
+ try:
+ self.loop.quit()
+ except AttributeError:
+ pass
- def go(self):
- self.run()
- if self._start_loop:
- self._loop_start()
-
-
-class JPWithProfile(JP):
- """Manage a bridge (inherit from :class:`JP`), but it also adds
- profile managment, ie, connection to the profile.
-
- Moreover, some useful methods are predefined such as
- :py:meth:`check_jids`. The connection to XMPP is automatically
- managed.
- """
-
- def __init__(self, profile_name, start_mainloop = False):
- JP.__init__(self, start_mainloop)
- self.profile_name = profile_name
+ def quit(self, errcode=0):
+ self.stop_loop()
+ if errcode:
+ sys.exit(errcode)
def check_jids(self, jids):
"""Check jids validity, transform roster name to corresponding jids
- :param profile: A profile name
- :param jids: A list of jids
- :rtype: A list of jids
+ @param profile: profile name
+ @param jids: list of jids
+ @return: List of jids
+
"""
names2jid = {}
nodes2jid = {}
@@ -151,7 +188,7 @@ class JPWithProfile(JP):
names2jid[attr["name"].lower()] = _jid
nodes2jid[JID(_jid).node.lower()] = _jid
- def expandJid(jid):
+ def expand_jid(jid):
_jid = jid.lower()
if _jid in names2jid:
expanded = names2jid[_jid]
@@ -164,100 +201,204 @@ class JPWithProfile(JP):
def check(jid):
if not jid.is_valid:
error (_("%s is not a valid JID !"), jid)
- exit(1)
+ self.quit(1)
dest_jids=[]
try:
for i in range(len(jids)):
- dest_jids.append(expandJid(jids[i]))
+ dest_jids.append(expand_jid(jids[i]))
check(dest_jids[i])
except AttributeError:
pass
return dest_jids
- def check_jabber_connection(self):
- """Check that jabber status is allright"""
- def cantConnect(arg):
- print arg
+ def connect_profile(self, callback):
+ """ Check if the profile is connected
+ @param callback: method to call when profile is connected
+ @exit: - 1 when profile is not connected and --connect is not set
+ - 1 when the profile doesn't exists
+ - 1 when there is a connection error
+ """
+ # FIXME: need better exit codes
+
+ def cant_connect():
error(_(u"Can't connect profile"))
- exit(1)
+ self.quit(1)
+
+ self.profile = self.bridge.getProfileName(self.args.profile)
- self.profile = self.bridge.getProfileName(self.profile_name)
if not self.profile:
- error(_("The profile asked doesn't exist"))
- exit(1)
+ error(_("The profile [%s] doesn't exist") % self.args.profile)
+ self.quit(1)
- if self.bridge.isConnected(self.profile):
- print "Already connected"
- else:
- self._start_loop = True
- self.bridge.asyncConnect(self.profile, self._run, cantConnect)
+ if self.args.connect: #if connection is asked, we connect the profile
+ self.bridge.asyncConnect(self.profile, callback, cant_connect)
+ self._auto_loop = True
return
- self.run()
+ elif not self.bridge.isConnected(self.profile):
+ error(_(u"Profile [%(profile)s] is not connected, please connect it before using jp, or use --connect option") % { "profile": self.profile })
+ self.quit(1)
- def _getFullJid(self, param_jid):
- """Return the full jid if possible (add last resource when find a bare jid"""
+ callback()
+
+ def get_full_jid(self, param_jid):
+ """Return the full jid if possible (add last resource when find a bare jid)"""
_jid = JID(param_jid)
if not _jid.resource:
#if the resource is not given, we try to add the last known resource
- last_resource = self.bridge.getLastResource(param_jid, self.profile_name)
+ last_resource = self.bridge.getLastResource(param_jid, self.profile)
if last_resource:
return "%s/%s" % (_jid.bare, last_resource)
return param_jid
- def go(self):
- self.check_jabber_connection()
- if self._start_loop:
- self._loop_start()
+ def watch_progress(self):
+ self.pbar = None
+ gobject.timeout_add(10, self._progress_cb)
+
+ def _progress_cb(self):
+ if self.progress_id:
+ data = self.bridge.getProgress(self.progress_id, self.profile)
+ if data:
+ if not data['position']:
+ data['position'] = '0'
+ if not self.pbar:
+ #first answer, we must construct the bar
+ self.pbar = progressbar.ProgressBar(int(data['size']),
+ [_("Progress: "),progressbar.Percentage(),
+ " ",
+ progressbar.Bar(),
+ " ",
+ progressbar.FileTransferSpeed(),
+ " ",
+ progressbar.ETA()])
+ self.pbar.start()
+
+ self.pbar.update(int(data['position']))
+
+ elif self.pbar:
+ self.pbar.finish()
+ if self.quit_on_progress_end:
+ self.quit()
+ return False
+
+ return True
+class CommandBase(object):
-class JPAsk(JPWithProfile):
- def confirm_type(self):
- """Must return a string containing the confirm type. For instance,
- FILE_TRANSFER or PIPE_TRANSFER, etc.
+ def __init__(self, host, name, use_profile=True, use_progress=False, help=None, **kwargs):
+ """ Initialise CommandBase
+ @param host: Jp instance
+ @param name: name of the new command
+ @param use_profile: if True, add profile selection/connection commands
+ @param use_progress: if True, add progress bar activation commands
+ @param help: help message to display
+ @param **kwargs: args passed to ArgumentParser
- :rtype: str
"""
- raise NotImplemented
+ try: # If we have subcommands, host is a CommandBase and we need to use host.host
+ self.host = host.host
+ except AttributeError:
+ self.host = host
- def dest_jids(self):
- return None
+ parents = kwargs.setdefault('parents', set())
+ if use_profile:
+ #self.host.parents['profile'] is an ArgumentParser with profile connection arguments
+ parents.add(self.host.parents['profile'])
+ if use_progress:
+ parents.add(self.host.parents['progress'])
- def _askConfirmation(self, confirm_id, confirm_type, data, profile):
+ self.parser = host.subparsers.add_parser(name, help=help, **kwargs)
+ if hasattr(self, "subcommands"):
+ self.subparsers = self.parser.add_subparsers()
+ else:
+ self.parser.set_defaults(func=self.run)
+ self.add_parser_options()
+
+ @property
+ def args(self):
+ return self.host.args
+
+ @property
+ def need_loop(self):
+ return self.host.need_loop
+
+ @need_loop.setter
+ def need_loop(self, value):
+ self.host.need_loop = value
+
+ @property
+ def profile(self):
+ return self.host.profile
+
+ @property
+ def progress_id(self):
+ return self.host.progress_id
+
+ @progress_id.setter
+ def progress_id(self, value):
+ self.host.progress_id = value
+
+ def add_parser_options(self):
+ try:
+ subcommands = self.subcommands
+ except AttributeError:
+ # We don't have subcommands, the class need to implements add_parser_options
+ raise NotImplementedError
+
+ # now we add subcommands to ourself
+ for cls in subcommands:
+ cls(self)
+
+ def run(self):
+ try:
+ if self.args.profile:
+ self.host.connect_profile(self.connected)
+ except AttributeError:
+ # the command doesn't need to connect profile
+ pass
+ try:
+ if self.args.progress:
+ self.host.watch_progress()
+ except AttributeError:
+ # the command doesn't use progress bar
+ pass
+
+ def connected(self):
+ if not self.need_loop:
+ self.host.stop_loop()
+
+
+class CommandAnswering(CommandBase):
+ #FIXME: temp, will be refactored when progress_bar/confirmations will be refactored
+
+ def _ask_confirmation(self, confirm_id, confirm_type, data, profile):
+ """ Callback used for file transfer, accept files depending on parameters"""
if profile != self.profile:
debug("Ask confirmation ignored: not our profile")
return
- if confirm_type == self.confirm_type():
- self._confirm_id = confirm_id
- if self.dest_jids() and not JID(data['from']).bare in [JID(_jid).bare for _jid in self.dest_jids()]:
+ if confirm_type == self.confirm_type:
+ if self.dest_jids and not JID(data['from']).bare in [JID(_jid).bare for _jid in self.dest_jids()]:
return #file is not sent by a filtered jid
else:
- self.ask(data)
+ self.ask(data, confirm_id)
def ask(self):
"""
The return value is used to answer to the bridge.
- :rtype: (bool, dict)
+ @return: bool or dict
"""
raise NotImplementedError
- def answer(self, accepted, answer_data):
- """
- :param accepted: boolean
- :param aswer_data: dict of answer datas
- """
- self.bridge.confirmationAnswer(self._confirm_id, False, answer_data, self.profile)
-
- def run(self):
+ def connected(self):
"""Auto reply to confirmations requests"""
- #we register incoming confirmation
- self.bridge.register("askConfirmation", self._askConfirmation)
+ self.need_loop = True
+ super(CommandAnswering, self).connected()
+ # we watch confirmation signals
+ self.host.bridge.register("ask_confirmation", self._ask_confirmation)
#and we ask those we have missed
- for confirm_id, confirm_type, data in self.bridge.getWaitingConf(self.profile):
- self._askConfirmation(confirm_id, confirm_type, data, self.profile)
-
-
+ for confirm_id, confirm_type, data in self.host.bridge.getWaitingConf(self.profile):
+ self._ask_confirmation(confirm_id, confirm_type, data, self.profile)
diff --git a/frontends/src/jp/cmd_file.py b/frontends/src/jp/cmd_file.py
new file mode 100644
index 00000000..1046d239
--- /dev/null
+++ b/frontends/src/jp/cmd_file.py
@@ -0,0 +1,126 @@
+#! /usr/bin/python
+# -*- coding: utf-8 -*-
+
+# jp: a SAT command line tool
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from logging import debug, info, error, warning
+
+import base
+import sys
+import os
+import os.path
+import tarfile
+#import tempfile
+from sat.core.i18n import _
+
+__commands__ = ["File"]
+
+class Send(base.CommandBase):
+ def __init__(self, host):
+ super(Send, self).__init__(host, 'send', use_progress=True, help=_('Send a file to a contact'))
+
+ def add_parser_options(self):
+ self.parser.add_argument("files", type=str, nargs = '+', help=_("A list of file"))
+ self.parser.add_argument("jid", type=base.unicode_decoder, help=_("The destination jid"))
+ self.parser.add_argument("-b", "--bz2", action="store_true", help=_("Make a bzip2 tarball"))
+
+ def connected(self):
+ """Send files to jabber contact"""
+ self.need_loop=True
+ super(Send, self).connected()
+ self.send_files()
+
+ def send_files(self):
+
+ for file_ in self.args.files:
+ if not os.path.exists(file_):
+ error (_(u"file [%s] doesn't exist !") % file_)
+ self.host.quit(1)
+ if not self.args.bz2 and os.path.isdir(file_):
+ error (_("[%s] is a dir ! Please send files inside or use compression") % file_)
+ self.host.quit(1)
+
+ full_dest_jid = self.host.get_full_jid(self.args.jid)
+
+ if self.args.bz2:
+ tmpfile = (os.path.basename(self.args.files[0]) or os.path.basename(os.path.dirname(self.args.files[0])) ) + '.tar.bz2' #FIXME: tmp, need an algorithm to find a good name/path
+ if os.path.exists(tmpfile):
+ error (_("tmp file_ (%s) already exists ! Please remove it"), tmpfile)
+ exit(1)
+ warning(_("bz2 is an experimental option at an early dev stage, use with caution"))
+ #FIXME: check free space, writting perm, tmp dir, filename (watch for OS used)
+ print _(u"Starting compression, please wait...")
+ sys.stdout.flush()
+ bz2 = tarfile.open(tmpfile, "w:bz2")
+ for file_ in self.args.files:
+ print _(u"Adding %s") % file_
+ bz2.add(file_)
+ bz2.close()
+ print _(u"Done !")
+ path = os.path.abspath(tmpfile)
+ self.progress_id = self.host.bridge.sendFile(full_dest_jid, path, {}, self.profile)
+ else:
+ for file_ in self.args.files:
+ path = os.path.abspath(file_)
+ self.progress_id = self.host.bridge.sendFile(full_dest_jid, path, {}, self.profile) #FIXME: show progress only for last progress_id
+
+
+class Receive(base.CommandAnswering):
+ confirm_type = "FILE_TRANSFER"
+
+ def __init__(self, host):
+ super(Receive, self).__init__(host, 'recv', use_progress=True, help=_('Wait for a file to be sent by a contact'))
+
+ @property
+ def dest_jids(self):
+ return self.args.jids
+
+ def add_parser_options(self):
+ self.parser.add_argument("jids", type=base.unicode_decoder, nargs="*", help=_('Jids accepted (none means "accept everything")'))
+ self.parser.add_argument("-m", "--multiple", action="store_true", help=_("Accept multiple files (you'll have to stop manually)"))
+ self.parser.add_argument("-f", "--force", action="store_true", help=_("Force overwritting of existing files"))
+
+
+ def ask(self, data, confirm_id):
+ answer_data = {}
+ answer_data["dest_path"] = os.path.join(os.getcwd(), data['filename'])
+
+ if self.args.force or not os.path.exists(answer_data["dest_path"]):
+ self.host.bridge.confirmationAnswer(confirm_id, True, answer_data, self.profile)
+ info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']})
+ self.progress_id = confirm_id
+ else:
+ self.host.bridge.confirmationAnswer(confirm_id, False, answer_data, self.profile)
+ warning(_("Refused file [%(filename)s] from %(sender)s: a file with the same name already exist") % {'filename':data['filename'], 'sender':data['from']})
+ if not self.args.multiple:
+ self.host.quit()
+
+ if not self.args.multiple and not self.args.progress:
+ #we just accept one file
+ self.host.quit()
+
+ def run(self):
+ super(Receive, self).run()
+ if self.args.multiple:
+ self.host.quit_on_progress_end = False
+
+
+class File(base.CommandBase):
+ subcommands = (Send, Receive)
+
+ def __init__(self, host):
+ super(File, self).__init__(host, 'file', use_profile=False, help=_('File sending/receiving'))
diff --git a/frontends/src/jp/cmd_message.py b/frontends/src/jp/cmd_message.py
new file mode 100644
index 00000000..0527d53b
--- /dev/null
+++ b/frontends/src/jp/cmd_message.py
@@ -0,0 +1,61 @@
+#! /usr/bin/python
+# -*- coding: utf-8 -*-
+
+# jp: a SAT command line tool
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from sat_frontends.jp import base
+import sys
+from sat.core.i18n import _
+from sat.tools.utils import clean_ustr
+
+__commands__ = ["Message"]
+
+
+class Message(base.CommandBase):
+
+ def __init__(self, host):
+ super(Message, self).__init__(host, 'message', help=_('Send a message to a contact'))
+
+ def add_parser_options(self):
+ self.parser.add_argument("-s", "--separate", action="store_true", help=_("Separate xmpp messages: send one message per line instead of one message alone."))
+ self.parser.add_argument("-n", "--new-line", action="store_true", help=_("Add a new line at the beginning of the input (usefull for ascii art ;))"))
+ self.parser.add_argument("jid", type=str, help=_("The destination jid"))
+
+ def connected(self):
+ super(Message, self).connected()
+ jids = self.host.check_jids([self.args.jid])
+ jid = jids[0]
+ self.send_stdin(jid)
+
+ def send_stdin(self, dest_jid):
+ """Send incomming data on stdin to jabber contact
+ @param dest_jid: destination jid"""
+ header = "\n" if self.args.new_line else ""
+
+ if self.args.separate: #we send stdin in several messages
+
+ if header:
+ self.host.bridge.sendMessage(dest_jid, header, profile_key=self.profile, callback=lambda: None, errback=lambda ignore: ignore)
+
+ while (True):
+ line = clean_ustr(sys.stdin.readline().decode('utf-8','ignore'))
+ if not line:
+ break
+ self.host.bridge.sendMessage(dest_jid, line.replace("\n",""), profile_key=self.host.profile, callback=lambda: None, errback=lambda ignore: ignore)
+
+ else:
+ self.host.bridge.sendMessage(dest_jid, header + clean_ustr(u"".join([stream.decode('utf-8','ignore') for stream in sys.stdin.readlines()])), profile_key=self.host.profile, callback=lambda: None, errback=lambda ignore: ignore)
diff --git a/frontends/src/jp/cmd_pipe.py b/frontends/src/jp/cmd_pipe.py
new file mode 100644
index 00000000..935fe4c7
--- /dev/null
+++ b/frontends/src/jp/cmd_pipe.py
@@ -0,0 +1,87 @@
+#! /usr/bin/python
+# -*- coding: utf-8 -*-
+
+# jp: a SAT command line tool
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from sat_frontends.jp import base
+
+import tempfile
+import sys
+import os
+import os.path
+import shutil
+from sat.core.i18n import _
+
+__commands__ = ["Pipe"]
+
+class PipeOut(base.CommandBase):
+
+ def __init__(self, host):
+ super(PipeOut, self).__init__(host, 'out', help=_('Pipe a stream out'))
+
+ def add_parser_options(self):
+ self.parser.add_argument("jid", type=base.unicode_decoder, help=_("The destination jid"))
+
+ def pipe_out(self):
+ """ Create named pipe, and send stdin to it """
+ tmp_dir = tempfile.mkdtemp()
+ fifopath = os.path.join(tmp_dir,"pipe_out")
+ os.mkfifo(fifopath)
+ self.host.bridge.pipeOut(self.host.get_full_jid(self.args.jid), fifopath, {}, self.profile)
+ with open(fifopath, 'w') as f:
+ shutil.copyfileobj(sys.stdin, f)
+ shutil.rmtree(tmp_dir)
+ self.host.quit()
+
+ def connected(self):
+ # TODO: check_jids
+ self.need_loop = True
+ super(PipeOut, self).connected()
+ self.pipe_out()
+
+
+class PipeIn(base.CommandAnswering):
+ confirm_type = "PIPE_TRANSFER"
+
+ def __init__(self, host):
+ super(PipeIn, self).__init__(host, 'in', help=_('Wait for the reception of a pipe stream'))
+
+ @property
+ def dest_jids(self):
+ return self.args.jids
+
+ def add_parser_options(self):
+ self.parser.add_argument("jids", type=base.unicode_decoder, nargs="*", help=_('Jids accepted (none means "accept everything")'))
+
+ def ask(self, data, confirm_id):
+ answer_data = {}
+ tmp_dir = tempfile.mkdtemp()
+ fifopath = os.path.join(tmp_dir,"pipe_in")
+ answer_data["dest_path"] = fifopath
+ os.mkfifo(fifopath)
+ self.host.bridge.confirmationAnswer(confirm_id, True, answer_data, self.profile)
+ with open(fifopath, 'r') as f:
+ shutil.copyfileobj(f, sys.stdout)
+ shutil.rmtree(tmp_dir)
+ self.host.quit()
+
+
+class Pipe(base.CommandBase):
+ subcommands = (PipeOut, PipeIn)
+
+ def __init__(self, host):
+ super(Pipe, self).__init__(host, 'pipe', use_profile=False, help=_('Stream piping through XMPP'))
diff --git a/frontends/src/jp/cmd_profile.py b/frontends/src/jp/cmd_profile.py
new file mode 100644
index 00000000..ecacfba2
--- /dev/null
+++ b/frontends/src/jp/cmd_profile.py
@@ -0,0 +1,115 @@
+#! /usr/bin/python
+# -*- coding: utf-8 -*-
+
+# jp: a SAT command line tool
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+"""This module permits to manage profiles. It can list, create, delete
+and retrieve informations about a profile."""
+
+from logging import debug, info, error, warning
+from sat.core.i18n import _
+from sat_frontends.jp import base
+from sat.tools.jid import JID
+
+__commands__ = ["Profile"]
+
+PROFILE_HELP = _('The name of the profile')
+
+
+class ProfileDelete(base.CommandBase):
+ def __init__(self, host):
+ super(ProfileDelete, self).__init__(host, 'delete', use_profile=False, help=_('Delete a profile'))
+
+ def add_parser_options(self):
+ self.parser.add_argument('profile', type=str, help=PROFILE_HELP)
+
+ def run(self):
+ super(ProfileDelete, self).run()
+ if self.args.profile not in self.host.bridge.getProfilesList():
+ error("Profile %s doesn't exist." % self.args.profile)
+ self.host.quit(1)
+ self.host.bridge.deleteProfile(self.args.profile)
+
+
+class ProfileInfo(base.CommandBase):
+ def __init__(self, host):
+ super(ProfileInfo, self).__init__(host, 'info', use_profile=False, help=_('Get informations about a profile'))
+
+ def add_parser_options(self):
+ self.parser.add_argument('profile', type=str, help=PROFILE_HELP)
+
+ def run(self):
+ super(ProfileInfo, self).run()
+ self.need_loop = True
+
+ def getPassword(password):
+ print "pwd: %s" % password
+ self.host.quit()
+
+ def getJID(jid):
+ print "jid: %s" % jid
+ self.host.bridge.asyncGetParamA("Password", "Connection", profile_key=self.args.profile, callback=getPassword)
+
+ if self.args.profile not in self.host.bridge.getProfilesList():
+ error("Profile %s doesn't exist." % self.args.profile)
+ self.host.quit(1)
+
+ self.host.bridge.asyncGetParamA("JabberID", "Connection", profile_key=self.args.profile, callback=getJID)
+
+
+class ProfileList(base.CommandBase):
+ def __init__(self, host):
+ super(ProfileList, self).__init__(host, 'list', use_profile=False, help=_('List profiles'))
+
+ def add_parser_options(self):
+ pass
+
+ def run(self):
+ super(ProfileList, self).run()
+ for profile in self.host.bridge.getProfilesList():
+ print profile
+
+
+class ProfileCreate(base.CommandBase):
+ def __init__(self, host):
+ super(ProfileCreate, self).__init__(host, 'create', use_profile=False, help=_('Create a new profile'))
+
+ def add_parser_options(self):
+ self.parser.add_argument('profile', type=str, help=_('the name of the profile'))
+ self.parser.add_argument('jid', type=str, help=_('the jid of the profile'))
+ self.parser.add_argument('password', type=str, help=_('the password of the profile'))
+
+ def _profile_created(self):
+ self.host.bridge.setParam("JabberID", self.args.jid, "Connection" ,profile_key=self.args.profile)
+ self.host.bridge.setParam("Server", JID(self.args.jid).domain, "Connection", profile_key=self.args.profile)
+ self.host.bridge.setParam("Password", self.args.password, "Connection", profile_key=self.args.profile)
+ self.host.quit()
+
+ def run(self):
+ """Create a new profile"""
+ self.need_loop = True
+ if self.args.profile in self.host.bridge.getProfilesList():
+ error("Profile %s already exists." % self.args.profile)
+ self.host.quit(1)
+ self.host.bridge.asyncCreateProfile(self.args.profile, self._profile_created, None)
+
+
+class Profile(base.CommandBase):
+ subcommands = (ProfileDelete, ProfileInfo, ProfileList, ProfileCreate)
+
+ def __init__(self, host):
+ super(Profile, self).__init__(host, 'profile', use_profile=False, help=_('Profile commands'))
diff --git a/frontends/src/jp/common.py b/frontends/src/jp/common.py
deleted file mode 100644
index a9885a99..00000000
--- a/frontends/src/jp/common.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-
-# jp: a SAT command line tool
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-
-
-class MissingPlugin(Exception):
- pass
-
-def require(plugin_name):
- suported_plugins = ["profile"]
- if plugin_name not in Supported_plugins:
- raise MissingPlugin
diff --git a/frontends/src/jp/file.py b/frontends/src/jp/file.py
deleted file mode 100644
index 5e64db65..00000000
--- a/frontends/src/jp/file.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-
-# jp: a SAT command line tool
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-from logging import debug, info, error, warning
-
-import base
-import sys
-import os
-import os.path
-import tarfile
-#import tempfile
-from os.path import abspath, basename, dirname
-from sat.core.i18n import _
-
-file_parser = base.subparser.add_parser('file',
- help = "File managment")
-
-file_parser.add_argument("-p", "--profile", action="store", type=str, default='@DEFAULT@',
- help=_("Use PROFILE profile key (default: %(default)s)"))
-file_subparser = file_parser.add_subparsers()
-file_send = file_subparser.add_parser('send',
- help = "Send a file to a contact")
-file_send.add_argument("file", type=str, nargs = '*',
- help=_("A list of file"))
-file_send.add_argument("jid", type=str,
- help=_("The destination jid"))
-file_send.add_argument("-b", "--bz2", action="store_true", default=False,
- help=_("Make a bzip2 tarball"))
-
-file_send.set_defaults(func=lambda args : FileSend(args.profile, args.jid, args.file, args.bz2).go())
-
-
-file_recv = file_subparser.add_parser('recv',
- help = "Receive a file to a contact")
-file_recv.add_argument("jids", type=str, nargs="*",
- help=_("A list of destination jids"))
-file_recv.add_argument("-m", "--multiple", action="store_true", default=False,
- help=_("Wait for a file to be sent by a contact"))
-file_recv.add_argument("-f", "--force", action="store_true", default=False,
- help=_("Force overwritting of existing files"))
-
-file_recv.set_defaults(func=lambda args : FileRecv(args.profile,
- args.jids,
- args.multiple,
- args.force).go())
-
-
-
-class FileSend(base.JPWithProfile):
- def __init__(self, profile, dest_jid, files, bz2):
- base.JPWithProfile.__init__(self,profile)
- self.dest_jid = dest_jid
- self.files = files
- self.bz2 = bz2
-
- def send_files(self):
- """Send files to jabber contact"""
- for file in self.files:
- if not os.path.exists(file):
- error (_(u"File [%s] doesn't exist !") % file)
- exit(1)
- if not self.bz2 and os.path.isdir(file):
- error (_("[%s] is a dir ! Please send files inside or use compression") % file)
- exit(1)
-
- full_dest_jid = self._getFullJid(self.dest_jid)
- if self.bz2:
- tmpfile = (basename(self.files[0]) or basename(dirname(self.files[0])) ) + '.tar.bz2' #FIXME: tmp, need an algorithm to find a good name/path
- if os.path.exists(tmpfile):
- error (_("tmp file (%s) already exists ! Please remove it"), tmpfile)
- exit(1)
- warning(_("bz2 is an experimental option at an early dev stage, use with caution"))
- #FIXME: check free space, writting perm, tmp dir, filename (watch for OS used)
- info(_("Starting compression, please wait..."))
- sys.stdout.flush()
- bz2=tarfile.open(tmpfile, "w:bz2")
- for file in self.files:
- info(_("Adding %s"), file)
- bz2.add(file)
- bz2.close()
- info(_("OK !"))
- path = abspath(tmpfile)
- self.transfer_data = self.bridge.sendFile(full_dest_jid, path, {}, self.profile)
- else:
- for file in self.files:
- path = abspath(file)
- self.transfer_data = self.bridge.sendFile(full_dest_jid, path, {}, self.profile) #FIXME: show progress only for last transfer_id
-
- def run(self):
- self.send_files()
-
-
-class FileRecv(base.JPAsk):
- def __init__(self, profile, dest_jids, multiple, force, progress = False):
- base.JPAsk.__init__(self,profile, start_mainloop = True)
- self._dest_jids = dest_jids
- self.multiple = multiple
- self.force = force
- self.progress = progress
-
- def dest_jids(self):
- return self._dest_jids
-
- def confirm_type(self):
- return "FILE_TRANSFER"
-
- def ask(self, data):
- answer_data = {}
- answer_data["dest_path"] = os.getcwd()+'/'+data['filename']
-
- if self.force or not os.path.exists(answer_data["dest_path"]):
- self.answer(True, answer_data)
- info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']})
- # self.transfer_data = self.confirm_id # Used by progress
- else:
- self.answer(False, answer_data)
- warning(_("Refused file [%(filename)s] from %(sender)s: a file with the same name already exist") % {'filename':data['filename'], 'sender':data['from']})
-
-
- if not self.multiple and not self.progress:
- #we just accept one file
- self.loop.quit()
diff --git a/frontends/src/jp/jp b/frontends/src/jp/jp
index b2a5baf1..a6c05b7e 100755
--- a/frontends/src/jp/jp
+++ b/frontends/src/jp/jp
@@ -17,13 +17,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import base
-import message
-import pipe
-import profile
-import file
+from sat_frontends.jp import base
if __name__ == "__main__":
- args = base.parser.parse_args()
- args.func(args)
-
+ jp = base.Jp()
+ jp.import_commands()
+ jp.run()
diff --git a/frontends/src/jp/message.py b/frontends/src/jp/message.py
deleted file mode 100644
index 86e04717..00000000
--- a/frontends/src/jp/message.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-
-# jp: a SAT command line tool
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import base
-import sys
-from sat.core.i18n import _
-
-message_parser = base.subparser.add_parser('message', help = "Send a message to a contact")
-message_parser.add_argument("-p", "--profile", action="store", type=str, default='@DEFAULT@',
- help=_("Use PROFILE profile key (default: %(default)s)"))
-
-message_parser.add_argument("-s", "--separate", action="store_true", default=False,
- help=_("Separate xmpp messages: send one message per line instead of one message alone."))
-message_parser.add_argument("-n", "--new-line", action="store_true", default=False,
- help=_("Add a new line at the beginning of the input (usefull for ascii art ;))"))
-message_parser.add_argument("jid", type=str,
- help=_("The destination jid"))
-
-def launch(args):
- profile = args.profile
- jp = Message(profile, args.jid, args.new_line, args.separate)
- jp.go()
-
-message_parser.set_defaults(func=launch)
-
-class Message(base.JPWithProfile):
- def __init__(self, profile, dest_jid, new_line = False, separate = False):
- base.JPWithProfile.__init__(self,profile)
- self.dest_jid = dest_jid
- self.new_line = new_line
- self.separate = separate
-
-
- def send_stdin(self, dest_jid , new_line = False, separate = False):
- """Send incomming data on stdin to jabber contact"""
- header = "\n" if new_line else ""
-
- if separate: #we send stdin in several messages
- if header:
- self.bridge.sendMessage(dest_jid, header, profile_key=self.profile, callback=lambda: None, errback=lambda ignore: ignore)
- while (True):
- line = base.clean_ustr(sys.stdin.readline().decode('utf-8','ignore'))
- if not line:
- break
- self.bridge.sendMessage(dest_jid, line.replace("\n",""), profile_key=self.profile, callback=lambda: None, errback=lambda ignore: ignore)
- else:
- self.bridge.sendMessage(dest_jid, header + base.clean_ustr(u"".join([stream.decode('utf-8','ignore') for stream in sys.stdin.readlines()])), profile_key=self.profile, callback=lambda: None, errback=lambda ignore: ignore)
-
- def run(self):
- jids = self.check_jids([self.dest_jid])
- jid = jids[0]
- self.send_stdin(jid, self.new_line, self.separate)
diff --git a/frontends/src/jp/pipe.py b/frontends/src/jp/pipe.py
deleted file mode 100644
index 0f98359b..00000000
--- a/frontends/src/jp/pipe.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-
-# jp: a SAT command line tool
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import base
-
-import tempfile
-import os
-import shutil
-from sat.core.i18n import _
-
-
-parser = base.subparser.add_parser('pipe',
- help = "File managment")
-
-parser.add_argument("-p", "--profile", action="store", type=str, default='@DEFAULT@',
- help=_("Use PROFILE profile key (default: %(default)s)"))
-
-subparser = parser.add_subparsers()
-pipein = subparser.add_parser('out',
- help = "Send a pipe to a contact")
-pipein.add_argument("jid", type=str,
- help=_("The destination jid"))
-
-pipein.set_defaults(func=lambda args : PipeOut(args.profile, args.jid).go())
-
-pipeout = subparser.add_parser('in',
- help = "Send a pipe to a contact")
-pipeout.add_argument("jids", type=str, nargs="*",
- help=_("The destination jid"))
-
-pipeout.set_defaults(func=lambda args : PipeIn(args.profile, args.jids).go())
-
-class PipeOut(base.JPWithProfile):
- def __init__(self, profile, dest_jid):
- base.JPWithProfile.__init__(self,profile)
- self.dest_jid = dest_jid
-
- def pipe_out(self, dest_jid):
- """Create named pipe, and send stdin to it"""
- tmp_dir = tempfile.mkdtemp()
- fifopath = os.path.join(tmp_dir,"pipe_out")
- os.mkfifo(fifopath)
- self.bridge.pipeOut(self._getFullJid(dest_jid), fifopath, {}, self.profile)
- with open(fifopath, 'w') as f:
- shutil.copyfileobj(sys.stdin, f)
- shutil.rmtree(tmp_dir)
-
- def run(self):
- jids = self.check_jids([self.dest_jid])
- jid = jids[0]
- self.pipe_out(jid)
-
-class PipeIn(base.JPAsk):
- def __init__(self, profile, dest_jids):
- base.JPAsk.__init__(self,profile, start_mainloop = True)
- self._dest_jids = dest_jids
-
- def dest_jids(self):
- return self._dest_jids
-
- def confirm_type(self):
- return "PIPE_TRANSFER"
-
- def ask(self, data):
- answer_data = {}
- tmp_dir = tempfile.mkdtemp()
- fifopath = os.path.join(tmp_dir,"pipe_in")
- answer_data["dest_path"] = fifopath
- os.mkfifo(fifopath)
- self.answer(True, answer_data)
- with open(fifopath, 'r') as f:
- shutil.copyfileobj(f, sys.stdout)
- shutil.rmtree(tmp_dir)
- self.loop.quit()
diff --git a/frontends/src/jp/profile.py b/frontends/src/jp/profile.py
deleted file mode 100644
index 33833469..00000000
--- a/frontends/src/jp/profile.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-
-# jp: a SAT command line tool
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""This module permits to manage profiles. It can list, create, delete
-and retrieve informations about a profile."""
-
-import base
-import sys
-
-from logging import debug, info, error, warning
-from sat.core.i18n import _
-
-profile_parser = base.subparser.add_parser('profile',
- help = "Profile Commands")
-profile_subparser = profile_parser.add_subparsers()
-
-################################################################################
-# DELETE #
-################################################################################
-profile_delete = profile_subparser.add_parser('delete',
- help = "Delete a profile")
-profile_delete.add_argument('profile', type=str,
- help='the name of the profile')
-profile_delete.set_defaults(
- func = lambda args : ProfileDelete(args.profile).go())
-
-class ProfileDelete(base.JP):
- def __init__(self, profile_name):
- base.JP.__init__(self)
- self.profile_name = profile_name
-
- def run(self):
- if self.profile_name not in self.bridge.getProfilesList():
- error("Profile %s doesn't exist."%self.profile_name)
- exit(1)
- self.bridge.deleteProfile(self.profile_name)
-
-################################################################################
-# INFO #
-################################################################################
-profile_info = profile_subparser.add_parser('info',
- help = "Get informations about a profile")
-profile_info.add_argument('profile', type=str,
- help='the name of the profile')
-profile_info.set_defaults(
- func = lambda args : ProfileInfo(args.profile).go())
-
-class ProfileInfo(base.JP):
- def __init__(self, profile_name):
- base.JP.__init__(self)
- self.profile_name = profile_name
-
- def run(self):
- def getJID(jid):
- info("jid: %s"%jid)
- self.bridge.asyncGetParamA("Password", "Connection", profile_key=self.profile_name, callback=getPassword)
- def getPassword(password):
- info("pwd: %s"%password)
- self.loop.quit()
- if self.profile_name not in self.bridge.getProfilesList():
- error("Profile %s doesn't exist."%self.profile_name)
- exit(1)
-
- self.start_mainloop()
- self.bridge.asyncGetParamA("JabberID", "Connection", profile_key=self.profile_name, callback=getJID)
-
-################################################################################
-# LIST #
-################################################################################
-profile_list = profile_subparser.add_parser('list',
- help = "List profiles")
-profile_list.set_defaults(
- func = lambda args : ProfileList().go())
-
-class ProfileList(base.JP):
- def run(self):
- for p in self.bridge.getProfilesList():
- info(p)
-
-################################################################################
-# CREATE #
-################################################################################
-create_parser = profile_subparser.add_parser('create',
- help = "Create a new profile")
-create_parser.add_argument('profile', type=str,
- help='the name of the profile')
-create_parser.add_argument('jid', type=str,
- help='the jid of the profile')
-create_parser.add_argument('password', type=str,
- help='the password of the profile')
-create_parser.set_defaults(
- func = lambda args : ProfileCreate(args.profile, args.jid, args.password).go())
-
-class ProfileCreate(base.JP):
- def __init__(self, profile_name, jid, password):
- base.JP.__init__(self)
- self.profile_name = profile_name
- self.jid = jid
- self.password = password
-
- def _create_profile(self, profile_name, jid, password):
- self.bridge.setParam("JabberID", jid, "Connection" ,profile_key=profile_name)
- self.bridge.setParam("Server", base.JID(jid).domain, "Connection", profile_key=profile_name)
- self.bridge.setParam("Password", password, "Connection", profile_key=profile_name)
- self.loop.quit()
-
- def run(self):
- """Create a new profile"""
- if self.profile_name in self.bridge.getProfilesList():
- error("Profile %s already exists."%self.profile_name)
- exit(1)
- self.start_mainloop()
- self.bridge.asyncCreateProfile(self.profile_name, lambda : self._create_profile(self.profile_name, self.jid, self.password), None)
-