Merge branch 'plugininstaller' into 'gtk3'
Plugin Installer Version 0.18 See merge request !24
This commit is contained in:
20
plugin_installer/DST_Root_CA_X3.pem
Normal file
20
plugin_installer/DST_Root_CA_X3.pem
Normal file
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,326 +1,338 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.18.3 -->
|
||||
<!-- Generated with glade 3.20.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.0"/>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<requires lib="gtk+" version="3.14"/>
|
||||
<object class="GtkWindow" id="ConfigWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkHPaned" id="hpaned2">
|
||||
<property name="width_request">800</property>
|
||||
<object class="GtkGrid" id="config_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="position">340</property>
|
||||
<property name="position_set">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="margin_top">12</property>
|
||||
<property name="margin_bottom">12</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox1">
|
||||
<object class="GtkCheckButton" id="check_update">
|
||||
<property name="label" translatable="yes">Check update after start</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_check_update_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="plugin_store">
|
||||
<columns>
|
||||
<!-- column-name icon -->
|
||||
<column type="GdkPixbuf"/>
|
||||
<!-- column-name dir -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name name -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name localversion -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name version -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name upgrade -->
|
||||
<column type="gboolean"/>
|
||||
<!-- column-name description -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name authors -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name homepage -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkImage" id="refresh">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="AvailablePlugins">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkPaned" id="paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="plugin_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkProgressBar" id="progressbar">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="available_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="model">plugin_store</property>
|
||||
<property name="headers_clickable">False</property>
|
||||
<property name="search_column">1</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection1"/>
|
||||
<object class="GtkTreeSelection">
|
||||
<signal name="changed" handler="available_plugins_treeview_selection_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="title" translatable="yes">Plugin</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf" id="pixbufrenderer"/>
|
||||
<attributes>
|
||||
<attribute name="pixbuf">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="plugintextrenderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="title" translatable="yes">Installed</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="versiontextrenderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="title" translatable="yes">Available</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="availabletextrenderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="title" translatable="yes">Install /
|
||||
Upgrade</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="togglerenderer">
|
||||
<signal name="toggled" handler="available_plugins_toggled_cb" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">5</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkProgressBar" id="progressbar">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">False</property>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox2">
|
||||
<object class="GtkGrid" id="description_grid">
|
||||
<property name="width_request">350</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="row_spacing">3</property>
|
||||
<property name="column_spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="plugin_name_label">
|
||||
<property name="visible">True</property>
|
||||
<object class="GtkLabel" id="name_label">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">&lt;empty&gt;</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox1">
|
||||
<object class="GtkLabel" id="versionlabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Version:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="plugin_version_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><empty></property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Version:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox3">
|
||||
<object class="GtkLabel" id="authorslabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Authors:</property>
|
||||
<property name="yalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="plugin_authors_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><empty></property>
|
||||
<property name="wrap_mode">word-char</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="label" translatable="yes">Authors:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox4">
|
||||
<object class="GtkLabel" id="homepage_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Homepage:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="description_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Description:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="version_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">False</property>
|
||||
<property name="selectable">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="authors_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="wrap_mode">word-char</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLinkButton" id="homepage_linkbutton">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="relief">none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="layout_style">start</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Homepage:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLinkButton" id="plugin_homepage_linkbutton">
|
||||
<object class="GtkButton" id="install_button">
|
||||
<property name="label" translatable="yes">Install/Upgrade</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>
|
||||
<property name="valign">start</property>
|
||||
<property name="vexpand">False</property>
|
||||
<property name="image">refresh</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_install_upgrade_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Description:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox15">
|
||||
<object class="GtkScrolledWindow" id="scrolled_description_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHButtonBox" id="hbuttonbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="inslall_upgrade_button">
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="on_inslall_upgrade_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Install/Upgrade</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<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">5</property>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
@@ -332,87 +344,4 @@
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkWindow" id="window2">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="hbox111">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">6</property>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">FTP Server:</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</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">●</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check_update">
|
||||
<property name="label" translatable="yes">Check update after start</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_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</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>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
[info]
|
||||
name: Plugin Installer
|
||||
short_name: plugin_installer
|
||||
version: 0.17
|
||||
version: 0.18
|
||||
description: Install and upgrade plugins from ftp
|
||||
authors: Denis Fomin <fominde@gmail.com>
|
||||
Yann Leboulanger <asterix@lagaule.org>
|
||||
Thilo Molitor <thilo@eightysoft.de>
|
||||
homepage: http://trac-plugins.gajim.org/wiki/PluginInstallerPlugin
|
||||
Philipp Hörist <philipp@hoerist.com>
|
||||
homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/PluginInstallerPlugin
|
||||
min_gajim_version: 0.16.10
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
##
|
||||
## Copyright (C) 2010-2012 Denis Fomin <fominde AT gmail.com>
|
||||
## Copyright (C) 2011-2012 Yann Leboulanger <asterix AT lagaule.org>
|
||||
## Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
@@ -23,311 +24,227 @@ from gi.repository import Gtk
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GObject
|
||||
|
||||
import ftplib
|
||||
import io
|
||||
import threading
|
||||
import configparser
|
||||
import os
|
||||
import fnmatch
|
||||
import sys
|
||||
import zipfile
|
||||
import ssl
|
||||
import logging
|
||||
import posixpath
|
||||
import urllib.error
|
||||
|
||||
from zipfile import ZipFile
|
||||
from distutils.version import LooseVersion as V
|
||||
from urllib.request import urlopen
|
||||
from common import gajim
|
||||
from plugins import GajimPlugin
|
||||
from plugins.helpers import log_calls, log
|
||||
from htmltextview import HtmlTextView
|
||||
from dialogs import WarningDialog, HigDialog, YesNoDialog
|
||||
from plugins.gui import GajimPluginConfigDialog
|
||||
from enum import IntEnum
|
||||
from gtkgui_helpers import get_action
|
||||
|
||||
log = logging.getLogger('gajim.plugin_system.plugin_installer')
|
||||
|
||||
(
|
||||
C_PIXBUF,
|
||||
C_DIR,
|
||||
C_NAME,
|
||||
C_LOCAL_VERSION,
|
||||
C_VERSION,
|
||||
C_UPGRADE,
|
||||
C_DESCRIPTION,
|
||||
C_AUTHORS,
|
||||
C_HOMEPAGE
|
||||
) = range(9)
|
||||
PLUGINS_URL = 'https://ftp.gajim.org/plugins_1/'
|
||||
MANIFEST_URL = 'https://ftp.gajim.org/plugins_1/manifests.zip'
|
||||
MANIFEST_IMAGE_URL = 'https://ftp.gajim.org/plugins_1/manifests_images.zip'
|
||||
MANDATORY_FIELDS = ['name', 'version', 'description', 'authors', 'homepage']
|
||||
|
||||
|
||||
class Column(IntEnum):
|
||||
PIXBUF = 0
|
||||
DIR = 1
|
||||
NAME = 2
|
||||
LOCAL_VERSION = 3
|
||||
VERSION = 4
|
||||
UPGRADE = 5
|
||||
DESCRIPTION = 6
|
||||
AUTHORS = 7
|
||||
HOMEPAGE = 8
|
||||
|
||||
|
||||
def get_local_version(plugin_name):
|
||||
for plugin in gajim.plugin_manager.plugins:
|
||||
if plugin.name == plugin_name:
|
||||
return plugin.version
|
||||
|
||||
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.description = _('Install and Upgrade Plugins')
|
||||
self.config_dialog = PluginInstallerPluginConfigDialog(self)
|
||||
self.config_default_values = {'ftp_server': ('ftp.gajim.org', ''),
|
||||
'check_update': (True, ''),
|
||||
'check_update_periodically': (True, '')}
|
||||
self.config_default_values = {'check_update': (True, '')}
|
||||
self.window = None
|
||||
self.progressbar = None
|
||||
self.available_plugins_model = None
|
||||
self.upgrading = False # True when opened from upgrade popup dialog
|
||||
self.timeout_id = 0
|
||||
self.connected_ids = {}
|
||||
icon = Gtk.Image()
|
||||
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
|
||||
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'
|
||||
else:
|
||||
self.server_folder = 'plugins_0.16'
|
||||
self.def_icon = icon.render_icon(
|
||||
Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU)
|
||||
|
||||
@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)
|
||||
if self.config['check_update']:
|
||||
self.timeout_id = GLib.timeout_add_seconds(30, self.check_update)
|
||||
if 'plugins' in gajim.interface.instances:
|
||||
self.on_activate(gajim.interface.instances['plugins'])
|
||||
|
||||
@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
|
||||
page = nb.page_num(self.hpaned)
|
||||
GLib.idle_add(nb.set_current_page, page)
|
||||
get_action('plugins').activate()
|
||||
page = self.notebook.page_num(self.paned)
|
||||
self.notebook.set_current_page(page)
|
||||
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)
|
||||
|
||||
def ftp_connect(self):
|
||||
if os.name == 'nt':
|
||||
ctx = ssl.create_default_context()
|
||||
con = ftplib.FTP_TLS(self.config['ftp_server'], context=ctx)
|
||||
plugins_str = '\n' + '\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)
|
||||
else:
|
||||
con = ftplib.FTP_TLS(self.config['ftp_server'])
|
||||
log.info('No updates found')
|
||||
if hasattr(self, 'thread'):
|
||||
del self.thread
|
||||
|
||||
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()
|
||||
for filename in manifest_list:
|
||||
config = configparser.ConfigParser()
|
||||
conf_file = zip_file.open(filename)
|
||||
config.read_file(io.TextIOWrapper(conf_file, encoding='utf-8'))
|
||||
conf_file.close()
|
||||
if not config.has_section('info'):
|
||||
continue
|
||||
opts = config.options('info')
|
||||
if 'name' not in opts or 'version' not in opts or \
|
||||
'description' not in opts or 'authors' not in opts or \
|
||||
'homepage' not in opts:
|
||||
continue
|
||||
local_version = ftp.get_plugin_version(config.get(
|
||||
'info', 'name'))
|
||||
if local_version:
|
||||
local = convert_version_to_list(local_version)
|
||||
remote = convert_version_to_list(config.get('info',
|
||||
'version'))
|
||||
if remote > local:
|
||||
to_update.append(config.get('info', 'name'))
|
||||
con.quit()
|
||||
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:
|
||||
log.debug('Ftp error when check updates: %s' % str(e))
|
||||
ftp = Ftp(self)
|
||||
ftp.run = _run
|
||||
ftp.start()
|
||||
if hasattr(self, 'thread'):
|
||||
return
|
||||
log.info('Checking for Updates...')
|
||||
self.start_download(check_update=True)
|
||||
self.timeout_id = 0
|
||||
|
||||
@log_calls('PluginInstallerPlugin')
|
||||
def deactivate(self):
|
||||
self.pl_menuitem.disconnect(self.id_)
|
||||
if hasattr(self, 'page_num'):
|
||||
self.notebook.remove_page(self.notebook.page_num(self.hpaned))
|
||||
if hasattr(self, 'available_page'):
|
||||
self.notebook.remove_page(self.notebook.page_num(self.paned))
|
||||
self.notebook.set_current_page(0)
|
||||
for id_, widget in list(self.connected_ids.items()):
|
||||
widget.disconnect(id_)
|
||||
del self.page_num
|
||||
if hasattr(self, 'ftp'):
|
||||
del self.ftp
|
||||
del self.available_page
|
||||
if hasattr(self, 'thread'):
|
||||
del self.thread
|
||||
if self.timeout_id > 0:
|
||||
GLib.source_remove(self.timeout_id)
|
||||
self.timeout_id = 0
|
||||
|
||||
def on_activate(self, widget):
|
||||
if 'plugins' not in gajim.interface.instances:
|
||||
return
|
||||
if hasattr(self, 'page_num'):
|
||||
def on_activate(self, plugin_win):
|
||||
if hasattr(self, 'available_page'):
|
||||
# 'Available' tab exists
|
||||
return
|
||||
self.installed_plugins_model = gajim.interface.instances[
|
||||
'plugins'].installed_plugins_model
|
||||
self.notebook = gajim.interface.instances['plugins'].plugins_notebook
|
||||
if hasattr(self, 'thread'):
|
||||
del self.thread
|
||||
self.installed_plugins_model = plugin_win.installed_plugins_model
|
||||
self.notebook = plugin_win.plugins_notebook
|
||||
id_ = self.notebook.connect('switch-page', self.on_notebook_switch_page)
|
||||
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)
|
||||
self.connected_ids[id_] = self.window
|
||||
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'])
|
||||
self.hpaned = self.xml.get_object('hpaned2')
|
||||
self.page_num = self.notebook.append_page(self.hpaned,
|
||||
Gtk.Label.new(_('Available')))
|
||||
self.xml.add_objects_from_file(self.Gtk_BUILDER_FILE_PATH,
|
||||
['refresh', 'paned', 'plugin_store'])
|
||||
|
||||
widgets_to_extract = (
|
||||
'plugin_name_label', 'available_treeview', 'progressbar',
|
||||
'inslall_upgrade_button', 'plugin_authors_label',
|
||||
'plugin_homepage_linkbutton', 'plugin_version_label')
|
||||
'name_label', 'available_treeview', 'progressbar', 'paned',
|
||||
'install_button', 'authors_label', 'homepage_linkbutton',
|
||||
'version_label', 'scrolled_description_window')
|
||||
|
||||
for widget_name in widgets_to_extract:
|
||||
setattr(self, widget_name, self.xml.get_object(widget_name))
|
||||
|
||||
self.available_plugins_model = Gtk.ListStore(GdkPixbuf.Pixbuf,
|
||||
object, str, str, str, bool,object, object, object)
|
||||
self.available_treeview.set_model(self.available_plugins_model)
|
||||
self.available_treeview.set_rules_hint(True)
|
||||
self.available_plugins_model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
|
||||
# Make Link in LinkButton not centered
|
||||
style_provider = Gtk.CssProvider()
|
||||
css = '.link { padding-left: 0px; padding-right: 0px; }'
|
||||
style_provider.load_from_data(css.encode())
|
||||
context = self.homepage_linkbutton.get_style_context()
|
||||
context.add_provider(style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
self.progressbar.set_property('no-show-all', True)
|
||||
renderer = Gtk.CellRendererText()
|
||||
col = Gtk.TreeViewColumn(_('Plugin'))
|
||||
cell = Gtk.CellRendererPixbuf()
|
||||
col.pack_start(cell, False)
|
||||
col.add_attribute(cell, 'pixbuf', C_PIXBUF)
|
||||
col.pack_start(renderer, True)
|
||||
col.add_attribute(renderer, 'text', C_NAME)
|
||||
col.set_resizable(True)
|
||||
col.set_property('expand', True)
|
||||
col.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY)
|
||||
self.available_treeview.append_column(col)
|
||||
col = Gtk.TreeViewColumn(_('Installed\nversion'), renderer,
|
||||
text=C_LOCAL_VERSION)
|
||||
self.available_treeview.append_column(col)
|
||||
col = Gtk.TreeViewColumn(_('Available\nversion'), renderer,
|
||||
text=C_VERSION)
|
||||
col.set_property('expand', False)
|
||||
self.available_treeview.append_column(col)
|
||||
self.available_page = self.notebook.append_page(
|
||||
self.paned, Gtk.Label.new(_('Available')))
|
||||
|
||||
renderer = Gtk.CellRendererToggle()
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self.available_plugins_toggled_cb)
|
||||
col = Gtk.TreeViewColumn(_('Install /\nUpgrade'), renderer,
|
||||
active=C_UPGRADE)
|
||||
self.available_treeview.append_column(col)
|
||||
self.available_plugins_model = self.xml.get_object('plugin_store')
|
||||
self.available_plugins_model.set_sort_column_id(
|
||||
2, Gtk.SortType.ASCENDING)
|
||||
|
||||
if GObject.signal_lookup('error_signal', self.window) is 0:
|
||||
GObject.signal_new('error_signal', self.window,
|
||||
GObject.SignalFlags.RUN_LAST, GObject.TYPE_STRING,
|
||||
(GObject.TYPE_STRING,))
|
||||
GObject.signal_new('plugin_downloaded', self.window,
|
||||
GObject.SignalFlags.RUN_LAST, GObject.TYPE_STRING,
|
||||
(GObject.TYPE_PYOBJECT,))
|
||||
|
||||
id_ = self.window.connect('error_signal', self.on_some_ftp_error)
|
||||
self.connected_ids[id_] = self.window
|
||||
id_ = self.window.connect('plugin_downloaded',
|
||||
self.on_plugin_downloaded)
|
||||
self.connected_ids[id_] = self.window
|
||||
|
||||
selection = self.available_treeview.get_selection()
|
||||
selection.connect('changed',
|
||||
self.available_plugins_treeview_selection_changed)
|
||||
selection.set_mode(Gtk.SelectionMode.SINGLE)
|
||||
|
||||
self._clear_available_plugin_info()
|
||||
|
||||
self.plugin_description_textview = HtmlTextView()
|
||||
self.plugin_description_textview.set_wrap_mode(Gtk.WrapMode.WORD)
|
||||
sw = self.xml.get_object('scrolledwindow1')
|
||||
sw.add(self.plugin_description_textview)
|
||||
self.description_textview = HtmlTextView()
|
||||
self.description_textview.set_wrap_mode(Gtk.WrapMode.WORD)
|
||||
self.scrolled_description_window.add(self.description_textview)
|
||||
|
||||
self.xml.connect_signals(self)
|
||||
self.window.show_all()
|
||||
|
||||
def on_win_destroy(self, widget):
|
||||
if hasattr(self, 'ftp'):
|
||||
del self.ftp
|
||||
if hasattr(self, 'page_num'):
|
||||
del self.page_num
|
||||
if hasattr(self, 'thread'):
|
||||
del self.thread
|
||||
if hasattr(self, 'available_page'):
|
||||
del self.available_page
|
||||
|
||||
def available_plugins_toggled_cb(self, cell, path):
|
||||
is_active = self.available_plugins_model[path][C_UPGRADE]
|
||||
self.available_plugins_model[path][C_UPGRADE] = not is_active
|
||||
is_active = self.available_plugins_model[path][Column.UPGRADE]
|
||||
self.available_plugins_model[path][Column.UPGRADE] = not is_active
|
||||
dir_list = []
|
||||
for i in range(len(self.available_plugins_model)):
|
||||
if self.available_plugins_model[i][C_UPGRADE]:
|
||||
dir_list.append(self.available_plugins_model[i][C_DIR])
|
||||
if not dir_list:
|
||||
self.inslall_upgrade_button.set_property('sensitive', False)
|
||||
else:
|
||||
self.inslall_upgrade_button.set_property('sensitive', True)
|
||||
if self.available_plugins_model[i][Column.UPGRADE]:
|
||||
dir_list.append(self.available_plugins_model[i][Column.DIR])
|
||||
self.install_button.set_property('sensitive', bool(dir_list))
|
||||
|
||||
def on_notebook_switch_page(self, widget, page, page_num):
|
||||
tab_label_text = self.notebook.get_tab_label_text(self.hpaned)
|
||||
tab_label_text = self.notebook.get_tab_label_text(page)
|
||||
if tab_label_text != (_('Available')):
|
||||
return
|
||||
if not hasattr(self, 'ftp'):
|
||||
if not hasattr(self, 'thread'):
|
||||
self.available_plugins_model.clear()
|
||||
self.progressbar.show()
|
||||
self.ftp = Ftp(self)
|
||||
self.ftp.remote_dirs = None
|
||||
self.ftp.upgrading = True
|
||||
self.ftp.start()
|
||||
self.start_download(upgrading=True)
|
||||
|
||||
def on_inslall_upgrade_clicked(self, widget):
|
||||
self.inslall_upgrade_button.set_property('sensitive', False)
|
||||
def on_install_upgrade_clicked(self, widget):
|
||||
self.install_button.set_property('sensitive', False)
|
||||
dir_list = []
|
||||
for i in range(len(self.available_plugins_model)):
|
||||
if self.available_plugins_model[i][C_UPGRADE]:
|
||||
dir_list.append(self.available_plugins_model[i][C_DIR])
|
||||
if self.available_plugins_model[i][Column.UPGRADE]:
|
||||
dir_list.append(self.available_plugins_model[i][Column.DIR])
|
||||
|
||||
ftp = Ftp(self)
|
||||
ftp.remote_dirs = dir_list
|
||||
ftp.start()
|
||||
self.start_download(remote_dirs=dir_list)
|
||||
|
||||
def on_some_ftp_error(self, widget, error_text):
|
||||
for i in range(len(self.available_plugins_model)):
|
||||
self.available_plugins_model[i][C_UPGRADE] = False
|
||||
self.progressbar.hide()
|
||||
def warn():
|
||||
WarningDialog(_('Ftp error'), error_text, self.window)
|
||||
GLib.idle_add(warn)
|
||||
def on_error(self, reason):
|
||||
if reason == 'CERTIFICATE_VERIFY_FAILED':
|
||||
YesNoDialog(
|
||||
_('Security error during download'),
|
||||
_('A security error occurred when '
|
||||
'downloading. The certificate of the '
|
||||
'plugin archive could not be verified. '
|
||||
'this might be a security attack. '
|
||||
'\n\nYou can continue at your risk. '
|
||||
'Do you want to do so? '
|
||||
'(not recommended)'
|
||||
),
|
||||
on_response_yes=lambda dlg:
|
||||
self.start_download(secure=False, upgrading=True))
|
||||
else:
|
||||
if self.available_plugins_model:
|
||||
for i in range(len(self.available_plugins_model)):
|
||||
self.available_plugins_model[i][Column.UPGRADE] = False
|
||||
self.progressbar.hide()
|
||||
text = GLib.markup_escape_text(reason)
|
||||
WarningDialog(_('Error in download'),
|
||||
_('An error occurred when downloading\n\n'
|
||||
'<tt>[%s]</tt>' % (str(text))), self.window)
|
||||
|
||||
def on_plugin_downloaded(self, widget, plugin_dirs):
|
||||
dialog = HigDialog(None, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
|
||||
'', _('All selected plugins downloaded'))
|
||||
dialog.set_modal(False)
|
||||
dialog.set_transient_for(self.window)
|
||||
def start_download(self, secure=True, remote_dirs=False,
|
||||
upgrading=False, check_update=False):
|
||||
log.info('Start Download...')
|
||||
log.debug(
|
||||
'secure: %s, remote_dirs: %s, upgrading: %s, check_update: %s',
|
||||
secure, remote_dirs, upgrading, check_update)
|
||||
self.thread = DownloadAsync(
|
||||
self, secure=secure, remote_dirs=remote_dirs,
|
||||
upgrading=upgrading, check_update=check_update)
|
||||
self.thread.start()
|
||||
|
||||
def on_plugin_downloaded(self, plugin_dirs):
|
||||
for _dir in plugin_dirs:
|
||||
is_active = False
|
||||
plugins = None
|
||||
@@ -336,8 +253,8 @@ class PluginInstaller(GajimPlugin):
|
||||
if plugin:
|
||||
if plugin.active:
|
||||
is_active = True
|
||||
GLib.idle_add(gajim.plugin_manager.deactivate_plugin,
|
||||
plugin)
|
||||
log.info('Deactivate Plugin: %s', plugin)
|
||||
gajim.plugin_manager.deactivate_plugin(plugin)
|
||||
gajim.plugin_manager.plugins.remove(plugin)
|
||||
|
||||
model = self.installed_plugins_model
|
||||
@@ -346,315 +263,257 @@ class PluginInstaller(GajimPlugin):
|
||||
model.remove(model.get_iter((row, 0)))
|
||||
break
|
||||
|
||||
plugins = self.scan_dir_for_plugin(plugin_dir)
|
||||
log.info('Load Plugin from: %s', plugin_dir)
|
||||
plugins = gajim.plugin_manager.scan_dir_for_plugins(
|
||||
plugin_dir, package=True)
|
||||
if not plugins:
|
||||
log.warn('Loading Plugin failed')
|
||||
continue
|
||||
gajim.plugin_manager.add_plugin(plugins[0])
|
||||
plugin = gajim.plugin_manager.plugins[-1]
|
||||
log.info('Loading successful')
|
||||
for row in range(len(self.available_plugins_model)):
|
||||
if plugin.name == self.available_plugins_model[row][C_NAME]:
|
||||
self.available_plugins_model[row][C_LOCAL_VERSION] = \
|
||||
plugin.version
|
||||
self.available_plugins_model[row][C_UPGRADE] = False
|
||||
model_row = self.available_plugins_model[row]
|
||||
if plugin.name == model_row[Column.NAME]:
|
||||
model_row[Column.LOCAL_VERSION] = plugin.version
|
||||
model_row[Column.UPGRADE] = False
|
||||
if is_active:
|
||||
GLib.idle_add(gajim.plugin_manager.activate_plugin, plugin)
|
||||
log.info('Activate Plugin: %s', plugin)
|
||||
gajim.plugin_manager.activate_plugin(plugin)
|
||||
# get plugin icon
|
||||
icon_file = os.path.join(plugin.__path__, os.path.split(
|
||||
plugin.__path__)[1]) + '.png'
|
||||
icon = self.def_icon
|
||||
if os.path.isfile(icon_file):
|
||||
icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16)
|
||||
if not hasattr(plugin, 'activatable'):
|
||||
# version 0.15
|
||||
plugin.activatable = False
|
||||
row = [plugin, plugin.name, is_active, plugin.activatable, icon]
|
||||
self.installed_plugins_model.append(row)
|
||||
|
||||
dialog = HigDialog(
|
||||
self.window, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
|
||||
'', _('All selected plugins downloaded'))
|
||||
dialog.set_modal(False)
|
||||
dialog.popup()
|
||||
|
||||
def available_plugins_treeview_selection_changed(self, treeview_selection):
|
||||
model, iter = treeview_selection.get_selected()
|
||||
self.xml.get_object('scrolledwindow1').get_children()[0].destroy()
|
||||
self.plugin_description_textview = HtmlTextView()
|
||||
self.plugin_description_textview.set_wrap_mode(Gtk.WrapMode.WORD)
|
||||
sw = self.xml.get_object('scrolledwindow1')
|
||||
sw.add(self.plugin_description_textview)
|
||||
sw.show_all()
|
||||
if iter:
|
||||
self.plugin_name_label.set_text(model.get_value(iter, C_NAME))
|
||||
self.plugin_version_label.set_text(model.get_value(iter, C_VERSION))
|
||||
self.plugin_authors_label.set_text(model.get_value(iter, C_AUTHORS))
|
||||
self.plugin_homepage_linkbutton.set_uri(model.get_value(iter,
|
||||
C_HOMEPAGE))
|
||||
self.plugin_homepage_linkbutton.set_label(model.get_value(iter,
|
||||
C_HOMEPAGE))
|
||||
label = self.plugin_homepage_linkbutton.get_children()[0]
|
||||
label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
self.plugin_homepage_linkbutton.set_property('sensitive', True)
|
||||
desc = _(model.get_value(iter, C_DESCRIPTION))
|
||||
if not desc.startswith('<body '):
|
||||
desc = '<body xmlns=\'http://www.w3.org/1999/xhtml\'>' + \
|
||||
desc + ' </body>'
|
||||
desc = desc.replace('\n', '<br/>')
|
||||
self.plugin_description_textview.display_html(
|
||||
desc, self.plugin_description_textview, None)
|
||||
self.plugin_description_textview.set_property('sensitive', True)
|
||||
else:
|
||||
self._clear_available_plugin_info()
|
||||
|
||||
def _clear_available_plugin_info(self):
|
||||
self.plugin_name_label.set_text('')
|
||||
self.plugin_version_label.set_text('')
|
||||
self.plugin_authors_label.set_text('')
|
||||
self.plugin_homepage_linkbutton.set_uri('')
|
||||
self.plugin_homepage_linkbutton.set_label('')
|
||||
self.plugin_homepage_linkbutton.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:
|
||||
full_module_name = '%s.%s' % (mod, module_name)
|
||||
if full_module_name in sys.modules:
|
||||
from imp import reload
|
||||
module = reload(sys.modules[full_module_name])
|
||||
else:
|
||||
module = __import__(full_module_name)
|
||||
except ValueError as value_error:
|
||||
pass
|
||||
except ImportError as import_error:
|
||||
pass
|
||||
except AttributeError as 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
|
||||
with open(manifest_path) as _file:
|
||||
conf.read_file(_file)
|
||||
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 as type_error:
|
||||
pass
|
||||
except configparser.NoOptionError as type_error:
|
||||
# all fields are required
|
||||
pass
|
||||
return plugins_found
|
||||
self.description_textview.get_buffer().set_text('')
|
||||
self.name_label.set_text(model.get_value(iter, Column.NAME))
|
||||
self.version_label.set_text(model.get_value(iter, Column.VERSION))
|
||||
self.authors_label.set_text(model.get_value(iter, Column.AUTHORS))
|
||||
self.homepage_linkbutton.set_uri(
|
||||
model.get_value(iter, Column.HOMEPAGE))
|
||||
self.homepage_linkbutton.set_label(
|
||||
model.get_value(iter, Column.HOMEPAGE))
|
||||
link_label = self.homepage_linkbutton.get_children()[0]
|
||||
link_label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
desc = _(model.get_value(iter, Column.DESCRIPTION))
|
||||
if not desc.startswith('<body '):
|
||||
desc = ('<body xmlns=\'http://www.w3.org/1999/xhtml\'>'
|
||||
'%s</body>') % desc
|
||||
desc = desc.replace('\n', '<br/>')
|
||||
self.description_textview.display_html(
|
||||
desc, self.description_textview, None)
|
||||
|
||||
def select_root_iter(self):
|
||||
if hasattr(self, 'page_num'):
|
||||
selection = self.available_treeview.get_selection()
|
||||
if selection.count_selected_rows() == 0:
|
||||
root_iter = self.available_plugins_model.get_iter_first()
|
||||
selection.select_iter(root_iter)
|
||||
scr_win = self.xml.get_object('scrolledwindow2')
|
||||
vadjustment = scr_win.get_vadjustment()
|
||||
if vadjustment:
|
||||
vadjustment.set_value(0)
|
||||
selection = self.available_treeview.get_selection()
|
||||
if selection.count_selected_rows() == 0:
|
||||
root_iter = self.available_plugins_model.get_iter_first()
|
||||
path = self.available_plugins_model.get_path(root_iter)
|
||||
selection.select_iter(root_iter)
|
||||
self.name_label.show()
|
||||
self.homepage_linkbutton.show()
|
||||
self.available_treeview.scroll_to_cell(path)
|
||||
|
||||
|
||||
class Ftp(threading.Thread):
|
||||
def __init__(self, plugin):
|
||||
super(Ftp, self).__init__()
|
||||
class DownloadAsync(threading.Thread):
|
||||
def __init__(self, plugin, secure, remote_dirs, upgrading, check_update):
|
||||
threading.Thread.__init__(self)
|
||||
self.plugin = plugin
|
||||
self.window = plugin.window
|
||||
self.progressbar = plugin.progressbar
|
||||
self.model = plugin.available_plugins_model
|
||||
self.buffer_ = io.BytesIO()
|
||||
self.remote_dirs = None
|
||||
self.append_to_model = True
|
||||
self.upgrading = False
|
||||
self.remote_dirs = remote_dirs
|
||||
self.upgrading = upgrading
|
||||
self.secure = secure
|
||||
self.check_update = check_update
|
||||
self.pulse = None
|
||||
icon = Gtk.Image()
|
||||
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
|
||||
Gtk.IconSize.MENU)
|
||||
self.def_icon = icon.render_icon(
|
||||
Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU)
|
||||
|
||||
def model_append(self, row):
|
||||
self.model.append(row)
|
||||
row_data = [
|
||||
row['icon'], row['remote_dir'], row['name'], row['local_version'],
|
||||
row['version'], row['upgrade'], row['description'], row['authors'],
|
||||
row['homepage']
|
||||
]
|
||||
self.model.append(row_data)
|
||||
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:
|
||||
GLib.idle_add(self.progressbar.set_text,
|
||||
_('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:
|
||||
GLib.idle_add(self.progressbar.set_text,
|
||||
_('Scan files on the server'))
|
||||
self.ftp.retrbinary('RETR manifests_images.zip', self.handleDownload)
|
||||
zip_file = zipfile.ZipFile(self.buffer_)
|
||||
manifest_list = zip_file.namelist()
|
||||
progress_step = 1.0 / len(manifest_list)
|
||||
for filename in manifest_list:
|
||||
if not filename.endswith('manifest.ini'):
|
||||
continue
|
||||
dir_ = filename.split('/')[0]
|
||||
fract = self.progressbar.get_fraction() + progress_step
|
||||
GLib.idle_add(self.progressbar.set_fraction, fract)
|
||||
GLib.idle_add(self.progressbar.set_text,
|
||||
_('Reading "%s"') % dir_)
|
||||
if self.check_update:
|
||||
self.run_check_update()
|
||||
else:
|
||||
GLib.idle_add(self.progressbar.show)
|
||||
self.pulse = GLib.timeout_add(150, self.progressbar_pulse)
|
||||
self.run_download_plugin_list()
|
||||
except urllib.error.URLError as exc:
|
||||
if isinstance(exc.reason, ssl.SSLError):
|
||||
ssl_reason = exc.reason.reason
|
||||
if ssl_reason == 'CERTIFICATE_VERIFY_FAILED':
|
||||
log.exception('Certificate verify failed')
|
||||
GLib.idle_add(self.plugin.on_error, ssl_reason)
|
||||
except Exception as exc:
|
||||
GLib.idle_add(self.plugin.on_error, str(exc))
|
||||
log.exception('Error fetching plugin list')
|
||||
finally:
|
||||
if self.pulse:
|
||||
GLib.source_remove(self.pulse)
|
||||
GLib.idle_add(self.progressbar.hide)
|
||||
self.pulse = None
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
conf_file = zip_file.open(filename)
|
||||
config.read_file(io.TextIOWrapper(conf_file, encoding='utf-8'))
|
||||
conf_file.close()
|
||||
if not config.has_section('info'):
|
||||
continue
|
||||
opts = config.options('info')
|
||||
if 'name' not in opts or 'version' not in opts or \
|
||||
'description' not in opts or 'authors' not in opts or \
|
||||
'homepage' not in opts:
|
||||
continue
|
||||
def parse_manifest(self, buf):
|
||||
'''
|
||||
given the buffer of the zipfile, returns the list of plugin manifests
|
||||
'''
|
||||
zip_file = ZipFile(buf)
|
||||
manifest_list = zip_file.namelist()
|
||||
plugins = []
|
||||
for filename in manifest_list:
|
||||
# Parse manifest
|
||||
if not filename.endswith('manifest.ini'):
|
||||
continue
|
||||
config = configparser.ConfigParser()
|
||||
conf_file = zip_file.open(filename)
|
||||
config.read_file(io.TextIOWrapper(conf_file, encoding='utf-8'))
|
||||
conf_file.close()
|
||||
if not config.has_section('info'):
|
||||
log.warn('Plugin is missing INFO section in manifest.ini. '
|
||||
'Plugin not loaded.')
|
||||
continue
|
||||
opts = config.options('info')
|
||||
if not set(MANDATORY_FIELDS).issubset(opts):
|
||||
log.warn('Plugin is missing mandatory fields in manifest.ini. '
|
||||
'Plugin not loaded.')
|
||||
continue
|
||||
# Add icon and remote dir
|
||||
icon = None
|
||||
remote_dir = filename.split('/')[0]
|
||||
png_filename = '{0}/{0}.png'.format(remote_dir)
|
||||
icon = self.def_icon
|
||||
if png_filename in manifest_list:
|
||||
data = zip_file.open(png_filename).read()
|
||||
pix = GdkPixbuf.PixbufLoader()
|
||||
pix.set_size(16, 16)
|
||||
pix.write(data)
|
||||
pix.close()
|
||||
icon = pix.get_pixbuf()
|
||||
|
||||
local_version = self.get_plugin_version(
|
||||
config.get('info', 'name'))
|
||||
upgrade = False
|
||||
if self.upgrading and local_version:
|
||||
local = convert_version_to_list(local_version)
|
||||
remote = convert_version_to_list(config.get('info',
|
||||
'version'))
|
||||
if remote > local:
|
||||
upgrade = True
|
||||
GLib.idle_add(
|
||||
self.plugin.inslall_upgrade_button.set_property,
|
||||
'sensitive', True)
|
||||
png_filename = dir_ + '/' + dir_ + '.png'
|
||||
if png_filename in manifest_list:
|
||||
data = zip_file.open(png_filename).read()
|
||||
pbl = GdkPixbuf.PixbufLoader()
|
||||
pbl.set_size(16, 16)
|
||||
pbl.write(data)
|
||||
pbl.close()
|
||||
def_icon = pbl.get_pixbuf()
|
||||
else:
|
||||
def_icon = self.def_icon
|
||||
if local_version:
|
||||
base_dir, user_dir = gajim.PLUGINS_DIRS
|
||||
local_dir = os.path.join(user_dir, dir_)
|
||||
# transform to dictonary
|
||||
config_dict = {}
|
||||
for key, value in config.items('info'):
|
||||
config_dict[key] = value
|
||||
config_dict['icon'] = icon
|
||||
config_dict['remote_dir'] = remote_dir
|
||||
config_dict['upgrade'] = False
|
||||
|
||||
GLib.idle_add(self.model_append, [def_icon, dir_,
|
||||
config.get('info', 'name'), local_version,
|
||||
config.get('info', 'version'), upgrade,
|
||||
config.get('info', 'description'),
|
||||
config.get('info', 'authors'),
|
||||
config.get('info', 'homepage'), ])
|
||||
self.ftp.quit()
|
||||
GLib.idle_add(self.progressbar.set_fraction, 0)
|
||||
if self.remote_dirs:
|
||||
self.download_plugin()
|
||||
GLib.idle_add(self.progressbar.hide)
|
||||
plugins.append(config_dict)
|
||||
return plugins
|
||||
|
||||
def download_url(self, url):
|
||||
log.info('Fetching %s', url)
|
||||
ssl_args = {}
|
||||
if self.secure:
|
||||
ssl_args['context'] = ssl.create_default_context(
|
||||
cafile=self.plugin.local_file_path('DST_Root_CA_X3.pem'))
|
||||
else:
|
||||
ssl_args['context'] = ssl.create_default_context()
|
||||
ssl_args['context'].check_hostname = False
|
||||
ssl_args['context'].verify_mode = ssl.CERT_NONE
|
||||
|
||||
for flag in ('OP_NO_SSLv2', 'OP_NO_SSLv3',
|
||||
'OP_NO_TLSv1', 'OP_NO_TLSv1_1',
|
||||
'OP_NO_COMPRESSION',
|
||||
):
|
||||
log.debug('SSL Options: +%s' % flag)
|
||||
ssl_args['context'].options |= getattr(ssl, flag)
|
||||
request = urlopen(url, **ssl_args)
|
||||
|
||||
return io.BytesIO(request.read())
|
||||
|
||||
def run_check_update(self):
|
||||
to_update = []
|
||||
zipbuf = self.download_url(MANIFEST_URL)
|
||||
plugin_list = self.parse_manifest(zipbuf)
|
||||
for plugin in plugin_list:
|
||||
local_version = get_local_version(plugin['name'])
|
||||
if local_version:
|
||||
if V(plugin['version']) > V(local_version):
|
||||
to_update.append(plugin['name'])
|
||||
GLib.idle_add(self.plugin.warn_update, to_update)
|
||||
|
||||
def run_download_plugin_list(self):
|
||||
if not self.remote_dirs:
|
||||
log.info('Downloading Pluginlist...')
|
||||
zipbuf = self.download_url(MANIFEST_IMAGE_URL)
|
||||
plugin_list = self.parse_manifest(zipbuf)
|
||||
for plugin in plugin_list:
|
||||
plugin['local_version'] = get_local_version(plugin['name'])
|
||||
if self.upgrading and plugin['local_version']:
|
||||
if V(plugin['version']) > V(plugin['local_version']):
|
||||
plugin['upgrade'] = True
|
||||
GLib.idle_add(
|
||||
self.plugin.install_button.set_property,
|
||||
'sensitive', True)
|
||||
GLib.idle_add(self.model_append, plugin)
|
||||
GLib.idle_add(self.plugin.select_root_iter)
|
||||
except Exception as e:
|
||||
self.window.emit('error_signal', str(e))
|
||||
|
||||
def handleDownload(self, block):
|
||||
self.buffer_.write(block)
|
||||
else:
|
||||
self.download_plugin()
|
||||
|
||||
def download_plugin(self):
|
||||
GLib.idle_add(self.progressbar.show)
|
||||
self.pulse = GLib.timeout_add(150, self.progressbar_pulse)
|
||||
GLib.idle_add(self.progressbar.set_text, _('Creating a list of files'))
|
||||
for remote_dir in self.remote_dirs:
|
||||
filename = remote_dir + '.zip'
|
||||
log.info('Download: %s', filename)
|
||||
base_dir, user_dir = gajim.PLUGINS_DIRS
|
||||
if not os.path.isdir(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):
|
||||
os.mkdir(local_dir)
|
||||
local_dir = os.path.split(user_dir)[0]
|
||||
|
||||
# downloading zip file
|
||||
GLib.idle_add(self.progressbar.set_text,
|
||||
_('Downloading "%s"') % filename)
|
||||
full_filename = os.path.join(user_dir, filename)
|
||||
self.buffer_ = io.BytesIO()
|
||||
try:
|
||||
self.ftp.retrbinary('RETR %s' % filename, self.handleDownload)
|
||||
except ftplib.all_errors as e:
|
||||
print (str(e))
|
||||
|
||||
with zipfile.ZipFile(self.buffer_) as zip_file:
|
||||
zip_file.extractall(os.path.join(user_dir))
|
||||
|
||||
self.ftp.quit()
|
||||
GLib.idle_add(self.window.emit, 'plugin_downloaded', self.remote_dirs)
|
||||
GLib.source_remove(self.pulse)
|
||||
plugin = posixpath.join(PLUGINS_URL, filename)
|
||||
buf = self.download_url(plugin)
|
||||
except:
|
||||
log.exception("Error downloading plugin %s" % filename)
|
||||
continue
|
||||
with ZipFile(buf) as zip_file:
|
||||
zip_file.extractall(os.path.join(local_dir, 'plugins'))
|
||||
GLib.idle_add(self.plugin.on_plugin_downloaded, self.remote_dirs)
|
||||
|
||||
|
||||
class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog):
|
||||
def init(self):
|
||||
self.Gtk_BUILDER_FILE_PATH = self.plugin.local_file_path(
|
||||
'config_dialog.ui')
|
||||
glade_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.get_child().pack_start(hbox, True, True, 0)
|
||||
self.xml.add_objects_from_file(glade_file_path, ['config_grid'])
|
||||
grid = self.xml.get_object('config_grid')
|
||||
self.get_child().pack_start(grid, True, True, 0)
|
||||
|
||||
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']))
|
||||
self.xml.get_object('check_update').set_active(
|
||||
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):
|
||||
widget = self.xml.get_object('ftp_server')
|
||||
self.plugin.config['ftp_server'] = widget.get_text()
|
||||
|
||||
def on_check_update_toggled(self, widget):
|
||||
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