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