#! /usr/bin/python # -*- coding: utf-8 -*- """ jp: a SAT command line tool Copyright (C) 2009, 2010 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 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ #consts name = "jp" version = "0.0.1" about = name+" v"+version+""" (c) Jérôme Poisson (aka Goffi) 2009, 2010 --- """+name+""" Copyright (C) 2009, 2010 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 gettext gettext.install('jp', "i18n", unicode=True) import sys import os from os.path import abspath, basename, dirname from optparse import OptionParser import pdb from tools.jid import JID import gobject from sat_bridge_frontend.DBus import DBusBridgeFrontend import tarfile 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(): def __init__(self): self.bridge=DBusBridgeFrontend() self.transfert_id = 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 """) parser = OptionParser(usage=usage,version=about) 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("-p", "--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 ;))")) (self.options, args) = parser.parse_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: #several jid self.dest_jids = args else: #one dest_jid, other args are files self.dest_jid = JID(args[-1]) if not self.dest_jid.is_valid: error (_("%s is not a valid JID !"), self.dest_jid) exit(1) 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: self.start_loop = True #We have to use loop for these options else: self.start_loop = False return args def check_jabber_status(self): """Check that jabber status is allright""" if not self.bridge.isConnected(): error(_("SAT is not conneted, please connect before using jp")) exit(1) 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) while (True): line = sys.stdin.readline() if not line: break self.bridge.sendMessage(self.dest_jid, line.replace("\n","")) else: self.bridge.sendMessage(self.dest_jid, header + "".join(sys.stdin.readlines())) def send_files(self): """Send files to jabber contact""" for file in self.files: if not os.path.exists(file): error (_("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) 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.transfert_id = self.bridge.sendFile(self.dest_jid, path) else: for file in self.files: path = abspath(file) self.transfert_id = self.bridge.sendFile(self.dest_jid, path) #FIXME: show progress only for last transfert_id #TODO: manage ProgressBar def askConfirmation(self, type, id, data): """CB used for file transfert, accept files depending on parameters""" answer_data={} if type == "FILE_TRANSFERT": if self.dest_jids and not data['from'] 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(id, True, answer_data) info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']}) self.transfert_id = id else: self.bridge.confirmationAnswer(id, 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.options.multiple and not self.options.progress: #we just accept one file self.loop.quit() def actionResult(self, type, id, data): #FIXME info (_("FIXME: actionResult not implemented")) def wait_file(self): """Wait for a file and write it on local dir""" self.bridge.register("askConfirmation", self.askConfirmation, "request") def progressCB(self): if self.transfert_id: data = self.bridge.getProgress(self.transfert_id) 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() self.check_jabber_status() if self.options.wait_file: self.wait_file() else: if not self.files: #we send message only if there are no files to send self.send_stdin() else: self.send_files() if self.start_loop: self.loop = gobject.MainLoop() if self.options.progress: self.pbar = None gobject.timeout_add(10, self.progressCB) try: self.loop.run() except KeyboardInterrupt: info(_("User interruption: good bye")) if __name__ == "__main__": jp = JP() jp.go()