comparison frontends/jp/jp @ 0:c4bc297b82f0

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