jp: refactoring using ArgParse
This commit is contained in:
parent
eeff94469a
commit
f4de26e4e8
1 changed files with 631 additions and 441 deletions
263
frontends/src/jp/base.py
Normal file
263
frontends/src/jp/base.py
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
#! /usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# jp: a SAT command line tool
|
||||
# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import with_statement
|
||||
from sat.core.i18n import _
|
||||
|
||||
#consts
|
||||
name = u"jp"
|
||||
about = name+u""" v%s (c) Jérôme Poisson (aka Goffi) 2009, 2010, 2011, 2012, 2013, 2014
|
||||
|
||||
---
|
||||
"""+name+u""" Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (aka Goffi)
|
||||
This program comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions.
|
||||
---
|
||||
|
||||
This software is a command line tool for jabber
|
||||
Get the latest version at http://www.goffi.org
|
||||
"""
|
||||
|
||||
global pbar_available
|
||||
pbar_available = True #checked before using ProgressBar
|
||||
|
||||
### logging ###
|
||||
import logging
|
||||
from logging import debug, info, error, warning
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format='%(message)s')
|
||||
###
|
||||
|
||||
import sys
|
||||
import os
|
||||
from os.path import abspath, basename, dirname
|
||||
from argparse import ArgumentParser
|
||||
from sat.tools.jid import JID
|
||||
import gobject
|
||||
from sat_frontends.bridge.DBus import DBusBridgeFrontend
|
||||
from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
|
||||
from sat.tools.utils import clean_ustr
|
||||
import tarfile
|
||||
import tempfile
|
||||
import shutil
|
||||
try:
|
||||
from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed
|
||||
except ImportError, e:
|
||||
info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar'))
|
||||
info (_('Progress bar deactivated\n--\n'))
|
||||
pbar_available=False
|
||||
|
||||
|
||||
#version = unicode(self.bridge.getVersion())
|
||||
version = "undefined"
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--version', action='version', version=about % version)
|
||||
subparser = parser.add_subparsers(dest='subparser_name')
|
||||
# File managment
|
||||
|
||||
|
||||
|
||||
class JP(object):
|
||||
"""
|
||||
This class can be use to establish a connection with the
|
||||
bridge. Moreover, it should manage a main loop.
|
||||
|
||||
To use it, you mainly have to redefine the method run to perform
|
||||
specify what kind of operation you want to perform.
|
||||
|
||||
"""
|
||||
def __init__(self, start_mainloop = False):
|
||||
try:
|
||||
self.bridge=DBusBridgeFrontend()
|
||||
except BridgeExceptionNoService:
|
||||
print(_(u"Can't connect to SàT backend, are you sure it's launched ?"))
|
||||
sys.exit(1)
|
||||
except BridgeInitError:
|
||||
print(_(u"Can't init bridge"))
|
||||
sys.exit(1)
|
||||
|
||||
self._start_loop = start_mainloop
|
||||
|
||||
def run(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def _run(self):
|
||||
"""Call run and lauch a loop if needed"""
|
||||
print "You are connected!"
|
||||
self.run()
|
||||
if self._start_loop:
|
||||
print "Exiting loop..."
|
||||
self.loop.quit()
|
||||
|
||||
def _loop_start(self):
|
||||
self.loop = gobject.MainLoop()
|
||||
try:
|
||||
self.loop.run()
|
||||
except KeyboardInterrupt:
|
||||
info(_("User interruption: good bye"))
|
||||
|
||||
def start_mainloop(self):
|
||||
self._start_loop = True
|
||||
|
||||
def go(self):
|
||||
self.run()
|
||||
if self._start_loop:
|
||||
self._loop_start()
|
||||
|
||||
|
||||
class JPWithProfile(JP):
|
||||
"""Manage a bridge (inherit from :class:`JP`), but it also adds
|
||||
profile managment, ie, connection to the profile.
|
||||
|
||||
Moreover, some useful methods are predefined such as
|
||||
:py:meth:`check_jids`. The connection to XMPP is automatically
|
||||
managed.
|
||||
"""
|
||||
|
||||
def __init__(self, profile_name, start_mainloop = False):
|
||||
JP.__init__(self, start_mainloop)
|
||||
self.profile_name = profile_name
|
||||
|
||||
def check_jids(self, jids):
|
||||
"""Check jids validity, transform roster name to corresponding jids
|
||||
|
||||
:param profile: A profile name
|
||||
:param jids: A list of jids
|
||||
:rtype: A list of jids
|
||||
"""
|
||||
names2jid = {}
|
||||
nodes2jid = {}
|
||||
|
||||
for contact in self.bridge.getContacts(self.profile):
|
||||
_jid, attr, groups = contact
|
||||
if attr.has_key("name"):
|
||||
names2jid[attr["name"].lower()] = _jid
|
||||
nodes2jid[JID(_jid).node.lower()] = _jid
|
||||
|
||||
def expandJid(jid):
|
||||
_jid = jid.lower()
|
||||
if _jid in names2jid:
|
||||
expanded = names2jid[_jid]
|
||||
elif _jid in nodes2jid:
|
||||
expanded = nodes2jid[_jid]
|
||||
else:
|
||||
expanded = jid
|
||||
return unicode(expanded)
|
||||
|
||||
def check(jid):
|
||||
if not jid.is_valid:
|
||||
error (_("%s is not a valid JID !"), jid)
|
||||
exit(1)
|
||||
|
||||
dest_jids=[]
|
||||
try:
|
||||
for i in range(len(jids)):
|
||||
dest_jids.append(expandJid(jids[i]))
|
||||
check(dest_jids[i])
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return dest_jids
|
||||
|
||||
def check_jabber_connection(self):
|
||||
"""Check that jabber status is allright"""
|
||||
def cantConnect(arg):
|
||||
print arg
|
||||
error(_(u"Can't connect profile"))
|
||||
exit(1)
|
||||
|
||||
self.profile = self.bridge.getProfileName(self.profile_name)
|
||||
if not self.profile:
|
||||
error(_("The profile asked doesn't exist"))
|
||||
exit(1)
|
||||
|
||||
if self.bridge.isConnected(self.profile):
|
||||
print "Already connected"
|
||||
else:
|
||||
self._start_loop = True
|
||||
self.bridge.asyncConnect(self.profile, self._run, cantConnect)
|
||||
return
|
||||
self.run()
|
||||
|
||||
|
||||
def _getFullJid(self, param_jid):
|
||||
"""Return the full jid if possible (add last resource when find a bare jid"""
|
||||
_jid = JID(param_jid)
|
||||
if not _jid.resource:
|
||||
#if the resource is not given, we try to add the last known resource
|
||||
last_resource = self.bridge.getLastResource(param_jid, self.profile_name)
|
||||
if last_resource:
|
||||
return "%s/%s" % (_jid.bare, last_resource)
|
||||
return param_jid
|
||||
|
||||
def go(self):
|
||||
self.check_jabber_connection()
|
||||
if self._start_loop:
|
||||
self._loop_start()
|
||||
|
||||
|
||||
|
||||
class JPAsk(JPWithProfile):
|
||||
def confirm_type(self):
|
||||
"""Must return a string containing the confirm type. For instance,
|
||||
FILE_TRANSFER or PIPE_TRANSFER, etc.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
raise NotImplemented
|
||||
|
||||
def dest_jids(self):
|
||||
return None
|
||||
|
||||
def _askConfirmation(self, confirm_id, confirm_type, data, profile):
|
||||
if profile != self.profile:
|
||||
debug("Ask confirmation ignored: not our profile")
|
||||
return
|
||||
if confirm_type == self.confirm_type():
|
||||
self._confirm_id = confirm_id
|
||||
if self.dest_jids() and not JID(data['from']).bare in [JID(_jid).bare for _jid in self.dest_jids()]:
|
||||
return #file is not sent by a filtered jid
|
||||
else:
|
||||
self.ask(data)
|
||||
|
||||
def ask(self):
|
||||
"""
|
||||
The return value is used to answer to the bridge.
|
||||
:rtype: (bool, dict)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def answer(self, accepted, answer_data):
|
||||
"""
|
||||
:param accepted: boolean
|
||||
:param aswer_data: dict of answer datas
|
||||
"""
|
||||
self.bridge.confirmationAnswer(self._confirm_id, False, answer_data, self.profile)
|
||||
|
||||
def run(self):
|
||||
"""Auto reply to confirmations requests"""
|
||||
#we register incoming confirmation
|
||||
self.bridge.register("askConfirmation", self._askConfirmation)
|
||||
|
||||
#and we ask those we have missed
|
||||
for confirm_id, confirm_type, data in self.bridge.getWaitingConf(self.profile):
|
||||
self._askConfirmation(confirm_id, confirm_type, data, self.profile)
|
||||
|
||||
|
||||
Loading…
Reference in a new issue