267 lines
10 KiB
Python
Executable file
267 lines
10 KiB
Python
Executable file
#! /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 <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
#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("-p", "--profile", action="store", type="string", default='@DEFAULT@',
|
|
help=_("Use PROFILE profile key"))
|
|
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 ;))"))
|
|
|
|
(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"""
|
|
|
|
self.profile = self.bridge.getProfileName(self.options.profile)
|
|
if not self.profile:
|
|
error(_("The profile asked doesn't exist"))
|
|
exit(1)
|
|
|
|
if not self.bridge.isConnected(self.profile):
|
|
error(_(u"SàT 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, profile_key=self.profile)
|
|
while (True):
|
|
line = sys.stdin.readline()
|
|
if not line:
|
|
break
|
|
self.bridge.sendMessage(self.dest_jid, line.replace("\n",""), profile_key=self.profile)
|
|
else:
|
|
self.bridge.sendMessage(self.dest_jid, header + "".join(sys.stdin.readlines()), profile_key=self.profile)
|
|
|
|
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, profile_key=self.profile)
|
|
else:
|
|
for file in self.files:
|
|
path = abspath(file)
|
|
self.transfert_id = self.bridge.sendFile(self.dest_jid, path, profile_key=self.profile) #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()
|