comparison frontends/src/jp/jp @ 223:86d249b6d9b7

Files reorganisation
author Goffi <goffi@goffi.org>
date Wed, 29 Dec 2010 01:06:29 +0100
parents frontends/jp/jp@1438a1337732
children fd9b7834d98a
comparison
equal deleted inserted replaced
222:3198bfd66daa 223:86d249b6d9b7
1 #! /usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 """
5 jp: a SAT command line tool
6 Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """
21
22 #consts
23 name = u"jp"
24 about = name+u""" v%s (c) Jérôme Poisson (aka Goffi) 2009, 2010
25
26 ---
27 """+name+u""" Copyright (C) 2009, 2010 Jérôme Poisson (aka Goffi)
28 This program comes with ABSOLUTELY NO WARRANTY;
29 This is free software, and you are welcome to redistribute it
30 under certain conditions.
31 ---
32
33 This software is a command line tool for jabber
34 Get the latest version at http://www.goffi.org
35 """
36
37 global pbar_available
38 pbar_available = True #checked before using ProgressBar
39
40 ### logging ###
41 import logging
42 from logging import debug, info, error, warning
43 logging.basicConfig(level=logging.DEBUG,
44 format='%(message)s')
45 ###
46
47 import gettext
48 gettext.install('jp', "i18n", unicode=True)
49
50 import sys
51 import os
52 from os.path import abspath, basename, dirname
53 from optparse import OptionParser
54 import pdb
55 from tools.jid import JID
56 import gobject
57 from sat_bridge_frontend.DBus import DBusBridgeFrontend,BridgeExceptionNoService
58 import tarfile
59 try:
60 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed
61 except ImportError, e:
62 info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar'))
63 info (_('Progress bar deactivated\n--\n'))
64 pbar_available=False
65
66
67
68
69 class JP():
70 def __init__(self):
71 try:
72 self.bridge=DBusBridgeFrontend()
73 except BridgeExceptionNoService:
74 print(_(u"Can't connect to SàT backend, are you sure it's launched ?"))
75 import sys
76 sys.exit(1)
77 self.transfert_id = None
78
79 def check_options(self):
80 """Check command line options"""
81 usage=_("""
82 %prog [options] [FILE1 FILE2 ...] JID
83 %prog -w [options] [JID1 JID2 ...]
84
85 %prog --help for options list
86 """)
87 version = unicode(self.bridge.getVersion())
88 parser = OptionParser(usage=usage,version=about % version)
89
90 parser.add_option("-p", "--profile", action="store", type="string", default='@DEFAULT@',
91 help=_("Use PROFILE profile key (default: %default)"))
92 parser.add_option("-b", "--bz2", action="store_true", default=False,
93 help=_("Make a bzip2 tarball"))
94 parser.add_option("-w", "--wait-file", action="store_true", default=False,
95 help=_("Wait for a file to be sent by a contact"))
96 parser.add_option("-m", "--multiple", action="store_true", default=False,
97 help=_("Accept multiple files (you'll have to stop manually)"))
98 parser.add_option("-f", "--force", action="store_true", default=False,
99 help=_("Force overwritting of existing files"))
100 parser.add_option("-g", "--progress", action="store_true", default=False,
101 help=_("Show progress bar"))
102 parser.add_option("-s", "--separate", action="store_true", default=False,
103 help=_("Separate xmpp messages: send one message per line instead of one message alone."))
104 parser.add_option("-n", "--new-line", action="store_true", default=False,
105 help=_("Add a new line at the beginning of the input (usefull for ascii art ;))"))
106
107 (self.options, args) = parser.parse_args()
108
109 if len(args) < 1 and not self.options.wait_file:
110 parser.error(_("You must specify the destination JID (Jabber ID)").encode('utf-8'))
111
112 if self.options.wait_file:
113 #several jid
114 self.dest_jids = args
115 else:
116 #one dest_jid, other args are files
117 self.dest_jid = JID(args[-1])
118 if not self.dest_jid.is_valid:
119 error (_("%s is not a valid JID !"), self.dest_jid)
120 exit(1)
121 self.files = args[:-1]
122
123 if not pbar_available and self.options.progress:
124 self.options.progress = False
125 error (_("Option progress is not available, deactivated."))
126
127 if self.options.progress or self.options.wait_file:
128 self.start_loop = True #We have to use loop for these options
129 else:
130 self.start_loop = False
131
132
133 return args
134
135 def check_jabber_status(self):
136 """Check that jabber status is allright"""
137
138 self.profile = self.bridge.getProfileName(self.options.profile)
139 if not self.profile:
140 error(_("The profile asked doesn't exist"))
141 exit(1)
142
143 if not self.bridge.isConnected(self.profile):
144 error(_(u"SàT is not conneted, please connect before using jp"))
145 exit(1)
146
147
148 def send_stdin(self):
149 """Send incomming data on stdin to jabber contact"""
150 header = "\n" if self.options.new_line else ""
151
152 if self.options.separate: #we send stdin in several messages
153 if header:
154 self.bridge.sendMessage(self.dest_jid, header, profile_key=self.profile)
155 while (True):
156 line = sys.stdin.readline()
157 if not line:
158 break
159 self.bridge.sendMessage(self.dest_jid, line.replace("\n",""), profile_key=self.profile)
160 else:
161 self.bridge.sendMessage(self.dest_jid, header + "".join(sys.stdin.readlines()), profile_key=self.profile)
162
163 def send_files(self):
164 """Send files to jabber contact"""
165
166 for file in self.files:
167 if not os.path.exists(file):
168 error (_("File [%s] doesn't exist !") % file)
169 exit(1)
170 if not self.options.bz2 and os.path.isdir(file):
171 error (_("[%s] is a dir ! Please send files inside or use compression") % file)
172 exit(1)
173
174 if self.options.bz2:
175 tmpfile = (basename(self.files[0]) or basename(dirname(self.files[0])) ) + '.tar.bz2' #FIXME: tmp, need an algorithm to find a good name/path
176 if os.path.exists(tmpfile):
177 error (_("tmp file (%s) already exists ! Please remove it"), tmpfile)
178 exit(1)
179 warning(_("bz2 is an experimental option at an early dev stage, use with caution"))
180 #FIXME: check free space, writting perm, tmp dir, filename (watch for OS used)
181 info(_("Starting compression, please wait..."))
182 sys.stdout.flush()
183 bz2=tarfile.open(tmpfile, "w:bz2")
184 for file in self.files:
185 info(_("Adding %s"), file)
186 bz2.add(file)
187 bz2.close()
188 info(_("OK !"))
189 path = abspath(tmpfile)
190 self.transfert_id = self.bridge.sendFile(self.dest_jid, path, profile_key=self.profile)
191 else:
192 for file in self.files:
193 path = abspath(file)
194 self.transfert_id = self.bridge.sendFile(self.dest_jid, path, profile_key=self.profile) #FIXME: show progress only for last transfert_id
195
196 #TODO: manage ProgressBar
197
198 def askConfirmation(self, type, id, data):
199 """CB used for file transfert, accept files depending on parameters"""
200 answer_data={}
201 if type == "FILE_TRANSFERT":
202 if self.dest_jids and not data['from'] in self.dest_jids:
203 return #file is not sent by a filtered jid
204
205 answer_data["dest_path"] = os.getcwd()+'/'+data['filename']
206
207 if self.options.force or not os.path.exists(answer_data["dest_path"]):
208 self.bridge.confirmationAnswer(id, True, answer_data)
209 info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']})
210 self.transfert_id = id
211 else:
212 self.bridge.confirmationAnswer(id, False, answer_data)
213 warning(_("Refused file [%(filename)s] from %(sender)s: a file with the same name already exist") % {'filename':data['filename'], 'sender':data['from']})
214
215
216 if not self.options.multiple and not self.options.progress:
217 #we just accept one file
218 self.loop.quit()
219
220 def actionResult(self, type, id, data):
221 #FIXME
222 info (_("FIXME: actionResult not implemented"))
223
224 def wait_file(self):
225 """Wait for a file and write it on local dir"""
226 self.bridge.register("askConfirmation", self.askConfirmation, "request")
227
228 def progressCB(self):
229 if self.transfert_id:
230 data = self.bridge.getProgress(self.transfert_id)
231 if data:
232 if not data['position']:
233 data['position'] = '0'
234 if not self.pbar:
235 #first answer, we must construct the bar
236 self.pbar = ProgressBar(int(data['size']),[_("Progress: "),Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()])
237 self.pbar.start()
238
239 self.pbar.update(int(data['position']))
240 elif self.pbar:
241 self.pbar.finish()
242 if not self.options.multiple:
243 self.loop.quit()
244 return False
245
246 return True
247
248 def go(self):
249 self.check_options()
250 self.check_jabber_status()
251 if self.options.wait_file:
252 self.wait_file()
253 else:
254 if not self.files: #we send message only if there are no files to send
255 self.send_stdin()
256 else:
257 self.send_files()
258
259 if self.start_loop:
260 self.loop = gobject.MainLoop()
261 if self.options.progress:
262 self.pbar = None
263 gobject.timeout_add(10, self.progressCB)
264 try:
265 self.loop.run()
266 except KeyboardInterrupt:
267 info(_("User interruption: good bye"))
268
269
270 if __name__ == "__main__":
271 jp = JP()
272 jp.go()