Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim-plugins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Leboulanger <asterix@lagaule.org>2011-11-17 00:26:16 +0400
committerYann Leboulanger <asterix@lagaule.org>2011-11-17 00:26:16 +0400
commit8b612b98478fe908c9ad7c2697bcf030a9c19912 (patch)
tree828d5c040ee4f4bd9adfa3a4bae203f917d04579 /plugin_installer
parent330d242734abae9fcd68be9646cf12eda2d4e9c3 (diff)
add plugins from trunk: banner_tweaks, google_translation, length_notifier, plugin_installer, triggers, whiteboard
Diffstat (limited to 'plugin_installer')
-rw-r--r--plugin_installer/__init__.py1
-rw-r--r--plugin_installer/config_dialog.ui294
-rw-r--r--plugin_installer/manifest.ini8
-rw-r--r--plugin_installer/plugin_installer.py532
4 files changed, 835 insertions, 0 deletions
diff --git a/plugin_installer/__init__.py b/plugin_installer/__init__.py
new file mode 100644
index 0000000..a272f29
--- /dev/null
+++ b/plugin_installer/__init__.py
@@ -0,0 +1 @@
+from plugin_installer import PluginInstaller
diff --git a/plugin_installer/config_dialog.ui b/plugin_installer/config_dialog.ui
new file mode 100644
index 0000000..e637633
--- /dev/null
+++ b/plugin_installer/config_dialog.ui
@@ -0,0 +1,294 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkTextBuffer" id="textbuffer1">
+ <property name="text">Plug-in decription should be displayed here. This text will be erased during PluginsWindow initialization.</property>
+ </object>
+ <object class="GtkWindow" id="window1">
+ <child>
+ <object class="GtkHPaned" id="hpaned2">
+ <property name="width_request">600</property>
+ <property name="height_request">350</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">340</property>
+ <property name="position_set">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="border_width">6</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="available_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="search_column">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="progressbar">
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="plugin_name_label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label">&lt;empty&gt;</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Authors:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="plugin_authors_label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">6</property>
+ <property name="label">&lt;empty&gt;</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Homepage:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="plugin_homepage_linkbutton1">
+ <property name="label">button</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="focus_on_click">False</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Description:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTextView" id="plugin_description_textview1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="pixels_above_lines">6</property>
+ <property name="wrap_mode">word</property>
+ <property name="left_margin">6</property>
+ <property name="right_margin">6</property>
+ <property name="indent">1</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox15">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox3">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="inslall_upgrade_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_inslall_upgrade_clicked"/>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-refresh</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Install/Upgrade</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkWindow" id="window2">
+ <child>
+ <object class="GtkHBox" id="hbox111">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Ftp server:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="ftp_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/plugin_installer/manifest.ini b/plugin_installer/manifest.ini
new file mode 100644
index 0000000..7a15081
--- /dev/null
+++ b/plugin_installer/manifest.ini
@@ -0,0 +1,8 @@
+[info]
+name: Plugin Installer
+short_name: plugin_installer
+version: 0.5
+description: Install and upgrade plugins from ftp
+authors: Denis Fomin <fominde@gmail.com>
+ Yann Leboulanger <asterix@lagaule.org>
+homepage: http://www.gajim.org/
diff --git a/plugin_installer/plugin_installer.py b/plugin_installer/plugin_installer.py
new file mode 100644
index 0000000..1fe1314
--- /dev/null
+++ b/plugin_installer/plugin_installer.py
@@ -0,0 +1,532 @@
+# -*- coding: utf-8 -*-
+#
+## plugins/plugin_installer/plugin_installer.py
+##
+## Copyright (C) 2010-2011 Denis Fomin <fominde AT gmail.com>
+## Copyright (C) 2011 Yann Leboulanger <asterix AT lagaule.org>
+##
+## This file is part of Gajim.
+##
+## Gajim is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only.
+##
+## Gajim 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 General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+##
+import gtk
+import pango
+import gobject
+import ftplib
+import io
+import threading
+import ConfigParser
+import os
+import fnmatch
+import sys
+
+from common import gajim
+from plugins import GajimPlugin
+from plugins.helpers import log_calls, log
+from dialogs import WarningDialog, HigDialog, YesNoDialog
+from plugins.gui import GajimPluginConfigDialog
+
+
+def convert_version_to_list(version_str):
+ version_list = version_str.split('.')
+ l = []
+ while len(version_list):
+ l.append(int(version_list.pop(0)))
+ return l
+
+class PluginInstaller(GajimPlugin):
+
+ @log_calls('PluginInstallerPlugin')
+ def init(self):
+ self.description = _('Install and upgrade plugins from ftp')
+ self.config_dialog = PluginInstallerPluginConfigDialog(self)
+ self.config_default_values = {'ftp_server': ('ftp.gajim.org', '')}
+ self.window = None
+ self.progressbar = None
+ self.available_plugins_model = None
+ self.upgrading = False # True when opened from upgrade popup dialog
+
+ @log_calls('PluginInstallerPlugin')
+ 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)
+ gobject.timeout_add_seconds(30, self.check_update)
+
+ @log_calls('PluginInstallerPlugin')
+ def warn_update(self, plugins):
+ def open_update(dummy):
+ self.upgrading = True
+ self.pl_menuitem.activate()
+ nb = gajim.interface.instances['plugins'].plugins_notebook
+ gobject.idle_add(nb.set_current_page, 1)
+ if plugins:
+ plugins_str = '\n'.join(plugins)
+ YesNoDialog(_('Plugins updates'), _('Some updates are available for'
+ ' your installer plugins. Do you want to update those plugins:'
+ '\n%s') % plugins_str, on_response_yes=open_update)
+
+ @log_calls('PluginInstallerPlugin')
+ def check_update(self):
+ def _run():
+ try:
+ to_update = []
+ con = ftplib.FTP_TLS(ftp.server)
+ con.login()
+ con.prot_p()
+ con.cwd('plugins')
+ plugins_dirs = con.nlst()
+ for dir_ in plugins_dirs:
+ try:
+ con.retrbinary('RETR %s/manifest.ini' % dir_,
+ ftp.handleDownload)
+ except Exception, error:
+ if str(error).startswith('550'):
+ continue
+ ftp.config.readfp(io.BytesIO(ftp.buffer_.getvalue()))
+ local_version = ftp.get_plugin_version(ftp.config.get(
+ 'info', 'name'))
+ if local_version:
+ local = convert_version_to_list(local_version)
+ remote = convert_version_to_list(ftp.config.get('info',
+ 'version'))
+ if remote > local:
+ to_update.append(ftp.config.get('info', 'name'))
+ con.quit()
+ gobject.idle_add(self.warn_update, to_update)
+ except Exception, e:
+ log.debug('Ftp error when check updates: %s' % str(e))
+ ftp = Ftp(self)
+ ftp.run = _run
+ ftp.start()
+
+ @log_calls('PluginInstallerPlugin')
+ def deactivate(self):
+ self.pl_menuitem.disconnect(self.id_)
+ if hasattr(self, 'page_num'):
+ self.notebook.remove_page(self.page_num)
+ self.notebook.set_current_page(0)
+ if hasattr(self, 'ftp'):
+ del self.ftp
+
+ def on_activate(self, widget):
+ if 'plugins' not in gajim.interface.instances:
+ return
+ self.installed_plugins_model = gajim.interface.instances[
+ 'plugins'].installed_plugins_model
+ self.notebook = gajim.interface.instances['plugins'].plugins_notebook
+ self.id_n = self.notebook.connect('switch-page',
+ self.on_notebook_switch_page)
+ self.window = gajim.interface.instances['plugins'].window
+ self.window.connect('destroy', self.on_win_destroy)
+ self.GTK_BUILDER_FILE_PATH = self.local_file_path('config_dialog.ui')
+ self.xml = gtk.Builder()
+ self.xml.set_translation_domain('gajim_plugins')
+ self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, ['hpaned2'])
+ hpaned = self.xml.get_object('hpaned2')
+ self.page_num = self.notebook.append_page(hpaned,
+ gtk.Label(_('Available')))
+
+ widgets_to_extract = ('plugin_name_label1',
+ 'available_treeview', 'progressbar', 'inslall_upgrade_button',
+ 'plugin_authors_label1', 'plugin_authors_label1',
+ 'plugin_homepage_linkbutton1', 'plugin_description_textview1')
+
+ for widget_name in widgets_to_extract:
+ setattr(self, widget_name, self.xml.get_object(widget_name))
+
+ attr_list = pango.AttrList()
+ attr_list.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
+ self.plugin_name_label1.set_attributes(attr_list)
+
+ self.available_plugins_model = gtk.ListStore(gobject.TYPE_PYOBJECT,
+ gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING,
+ gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
+ gobject.TYPE_PYOBJECT)
+ self.available_treeview.set_model(self.available_plugins_model)
+
+ self.progressbar.set_property('no-show-all', True)
+ renderer = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(_('Plugin'), renderer, text=1)
+ col.set_resizable(True)
+ col.set_property('expand', True)
+ col.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
+ self.available_treeview.append_column(col)
+ col = gtk.TreeViewColumn(_('Installed\nversion'), renderer, text=2)
+ self.available_treeview.append_column(col)
+ col = gtk.TreeViewColumn(_('Available\nversion'), renderer, text=3)
+ col.set_property('expand', False)
+ self.available_treeview.append_column(col)
+
+ renderer = gtk.CellRendererToggle()
+ renderer.set_property('activatable', True)
+ renderer.connect('toggled', self.available_plugins_toggled_cb)
+ col = gtk.TreeViewColumn(_('Install /\nUpgrade'), renderer, active=4)
+ self.available_treeview.append_column(col)
+
+ if gobject.signal_lookup('error_signal', self.window) is 0:
+ gobject.signal_new('error_signal', self.window,
+ gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
+ (gobject.TYPE_STRING,))
+ gobject.signal_new('plugin_downloaded', self.window,
+ gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
+ (gobject.TYPE_PYOBJECT,))
+ self.window.connect('error_signal', self.on_some_ftp_error)
+ self.window.connect('plugin_downloaded', self.on_plugin_downloaded)
+
+ selection = self.available_treeview.get_selection()
+ selection.connect('changed',
+ self.available_plugins_treeview_selection_changed)
+ selection.set_mode(gtk.SELECTION_SINGLE)
+
+ self._clear_available_plugin_info()
+ self.xml.connect_signals(self)
+ self.window.show_all()
+
+ def on_win_destroy(self, widget):
+ if hasattr(self, 'ftp'):
+ del self.ftp
+
+ def available_plugins_toggled_cb(self, cell, path):
+ is_active = self.available_plugins_model[path][4]
+ self.available_plugins_model[path][4] = not is_active
+ dir_list = []
+ for i in xrange(len(self.available_plugins_model)):
+ if self.available_plugins_model[i][4]:
+ dir_list.append(self.available_plugins_model[i][0])
+ if not dir_list:
+ self.inslall_upgrade_button.set_property('sensitive', False)
+ else:
+ self.inslall_upgrade_button.set_property('sensitive', True)
+
+ def on_notebook_switch_page(self, widget, page, page_num):
+ if not hasattr(self, 'ftp') and self.page_num == page_num:
+ self.available_plugins_model.clear()
+ self.progressbar.show()
+ self.ftp = Ftp(self)
+ self.ftp.remote_dirs = None
+ self.ftp.upgrading = True
+ self.ftp.start()
+
+ def on_inslall_upgrade_clicked(self, widget):
+ self.inslall_upgrade_button.set_property('sensitive', False)
+ dir_list = []
+ for i in xrange(len(self.available_plugins_model)):
+ if self.available_plugins_model[i][4]:
+ dir_list.append(self.available_plugins_model[i][0])
+
+ ftp = Ftp(self)
+ ftp.remote_dirs = dir_list
+ ftp.start()
+
+ def on_some_ftp_error(self, widget, error_text):
+ for i in xrange(len(self.available_plugins_model)):
+ self.available_plugins_model[i][4] = False
+ self.progressbar.hide()
+ WarningDialog(_('Ftp error'), error_text, self.window)
+
+ def on_plugin_downloaded(self, widget, plugin_dirs):
+ for _dir in plugin_dirs:
+ is_active = False
+ plugins = None
+ plugin_dir = os.path.join(gajim.PLUGINS_DIRS[1], _dir)
+ plugin = gajim.plugin_manager.get_plugin_by_path(plugin_dir)
+ if plugin:
+ if plugin.active and plugin.name != self.name:
+ is_active = True
+ gobject.idle_add(gajim.plugin_manager.deactivate_plugin,
+ plugin)
+ gajim.plugin_manager.plugins.remove(plugin)
+
+ model = self.installed_plugins_model
+ for row in xrange(len(model)):
+ if plugin == model[row][0]:
+ model.remove(model.get_iter((row, 0)))
+ break
+
+ plugins = self.scan_dir_for_plugin(plugin_dir)
+ if not plugins:
+ continue
+ gajim.plugin_manager.add_plugin(plugins[0])
+ plugin = gajim.plugin_manager.plugins[-1]
+ for row in xrange(len(self.available_plugins_model)):
+ if plugin.name == self.available_plugins_model[row][1]:
+ self.available_plugins_model[row][2] = plugin.version
+ self.available_plugins_model[row][4] = False
+ continue
+ if is_active and plugin.name != self.name:
+ gobject.idle_add(gajim.plugin_manager.activate_plugin, plugin)
+ if plugin.name != 'Plugin Installer':
+ self.installed_plugins_model.append([plugin, plugin.name,
+ is_active])
+ dialog = HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
+ '', _('All selected plugins downloaded'))
+ dialog.set_modal(False)
+ dialog.set_transient_for(self.window)
+ dialog.popup()
+
+ def available_plugins_treeview_selection_changed(self, treeview_selection):
+ model, iter = treeview_selection.get_selected()
+ if iter:
+ self.plugin_name_label1.set_text(model.get_value(iter, 1))
+ self.plugin_authors_label1.set_text(model.get_value(iter, 6))
+ self.plugin_homepage_linkbutton1.set_uri(model.get_value(iter, 7))
+ self.plugin_homepage_linkbutton1.set_label(model.get_value(iter, 7))
+ label = self.plugin_homepage_linkbutton1.get_children()[0]
+ label.set_ellipsize(pango.ELLIPSIZE_END)
+ self.plugin_homepage_linkbutton1.set_property('sensitive', True)
+ desc_textbuffer = self.plugin_description_textview1.get_buffer()
+ desc_textbuffer.set_text(_(model.get_value(iter, 5)))
+ self.plugin_description_textview1.set_property('sensitive', True)
+ else:
+ self._clear_available_plugin_info()
+
+ def _clear_available_plugin_info(self):
+ self.plugin_name_label1.set_text('')
+ self.plugin_authors_label1.set_text('')
+ self.plugin_homepage_linkbutton1.set_uri('')
+ self.plugin_homepage_linkbutton1.set_label('')
+ self.plugin_homepage_linkbutton1.set_property('sensitive', False)
+
+ desc_textbuffer = self.plugin_description_textview1.get_buffer()
+ desc_textbuffer.set_text('')
+ self.plugin_description_textview1.set_property('sensitive', False)
+
+ def scan_dir_for_plugin(self, path):
+ plugins_found = []
+ conf = ConfigParser.ConfigParser()
+ fields = ('name', 'short_name', 'version', 'description', 'authors',
+ 'homepage')
+ if not os.path.isdir(path):
+ return plugins_found
+
+ dir_list = os.listdir(path)
+ dir_, mod = os.path.split(path)
+ sys.path.insert(0, dir_)
+
+ manifest_path = os.path.join(path, 'manifest.ini')
+ if not os.path.isfile(manifest_path):
+ return plugins_found
+
+ for elem_name in dir_list:
+ file_path = os.path.join(path, elem_name)
+ module = None
+
+ if os.path.isfile(file_path) and fnmatch.fnmatch(file_path, '*.py'):
+ module_name = os.path.splitext(elem_name)[0]
+ if module_name == '__init__':
+ continue
+ try:
+ module = __import__('%s.%s' % (mod, module_name))
+ except ValueError, value_error:
+ pass
+ except ImportError, import_error:
+ pass
+ except AttributeError, attribute_error:
+ pass
+ if module is None:
+ continue
+
+ for module_attr_name in [attr_name for attr_name in dir(module)
+ if not (attr_name.startswith('__') or attr_name.endswith('__'))]:
+ module_attr = getattr(module, module_attr_name)
+ try:
+ if not issubclass(module_attr, GajimPlugin) or \
+ module_attr is GajimPlugin:
+ continue
+ module_attr.__path__ = os.path.abspath(os.path.dirname(
+ file_path))
+
+ # read metadata from manifest.ini
+ conf.readfp(open(manifest_path, 'r'))
+ for option in fields:
+ if conf.get('info', option) is '':
+ raise ConfigParser.NoOptionError, 'field empty'
+ setattr(module_attr, option, conf.get('info', option))
+ conf.remove_section('info')
+ plugins_found.append(module_attr)
+
+ except TypeError, type_error:
+ pass
+ except ConfigParser.NoOptionError, type_error:
+ # all fields are required
+ pass
+ return plugins_found
+
+
+class Ftp(threading.Thread):
+ def __init__(self, plugin):
+ super(Ftp, self).__init__()
+ self.plugin = plugin
+ self.window = plugin.window
+ self.server = plugin.config['ftp_server']
+ self.progressbar = plugin.progressbar
+ self.model = plugin.available_plugins_model
+ self.config = ConfigParser.ConfigParser()
+ self.buffer_ = io.BytesIO()
+ self.remote_dirs = None
+ self.append_to_model = True
+ self.upgrading = False
+
+ def model_append(self, row):
+ self.model.append(row)
+ return False
+
+ def progressbar_pulse(self):
+ self.progressbar.pulse()
+ return True
+
+ def get_plugin_version(self, plugin_name):
+ for plugin in gajim.plugin_manager.plugins:
+ if plugin.name == plugin_name:
+ return plugin.version
+
+ def run(self):
+ try:
+ gobject.idle_add(self.progressbar.set_text,
+ _('Connecting to server'))
+ self.ftp = ftplib.FTP_TLS(self.server)
+ self.ftp.login()
+ self.ftp.prot_p()
+ self.ftp.cwd('plugins')
+ if not self.remote_dirs:
+ self.plugins_dirs = self.ftp.nlst()
+ progress_step = 1.0 / len(self.plugins_dirs)
+ gobject.idle_add(self.progressbar.set_text,
+ _('Scan files on the server'))
+ for dir_ in self.plugins_dirs:
+ fract = self.progressbar.get_fraction() + progress_step
+ gobject.idle_add(self.progressbar.set_fraction, fract)
+ gobject.idle_add(self.progressbar.set_text,
+ _('Read "%s"') % dir_)
+ try:
+ self.ftp.retrbinary('RETR %s/manifest.ini' % dir_,
+ self.handleDownload)
+ except Exception, error:
+ if str(error).startswith('550'):
+ continue
+ self.config.readfp(io.BytesIO(self.buffer_.getvalue()))
+ local_version = self.get_plugin_version(
+ self.config.get('info', 'name'))
+ upgrade = False
+ if self.upgrading and local_version:
+ local = convert_version_to_list(local_version)
+ remote = convert_version_to_list(self.config.get('info',
+ 'version'))
+ if remote > local:
+ upgrade = True
+ gobject.idle_add(
+ self.plugin.inslall_upgrade_button.set_property,
+ 'sensitive', True)
+ gobject.idle_add(self.model_append, [dir_,
+ self.config.get('info', 'name'), local_version,
+ self.config.get('info', 'version'), upgrade,
+ self.config.get('info', 'description'),
+ self.config.get('info', 'authors'),
+ self.config.get('info', 'homepage'), ])
+ self.plugins_dirs = None
+ self.ftp.quit()
+ gobject.idle_add(self.progressbar.set_fraction, 0)
+ if self.remote_dirs:
+ self.download_plugin()
+ gobject.idle_add(self.progressbar.hide)
+ except Exception, e:
+ self.window.emit('error_signal', str(e))
+
+ def handleDownload(self, block):
+ self.buffer_.write(block)
+
+ def download_plugin(self):
+ gobject.idle_add(self.progressbar.show)
+ self.pulse = gobject.timeout_add(150, self.progressbar_pulse)
+ gobject.idle_add(self.progressbar.set_text, _('Create a list of files'))
+ for remote_dir in self.remote_dirs:
+
+ def nlstr(dir_, subdir=None):
+ if subdir:
+ dir_ = dir_ + '/' + subdir
+ list_ = self.ftp.nlst(dir_)
+ for i in list_:
+ name = i.split('/')[-1]
+ if '.' not in name:
+ try:
+ if i == self.ftp.nlst(i)[0]:
+ files.append(i[1:])
+ del dirs[i[1:]]
+ except Exception, e:
+ # empty dir or file
+ continue
+ dirs.append(i[1:])
+ subdirs = name
+ nlstr(dir_, subdirs)
+ else:
+ files.append(i[1:])
+ dirs, files = [], []
+ nlstr('/plugins/' + remote_dir)
+
+ if not os.path.isdir(gajim.PLUGINS_DIRS[1]):
+ os.mkdir(gajim.PLUGINS_DIRS[1])
+ local_dir = ld = os.path.join(gajim.PLUGINS_DIRS[1], remote_dir)
+ if not os.path.isdir(local_dir):
+ os.mkdir(local_dir)
+ local_dir = os.path.split(gajim.PLUGINS_DIRS[1])[0]
+
+ # creating dirs
+ for dir_ in dirs:
+ try:
+ os.mkdir(os.path.join(local_dir, dir_))
+ except OSError, e:
+ if str(e).startswith('[Errno 17]'):
+ continue
+ raise
+
+ # downloading files
+ for filename in files:
+ gobject.idle_add(self.progressbar.set_text,
+ _('Downloading "%s"') % filename)
+ full_filename = os.path.join(local_dir, filename)
+ try:
+ self.ftp.retrbinary('RETR /%s' % filename,
+ open(full_filename, 'wb').write)
+ #full_filename.close()
+ except ftplib.error_perm:
+ print 'ERROR: cannot read file "%s"' % filename
+ os.unlink(filename)
+ self.ftp.quit()
+ gobject.idle_add(self.window.emit, 'plugin_downloaded',
+ self.remote_dirs)
+ gobject.source_remove(self.pulse)
+
+
+class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog):
+ def init(self):
+ self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
+ 'config_dialog.ui')
+ self.xml = gtk.Builder()
+ self.xml.set_translation_domain('gajim_plugins')
+ self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, ['hbox111'])
+ hbox = self.xml.get_object('hbox111')
+ self.child.pack_start(hbox)
+
+ self.xml.connect_signals(self)
+ self.connect('hide', self.on_hide)
+
+ def on_run(self):
+ widget = self.xml.get_object('ftp_server')
+ widget.set_text(str(self.plugin.config['ftp_server']))
+
+ def on_hide(self, widget):
+ widget = self.xml.get_object('ftp_server')
+ self.plugin.config['ftp_server'] = widget.get_text()