Mercurial > libervia-backend
annotate frontends/src/jp/jp @ 391:c34fd9d6242e
spelling
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 29 Sep 2011 14:59:14 +0200 |
parents | 8e87af2e2d1f |
children | 393b35aa86d2 |
rev | line source |
---|---|
0 | 1 #! /usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 """ | |
5 jp: a SAT command line tool | |
228 | 6 Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) |
0 | 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 | |
191 | 23 name = u"jp" |
228 | 24 about = name+u""" v%s (c) Jérôme Poisson (aka Goffi) 2009, 2010, 2011 |
0 | 25 |
26 --- | |
228 | 27 """+name+u""" Copyright (C) 2009, 2010, 2011 Jérôme Poisson (aka Goffi) |
0 | 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 | |
70 | 47 import gettext |
48 gettext.install('jp', "i18n", unicode=True) | |
49 | |
0 | 50 import sys |
51 import os | |
52 from os.path import abspath, basename, dirname | |
53 from optparse import OptionParser | |
54 import pdb | |
236 | 55 from sat.tools.jid import JID |
0 | 56 import gobject |
225
fd9b7834d98a
distutils installation script, draft
Goffi <goffi@goffi.org>
parents:
223
diff
changeset
|
57 from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService |
0 | 58 import tarfile |
59 try: | |
60 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed | |
61 except ImportError, e: | |
70 | 62 info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar')) |
63 info (_('Progress bar deactivated\n--\n')) | |
0 | 64 pbar_available=False |
65 | |
66 | |
67 | |
68 | |
69 class JP(): | |
70 def __init__(self): | |
165
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
71 try: |
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
72 self.bridge=DBusBridgeFrontend() |
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
73 except BridgeExceptionNoService: |
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
74 print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) |
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
75 import sys |
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
76 sys.exit(1) |
391 | 77 self.transfer_id = None |
0 | 78 |
79 def check_options(self): | |
80 """Check command line options""" | |
70 | 81 usage=_(""" |
0 | 82 %prog [options] [FILE1 FILE2 ...] JID |
83 %prog -w [options] [JID1 JID2 ...] | |
84 | |
85 %prog --help for options list | |
70 | 86 """) |
191 | 87 version = unicode(self.bridge.getVersion()) |
88 parser = OptionParser(usage=usage,version=about % version) | |
0 | 89 |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
90 parser.add_option("-p", "--profile", action="store", type="string", default='@DEFAULT@', |
156
a216dfbb0d50
jp: added default value in --profile option's help
Goffi <goffi@goffi.org>
parents:
110
diff
changeset
|
91 help=_("Use PROFILE profile key (default: %default)")) |
0 | 92 parser.add_option("-b", "--bz2", action="store_true", default=False, |
70 | 93 help=_("Make a bzip2 tarball")) |
0 | 94 parser.add_option("-w", "--wait-file", action="store_true", default=False, |
70 | 95 help=_("Wait for a file to be sent by a contact")) |
0 | 96 parser.add_option("-m", "--multiple", action="store_true", default=False, |
70 | 97 help=_("Accept multiple files (you'll have to stop manually)")) |
0 | 98 parser.add_option("-f", "--force", action="store_true", default=False, |
70 | 99 help=_("Force overwritting of existing files")) |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
100 parser.add_option("-g", "--progress", action="store_true", default=False, |
70 | 101 help=_("Show progress bar")) |
0 | 102 parser.add_option("-s", "--separate", action="store_true", default=False, |
70 | 103 help=_("Separate xmpp messages: send one message per line instead of one message alone.")) |
0 | 104 parser.add_option("-n", "--new-line", action="store_true", default=False, |
70 | 105 help=_("Add a new line at the beginning of the input (usefull for ascii art ;))")) |
0 | 106 |
107 (self.options, args) = parser.parse_args() | |
108 | |
109 if len(args) < 1 and not self.options.wait_file: | |
70 | 110 parser.error(_("You must specify the destination JID (Jabber ID)").encode('utf-8')) |
0 | 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: | |
70 | 119 error (_("%s is not a valid JID !"), self.dest_jid) |
0 | 120 exit(1) |
121 self.files = args[:-1] | |
122 | |
123 if not pbar_available and self.options.progress: | |
124 self.options.progress = False | |
70 | 125 error (_("Option progress is not available, deactivated.")) |
0 | 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""" | |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
137 |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
138 self.profile = self.bridge.getProfileName(self.options.profile) |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
139 if not self.profile: |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
140 error(_("The profile asked doesn't exist")) |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
141 exit(1) |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
142 |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
143 if not self.bridge.isConnected(self.profile): |
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
144 error(_(u"SàT is not conneted, please connect before using jp")) |
0 | 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: | |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
154 self.bridge.sendMessage(self.dest_jid, header, profile_key=self.profile) |
0 | 155 while (True): |
156 line = sys.stdin.readline() | |
157 if not line: | |
158 break | |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
159 self.bridge.sendMessage(self.dest_jid, line.replace("\n",""), profile_key=self.profile) |
0 | 160 else: |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
161 self.bridge.sendMessage(self.dest_jid, header + "".join(sys.stdin.readlines()), profile_key=self.profile) |
0 | 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): | |
70 | 168 error (_("File [%s] doesn't exist !") % file) |
0 | 169 exit(1) |
170 if not self.options.bz2 and os.path.isdir(file): | |
70 | 171 error (_("[%s] is a dir ! Please send files inside or use compression") % file) |
0 | 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): | |
70 | 177 error (_("tmp file (%s) already exists ! Please remove it"), tmpfile) |
0 | 178 exit(1) |
70 | 179 warning(_("bz2 is an experimental option at an early dev stage, use with caution")) |
0 | 180 #FIXME: check free space, writting perm, tmp dir, filename (watch for OS used) |
70 | 181 info(_("Starting compression, please wait...")) |
0 | 182 sys.stdout.flush() |
183 bz2=tarfile.open(tmpfile, "w:bz2") | |
184 for file in self.files: | |
70 | 185 info(_("Adding %s"), file) |
0 | 186 bz2.add(file) |
187 bz2.close() | |
70 | 188 info(_("OK !")) |
0 | 189 path = abspath(tmpfile) |
391 | 190 self.transfer_id = self.bridge.sendFile(self.dest_jid, path, {}, profile_key=self.profile) |
0 | 191 else: |
192 for file in self.files: | |
193 path = abspath(file) | |
391 | 194 self.transfer_id = self.bridge.sendFile(self.dest_jid, path, {}, profile_key=self.profile) #FIXME: show progress only for last transfer_id |
0 | 195 |
196 #TODO: manage ProgressBar | |
197 | |
198 def askConfirmation(self, type, id, data): | |
391 | 199 """CB used for file transfer, accept files depending on parameters""" |
0 | 200 answer_data={} |
391 | 201 if type == "FILE_TRANSFER": |
0 | 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) | |
70 | 209 info(_("Accepted file [%(filename)s] from %(sender)s") % {'filename':data['filename'], 'sender':data['from']}) |
391 | 210 self.transfer_id = id |
0 | 211 else: |
212 self.bridge.confirmationAnswer(id, False, answer_data) | |
70 | 213 warning(_("Refused file [%(filename)s] from %(sender)s: a file with the same name already exist") % {'filename':data['filename'], 'sender':data['from']}) |
0 | 214 |
215 | |
216 if not self.options.multiple and not self.options.progress: | |
217 #we just accept one file | |
218 self.loop.quit() | |
219 | |
22
bb72c29f3432
added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents:
0
diff
changeset
|
220 def actionResult(self, type, id, data): |
bb72c29f3432
added action cb mechanism for buttons. Tested with a temporary new user registration button.
Goffi <goffi@goffi.org>
parents:
0
diff
changeset
|
221 #FIXME |
70 | 222 info (_("FIXME: actionResult not implemented")) |
0 | 223 |
224 def wait_file(self): | |
225 """Wait for a file and write it on local dir""" | |
390 | 226 self.bridge.register("askConfirmation", self.askConfirmation) |
0 | 227 |
228 def progressCB(self): | |
391 | 229 if self.transfer_id: |
230 data = self.bridge.getProgress(self.transfer_id) | |
0 | 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 | |
70 | 236 self.pbar = ProgressBar(int(data['size']),[_("Progress: "),Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()]) |
0 | 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: | |
70 | 267 info(_("User interruption: good bye")) |
0 | 268 |
269 | |
270 if __name__ == "__main__": | |
271 jp = JP() | |
272 jp.go() |