[plugin_installer] Port recent plugin_installer
This inlcudes slight refactoring and switch to https instead of ftps
This commit is contained in:
@@ -394,24 +394,6 @@
|
|||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkCheckButton" id="check_update_periodically">
|
|
||||||
<property name="label" translatable="yes">Check update every 24 hours</property>
|
|
||||||
<property name="use_action_appearance">False</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="receives_default">False</property>
|
|
||||||
<property name="focus_on_click">False</property>
|
|
||||||
<property name="xalign">0.5</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
<signal name="toggled" handler="on_check_update_periodically_toggled" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from gi.repository import Pango
|
|||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
|
||||||
import ftplib
|
|
||||||
import io
|
import io
|
||||||
import threading
|
import threading
|
||||||
import configparser
|
import configparser
|
||||||
@@ -33,9 +32,11 @@ import os
|
|||||||
import fnmatch
|
import fnmatch
|
||||||
import sys
|
import sys
|
||||||
import zipfile
|
import zipfile
|
||||||
import ssl
|
|
||||||
import logging
|
import logging
|
||||||
|
import posixpath
|
||||||
|
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from urllib.parse import urlparse, urljoin
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from plugins import GajimPlugin
|
from plugins import GajimPlugin
|
||||||
from plugins.helpers import log_calls, log
|
from plugins.helpers import log_calls, log
|
||||||
@@ -68,11 +69,11 @@ class PluginInstaller(GajimPlugin):
|
|||||||
|
|
||||||
@log_calls('PluginInstallerPlugin')
|
@log_calls('PluginInstallerPlugin')
|
||||||
def init(self):
|
def init(self):
|
||||||
self.description = _('Install and upgrade plugins from ftp')
|
self.description = _('Install and Upgrade Plugins')
|
||||||
self.config_dialog = PluginInstallerPluginConfigDialog(self)
|
self.config_dialog = PluginInstallerPluginConfigDialog(self)
|
||||||
self.config_default_values = {'ftp_server': ('ftp.gajim.org', ''),
|
self.config_default_values = {'http_server': ('https://ftp.gajim.org', ''),
|
||||||
'check_update': (True, ''),
|
'check_update': (True, ''),
|
||||||
'check_update_periodically': (True, '')}
|
}
|
||||||
self.window = None
|
self.window = None
|
||||||
self.progressbar = None
|
self.progressbar = None
|
||||||
self.available_plugins_model = None
|
self.available_plugins_model = None
|
||||||
@@ -82,20 +83,10 @@ class PluginInstaller(GajimPlugin):
|
|||||||
icon = Gtk.Image()
|
icon = Gtk.Image()
|
||||||
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
|
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
|
||||||
Gtk.IconSize.MENU)
|
Gtk.IconSize.MENU)
|
||||||
if gajim.version.startswith('0.15'):
|
|
||||||
self.server_folder = 'plugins_0.15'
|
|
||||||
elif gajim.version.startswith('0.16.10'):
|
|
||||||
self.server_folder = 'plugins_1'
|
self.server_folder = 'plugins_1'
|
||||||
else:
|
|
||||||
self.server_folder = 'plugins_0.16'
|
|
||||||
|
|
||||||
@log_calls('PluginInstallerPlugin')
|
@log_calls('PluginInstallerPlugin')
|
||||||
def activate(self):
|
def activate(self):
|
||||||
self.pl_menuitem = gajim.interface.roster.xml.get_object(
|
|
||||||
'plugins_menuitem')
|
|
||||||
self.id_ = self.pl_menuitem.connect_after('activate', self.on_activate)
|
|
||||||
if 'plugins' in gajim.interface.instances:
|
|
||||||
self.on_activate(None)
|
|
||||||
if self.config['check_update']:
|
if self.config['check_update']:
|
||||||
self.timeout_id = GLib.timeout_add_seconds(30, self.check_update)
|
self.timeout_id = GLib.timeout_add_seconds(30, self.check_update)
|
||||||
|
|
||||||
@@ -113,27 +104,13 @@ class PluginInstaller(GajimPlugin):
|
|||||||
' your installer plugins. Do you want to update those plugins:'
|
' your installer plugins. Do you want to update those plugins:'
|
||||||
'\n%s') % plugins_str, on_response_yes=open_update)
|
'\n%s') % plugins_str, on_response_yes=open_update)
|
||||||
|
|
||||||
def ftp_connect(self):
|
def parse_manifest(self, buf):
|
||||||
if os.name == 'nt':
|
'''
|
||||||
ctx = ssl.create_default_context()
|
given the buffer of the zipfile, returns the list of plugin manifests
|
||||||
con = ftplib.FTP_TLS(self.config['ftp_server'], context=ctx)
|
'''
|
||||||
else:
|
zip_file = zipfile.ZipFile(buf)
|
||||||
con = ftplib.FTP_TLS(self.config['ftp_server'])
|
|
||||||
|
|
||||||
con.login()
|
|
||||||
con.prot_p()
|
|
||||||
return con
|
|
||||||
|
|
||||||
@log_calls('PluginInstallerPlugin')
|
|
||||||
def check_update(self):
|
|
||||||
def _run():
|
|
||||||
try:
|
|
||||||
to_update = []
|
|
||||||
con = self.ftp_connect()
|
|
||||||
con.cwd(self.server_folder)
|
|
||||||
con.retrbinary('RETR manifests.zip', ftp.handleDownload)
|
|
||||||
zip_file = zipfile.ZipFile(ftp.buffer_)
|
|
||||||
manifest_list = zip_file.namelist()
|
manifest_list = zip_file.namelist()
|
||||||
|
plugins = []
|
||||||
for filename in manifest_list:
|
for filename in manifest_list:
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
conf_file = zip_file.open(filename)
|
conf_file = zip_file.open(filename)
|
||||||
@@ -141,6 +118,39 @@ class PluginInstaller(GajimPlugin):
|
|||||||
conf_file.close()
|
conf_file.close()
|
||||||
if not config.has_section('info'):
|
if not config.has_section('info'):
|
||||||
continue
|
continue
|
||||||
|
plugins.append(config)
|
||||||
|
return plugins
|
||||||
|
|
||||||
|
def retrieve_path(self, directory, fname):
|
||||||
|
print('retrive path')
|
||||||
|
server = self.config['http_server']
|
||||||
|
if not server:
|
||||||
|
server = self.config_default_values['http_server'][0]
|
||||||
|
if not urlparse(server).scheme:
|
||||||
|
server = 'https://' + server
|
||||||
|
if urlparse(server).scheme != 'https':
|
||||||
|
log.warn('Warning: not using HTTPS is a '
|
||||||
|
'very serious security issue!')
|
||||||
|
location = posixpath.join(directory, fname)
|
||||||
|
uri = urljoin(server, location)
|
||||||
|
log.debug('Fetching {}'.format(uri))
|
||||||
|
request = urlopen(uri)
|
||||||
|
|
||||||
|
manifest_buffer = io.BytesIO(request.read())
|
||||||
|
|
||||||
|
return manifest_buffer
|
||||||
|
|
||||||
|
def retrieve_manifest(self):
|
||||||
|
return self.retrieve_path(self.server_folder, 'manifests.zip')
|
||||||
|
|
||||||
|
@log_calls('PluginInstallerPlugin')
|
||||||
|
def check_update(self):
|
||||||
|
def _run():
|
||||||
|
try:
|
||||||
|
to_update = []
|
||||||
|
zipbuf = self.retrieve_manifest()
|
||||||
|
plugin_manifests = self.parse_manifest(zipbuf)
|
||||||
|
for config in plugin_manifests:
|
||||||
opts = config.options('info')
|
opts = config.options('info')
|
||||||
if 'name' not in opts or 'version' not in opts or \
|
if 'name' not in opts or 'version' not in opts or \
|
||||||
'description' not in opts or 'authors' not in opts or \
|
'description' not in opts or 'authors' not in opts or \
|
||||||
@@ -154,13 +164,9 @@ class PluginInstaller(GajimPlugin):
|
|||||||
'version'))
|
'version'))
|
||||||
if remote > local:
|
if remote > local:
|
||||||
to_update.append(config.get('info', 'name'))
|
to_update.append(config.get('info', 'name'))
|
||||||
con.quit()
|
|
||||||
GLib.idle_add(self.warn_update, to_update)
|
GLib.idle_add(self.warn_update, to_update)
|
||||||
# check for updates at least once every 24 hours
|
|
||||||
if self.config['check_update_periodically']:
|
|
||||||
self.timeout_id = GLib.timeout_add_seconds(24*3600, self.check_update)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug('Ftp error when check updates: %s' % str(e))
|
log.error('Ftp error when check updates: %s' % str(e), exc_info=True)
|
||||||
ftp = Ftp(self)
|
ftp = Ftp(self)
|
||||||
ftp.run = _run
|
ftp.run = _run
|
||||||
ftp.start()
|
ftp.start()
|
||||||
@@ -181,18 +187,15 @@ class PluginInstaller(GajimPlugin):
|
|||||||
GLib.source_remove(self.timeout_id)
|
GLib.source_remove(self.timeout_id)
|
||||||
self.timeout_id = 0
|
self.timeout_id = 0
|
||||||
|
|
||||||
def on_activate(self, widget):
|
def on_activate(self, plugin_win):
|
||||||
if 'plugins' not in gajim.interface.instances:
|
|
||||||
return
|
|
||||||
if hasattr(self, 'page_num'):
|
if hasattr(self, 'page_num'):
|
||||||
# 'Available' tab exists
|
# 'Available' tab exists
|
||||||
return
|
return
|
||||||
self.installed_plugins_model = gajim.interface.instances[
|
self.installed_plugins_model = plugin_win.installed_plugins_model
|
||||||
'plugins'].installed_plugins_model
|
self.notebook = plugin_win.plugins_notebook
|
||||||
self.notebook = gajim.interface.instances['plugins'].plugins_notebook
|
|
||||||
id_ = self.notebook.connect('switch-page', self.on_notebook_switch_page)
|
id_ = self.notebook.connect('switch-page', self.on_notebook_switch_page)
|
||||||
self.connected_ids[id_] = self.notebook
|
self.connected_ids[id_] = self.notebook
|
||||||
self.window = gajim.interface.instances['plugins'].window
|
self.window = plugin_win.window
|
||||||
id_ = self.window.connect('destroy', self.on_win_destroy)
|
id_ = self.window.connect('destroy', self.on_win_destroy)
|
||||||
self.connected_ids[id_] = self.window
|
self.connected_ids[id_] = self.window
|
||||||
self.Gtk_BUILDER_FILE_PATH = self.local_file_path('config_dialog.ui')
|
self.Gtk_BUILDER_FILE_PATH = self.local_file_path('config_dialog.ui')
|
||||||
@@ -461,11 +464,10 @@ class PluginInstaller(GajimPlugin):
|
|||||||
file_path))
|
file_path))
|
||||||
|
|
||||||
# read metadata from manifest.ini
|
# read metadata from manifest.ini
|
||||||
with open(manifest_path) as _file:
|
conf.readfp(open(manifest_path, 'r'))
|
||||||
conf.read_file(_file)
|
|
||||||
for option in fields:
|
for option in fields:
|
||||||
if conf.get('info', option) is '':
|
if conf.get('info', option) is '':
|
||||||
raise configparser.NoOptionError('field empty')
|
raise configparser.NoOptionError
|
||||||
setattr(module_attr, option, conf.get('info', option))
|
setattr(module_attr, option, conf.get('info', option))
|
||||||
conf.remove_section('info')
|
conf.remove_section('info')
|
||||||
plugins_found.append(module_attr)
|
plugins_found.append(module_attr)
|
||||||
@@ -496,13 +498,12 @@ class Ftp(threading.Thread):
|
|||||||
self.window = plugin.window
|
self.window = plugin.window
|
||||||
self.progressbar = plugin.progressbar
|
self.progressbar = plugin.progressbar
|
||||||
self.model = plugin.available_plugins_model
|
self.model = plugin.available_plugins_model
|
||||||
self.buffer_ = io.BytesIO()
|
|
||||||
self.remote_dirs = None
|
self.remote_dirs = None
|
||||||
self.append_to_model = True
|
self.append_to_model = True
|
||||||
self.upgrading = False
|
self.upgrading = False
|
||||||
icon = Gtk.Image()
|
icon = Gtk.Image()
|
||||||
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
|
self.def_icon = icon.render_icon(
|
||||||
Gtk.IconSize.MENU)
|
Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU)
|
||||||
|
|
||||||
def model_append(self, row):
|
def model_append(self, row):
|
||||||
self.model.append(row)
|
self.model.append(row)
|
||||||
@@ -521,14 +522,15 @@ class Ftp(threading.Thread):
|
|||||||
try:
|
try:
|
||||||
GLib.idle_add(self.progressbar.set_text,
|
GLib.idle_add(self.progressbar.set_text,
|
||||||
_('Connecting to server'))
|
_('Connecting to server'))
|
||||||
self.ftp = self.plugin.ftp_connect()
|
|
||||||
self.ftp.cwd(self.plugin.server_folder)
|
|
||||||
self.progressbar.set_show_text(True)
|
|
||||||
if not self.remote_dirs:
|
if not self.remote_dirs:
|
||||||
GLib.idle_add(self.progressbar.set_text,
|
GLib.idle_add(self.progressbar.set_text,
|
||||||
_('Scan files on the server'))
|
_('Scan files on the server'))
|
||||||
self.ftp.retrbinary('RETR manifests_images.zip', self.handleDownload)
|
try:
|
||||||
zip_file = zipfile.ZipFile(self.buffer_)
|
buf = self.plugin.retrieve_path(self.plugin.server_folder, 'manifests_images.zip')
|
||||||
|
except:
|
||||||
|
log.exception("Error fetching plugin list")
|
||||||
|
return
|
||||||
|
zip_file = zipfile.ZipFile(buf)
|
||||||
manifest_list = zip_file.namelist()
|
manifest_list = zip_file.namelist()
|
||||||
progress_step = 1.0 / len(manifest_list)
|
progress_step = 1.0 / len(manifest_list)
|
||||||
for filename in manifest_list:
|
for filename in manifest_list:
|
||||||
@@ -593,9 +595,6 @@ class Ftp(threading.Thread):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.window.emit('error_signal', str(e))
|
self.window.emit('error_signal', str(e))
|
||||||
|
|
||||||
def handleDownload(self, block):
|
|
||||||
self.buffer_.write(block)
|
|
||||||
|
|
||||||
def download_plugin(self):
|
def download_plugin(self):
|
||||||
GLib.idle_add(self.progressbar.show)
|
GLib.idle_add(self.progressbar.show)
|
||||||
self.pulse = GLib.timeout_add(150, self.progressbar_pulse)
|
self.pulse = GLib.timeout_add(150, self.progressbar_pulse)
|
||||||
@@ -605,7 +604,7 @@ class Ftp(threading.Thread):
|
|||||||
base_dir, user_dir = gajim.PLUGINS_DIRS
|
base_dir, user_dir = gajim.PLUGINS_DIRS
|
||||||
if not os.path.isdir(user_dir):
|
if not os.path.isdir(user_dir):
|
||||||
os.mkdir(user_dir)
|
os.mkdir(user_dir)
|
||||||
local_dir = ld = os.path.join(user_dir, remote_dir)
|
local_dir = os.path.join(user_dir, remote_dir)
|
||||||
if not os.path.isdir(local_dir):
|
if not os.path.isdir(local_dir):
|
||||||
os.mkdir(local_dir)
|
os.mkdir(local_dir)
|
||||||
local_dir = os.path.split(user_dir)[0]
|
local_dir = os.path.split(user_dir)[0]
|
||||||
@@ -613,16 +612,14 @@ class Ftp(threading.Thread):
|
|||||||
# downloading zip file
|
# downloading zip file
|
||||||
GLib.idle_add(self.progressbar.set_text,
|
GLib.idle_add(self.progressbar.set_text,
|
||||||
_('Downloading "%s"') % filename)
|
_('Downloading "%s"') % filename)
|
||||||
full_filename = os.path.join(user_dir, filename)
|
|
||||||
self.buffer_ = io.BytesIO()
|
|
||||||
try:
|
try:
|
||||||
self.ftp.retrbinary('RETR %s' % filename, self.handleDownload)
|
buf = self.plugin.retrieve_path(self.plugin.server_folder,
|
||||||
except ftplib.all_errors as e:
|
filename)
|
||||||
print (str(e))
|
except:
|
||||||
|
log.exception("Error downloading plugin %s" % filename)
|
||||||
with zipfile.ZipFile(self.buffer_) as zip_file:
|
continue
|
||||||
zip_file.extractall(os.path.join(user_dir))
|
with zipfile.ZipFile(buf) as zip_file:
|
||||||
|
zip_file.extractall(os.path.join(local_dir, 'plugins'))
|
||||||
self.ftp.quit()
|
self.ftp.quit()
|
||||||
GLib.idle_add(self.window.emit, 'plugin_downloaded', self.remote_dirs)
|
GLib.idle_add(self.window.emit, 'plugin_downloaded', self.remote_dirs)
|
||||||
GLib.source_remove(self.pulse)
|
GLib.source_remove(self.pulse)
|
||||||
@@ -642,12 +639,10 @@ class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog):
|
|||||||
self.connect('hide', self.on_hide)
|
self.connect('hide', self.on_hide)
|
||||||
|
|
||||||
def on_run(self):
|
def on_run(self):
|
||||||
widget = self.xml.get_object('ftp_server')
|
widget = self.xml.get_object('http_server')
|
||||||
widget.set_text(str(self.plugin.config['ftp_server']))
|
widget.set_text(str(self.plugin.config['http_server']))
|
||||||
self.xml.get_object('check_update').set_active(
|
self.xml.get_object('check_update').set_active(
|
||||||
self.plugin.config['check_update'])
|
self.plugin.config['check_update'])
|
||||||
self.xml.get_object('check_update_periodically').set_active(
|
|
||||||
self.plugin.config['check_update_periodically'])
|
|
||||||
|
|
||||||
def on_hide(self, widget):
|
def on_hide(self, widget):
|
||||||
widget = self.xml.get_object('ftp_server')
|
widget = self.xml.get_object('ftp_server')
|
||||||
@@ -655,6 +650,3 @@ class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog):
|
|||||||
|
|
||||||
def on_check_update_toggled(self, widget):
|
def on_check_update_toggled(self, widget):
|
||||||
self.plugin.config['check_update'] = widget.get_active()
|
self.plugin.config['check_update'] = widget.get_active()
|
||||||
|
|
||||||
def on_check_update_periodically_toggled(self, widget):
|
|
||||||
self.plugin.config['check_update_periodically'] = widget.get_active()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user