Commit c0b3f36b authored by Philipp Hörist's avatar Philipp Hörist

[plugin_installer] Port recent plugin_installer

This inlcudes slight refactoring and switch to https instead of ftps
parent 3347951d
...@@ -394,24 +394,6 @@ ...@@ -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 ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment