Mercurial > libervia-backend
comparison frontends/src/jp/base.py @ 814:59c7bc51c323
jp: refactoring using ArgParse
author | Dal <kedals0@gmail.com> |
---|---|
date | Wed, 05 Feb 2014 14:35:26 +0100 |
parents | frontends/src/jp/jp@1fe00f0c9a91 |
children | c39117d00f35 |
comparison
equal
deleted
inserted
replaced
813:1a1600491d9d | 814:59c7bc51c323 |
---|---|
1 #! /usr/bin/python | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # jp: a SAT command line tool | |
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 from __future__ import with_statement | |
21 from sat.core.i18n import _ | |
22 | |
23 #consts | |
24 name = u"jp" | |
25 about = name+u""" v%s (c) Jérôme Poisson (aka Goffi) 2009, 2010, 2011, 2012, 2013, 2014 | |
26 | |
27 --- | |
28 """+name+u""" Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 argparse import ArgumentParser | |
52 from sat.tools.jid import JID | |
53 import gobject | |
54 from sat_frontends.bridge.DBus import DBusBridgeFrontend | |
55 from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError | |
56 from sat.tools.utils import clean_ustr | |
57 import tarfile | |
58 import tempfile | |
59 import shutil | |
60 try: | |
61 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed | |
62 except ImportError, e: | |
63 info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar')) | |
64 info (_('Progress bar deactivated\n--\n')) | |
65 pbar_available=False | |
66 | |
67 | |
68 #version = unicode(self.bridge.getVersion()) | |
69 version = "undefined" | |
70 parser = ArgumentParser() | |
71 parser.add_argument('--version', action='version', version=about % version) | |
72 subparser = parser.add_subparsers(dest='subparser_name') | |
73 # File managment | |
74 | |
75 | |
76 | |
77 class JP(object): | |
78 """ | |
79 This class can be use to establish a connection with the | |
80 bridge. Moreover, it should manage a main loop. | |
81 | |
82 To use it, you mainly have to redefine the method run to perform | |
83 specify what kind of operation you want to perform. | |
84 | |
85 """ | |
86 def __init__(self, start_mainloop = False): | |
87 try: | |
88 self.bridge=DBusBridgeFrontend() | |
89 except BridgeExceptionNoService: | |
90 print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) | |
91 sys.exit(1) | |
92 except BridgeInitError: | |
93 print(_(u"Can't init bridge")) | |
94 sys.exit(1) | |
95 | |
96 self._start_loop = start_mainloop | |
97 | |
98 def run(self): | |
99 raise NotImplementedError | |
100 | |
101 def _run(self): | |
102 """Call run and lauch a loop if needed""" | |
103 print "You are connected!" | |
104 self.run() | |
105 if self._start_loop: | |
106 print "Exiting loop..." | |
107 self.loop.quit() | |
108 | |
109 def _loop_start(self): | |
110 self.loop = gobject.MainLoop() | |
111 try: | |
112 self.loop.run() | |
113 except KeyboardInterrupt: | |
114 info(_("User interruption: good bye")) | |
115 | |
116 def start_mainloop(self): | |
117 self._start_loop = True | |
118 | |
119 def go(self): | |
120 self.run() | |
121 if self._start_loop: | |
122 self._loop_start() | |
123 | |
124 | |
125 class JPWithProfile(JP): | |
126 """Manage a bridge (inherit from :class:`JP`), but it also adds | |
127 profile managment, ie, connection to the profile. | |
128 | |
129 Moreover, some useful methods are predefined such as | |
130 :py:meth:`check_jids`. The connection to XMPP is automatically | |
131 managed. | |
132 """ | |
133 | |
134 def __init__(self, profile_name, start_mainloop = False): | |
135 JP.__init__(self, start_mainloop) | |
136 self.profile_name = profile_name | |
137 | |
138 def check_jids(self, jids): | |
139 """Check jids validity, transform roster name to corresponding jids | |
140 | |
141 :param profile: A profile name | |
142 :param jids: A list of jids | |
143 :rtype: A list of jids | |
144 """ | |
145 names2jid = {} | |
146 nodes2jid = {} | |
147 | |
148 for contact in self.bridge.getContacts(self.profile): | |
149 _jid, attr, groups = contact | |
150 if attr.has_key("name"): | |
151 names2jid[attr["name"].lower()] = _jid | |
152 nodes2jid[JID(_jid).node.lower()] = _jid | |
153 | |
154 def expandJid(jid): | |
155 _jid = jid.lower() | |
156 if _jid in names2jid: | |
157 expanded = names2jid[_jid] | |
158 elif _jid in nodes2jid: | |
159 expanded = nodes2jid[_jid] | |
160 else: | |
161 expanded = jid | |
162 return unicode(expanded) | |
163 | |
164 def check(jid): | |
165 if not jid.is_valid: | |
166 error (_("%s is not a valid JID !"), jid) | |
167 exit(1) | |
168 | |
169 dest_jids=[] | |
170 try: | |
171 for i in range(len(jids)): | |
172 dest_jids.append(expandJid(jids[i])) | |
173 check(dest_jids[i]) | |
174 except AttributeError: | |
175 pass | |
176 | |
177 return dest_jids | |
178 | |
179 def check_jabber_connection(self): | |
180 """Check that jabber status is allright""" | |
181 def cantConnect(arg): | |
182 print arg | |
183 error(_(u"Can't connect profile")) | |
184 exit(1) | |
185 | |
186 self.profile = self.bridge.getProfileName(self.profile_name) | |
187 if not self.profile: | |
188 error(_("The profile asked doesn't exist")) | |
189 exit(1) | |
190 | |
191 if self.bridge.isConnected(self.profile): | |
192 print "Already connected" | |
193 else: | |
194 self._start_loop = True | |
195 self.bridge.asyncConnect(self.profile, self._run, cantConnect) | |
196 return | |
197 self.run() | |
198 | |
199 | |
200 def _getFullJid(self, param_jid): | |
201 """Return the full jid if possible (add last resource when find a bare jid""" | |
202 _jid = JID(param_jid) | |
203 if not _jid.resource: | |
204 #if the resource is not given, we try to add the last known resource | |
205 last_resource = self.bridge.getLastResource(param_jid, self.profile_name) | |
206 if last_resource: | |
207 return "%s/%s" % (_jid.bare, last_resource) | |
208 return param_jid | |
209 | |
210 def go(self): | |
211 self.check_jabber_connection() | |
212 if self._start_loop: | |
213 self._loop_start() | |
214 | |
215 | |
216 | |
217 class JPAsk(JPWithProfile): | |
218 def confirm_type(self): | |
219 """Must return a string containing the confirm type. For instance, | |
220 FILE_TRANSFER or PIPE_TRANSFER, etc. | |
221 | |
222 :rtype: str | |
223 """ | |
224 raise NotImplemented | |
225 | |
226 def dest_jids(self): | |
227 return None | |
228 | |
229 def _askConfirmation(self, confirm_id, confirm_type, data, profile): | |
230 if profile != self.profile: | |
231 debug("Ask confirmation ignored: not our profile") | |
232 return | |
233 if confirm_type == self.confirm_type(): | |
234 self._confirm_id = confirm_id | |
235 if self.dest_jids() and not JID(data['from']).bare in [JID(_jid).bare for _jid in self.dest_jids()]: | |
236 return #file is not sent by a filtered jid | |
237 else: | |
238 self.ask(data) | |
239 | |
240 def ask(self): | |
241 """ | |
242 The return value is used to answer to the bridge. | |
243 :rtype: (bool, dict) | |
244 """ | |
245 raise NotImplementedError | |
246 | |
247 def answer(self, accepted, answer_data): | |
248 """ | |
249 :param accepted: boolean | |
250 :param aswer_data: dict of answer datas | |
251 """ | |
252 self.bridge.confirmationAnswer(self._confirm_id, False, answer_data, self.profile) | |
253 | |
254 def run(self): | |
255 """Auto reply to confirmations requests""" | |
256 #we register incoming confirmation | |
257 self.bridge.register("askConfirmation", self._askConfirmation) | |
258 | |
259 #and we ask those we have missed | |
260 for confirm_id, confirm_type, data in self.bridge.getWaitingConf(self.profile): | |
261 self._askConfirmation(confirm_id, confirm_type, data, self.profile) | |
262 | |
263 |