# HG changeset patch # User Dal # Date 1391607326 -3600 # Node ID 59c7bc51c3239a34bd053ca8b7dbeb95e01cfeb1 # Parent 1a1600491d9d43e7c9aceccf013273970b1313ac jp: refactoring using ArgParse diff -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/base.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/base.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,263 @@ +#! /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 __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 + +### logging ### +import logging +from logging import debug, info, error, warning +logging.basicConfig(level=logging.DEBUG, + format='%(message)s') +### + +import sys +import os +from os.path import abspath, basename, dirname +from argparse import ArgumentParser +from sat.tools.jid import JID +import gobject +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 +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 + + +#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 + + + +class JP(object): + """ + This class can be use to establish a connection with the + bridge. Moreover, it should manage a main loop. + + To use it, you mainly have to redefine the method run to perform + specify what kind of operation you want to perform. + + """ + def __init__(self, start_mainloop = False): + try: + self.bridge=DBusBridgeFrontend() + except BridgeExceptionNoService: + print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) + sys.exit(1) + except BridgeInitError: + print(_(u"Can't init bridge")) + sys.exit(1) + + self._start_loop = start_mainloop + + def run(self): + raise NotImplementedError + + 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() + + def _loop_start(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 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 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 + """ + names2jid = {} + nodes2jid = {} + + for contact in self.bridge.getContacts(self.profile): + _jid, attr, groups = contact + if attr.has_key("name"): + names2jid[attr["name"].lower()] = _jid + nodes2jid[JID(_jid).node.lower()] = _jid + + def expandJid(jid): + _jid = jid.lower() + if _jid in names2jid: + expanded = names2jid[_jid] + elif _jid in nodes2jid: + expanded = nodes2jid[_jid] + else: + expanded = jid + return unicode(expanded) + + def check(jid): + if not jid.is_valid: + error (_("%s is not a valid JID !"), jid) + exit(1) + + dest_jids=[] + try: + for i in range(len(jids)): + dest_jids.append(expandJid(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 + error(_(u"Can't connect profile")) + exit(1) + + self.profile = self.bridge.getProfileName(self.profile_name) + if not self.profile: + error(_("The profile asked doesn't exist")) + exit(1) + + if self.bridge.isConnected(self.profile): + print "Already connected" + else: + self._start_loop = True + self.bridge.asyncConnect(self.profile, self._run, cantConnect) + return + self.run() + + + def _getFullJid(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) + 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() + + + +class JPAsk(JPWithProfile): + def confirm_type(self): + """Must return a string containing the confirm type. For instance, + FILE_TRANSFER or PIPE_TRANSFER, etc. + + :rtype: str + """ + raise NotImplemented + + def dest_jids(self): + return None + + def _askConfirmation(self, confirm_id, confirm_type, data, profile): + 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()]: + return #file is not sent by a filtered jid + else: + self.ask(data) + + def ask(self): + """ + The return value is used to answer to the bridge. + :rtype: (bool, 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): + """Auto reply to confirmations requests""" + #we register incoming confirmation + self.bridge.register("askConfirmation", self._askConfirmation) + + #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) + + diff -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/common.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/common.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,9 @@ + + +class MissingPlugin(Exception): + pass + +def require(plugin_name): + suported_plugins = ["profile"] + if plugin_name not in Supported_plugins: + raise MissingPlugin diff -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/file.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/file.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,119 @@ +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 -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/jp --- a/frontends/src/jp/jp Tue Feb 04 18:54:06 2014 +0100 +++ b/frontends/src/jp/jp Wed Feb 05 14:35:26 2014 +0100 @@ -1,444 +1,12 @@ -#! /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 __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 - ---- -"""+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 - -### logging ### -import logging -from logging import debug, info, error, warning -logging.basicConfig(level=logging.DEBUG, - format='%(message)s') -### - -import sys -import os -from os.path import abspath, basename, dirname -from optparse import OptionParser -from sat.tools.jid import JID -import gobject -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 -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 - - - - -class JP(object): - def __init__(self): - try: - self.bridge=DBusBridgeFrontend() - except BridgeExceptionNoService: - print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) - sys.exit(1) - except BridgeInitError: - print(_(u"Can't init bridge")) - sys.exit(1) - self.transfer_data = None - - def check_options(self): - """Check command line options""" - usage=_(""" - %prog [options] [FILE1 FILE2 ...] JID - %prog -w [options] [JID1 JID2 ...] - - %prog --help for options list - """) - version = unicode(self.bridge.getVersion()) - parser = OptionParser(usage=usage,version=about % version) - - parser.add_option("-p", "--profile", action="store", type="string", default='@DEFAULT@', - help=_("Use PROFILE profile key (default: %default)")) - parser.add_option("-b", "--bz2", action="store_true", default=False, - help=_("Make a bzip2 tarball")) - parser.add_option("-w", "--wait-file", action="store_true", default=False, - help=_("Wait for a file to be sent by a contact")) - parser.add_option("-m", "--multiple", action="store_true", default=False, - help=_("Accept multiple files (you'll have to stop manually)")) - parser.add_option("-f", "--force", action="store_true", default=False, - help=_("Force overwritting of existing files")) - parser.add_option("-g", "--progress", action="store_true", default=False, - help=_("Show progress bar")) - parser.add_option("-s", "--separate", action="store_true", default=False, - help=_("Separate xmpp messages: send one message per line instead of one message alone.")) - parser.add_option("-n", "--new-line", action="store_true", default=False, - help=_("Add a new line at the beginning of the input (usefull for ascii art ;))")) - parser.add_option("--list-profiles", action="store_true", default=False, - help=_("List available profiles")) - parser.add_option("-c", "--create-profile", action="store", type="string", nargs=3, - help=_("Create a profile (args: profile_name jid password)")) - parser.add_option("--get-profile", action="store", type="string", - help=_("Get profile informations (arg: profile_name)")) - parser.add_option("--rm-profile", action="store", type="string", - help=_("Remove profile")) - parser.add_option("--connect", action="store_true", default=False, - help=_("Connect the profile before doing anything else")) - parser.add_option("--pipe-in", action="store_true", default=False, - help=_("Wait for the reception of a pipe stream")) - parser.add_option("--pipe-out", action="store_true", default=False, - help=_("Pipe a stream out ")) - - (self.options, args) = parser.parse_args() - if self.options.list_profiles: - for p in self.bridge.getProfilesList(): - info(p) - exit(0) - if self.options.create_profile or self.options.get_profile: - self.start_loop = True - return args - if self.options.rm_profile: - self.start_loop = False - return args - - if len(args) < 1 and not self.options.wait_file: - parser.error(_("You must specify the destination JID (Jabber ID)").encode('utf-8')) - - if self.options.wait_file or self.options.pipe_in: - #several jid - self.dest_jids = [arg.decode('utf-8') for arg in args] - else: - #one dest_jid, other args are files - self.dest_jid = JID(args[-1].decode('utf-8')) - self.files = args[:-1] - - if not pbar_available and self.options.progress: - self.options.progress = False - error (_("Option progress is not available, deactivated.")) - - if self.options.progress or self.options.wait_file or self.options.connect or self.options.pipe_in: - self.start_loop = True #We have to use loop for these options - else: - self.start_loop = False - - - return args - - def create_profile(self): - """Create a new profile""" - profile, jid, password = self.options.create_profile - if profile in self.bridge.getProfilesList(): - error("Profile %s already exists."%profile) - exit(1) - self.bridge.asyncCreateProfile(profile, lambda : self._create_profile(profile, jid, password), None) - - def get_profile(self): - def setJID(jid): - info("jid: %s"%jid) - self.bridge.asyncGetParamA("Password", "Connection", profile_key=profile_name, callback=setPassword) - def setPassword(password): - info("pwd: %s"%password) - self.loop.quit() - profile_name = self.options.get_profile - if profile_name not in self.bridge.getProfilesList(): - error("Profile %s doesn't exist."%profile_name) - exit(1) - self.bridge.asyncGetParamA("JabberID", "Connection", profile_key=profile_name, callback=setJID) - - def rm_profile(self): - profile_name = self.options.rm_profile - if profile_name not in self.bridge.getProfilesList(): - error("Profile %s doesn't exist."%profile_name) - exit(1) - self.bridge.deleteProfile(profile_name) - - def _create_profile(self, profile_name, jid, password): - self.bridge.setParam("JabberID", jid, "Connection" ,profile_key=profile_name) - self.bridge.setParam("Server", JID(jid).domain, "Connection", profile_key=profile_name) - self.bridge.setParam("Password", password, "Connection", profile_key=profile_name) - self.loop.quit() - - def check_jabber_status(self): - """Check that jabber status is allright""" - def cantConnect(): - error(_(u"Can't connect profile")) - exit(1) - - - self.profile = self.bridge.getProfileName(self.options.profile) - if not self.profile: - error(_("The profile asked doesn't exist")) - exit(1) - - if self.options.connect: #if connection is asked, we connect the profile - self.bridge.asyncConnect(self.profile, self.connected, cantConnect) - return - 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 }) - exit(1) - - self.connected() - - def check_jids(self): - """Check jids validity, transform roster name to corresponding jids""" - names2jid = {} - nodes2jid = {} +#!/usr/bin/python - for contact in self.bridge.getContacts(self.options.profile): - _jid, attr, groups = contact - if attr.has_key("name"): - names2jid[attr["name"].lower()] = _jid - nodes2jid[JID(_jid).node.lower()] = _jid - - def expandJid(jid): - _jid = jid.lower() - if _jid in names2jid: - expanded = names2jid[_jid] - elif _jid in nodes2jid: - expanded = nodes2jid[_jid] - else: - expanded = jid - return unicode(expanded) - - def check(jid): - if not jid.is_valid: - error (_("%s is not a valid JID !"), self.dest_jid) - exit(1) - - try: - self.dest_jid = expandJid(self.dest_jid) - check(self.dest_jid) - except AttributeError: - pass - try: - for i in range(len(self.dest_jids)): - self.dest_jids[i] = expandJid(self.dest_jids[i]) - check(self.dest_jids[i]) - except AttributeError: - pass - - - def send_stdin(self): - """Send incomming data on stdin to jabber contact""" - header = "\n" if self.options.new_line else "" - - if self.options.separate: #we send stdin in several messages - if header: - self.bridge.sendMessage(self.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.bridge.sendMessage(self.dest_jid, line.replace("\n",""), profile_key=self.profile, callback=lambda: None, errback=lambda ignore: ignore) - else: - self.bridge.sendMessage(self.dest_jid, header + 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 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.bridge.pipeOut(self._getFullJid(self.dest_jid), fifopath, {}, self.profile) - with open(fifopath, 'w') as f: - shutil.copyfileobj(sys.stdin, f) - shutil.rmtree(tmp_dir) - - - 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.options.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.options.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 _getFullJid(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.options.profile) - if last_resource: - return "%s/%s" % (_jid.bare, last_resource) - return param_jid - - - def askConfirmation(self, confirm_id, confirm_type, data, profile): - """CB used for file transfer, accept files depending on parameters""" - if profile != self.profile: - debug("Ask confirmation ignored: not our profile") - return - answer_data={} - if confirm_type == "FILE_TRANSFER": - if not self.options.wait_file: - return - 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 - - answer_data["dest_path"] = os.getcwd()+'/'+data['filename'] - - if self.options.force or not os.path.exists(answer_data["dest_path"]): - self.bridge.confirmationAnswer(confirm_id, True, answer_data, profile) - info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']}) - self.transfer_data = confirm_id - else: - self.bridge.confirmationAnswer(confirm_id, False, answer_data, 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.options.multiple and not self.options.progress: - #we just accept one file - self.loop.quit() - elif confirm_type == "PIPE_TRANSFER": - if not self.options.pipe_in: - return - if self.dest_jids and not JID(data['from']).bare in [JID(_jid).bare for _jid in self.dest_jids]: - return #pipe stream is not sent by a filtered jid - - tmp_dir = tempfile.mkdtemp() - fifopath = os.path.join(tmp_dir,"pipe_in") - answer_data["dest_path"] = fifopath - os.mkfifo(fifopath) - self.bridge.confirmationAnswer(confirm_id, True, answer_data, profile) - with open(fifopath, 'r') as f: - shutil.copyfileobj(f, sys.stdout) - shutil.rmtree(tmp_dir) - self.loop.quit() - - - def actionResult(self, action_type, action_id, data, profile): - #FIXME - info (_("FIXME: actionResult not implemented")) - - def confirmation_reply(self): - """Auto reply to confirmations requests""" - #we register incoming confirmation - self.bridge.register("askConfirmation", self.askConfirmation) - - #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) - - def progressCB(self): - if self.transfer_data: - transfer_id = self.transfer_data - data = self.bridge.getProgress(transfer_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(int(data['size']),[_("Progress: "),Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()]) - self.pbar.start() - - self.pbar.update(int(data['position'])) - elif self.pbar: - self.pbar.finish() - if not self.options.multiple: - self.loop.quit() - return False - - return True - - def go(self): - self.check_options() - if self.options.create_profile: - self.create_profile() - elif self.options.get_profile: - self.get_profile() - elif self.options.rm_profile: - self.rm_profile() - else: - self.check_jabber_status() - if self.start_loop: - self.loop = gobject.MainLoop() - try: - self.loop.run() - except KeyboardInterrupt: - info(_("User interruption: good bye")) - - def connected(self): - """This is called when the profile is connected""" - self.check_jids() - if self.options.wait_file or self.options.pipe_in: - self.confirmation_reply() - else: - if self.files: - self.send_files() - elif self.options.pipe_out: - self.pipe_out() - else: - self.send_stdin() - - if self.options.progress: - self.pbar = None - gobject.timeout_add(10, self.progressCB) - - if self.start_loop and not self.options.progress and not self.options.wait_file and not self.options.pipe_in: - self.loop.quit() - +import base +import message +import pipe +import profile +import file if __name__ == "__main__": - jp = JP() - jp.go() + args = base.parser.parse_args() + args.func(args) + diff -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/message.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/message.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,49 @@ +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 -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/pipe.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/pipe.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,71 @@ +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 -r 1a1600491d9d -r 59c7bc51c323 frontends/src/jp/profile.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/jp/profile.py Wed Feb 05 14:35:26 2014 +0100 @@ -0,0 +1,111 @@ +"""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) +