SHARE
TWEET

mintUpdate.py - before Jun 28 2017

Kimarite Mar 11th, 2018 (edited) 467 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/python3
  2. ## https://github.com/linuxmint/mintupdate/commit/0953b8d23927e1bc72acfc2d83fa74ab58a8fe5c
  3. ## This is the Linux Mint 18.2 (Xfce)'s original file from Live system
  4.  
  5. import os
  6. import sys
  7. import gi
  8. import tempfile
  9. import threading
  10. import time
  11. import gettext
  12. import io
  13. import tarfile
  14. import urllib.request
  15. import proxygsettings
  16. import subprocess
  17. import pycurl
  18. import datetime
  19. import configparser
  20. import traceback
  21. import setproctitle
  22.  
  23. from kernelwindow import KernelWindow
  24. gi.require_version('Gtk', '3.0')
  25. gi.require_version('GdkX11', '3.0') # Needed to get xid
  26. gi.require_version('AppIndicator3', '0.1')
  27. from gi.repository import Gtk, Gdk, GdkPixbuf, GdkX11, Gio, Pango
  28. from gi.repository import AppIndicator3 as AppIndicator
  29.  
  30. from Classes import Update
  31.  
  32. try:
  33.     numMintUpdate = subprocess.check_output("ps -A | grep mintUpdate | wc -l", shell = True)
  34.     if (numMintUpdate != "0"):
  35.         os.system("killall mintUpdate")
  36. except Exception as e:
  37.     print (e)
  38.     print(sys.exc_info()[0])
  39.  
  40. setproctitle.setproctitle("mintUpdate")
  41.  
  42. # i18n
  43. gettext.install("mintupdate", "/usr/share/linuxmint/locale")
  44.  
  45. (TAB_UPDATES, TAB_UPTODATE, TAB_ERROR) = range(3)
  46.  
  47. (UPDATE_CHECKED, UPDATE_DISPLAY_NAME, UPDATE_LEVEL_PIX, UPDATE_OLD_VERSION, UPDATE_NEW_VERSION, UPDATE_SOURCE, UPDATE_LEVEL_STR, UPDATE_SIZE, UPDATE_SIZE_STR, UPDATE_TYPE_PIX, UPDATE_TYPE, UPDATE_TOOLTIP, UPDATE_SORT_STR, UPDATE_OBJ) = range(14)
  48.  
  49. def size_to_string(size):
  50.     strSize = str(size) + _("B")
  51.     if (size >= 1024):
  52.         strSize = str(size // 1024) + _("KB")
  53.     if (size >= (1024 * 1024)):
  54.         strSize = str(size // (1024 * 1024)) + _("MB")
  55.     if (size >= (1024 * 1024 * 1024)):
  56.         strSize = str(size // (1024 * 1024 * 1024)) + _("GB")
  57.     return strSize
  58.  
  59. class ChangelogRetriever(threading.Thread):
  60.     def __init__(self, package_update, application):
  61.         threading.Thread.__init__(self)
  62.         self.source_package = package_update.real_source_name
  63.         self.level = package_update.level
  64.         self.version = package_update.new_version
  65.         self.origin = package_update.origin
  66.         self.application = application
  67.         # get the proxy settings from gsettings
  68.         self.ps = proxygsettings.get_proxy_settings()
  69.  
  70.  
  71.         # Remove the epoch if present in the version
  72.         if ":" in self.version:
  73.             self.version = self.version.split(":")[-1]
  74.  
  75.     def get_ppa_info(self):
  76.         ppa_sources_file = "/etc/apt/sources.list"
  77.         ppa_sources_dir = "/etc/apt/sources.list.d/"
  78.         ppa_words = self.origin.lstrip("LP-PPA-").split("-")
  79.  
  80.         source = ppa_sources_file
  81.         if os.path.exists(ppa_sources_dir):
  82.             for filename in os.listdir(ppa_sources_dir):
  83.                 if filename.startswith(self.origin.lstrip("LP-PPA-")):
  84.                     source = os.path.join(ppa_sources_dir, filename)
  85.                     break
  86.         if not os.path.exists(source):
  87.             return None, None
  88.         try:
  89.             with open(source) as f:
  90.                 for line in f:
  91.                     if (not line.startswith("#") and all(word in line for word in ppa_words)):
  92.                         ppa_info = line.split("ppa.launchpad.net/")[1]
  93.                         break
  94.                 else:
  95.                     return None, None
  96.         except EnvironmentError as e:
  97.             print ("Error encountered while trying to get PPA owner and name: %s" % e)
  98.             return None, None
  99.         ppa_owner, ppa_name, ppa_x = ppa_info.split("/", 2)
  100.         return ppa_owner, ppa_name
  101.  
  102.     def get_ppa_changelog(self, ppa_owner, ppa_name):
  103.         max_tarball_size = 1000000
  104.         print ("\nFetching changelog for PPA package %s/%s/%s ..." % (ppa_owner, ppa_name, self.source_package))
  105.         if self.source_package.startswith("lib"):
  106.             ppa_abbr = self.source_package[:4]
  107.         else:
  108.             ppa_abbr = self.source_package[0]
  109.         deb_dsc_uri = "http://ppa.launchpad.net/%s/%s/ubuntu/pool/main/%s/%s/%s_%s.dsc" % (ppa_owner, ppa_name, ppa_abbr, self.source_package, self.source_package, self.version)
  110.         try:
  111.             deb_dsc = urllib.request.urlopen(deb_dsc_uri, None, 10).read().decode("utf-8")
  112.         except Exception as e:
  113.             print ("Could not open Launchpad URL %s - %s" % (deb_dsc_uri, e))
  114.             return
  115.         for line in deb_dsc.split("\n"):
  116.             if "debian.tar" not in line:
  117.                 continue
  118.             tarball_line = line.strip().split(" ", 2)
  119.             if len(tarball_line) == 3:
  120.                 deb_checksum, deb_size, deb_filename = tarball_line
  121.                 break
  122.         else:
  123.             deb_filename = None
  124.         if not deb_filename or not deb_size or not deb_size.isdigit():
  125.             print ("Unsupported debian .dsc file format. Skipping this package.")
  126.             return
  127.         if (int(deb_size) > max_tarball_size):
  128.             print ("Tarball size %s B exceeds maximum download size %d B. Skipping download." % (deb_size, max_tarball_size))
  129.             return
  130.         deb_file_uri = "http://ppa.launchpad.net/%s/%s/ubuntu/pool/main/%s/%s/%s" % (ppa_owner, ppa_name, ppa_abbr, self.source_package, deb_filename)
  131.         try:
  132.             deb_file = urllib.request.urlopen(deb_file_uri, None, 10).read().decode("utf-8")
  133.         except Exception as e:
  134.             print ("Could not download tarball from %s - %s" % (deb_file_uri, e))
  135.             return
  136.         if deb_filename.endswith(".xz"):
  137.             cmd = ["xz", "--decompress"]
  138.             try:
  139.                 xz = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  140.                 xz.stdin.write(deb_file)
  141.                 xz.stdin.close()
  142.                 deb_file = xz.stdout.read()
  143.                 xz.stdout.close()
  144.             except EnvironmentError as e:
  145.                 print ("Error encountered while decompressing xz file: %s" % e)
  146.                 return
  147.         deb_file = io.BytesIO(deb_file)
  148.         try:
  149.             with tarfile.open(fileobj = deb_file) as f:
  150.                 deb_changelog = f.extractfile("debian/changelog").read()
  151.         except tarfile.TarError as e:
  152.             print ("Error encountered while reading tarball: %s" % e)
  153.             return
  154.  
  155.         return deb_changelog
  156.  
  157.     def run(self):
  158.         Gdk.threads_enter()
  159.         self.application.builder.get_object("textview_changes").get_buffer().set_text(_("Downloading changelog..."))
  160.         Gdk.threads_leave()
  161.  
  162.         if self.ps == {}:
  163.             # use default urllib.request proxy mechanisms (possibly *_proxy environment vars)
  164.             proxy = urllib.request.ProxyHandler()
  165.         else:
  166.             # use proxy settings retrieved from gsettings
  167.             proxy = urllib.request.ProxyHandler(self.ps)
  168.  
  169.         opener = urllib.request.build_opener(proxy)
  170.         urllib.request.install_opener(opener)
  171.  
  172.         changelog = [_("No changelog available")]
  173.  
  174.         changelog_sources = []
  175.         if self.origin == "linuxmint":
  176.             changelog_sources.append("http://packages.linuxmint.com/dev/" + self.source_package + "_" + self.version + "_amd64.changes")
  177.             changelog_sources.append("http://packages.linuxmint.com/dev/" + self.source_package + "_" + self.version + "_i386.changes")
  178.         elif self.origin == "ubuntu":
  179.             if (self.source_package.startswith("lib")):
  180.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/main/%s/%s/%s_%s/changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  181.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/multiverse/%s/%s/%s_%s/changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  182.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/universe/%s/%s/%s_%s/changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  183.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/restricted/%s/%s/%s_%s/changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  184.             else:
  185.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/main/%s/%s/%s_%s/changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  186.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/multiverse/%s/%s/%s_%s/changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  187.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/universe/%s/%s/%s_%s/changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  188.                 changelog_sources.append("http://changelogs.ubuntu.com/changelogs/pool/restricted/%s/%s/%s_%s/changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  189.         elif self.origin == "debian":
  190.             if (self.source_package.startswith("lib")):
  191.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/main/%s/%s/%s_%s_changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  192.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/contrib/%s/%s/%s_%s_changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  193.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/non-free/%s/%s/%s_%s_changelog" % (self.source_package[0:4], self.source_package, self.source_package, self.version))
  194.             else:
  195.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/main/%s/%s/%s_%s_changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  196.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/contrib/%s/%s/%s_%s_changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  197.                 changelog_sources.append("http://metadata.ftp-master.debian.org/changelogs/non-free/%s/%s/%s_%s_changelog" % (self.source_package[0], self.source_package, self.source_package, self.version))
  198.         elif self.origin.startswith("LP-PPA"):
  199.             ppa_owner, ppa_name = self.get_ppa_info()
  200.             if ppa_owner and ppa_name:
  201.                 deb_changelog = self.get_ppa_changelog(ppa_owner, ppa_name)
  202.                 if not deb_changelog:
  203.                     changelog_sources.append("https://launchpad.net/~%s/+archive/ubuntu/%s/+files/%s_%s_source.changes" % (ppa_owner, ppa_name, self.source_package, self.version))
  204.                 else:
  205.                     changelog = "%s\n" % deb_changelog
  206.             else:
  207.                 print ("PPA owner or name could not be determined")
  208.  
  209.         for changelog_source in changelog_sources:
  210.             try:
  211.                 print("Trying to fetch the changelog from: %s" % changelog_source)
  212.                 url = urllib.request.urlopen(changelog_source, None, 10)
  213.                 source = url.read().decode("utf-8")
  214.                 url.close()
  215.  
  216.                 changelog = ""
  217.                 if "linuxmint.com" in changelog_source:
  218.                     changes = source.split("\n")
  219.                     for change in changes:
  220.                         stripped_change = change.strip()
  221.                         if stripped_change == ".":
  222.                             change = ""
  223.                         if change == "" or stripped_change.startswith("*") or stripped_change.startswith("["):
  224.                             changelog = changelog + change + "\n"
  225.                 elif "launchpad.net" in changelog_source:
  226.                     changes = source.split("Changes:")[1].split("Checksums")[0].split("\n")
  227.                     for change in changes:
  228.                         stripped_change = change.strip()
  229.                         if stripped_change != "":
  230.                             if stripped_change == ".":
  231.                                 stripped_change = ""
  232.                             changelog = changelog + stripped_change + "\n"
  233.                 else:
  234.                     changelog = source
  235.                 changelog = changelog.split("\n")
  236.                 break
  237.             except:
  238.                 pass
  239.  
  240.         Gdk.threads_enter()
  241.         self.application.builder.get_object("textview_changes").get_buffer().set_text("")
  242.         for change in changelog:
  243.             self.application.builder.get_object("textview_changes").get_buffer().insert(self.application.builder.get_object("textview_changes").get_buffer().get_end_iter(), change)
  244.             self.application.builder.get_object("textview_changes").get_buffer().insert(self.application.builder.get_object("textview_changes").get_buffer().get_end_iter(), "\n")
  245.         Gdk.threads_leave()
  246.  
  247. class AutomaticRefreshThread(threading.Thread):
  248.     def __init__(self, application):
  249.         threading.Thread.__init__(self)
  250.         self.application = application
  251.  
  252.     def run(self):
  253.         # Initial refresh (with APT cache refresh)
  254.         try:
  255.             timer = (self.application.settings.get_int("refresh-minutes") * 60) + (self.application.settings.get_int("refresh-hours") * 60 * 60) + (self.application.settings.get_int("refresh-days") * 24 * 60 * 60)
  256.             self.application.logger.write("Initial refresh will happen in " + str(self.application.settings.get_int("refresh-minutes")) + " minutes, " + str(self.application.settings.get_int("refresh-hours")) + " hours and " + str(self.application.settings.get_int("refresh-days")) + " days")
  257.             timetosleep = int(timer)
  258.             if (timetosleep == 0):
  259.                 time.sleep(60) # sleep 1 minute, don't mind the config we don't want an infinite loop to go nuts :)
  260.             else:
  261.                 time.sleep(timetosleep)
  262.                 if (self.application.app_hidden == True):
  263.                     self.application.logger.write("MintUpdate is in tray mode, performing initial refresh")
  264.                     refresh = RefreshThread(self.application, root_mode=True)
  265.                     refresh.start()
  266.                 else:
  267.                     self.application.logger.write("The mintUpdate window is open, skipping initial refresh")
  268.         except Exception as e:
  269.             print (e)
  270.             self.application.logger.write_error("Exception occurred during the initial refresh: " + str(sys.exc_info()[0]))
  271.  
  272.         # Autorefresh (also with APT cache refresh)
  273.         try:
  274.             while(True):
  275.                 timer = (self.application.settings.get_int("autorefresh-minutes") * 60) + (self.application.settings.get_int("autorefresh-hours") * 60 * 60) + (self.application.settings.get_int("autorefresh-days") * 24 * 60 * 60)
  276.                 self.application.logger.write("Auto-refresh will happen in " + str(self.application.settings.get_int("autorefresh-minutes")) + " minutes, " + str(self.application.settings.get_int("autorefresh-hours")) + " hours and " + str(self.application.settings.get_int("autorefresh-days")) + " days")
  277.                 timetosleep = int(timer)
  278.                 if (timetosleep == 0):
  279.                     time.sleep(60) # sleep 1 minute, don't mind the config we don't want an infinite loop to go nuts :)
  280.                 else:
  281.                     time.sleep(timetosleep)
  282.                     if (self.application.app_hidden == True):
  283.                         self.application.logger.write("MintUpdate is in tray mode, performing auto-refresh")
  284.                         refresh = RefreshThread(self.application, root_mode=True)
  285.                         refresh.start()
  286.                     else:
  287.                         self.application.logger.write("The mintUpdate window is open, skipping auto-refresh")
  288.         except Exception as e:
  289.             print (e)
  290.             self.application.logger.write_error("Exception occurred in the auto-refresh thread.. so it's probably dead now: " + str(sys.exc_info()[0]))
  291.  
  292. class InstallThread(threading.Thread):
  293.  
  294.     def __init__(self, application):
  295.         threading.Thread.__init__(self)
  296.         self.application = application
  297.         self.application.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH))
  298.         self.application.window.set_sensitive(False)
  299.  
  300.     def run(self):
  301.         try:
  302.             self.application.logger.write("Install requested by user")
  303.             Gdk.threads_enter()
  304.             installNeeded = False
  305.             packages = []
  306.             model = self.application.treeview.get_model()
  307.             Gdk.threads_leave()
  308.  
  309.             iter = model.get_iter_first()
  310.             while (iter != None):
  311.                 checked = model.get_value(iter, UPDATE_CHECKED)
  312.                 if (checked == "true"):
  313.                     installNeeded = True
  314.                     package_update = model.get_value(iter, UPDATE_OBJ)
  315.                     for package in package_update.package_names:
  316.                         packages.append(package)
  317.                         self.application.logger.write("Will install " + str(package))
  318.                 iter = model.iter_next(iter)
  319.  
  320.             if (installNeeded == True):
  321.  
  322.                 proceed = True
  323.                 try:
  324.                     pkgs = ' '.join(str(pkg) for pkg in packages)
  325.                     warnings = subprocess.check_output("/usr/lib/linuxmint/mintUpdate/checkWarnings.py %s" % pkgs, shell = True).decode("utf-8")
  326.                     #print ("/usr/lib/linuxmint/mintUpdate/checkWarnings.py %s" % pkgs)
  327.                     warnings = warnings.split("###")
  328.                     if len(warnings) == 2:
  329.                         installations = warnings[0].split()
  330.                         removals = warnings[1].split()
  331.                         if len(installations) > 0 or len(removals) > 0:
  332.                             Gdk.threads_enter()
  333.                             try:
  334.                                 dialog = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, None)
  335.                                 dialog.set_title("")
  336.                                 dialog.set_markup("<b>" + _("This upgrade will trigger additional changes") + "</b>")
  337.                                 #dialog.format_secondary_markup("<i>" + _("All available upgrades for this package will be ignored.") + "</i>")
  338.                                 dialog.set_icon_name("mintupdate")
  339.                                 dialog.set_default_size(320, 400)
  340.                                 dialog.set_resizable(True)
  341.  
  342.                                 if len(removals) > 0:
  343.                                     # Removals
  344.                                     label = Gtk.Label()
  345.                                     if len(removals) == 1:
  346.                                         label.set_text(_("The following package will be removed:"))
  347.                                     else:
  348.                                         label.set_text(_("The following %d packages will be removed:") % len(removals))
  349.                                     label.set_alignment(0, 0.5)
  350.                                     label.set_padding(20, 0)
  351.                                     scrolledWindow = Gtk.ScrolledWindow()
  352.                                     scrolledWindow.set_shadow_type(Gtk.ShadowType.IN)
  353.                                     scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
  354.                                     treeview = Gtk.TreeView()
  355.                                     column1 = Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0)
  356.                                     column1.set_sort_column_id(0)
  357.                                     column1.set_resizable(True)
  358.                                     treeview.append_column(column1)
  359.                                     treeview.set_headers_clickable(False)
  360.                                     treeview.set_reorderable(False)
  361.                                     treeview.set_headers_visible(False)
  362.                                     model = Gtk.TreeStore(str)
  363.                                     removals.sort()
  364.                                     for pkg in removals:
  365.                                         iter = model.insert_before(None, None)
  366.                                         model.set_value(iter, 0, pkg)
  367.                                     treeview.set_model(model)
  368.                                     treeview.show()
  369.                                     scrolledWindow.add(treeview)
  370.                                     dialog.vbox.pack_start(label, False, False, 0)
  371.                                     dialog.vbox.pack_start(scrolledWindow, True, True, 0)
  372.                                     dialog.vbox.set_border_width(6)
  373.  
  374.                                 if len(installations) > 0:
  375.                                     # Installations
  376.                                     label = Gtk.Label()
  377.                                     if len(installations) == 1:
  378.                                         label.set_text(_("The following package will be installed:"))
  379.                                     else:
  380.                                         label.set_text(_("The following %d packages will be installed:") % len(installations))
  381.                                     label.set_alignment(0, 0.5)
  382.                                     label.set_padding(20, 0)
  383.                                     scrolledWindow = Gtk.ScrolledWindow()
  384.                                     scrolledWindow.set_shadow_type(Gtk.ShadowType.IN)
  385.                                     scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
  386.                                     treeview = Gtk.TreeView()
  387.                                     column1 = Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0)
  388.                                     column1.set_sort_column_id(0)
  389.                                     column1.set_resizable(True)
  390.                                     treeview.append_column(column1)
  391.                                     treeview.set_headers_clickable(False)
  392.                                     treeview.set_reorderable(False)
  393.                                     treeview.set_headers_visible(False)
  394.                                     model = Gtk.TreeStore(str)
  395.                                     installations.sort()
  396.                                     for pkg in installations:
  397.                                         iter = model.insert_before(None, None)
  398.                                         model.set_value(iter, 0, pkg)
  399.                                     treeview.set_model(model)
  400.                                     treeview.show()
  401.                                     scrolledWindow.add(treeview)
  402.                                     dialog.vbox.pack_start(label, False, False, 0)
  403.                                     dialog.vbox.pack_start(scrolledWindow, True, True, 0)
  404.  
  405.                                 dialog.show_all()
  406.                                 if dialog.run() == Gtk.ResponseType.OK:
  407.                                     proceed = True
  408.                                 else:
  409.                                     proceed = False
  410.                                 dialog.destroy()
  411.                             except Exception as e:
  412.                                 print (e)
  413.                                 print(sys.exc_info()[0])
  414.                             Gdk.threads_leave()
  415.                         else:
  416.                             proceed = True
  417.                 except Exception as e:
  418.                     print (e)
  419.                     print(sys.exc_info()[0])
  420.  
  421.                 if proceed:
  422.                     Gdk.threads_enter()
  423.                     self.application.set_status(_("Installing updates"), _("Installing updates"), "mintupdate-installing", True)
  424.                     Gdk.threads_leave()
  425.                     self.application.logger.write("Ready to launch synaptic")
  426.                     cmd = ["pkexec", "/usr/sbin/synaptic", "--hide-main-window",  \
  427.                             "--non-interactive", "--parent-window-id", "%s" % self.application.window.get_window().get_xid()]
  428.                     cmd.append("-o")
  429.                     cmd.append("Synaptic::closeZvt=true")
  430.                     cmd.append("--progress-str")
  431.                     cmd.append("\"" + _("Please wait, this can take some time") + "\"")
  432.                     cmd.append("--finish-str")
  433.                     cmd.append("\"" + _("Update is complete") + "\"")
  434.                     f = tempfile.NamedTemporaryFile()
  435.  
  436.                     for pkg in packages:
  437.                         pkg_line = "%s\tinstall\n" % pkg
  438.                         f.write(pkg_line.encode("utf-8"))
  439.  
  440.                     cmd.append("--set-selections-file")
  441.                     cmd.append("%s" % f.name)
  442.                     f.flush()
  443.                     comnd = subprocess.Popen(' '.join(cmd), stdout=self.application.logger.log, stderr=self.application.logger.log, shell=True)
  444.                     returnCode = comnd.wait()
  445.                     self.application.logger.write("Return code:" + str(returnCode))
  446.                     f.close()
  447.  
  448.                     latest_apt_update = ''
  449.                     update_successful = False
  450.                     with open("/var/log/apt/history.log") as apt_history:
  451.                         for line in reversed(list(apt_history)):
  452.                             if "Start-Date" in line:
  453.                                 break
  454.                             else:
  455.                                 latest_apt_update += line
  456.                         if f.name in latest_apt_update and "End-Date" in latest_apt_update:
  457.                             update_successful = True
  458.                             self.application.logger.write("Install finished")
  459.                         else:
  460.                             self.application.logger.write("Install failed")
  461.  
  462.                     if update_successful and self.application.settings.get_boolean("hide-window-after-update"):
  463.                         Gdk.threads_enter()
  464.                         self.application.app_hidden = True
  465.                         self.application.window.hide()
  466.                         Gdk.threads_leave()
  467.  
  468.                     if "mintupdate" in packages or "mint-upgrade-info" in packages:
  469.                         # Restart
  470.                         try:
  471.                             self.application.logger.write("Mintupdate was updated, restarting it...")
  472.                             self.application.logger.close()
  473.                         except:
  474.                             pass #cause we might have closed it already
  475.  
  476.                         command = "/usr/lib/linuxmint/mintUpdate/mintUpdate.py show &"
  477.                         os.system(command)
  478.  
  479.                     if update_successful:
  480.                         # Refresh
  481.                         Gdk.threads_enter()
  482.                         self.application.set_status(_("Checking for updates"), _("Checking for updates"), "mintupdate-checking", not self.application.settings.get_boolean("hide-systray"))
  483.                         self.application.window.get_window().set_cursor(None)
  484.                         self.application.window.set_sensitive(True)
  485.                         Gdk.threads_leave()
  486.                         refresh = RefreshThread(self.application)
  487.                         refresh.start()
  488.                     else:
  489.                         Gdk.threads_enter()
  490.                         self.application.set_status(_("Could not install the security updates"), _("Could not install the security updates"), "mintupdate-error", True)
  491.                         self.application.window.get_window().set_cursor(None)
  492.                         self.application.window.set_sensitive(True)
  493.                         Gdk.threads_leave()
  494.  
  495.                 else:
  496.                     # Stop the blinking but don't refresh
  497.                     Gdk.threads_enter()
  498.                     self.application.window.get_window().set_cursor(None)
  499.                     self.application.window.set_sensitive(True)
  500.                     Gdk.threads_leave()
  501.             else:
  502.                 # Stop the blinking but don't refresh
  503.                 Gdk.threads_enter()
  504.                 self.application.window.get_window().set_cursor(None)
  505.                 self.application.window.set_sensitive(True)
  506.                 Gdk.threads_leave()
  507.  
  508.         except Exception as e:
  509.             print (e)
  510.             self.application.logger.write_error("Exception occurred in the install thread: " + str(sys.exc_info()[0]))
  511.             Gdk.threads_enter()
  512.             self.application.set_status(_("Could not install the security updates"), _("Could not install the security updates"), "mintupdate-error", True)
  513.             self.application.logger.write_error("Could not install security updates")
  514.             self.application.window.get_window().set_cursor(None)
  515.             self.application.window.set_sensitive(True)
  516.             Gdk.threads_leave()
  517.  
  518. class RefreshThread(threading.Thread):
  519.  
  520.     def __init__(self, application, root_mode=False):
  521.         threading.Thread.__init__(self)
  522.         self.root_mode = root_mode
  523.         self.application = application
  524.  
  525.     def check_policy(self):
  526.         # Check the presence of the Mint layer
  527.         p1 = subprocess.Popen(['apt-cache', 'policy'], stdout=subprocess.PIPE)
  528.         p = p1.communicate()[0]
  529.         mint_layer_found = False
  530.         output = p.decode("utf-8").split('\n')
  531.         for line in output:
  532.             line = line.strip()
  533.             if line.startswith("700") and line.endswith("Packages") and "/upstream" in line:
  534.                 mint_layer_found = True
  535.                 break
  536.         return mint_layer_found
  537.  
  538.     def run(self):
  539.  
  540.         if self.application.updates_inhibited:
  541.             self.application.logger.write("Updates are inhibited, skipping refresh.")
  542.             return False
  543.  
  544.         Gdk.threads_enter()
  545.         vpaned_position = self.application.builder.get_object("paned1").get_position()
  546.         for child in self.application.builder.get_object("hbox_infobar").get_children():
  547.             child.destroy()
  548.  
  549.         context = self.application.builder.get_object("textview_description").get_style_context()
  550.         insensitive_color = context.get_color(Gtk.StateFlags.INSENSITIVE)
  551.         insensitive_color = "#{0:02x}{1:02x}{2:02x}".format(int(insensitive_color.red  * 255), int(insensitive_color.green * 255), int(insensitive_color.blue * 255))
  552.         Gdk.threads_leave()
  553.         try:
  554.             if (self.root_mode):
  555.                 self.application.logger.write("Starting refresh (including refreshing the APT cache)")
  556.             else:
  557.                 self.application.logger.write("Starting refresh")
  558.             Gdk.threads_enter()
  559.             self.application.set_status_message(_("Starting refresh..."))
  560.             self.application.stack.set_visible_child_name("updates_available")
  561.             if (not self.application.app_hidden):
  562.                 self.application.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH))
  563.             self.application.window.set_sensitive(False)
  564.  
  565.             # Starts the blinking
  566.             self.application.statusIcon.set_from_icon_name("mintupdate-checking")
  567.             self.application.statusIcon.set_tooltip_text(_("Checking for updates"))
  568.             self.application.statusIcon.set_visible(not self.application.settings.get_boolean("hide-systray"))
  569.             self.application.builder.get_object("paned1").set_position(vpaned_position)
  570.             Gdk.threads_leave()
  571.  
  572.             model = Gtk.TreeStore(str, str, GdkPixbuf.Pixbuf, str, str, str, str, int, str, str, str, str, str, object)
  573.             # UPDATE_CHECKED, UPDATE_DISPLAY_NAME, UPDATE_LEVEL_PIX, UPDATE_OLD_VERSION, UPDATE_NEW_VERSION, UPDATE_SOURCE, UPDATE_LEVEL_STR,
  574.             # UPDATE_SIZE, UPDATE_SIZE_STR, UPDATE_TYPE_PIX, UPDATE_TYPE, UPDATE_TOOLTIP, UPDATE_SORT_STR, UPDATE_OBJ
  575.  
  576.             model.set_sort_column_id( UPDATE_SORT_STR, Gtk.SortType.ASCENDING )
  577.  
  578.             # Check to see if no other APT process is running
  579.             if self.root_mode:
  580.                 p1 = subprocess.Popen(['ps', '-U', 'root', '-o', 'comm'], stdout=subprocess.PIPE)
  581.                 p = p1.communicate()[0]
  582.                 running = False
  583.                 pslist = p.split(b'\n')
  584.                 for process in pslist:
  585.                     if process.strip() in ["dpkg", "apt-get","synaptic","update-manager", "adept", "adept-notifier"]:
  586.                         running = True
  587.                         break
  588.                 if (running == True):
  589.                     Gdk.threads_enter()
  590.                     self.application.set_status(_("Another application is using APT"), _("Another application is using APT"), "mintupdate-checking", not self.application.settings.get_boolean("hide-systray"))
  591.                     self.application.logger.write_error("Another application is using APT")
  592.                     if (not self.application.app_hidden):
  593.                         self.application.window.get_window().set_cursor(None)
  594.                     self.application.window.set_sensitive(True)
  595.                     Gdk.threads_leave()
  596.                     return False
  597.  
  598.             Gdk.threads_enter()
  599.             self.application.set_status_message(_("Finding the list of updates..."))
  600.             self.application.builder.get_object("paned1").set_position(vpaned_position)
  601.             Gdk.threads_leave()
  602.             if self.application.app_hidden:
  603.                 refresh_command = "/usr/lib/linuxmint/mintUpdate/checkAPT.py 2>/dev/null"
  604.             else:
  605.                 refresh_command = "/usr/lib/linuxmint/mintUpdate/checkAPT.py --use-synaptic %s 2>/dev/null" % self.application.window.get_window().get_xid()
  606.             if self.root_mode:
  607.                 refresh_command = "sudo %s" % refresh_command
  608.             output =  subprocess.check_output(refresh_command, shell = True).decode("utf-8")
  609.  
  610.             if len(output) > 0 and not "CHECK_APT_ERROR" in output:
  611.                 if not self.check_policy():
  612.                     Gdk.threads_enter()
  613.                     label1 = _("Your APT cache is corrupted.")
  614.                     label2 = _("Do not install or update anything, it could break your operating system!")
  615.                     label3 = _("Switch to a different Linux Mint mirror to solve this situation.")
  616.                     infobar = Gtk.InfoBar()
  617.                     infobar.set_message_type(Gtk.MessageType.ERROR)
  618.                     info_label = Gtk.Label()
  619.                     infobar_message = "%s\n<small>%s</small>" % (_("Please switch to another Linux Mint mirror"), _("Your APT cache is corrupted."))
  620.                     info_label.set_markup(infobar_message)
  621.                     infobar.get_content_area().pack_start(info_label,False, False,0)
  622.                     infobar.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
  623.                     infobar.connect("response", self._on_infobar_response)
  624.                     self.application.builder.get_object("hbox_infobar").pack_start(infobar, True, True,0)
  625.                     infobar.show_all()
  626.                     self.application.set_status(_("Could not refresh the list of updates"), "%s\n%s\n%s" % (label1, label2, label3), "mintupdate-error", True)
  627.                     self.application.logger.write("Error: The APT policy is incorrect!")
  628.                     self.application.stack.set_visible_child_name("status_error")
  629.                     self.application.builder.get_object("label_error_details").set_markup("<b>%s\n%s\n%s</b>" % (label1, label2, label3))
  630.                     self.application.builder.get_object("label_error_details").show()
  631.                     if (not self.application.app_hidden):
  632.                             self.application.window.get_window().set_cursor(None)
  633.                     self.application.window.set_sensitive(True)
  634.                     Gdk.threads_leave()
  635.                     return False
  636.  
  637.             lines = output.split("---EOL---")
  638.  
  639.             # Look at the updates one by one
  640.             num_visible = 0
  641.             num_safe = 0
  642.             download_size = 0
  643.  
  644.             if (len(lines) == None):
  645.                 Gdk.threads_enter()
  646.                 self.application.stack.set_visible_child_name("status_updated")
  647.                 self.application.set_status(_("Your system is up to date"), _("Your system is up to date"), "mintupdate-up-to-date", not self.application.settings.get_boolean("hide-systray"))
  648.                 self.application.logger.write("System is up to date")
  649.                 Gdk.threads_leave()
  650.             else:
  651.                 for line in lines:
  652.                     if line.startswith("CHECK_APT_ERROR"):
  653.                         try:
  654.                             error_msg = lines[1].replace("E:", "\n")
  655.                         except:
  656.                             error_msg = ""
  657.                         Gdk.threads_enter()
  658.                         self.application.set_status(_("Could not refresh the list of updates"), "%s\n\n%s" % (_("Could not refresh the list of updates"), error_msg), "mintupdate-error", True)
  659.                         self.application.logger.write("Error in checkAPT.py, could not refresh the list of updates")
  660.                         self.application.stack.set_visible_child_name("status_error")
  661.                         self.application.builder.get_object("label_error_details").set_markup("<b>%s</b>" % error_msg)
  662.                         self.application.builder.get_object("label_error_details").show()
  663.                         if (not self.application.app_hidden):
  664.                             self.application.window.get_window().set_cursor(None)
  665.                         self.application.window.set_sensitive(True)
  666.                         Gdk.threads_leave()
  667.                         return False
  668.  
  669.                     if "###" in line:
  670.                         update = Update(package=None, input_string=line, source_name=None)
  671.  
  672.                         level_is_visible = self.application.settings.get_boolean('level%s-is-visible' % str(update.level))
  673.                         level_is_safe = self.application.settings.get_boolean('level%s-is-safe' % str(update.level))
  674.  
  675.                         if update.type == "kernel":
  676.                             visible = (level_is_visible or self.application.settings.get_boolean('kernel-updates-are-visible'))
  677.                             safe = (level_is_safe or self.application.settings.get_boolean('kernel-updates-are-safe'))
  678.                         elif update.type == "security":
  679.                             visible = (level_is_visible or self.application.settings.get_boolean('security-updates-are-visible'))
  680.                             safe = (level_is_safe or self.application.settings.get_boolean('security-updates-are-safe'))
  681.                         else:
  682.                             visible = level_is_visible
  683.                             safe = level_is_safe
  684.  
  685.                         if visible:
  686.                             iter = model.insert_before(None, None)
  687.                             if safe:
  688.                                 model.set_value(iter, UPDATE_CHECKED, "true")
  689.                                 num_safe = num_safe + 1
  690.                                 download_size = download_size + update.size
  691.                             else:
  692.                                 model.set_value(iter, UPDATE_CHECKED, "false")
  693.  
  694.                             model.row_changed(model.get_path(iter), iter)
  695.  
  696.                             shortdesc = update.short_description
  697.                             if len(shortdesc) > 100:
  698.                                 try:
  699.                                     shortdesc = shortdesc[:100]
  700.                                     # Remove the last word.. in case we chomped
  701.                                     # a word containing an &#234; character..
  702.                                     # if we ended up with &.. without the code and ; sign
  703.                                     # pango would fail to set the markup
  704.                                     words = shortdesc.split()
  705.                                     shortdesc = " ".join(words[:-1]) + "..."
  706.                                 except:
  707.                                     pass
  708.  
  709.                             if (self.application.settings.get_boolean("show-descriptions")):
  710.                                 model.set_value(iter, UPDATE_DISPLAY_NAME, update.display_name + "\n<i><small><span foreground='%s'>%s</span></small></i>" % (insensitive_color, shortdesc))
  711.                             else:
  712.                                 model.set_value(iter, UPDATE_DISPLAY_NAME, update.display_name)
  713.  
  714.                             theme = Gtk.IconTheme.get_default()
  715.                             pixbuf = theme.load_icon("mintupdate-level" + str(update.level), 22, 0)
  716.  
  717.                             origin = update.origin
  718.                             origin = origin.replace("linuxmint", "Linux Mint").replace("ubuntu", "Ubuntu").replace("LP-PPA-", "PPA ")
  719.  
  720.                             if update.type == "kernel":
  721.                                 tooltip = _("Kernel update")
  722.                             elif update.type == "security":
  723.                                 tooltip = _("Security update")
  724.                             elif update.type == "backport":
  725.                                 tooltip = _("Software backport. Be careful when upgrading. New versions of software can introduce regressions.")
  726.                             elif update.type == "unstable":
  727.                                 tooltip = _("Unstable software. Only apply this update to help developers beta-test new software.")
  728.                             else:
  729.                                 tooltip = _("Software update")
  730.  
  731.                             model.set_value(iter, UPDATE_LEVEL_PIX, pixbuf)
  732.                             model.set_value(iter, UPDATE_OLD_VERSION, update.old_version)
  733.                             model.set_value(iter, UPDATE_NEW_VERSION, update.new_version)
  734.                             model.set_value(iter, UPDATE_SOURCE, "%s (%s)" % (origin, update.site))
  735.                             model.set_value(iter, UPDATE_LEVEL_STR, str(update.level))
  736.                             model.set_value(iter, UPDATE_SIZE, update.size)
  737.                             model.set_value(iter, UPDATE_SIZE_STR, size_to_string(update.size))
  738.                             model.set_value(iter, UPDATE_TYPE_PIX, "mintupdate-type-%s" % update.type)
  739.                             model.set_value(iter, UPDATE_TYPE, update.type)
  740.                             model.set_value(iter, UPDATE_TOOLTIP, tooltip)
  741.                             model.set_value(iter, UPDATE_SORT_STR, "%s%s" % (str(update.level), update.display_name))
  742.                             model.set_value(iter, UPDATE_OBJ, update)
  743.                             num_visible = num_visible + 1
  744.  
  745.                 Gdk.threads_enter()
  746.                 if (num_safe > 0):
  747.                     if (num_safe == 1):
  748.                         self.statusString = _("1 recommended update available (%(size)s)") % {'size':size_to_string(download_size)}
  749.                     else:
  750.                         self.statusString = _("%(recommended)d recommended updates available (%(size)s)") % {'recommended':num_safe, 'size':size_to_string(download_size)}
  751.                     self.application.set_status(self.statusString, self.statusString, "mintupdate-updates-available", True)
  752.                     self.application.logger.write("Found " + str(num_safe) + " recommended software updates")
  753.                 else:
  754.                     if num_visible == 0:
  755.                         self.application.stack.set_visible_child_name("status_updated")
  756.                     self.application.set_status(_("Your system is up to date"), _("Your system is up to date"), "mintupdate-up-to-date", not self.application.settings.get_boolean("hide-systray"))
  757.                     self.application.logger.write("System is up to date")
  758.  
  759.                 Gdk.threads_leave()
  760.  
  761.             Gdk.threads_enter()
  762.             self.application.logger.write("Refresh finished")
  763.  
  764.             # Stop the blinking
  765.             self.application.builder.get_object("notebook_details").set_current_page(0)
  766.             if (not self.application.app_hidden):
  767.                 self.application.window.get_window().set_cursor(None)
  768.             self.application.treeview.set_model(model)
  769.             del model
  770.             self.application.window.set_sensitive(True)
  771.             self.application.builder.get_object("paned1").set_position(vpaned_position)
  772.  
  773.             try:
  774.                 sources_path = "/etc/apt/sources.list.d/official-package-repositories.list"
  775.                 if os.path.exists("/usr/bin/mintsources") and os.path.exists(sources_path):
  776.                     mirror_url = None
  777.                     infobar_message = None
  778.                     infobar_message_type = Gtk.MessageType.QUESTION
  779.                     codename = subprocess.check_output("lsb_release -cs", shell = True).strip().decode("UTF-8")
  780.                     with open("/etc/apt/sources.list.d/official-package-repositories.list", 'r') as sources_file:
  781.                         for line in sources_file:
  782.                             line = line.strip()
  783.                             if line.startswith("deb ") and "%s main upstream import" % codename in line:
  784.                                 mirror_url = line.split()[1]
  785.                                 if mirror_url.endswith("/"):
  786.                                     mirror_url = mirror_url[:-1]
  787.                                 break
  788.                     if mirror_url is None:
  789.                         # Unable to find the Mint mirror being used..
  790.                         pass
  791.                     elif mirror_url == "http://packages.linuxmint.com":
  792.                         if not self.application.settings.get_boolean("default-repo-is-ok"):
  793.                             infobar_message = "%s\n<small>%s</small>" % (_("Do you want to switch to a local mirror?"), _("Local mirrors are usually faster than packages.linuxmint.com"))
  794.                     elif not self.application.app_hidden:
  795.                         # Only perform up-to-date checks when refreshing from the UI (keep the load lower on servers)
  796.                         mint_timestamp = self.get_url_last_modified("http://packages.linuxmint.com/db/version")
  797.                         mirror_timestamp = self.get_url_last_modified("%s/db/version" % mirror_url)
  798.                         if mirror_timestamp is None:
  799.                             if mint_timestamp is None:
  800.                                 # Both default repo and mirror are unreachable, assume there's no Internet connection
  801.                                 pass
  802.                             else:
  803.                                 infobar_message = "%s\n<small>%s</small>" % (_("Please switch to another mirror"), _("%s is unreachable") % mirror_url)
  804.                                 infobar_message_type = Gtk.MessageType.WARNING
  805.                         elif mint_timestamp is not None:
  806.                             mint_date = datetime.datetime.fromtimestamp(mint_timestamp)
  807.                             now = datetime.datetime.now()
  808.                             mint_age = (now - mint_date).days
  809.                             if (mint_age > 2):
  810.                                 mirror_date = datetime.datetime.fromtimestamp(mirror_timestamp)
  811.                                 mirror_age = (mint_date - mirror_date).days
  812.                                 if (mirror_age > 2):
  813.                                     infobar_message = "%s\n<small>%s</small>" % (_("Please switch to another mirror"), _("The last update on %(mirror)s was %(days)d days ago") % {'mirror': mirror_url, 'days':(now - mirror_date).days})
  814.                                     infobar_message_type = Gtk.MessageType.WARNING
  815.                     if infobar_message is not None:
  816.                         infobar = Gtk.InfoBar()
  817.                         infobar.set_message_type(infobar_message_type)
  818.                         info_label = Gtk.Label()
  819.                         info_label.set_markup(infobar_message)
  820.                         infobar.get_content_area().pack_start(info_label,False, False,0)
  821.                         infobar.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
  822.                         infobar.connect("response", self._on_infobar_response)
  823.                         self.application.builder.get_object("hbox_infobar").pack_start(infobar, True, True,0)
  824.                         infobar.show_all()
  825.             except Exception as e:
  826.                 print(sys.exc_info()[0])
  827.                 # best effort, just print out the error
  828.                 print("An exception occurred while checking if the repositories were up to date: %s" % sys.exc_info()[0])
  829.  
  830.             Gdk.threads_leave()
  831.  
  832.         except Exception as e:
  833.             traceback.print_exc()
  834.             print("-- Exception occurred in the refresh thread: " + str(sys.exc_info()[0]))
  835.             self.application.logger.write_error("Exception occurred in the refresh thread: " + str(sys.exc_info()[0]))
  836.             Gdk.threads_enter()
  837.             self.application.set_status(_("Could not refresh the list of updates"), _("Could not refresh the list of updates"), "mintupdate-error", True)
  838.             if (not self.application.app_hidden):
  839.                 self.application.window.get_window().set_cursor(None)
  840.             self.application.window.set_sensitive(True)
  841.             self.application.builder.get_object("paned1").set_position(vpaned_position)
  842.             Gdk.threads_leave()
  843.  
  844.     def _on_infobar_response(self, infobar, response_id):
  845.         infobar.destroy()
  846.         subprocess.Popen(["mintsources"])
  847.  
  848.     def get_url_last_modified(self, url):
  849.         try:
  850.             c = pycurl.Curl()
  851.             c.setopt(pycurl.URL, url)
  852.             c.setopt(pycurl.CONNECTTIMEOUT, 5)
  853.             c.setopt(pycurl.TIMEOUT, 30)
  854.             c.setopt(pycurl.FOLLOWLOCATION, 1)
  855.             c.setopt(pycurl.NOBODY, 1)
  856.             c.setopt(pycurl.OPT_FILETIME, 1)
  857.             c.perform()
  858.             filetime = c.getinfo(pycurl.INFO_FILETIME)
  859.             if filetime < 0:
  860.                 return None
  861.             else:
  862.                 return filetime
  863.         except Exception as e:
  864.             print (e)
  865.             return None
  866.  
  867.     def checkDependencies(self, changes, cache):
  868.         foundSomething = False
  869.         for pkg in changes:
  870.             for dep in pkg.candidateDependencies:
  871.                 for o in dep.or_dependencies:
  872.                     try:
  873.                         if cache[o.name].isUpgradable:
  874.                             pkgFound = False
  875.                             for pkg2 in changes:
  876.                                 if o.name == pkg2.name:
  877.                                     pkgFound = True
  878.                             if pkgFound == False:
  879.                                 newPkg = cache[o.name]
  880.                                 changes.append(newPkg)
  881.                                 foundSomething = True
  882.                     except Exception as e:
  883.                         print (e)
  884.                         pass # don't know why we get these..
  885.         if (foundSomething):
  886.             changes = self.checkDependencies(changes, cache)
  887.         return changes
  888.  
  889. class Logger():
  890.  
  891.     def __init__(self):
  892.         logdir = "/tmp/mintUpdate/"
  893.         if not os.path.exists(logdir):
  894.             os.system("mkdir -p " + logdir)
  895.             os.system("chmod a+rwx " + logdir)
  896.         self.log = tempfile.NamedTemporaryFile(mode = 'w', prefix = logdir, delete=False)
  897.         try:
  898.             os.system("chmod a+rw %s" % self.log.name)
  899.         except Exception as e:
  900.             print (e)
  901.             print(sys.exc_info()[0])
  902.  
  903.     def write(self, line):
  904.         try:
  905.             self.log.writelines("%s ++ %s \n" % (datetime.datetime.now().strftime('%m.%d@%H:%M'), line))
  906.             self.log.flush()
  907.         except:
  908.             pass # cause it might be closed already
  909.  
  910.     def write_error(self, line):
  911.         try:
  912.             self.log.writelines("%s -- %s \n" % (datetime.datetime.now().strftime('%m.%d@%H:%M'), line))
  913.             self.log.flush()
  914.         except:
  915.             pass # cause it might be closed already
  916.  
  917.     def close(self):
  918.         try:
  919.             self.log.close()
  920.         except:
  921.             pass # cause it might be closed already
  922.  
  923.  
  924. class StatusIcon():
  925.     def __init__(self, app):
  926.         self.app = app
  927.         self.icon = AppIndicator.Indicator.new("mintUpdate", "mintupdate", AppIndicator.IndicatorCategory.APPLICATION_STATUS)
  928.         self.icon.set_status(AppIndicator.IndicatorStatus.ACTIVE)
  929.         self.icon.set_title(_("Update Manager"))
  930.  
  931.         self.menu = Gtk.Menu()
  932.         item = Gtk.MenuItem()
  933.         item.set_label(_("Update Manager"))
  934.         item.connect("activate", self.app.on_statusicon_clicked)
  935.         self.menu.append(item)
  936.  
  937.         item = Gtk.MenuItem()
  938.         item.set_label(_("Exit"))
  939.         item.connect("activate", self.cb_exit, '')
  940.         self.menu.append(item)
  941.  
  942.         self.menu.show_all()
  943.         self.icon.set_menu(self.menu)
  944.  
  945.     def cb_exit(self, w, data):
  946.         self.app.quit_from_systray(None, None)
  947.  
  948.     def set_from_icon_name(self, name):
  949.         self.icon.set_icon(name)
  950.  
  951.     def set_tooltip_text(self, text):
  952.         pass # appindicator doesn't support that
  953.  
  954.     def set_visible(self, visible):
  955.         if visible:
  956.             self.icon.set_status(AppIndicator.IndicatorStatus.ACTIVE)
  957.         else:
  958.             self.icon.set_status(AppIndicator.IndicatorStatus.PASSIVE)
  959.  
  960. class MintUpdate():
  961.  
  962.     def __init__(self):
  963.         Gdk.threads_init()
  964.         self.app_hidden = True
  965.         self.updates_inhibited = False
  966.         self.logger = Logger()
  967.         self.logger.write("Launching mintUpdate")
  968.         self.settings = Gio.Settings("com.linuxmint.updates")
  969.         if os.getenv("XDG_CURRENT_DESKTOP") == "KDE":
  970.             self.statusIcon = StatusIcon(self)
  971.         else:
  972.             self.statusIcon = Gtk.StatusIcon()
  973.         self.statusIcon.set_from_icon_name("mintupdate-checking")
  974.         self.statusIcon.set_tooltip_text (_("Checking for updates"))
  975.         self.statusIcon.set_visible(not self.settings.get_boolean("hide-systray"))
  976.  
  977.         #Set the Glade file
  978.         gladefile = "/usr/share/linuxmint/mintupdate/main.ui"
  979.         self.builder = Gtk.Builder()
  980.         self.builder.add_from_file(gladefile)
  981.         self.statusbar = self.builder.get_object("statusbar")
  982.         self.context_id = self.statusbar.get_context_id("mintUpdate")
  983.         self.window = self.builder.get_object("main_window")
  984.         self.treeview = self.builder.get_object("treeview_update")
  985.         self.stack = Gtk.Stack()
  986.         self.builder.get_object("stack_container").pack_start(self.stack, True, True, 0)
  987.         self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
  988.         self.stack.set_transition_duration(175)
  989.  
  990.         try:
  991.             self.window.set_title(_("Update Manager"))
  992.  
  993.             vbox = self.builder.get_object("vbox_main")
  994.             self.window.set_icon_name("mintupdate")
  995.  
  996.             accel_group = Gtk.AccelGroup()
  997.             self.window.add_accel_group(accel_group)
  998.  
  999.             self.buffer = self.builder.get_object("textview_description").get_buffer()
  1000.             context = self.builder.get_object("textview_description").get_style_context()
  1001.             insensitive_color = context.get_color(Gtk.StateFlags.INSENSITIVE)
  1002.             insensitive_color = "#{0:02x}{1:02x}{2:02x}".format(int(insensitive_color.red  * 255), int(insensitive_color.green * 255), int(insensitive_color.blue * 255))
  1003.             self.buffer.create_tag("dimmed", scale=0.9, foreground="%s" % insensitive_color, style=Pango.Style.ITALIC)
  1004.  
  1005.             # Configure page
  1006.             configure_page = self.builder.get_object("configure_page")
  1007.             self.stack.add_named(configure_page, "configure")
  1008.             self.builder.get_object("button_configure_finish").connect("clicked", self.on_configure_finished)
  1009.             self.builder.get_object("button_configure_finish").set_label(_("OK"))
  1010.             self.builder.get_object("button_configure_help").connect("clicked", self.on_configure_help)
  1011.             self.builder.get_object("button_configure_help").set_label(_("Help"))
  1012.  
  1013.             # Updates page
  1014.             updates_page = self.builder.get_object("updates_page")
  1015.             self.stack.add_named(updates_page, "updates_available")
  1016.  
  1017.             # the treeview
  1018.             cr = Gtk.CellRendererToggle()
  1019.             cr.connect("toggled", self.toggled)
  1020.             column1 = Gtk.TreeViewColumn(_("Upgrade"), cr)
  1021.             column1.set_cell_data_func(cr, self.celldatafunction_checkbox)
  1022.             column1.set_sort_column_id(UPDATE_CHECKED)
  1023.             column1.set_resizable(True)
  1024.  
  1025.             column2 = Gtk.TreeViewColumn(_("Name"), Gtk.CellRendererText(), markup=UPDATE_DISPLAY_NAME)
  1026.             column2.set_sort_column_id(UPDATE_DISPLAY_NAME)
  1027.             column2.set_resizable(True)
  1028.  
  1029.             column3 = Gtk.TreeViewColumn(_("Level"), Gtk.CellRendererPixbuf(), pixbuf=UPDATE_LEVEL_PIX)
  1030.             column3.set_sort_column_id(UPDATE_LEVEL_STR)
  1031.             column3.set_resizable(True)
  1032.  
  1033.             column4 = Gtk.TreeViewColumn(_("Old version"), Gtk.CellRendererText(), text=UPDATE_OLD_VERSION)
  1034.             column4.set_sort_column_id(UPDATE_OLD_VERSION)
  1035.             column4.set_resizable(True)
  1036.  
  1037.             column5 = Gtk.TreeViewColumn(_("New version"), Gtk.CellRendererText(), text=UPDATE_NEW_VERSION)
  1038.             column5.set_sort_column_id(UPDATE_NEW_VERSION)
  1039.             column5.set_resizable(True)
  1040.  
  1041.             column6 = Gtk.TreeViewColumn(_("Size"), Gtk.CellRendererText(), text=UPDATE_SIZE_STR)
  1042.             column6.set_sort_column_id(UPDATE_SIZE)
  1043.             column6.set_resizable(True)
  1044.  
  1045.             column7 = Gtk.TreeViewColumn(_("Type"), Gtk.CellRendererPixbuf(), icon_name=UPDATE_TYPE_PIX)
  1046.             column7.set_sort_column_id(UPDATE_TYPE)
  1047.             column7.set_resizable(True)
  1048.  
  1049.             column8 = Gtk.TreeViewColumn(_("Origin"), Gtk.CellRendererText(), text=UPDATE_SOURCE)
  1050.             column8.set_sort_column_id(UPDATE_SOURCE)
  1051.             column8.set_resizable(True)
  1052.  
  1053.             self.treeview.set_tooltip_column(UPDATE_TOOLTIP)
  1054.  
  1055.             self.treeview.append_column(column7)
  1056.             self.treeview.append_column(column3)
  1057.             self.treeview.append_column(column1)
  1058.             self.treeview.append_column(column2)
  1059.             self.treeview.append_column(column4)
  1060.             self.treeview.append_column(column5)
  1061.             self.treeview.append_column(column8)
  1062.             self.treeview.append_column(column6)
  1063.  
  1064.             self.treeview.set_headers_clickable(True)
  1065.             self.treeview.set_reorderable(False)
  1066.             self.treeview.show()
  1067.  
  1068.             self.treeview.connect("button-release-event", self.treeview_right_clicked)
  1069.             self.treeview.connect("row-activated", self.treeview_row_activated)
  1070.  
  1071.             selection = self.treeview.get_selection()
  1072.             selection.connect("changed", self.display_selected_package)
  1073.             self.builder.get_object("notebook_details").connect("switch-page", self.switch_page)
  1074.             self.window.connect("delete_event", self.close_window)
  1075.             self.builder.get_object("tool_apply").connect("clicked", self.install)
  1076.             self.builder.get_object("tool_clear").connect("clicked", self.clear)
  1077.             self.builder.get_object("tool_select_all").connect("clicked", self.select_all)
  1078.             self.builder.get_object("tool_refresh").connect("clicked", self.force_refresh)
  1079.  
  1080.             menu = Gtk.Menu()
  1081.             menuItem3 = Gtk.ImageMenuItem(Gtk.STOCK_REFRESH)
  1082.             menuItem3.set_use_stock(True)
  1083.             menuItem3.connect('activate', self.force_refresh)
  1084.             menu.append(menuItem3)
  1085.             menuItem2 = Gtk.ImageMenuItem(Gtk.STOCK_DIALOG_INFO)
  1086.             menuItem2.set_use_stock(True)
  1087.             menuItem2.connect('activate', self.open_information)
  1088.             menu.append(menuItem2)
  1089.             menuItem4 = Gtk.ImageMenuItem(Gtk.STOCK_PREFERENCES)
  1090.             menuItem4.set_use_stock(True)
  1091.             menuItem4.connect('activate', self.open_preferences)
  1092.             menu.append(menuItem4)
  1093.             menuItem = Gtk.ImageMenuItem(Gtk.STOCK_QUIT)
  1094.             menuItem.set_use_stock(True)
  1095.             menuItem.connect('activate', self.quit_from_systray)
  1096.             menu.append(menuItem)
  1097.  
  1098.             if os.getenv("XDG_CURRENT_DESKTOP") != "KDE":
  1099.                 self.statusIcon.connect('activate', self.on_statusicon_clicked)
  1100.                 self.statusIcon.connect('popup-menu', self.show_statusicon_menu, menu)
  1101.  
  1102.             # Set text for all visible widgets (because of i18n)
  1103.             self.builder.get_object("tool_apply").set_label(_("Install Updates"))
  1104.             self.builder.get_object("tool_refresh").set_label(_("Refresh"))
  1105.             self.builder.get_object("tool_select_all").set_label(_("Select All"))
  1106.             self.builder.get_object("tool_clear").set_label(_("Clear"))
  1107.             self.builder.get_object("label9").set_text(_("Description"))
  1108.             self.builder.get_object("label8").set_text(_("Changelog"))
  1109.  
  1110.             self.builder.get_object("label_success").set_markup("<b>" + _("Your system is up to date") + "</b>")
  1111.             self.builder.get_object("label_error").set_markup("<b>" + _("Could not refresh the list of updates") + "</b>")
  1112.             self.builder.get_object("image_success_status").set_pixel_size(96)
  1113.             self.builder.get_object("image_error_status").set_pixel_size(96)
  1114.  
  1115.             #l10n for update policy page
  1116.             self.builder.get_object("label_welcome1").set_markup("<span size='large'><b>%s</b></span>" % _("Welcome to the Update Manager"))
  1117.             self.builder.get_object("label_welcome2").set_markup("%s" % _("This tool provides your operating system with software and security updates."))
  1118.             self.builder.get_object("label_welcome3").set_markup("%s" % _("Please choose an update policy."))
  1119.  
  1120.             self.builder.get_object("label_policy1_1").set_markup("<b>%s</b>" % _("Just keep my computer safe"))
  1121.             self.builder.get_object("label_policy1_2").set_markup("<i>%s</i>" % _("Recommended for novice users."))
  1122.             self.builder.get_object("label_policy1_3").set_markup("%s\n%s" % (_("Select updates which do not impact important parts of the operating systems."), _("Show security and kernel updates so I can review them and apply them with caution.")))
  1123.  
  1124.             self.builder.get_object("label_policy2_1").set_markup("<b>%s</b>" % _("Let me review sensitive updates"))
  1125.             self.builder.get_object("label_policy2_2").set_markup("<i>%s</i>" % _("Recommended for most users."))
  1126.             self.builder.get_object("label_policy2_3").set_markup("%s\n%s" % (_("Select security updates and updates which do not impact important parts of the operating systems."), _("Show kernel updates and sensitive updates so I can review them and apply them with caution.")))
  1127.  
  1128.             self.builder.get_object("label_policy3_1").set_markup("<b>%s</b>" % _("Always update everything"))
  1129.             self.builder.get_object("label_policy3_2").set_markup("<i>%s</i>" % _("Recommended for experienced users."))
  1130.             self.builder.get_object("label_policy3_3").set_markup("%s\n%s" % (_("Always select all updates."), _("If a regression breaks something, I'll fix it.")))
  1131.  
  1132.             self.builder.get_object("label_policy_hint").set_markup(_("Security and kernel updates are always visible and updates with known issues (very rare) are always hidden. You can change this and fine-tune your policy in the preferences."))
  1133.  
  1134.             fileMenu = Gtk.MenuItem.new_with_mnemonic(_("_File"))
  1135.             fileSubmenu = Gtk.Menu()
  1136.             fileMenu.set_submenu(fileSubmenu)
  1137.             closeMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_CLOSE)
  1138.             closeMenuItem.set_use_stock(True)
  1139.             closeMenuItem.set_image(Gtk.Image.new_from_icon_name("window-close-symbolic", Gtk.IconSize.MENU))
  1140.             closeMenuItem.set_label(_("Close"))
  1141.             closeMenuItem.connect("activate", self.hide_main_window)
  1142.             fileSubmenu.append(closeMenuItem)
  1143.  
  1144.             editMenu = Gtk.MenuItem.new_with_mnemonic(_("_Edit"))
  1145.             editSubmenu = Gtk.Menu()
  1146.             editMenu.set_submenu(editSubmenu)
  1147.             prefsMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_PREFERENCES)
  1148.             prefsMenuItem.set_use_stock(True)
  1149.             prefsMenuItem.set_label(_("Preferences"))
  1150.             prefsMenuItem.connect("activate", self.open_preferences)
  1151.             editSubmenu.append(prefsMenuItem)
  1152.             if os.path.exists("/usr/bin/software-sources") or os.path.exists("/usr/bin/software-properties-gtk") or os.path.exists("/usr/bin/software-properties-kde"):
  1153.                 sourcesMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_PREFERENCES)
  1154.                 sourcesMenuItem.set_use_stock(True)
  1155.                 sourcesMenuItem.set_image(Gtk.Image.new_from_icon_name("software-properties", Gtk.IconSize.MENU))
  1156.                 sourcesMenuItem.set_label(_("Software sources"))
  1157.                 sourcesMenuItem.connect("activate", self.open_repositories)
  1158.                 editSubmenu.append(sourcesMenuItem)
  1159.             configMenuItem = Gtk.ImageMenuItem()
  1160.             configMenuItem.set_image(Gtk.Image.new_from_icon_name("security-medium", Gtk.IconSize.MENU))
  1161.             configMenuItem.set_label(_("Update policy"))
  1162.             configMenuItem.connect("activate", self.show_configuration)
  1163.             editSubmenu.append(configMenuItem)
  1164.  
  1165.             editSubmenu.append(Gtk.SeparatorMenuItem())
  1166.  
  1167.             item = Gtk.ImageMenuItem(Gtk.STOCK_CLEAR)
  1168.             item.set_use_stock(True)
  1169.             item.set_label(_("Clear"))
  1170.             item.connect("activate", self.clear)
  1171.             key, mod = Gtk.accelerator_parse("<Control><Shift>A")
  1172.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1173.             editSubmenu.append(item)
  1174.  
  1175.             item = Gtk.ImageMenuItem(Gtk.STOCK_SELECT_ALL)
  1176.             item.set_use_stock(True)
  1177.             item.set_label(_("Select All"))
  1178.             item.connect("activate", self.select_all)
  1179.             key, mod = Gtk.accelerator_parse("<Control>A")
  1180.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1181.             editSubmenu.append(item)
  1182.  
  1183.             item = Gtk.ImageMenuItem(Gtk.STOCK_REFRESH)
  1184.             item.set_use_stock(True)
  1185.             item.set_label(_("Refresh"))
  1186.             item.connect("activate", self.force_refresh)
  1187.             key, mod = Gtk.accelerator_parse("<Control>R")
  1188.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1189.             editSubmenu.append(item)
  1190.  
  1191.             item = Gtk.ImageMenuItem(Gtk.STOCK_APPLY)
  1192.             item.set_use_stock(True)
  1193.             item.set_label(_("Install"))
  1194.             item.connect("activate", self.install)
  1195.             key, mod = Gtk.accelerator_parse("<Control>I")
  1196.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1197.             editSubmenu.append(item)
  1198.  
  1199.             editSubmenu.append(Gtk.SeparatorMenuItem())
  1200.  
  1201.             item = Gtk.MenuItem(_("Select level 1 updates"))
  1202.             item.connect("activate", self.select_level1)
  1203.             key, mod = Gtk.accelerator_parse("<Control>1")
  1204.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1205.             editSubmenu.append(item)
  1206.  
  1207.             item = Gtk.MenuItem(_("Select level 2 updates"))
  1208.             item.connect("activate", self.select_level2)
  1209.             key, mod = Gtk.accelerator_parse("<Control>2")
  1210.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1211.             editSubmenu.append(item)
  1212.  
  1213.             item = Gtk.MenuItem(_("Select level 3 updates"))
  1214.             item.connect("activate", self.select_level3)
  1215.             key, mod = Gtk.accelerator_parse("<Control>3")
  1216.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1217.             editSubmenu.append(item)
  1218.  
  1219.             item = Gtk.MenuItem(_("Select level 4 updates"))
  1220.             item.connect("activate", self.select_level4)
  1221.             key, mod = Gtk.accelerator_parse("<Control>4")
  1222.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1223.             editSubmenu.append(item)
  1224.  
  1225.             item = Gtk.MenuItem(_("Select security updates"))
  1226.             item.connect("activate", self.select_security_updates)
  1227.             key, mod = Gtk.accelerator_parse("<Control>S")
  1228.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1229.             editSubmenu.append(item)
  1230.  
  1231.             item = Gtk.MenuItem(_("Select kernel updates"))
  1232.             item.connect("activate", self.select_kernel_updates)
  1233.             key, mod = Gtk.accelerator_parse("<Control>K")
  1234.             item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1235.             editSubmenu.append(item)
  1236.  
  1237.             rel_edition = 'unknown'
  1238.             rel_codename = 'unknown'
  1239.             if os.path.exists("/etc/linuxmint/info"):
  1240.                 with open("/etc/linuxmint/info", "r") as info:
  1241.                     for line in info:
  1242.                         line = line.strip()
  1243.                         if "EDITION=" in line:
  1244.                             rel_edition = line.split('=')[1].replace('"', '').split()[0]
  1245.                         if "CODENAME=" in line:
  1246.                             rel_codename = line.split('=')[1].replace('"', '').split()[0]
  1247.  
  1248.             rel_path = "/usr/share/mint-upgrade-info/%s/info" % rel_codename
  1249.             if os.path.exists(rel_path):
  1250.                 config = configparser.ConfigParser()
  1251.                 config.read(rel_path)
  1252.                 if rel_edition.lower() in config['general']['editions']:
  1253.                     rel_target = config['general']['target_name']
  1254.                     relUpgradeMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_PREFERENCES)
  1255.                     relUpgradeMenuItem.set_use_stock(True)
  1256.                     relUpgradeMenuItem.set_image(Gtk.Image.new_from_icon_name("mintupdate-release-upgrade", Gtk.IconSize.MENU))
  1257.                     relUpgradeMenuItem.set_label(_("Upgrade to %s") % rel_target)
  1258.                     relUpgradeMenuItem.connect("activate", self.open_rel_upgrade)
  1259.                     editSubmenu.append(relUpgradeMenuItem)
  1260.  
  1261.             viewMenu = Gtk.MenuItem.new_with_mnemonic(_("_View"))
  1262.             viewSubmenu = Gtk.Menu()
  1263.             viewMenu.set_submenu(viewSubmenu)
  1264.             historyMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_INDEX)
  1265.             historyMenuItem.set_use_stock(True)
  1266.             historyMenuItem.set_label(_("History of updates"))
  1267.             historyMenuItem.connect("activate", self.open_history)
  1268.             kernelMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_EXECUTE)
  1269.             kernelMenuItem.set_use_stock(True)
  1270.             kernelMenuItem.set_label(_("Linux kernels"))
  1271.             kernelMenuItem.connect("activate", self.open_kernels)
  1272.             infoMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_DIALOG_INFO)
  1273.             infoMenuItem.set_use_stock(True)
  1274.             infoMenuItem.set_label(_("Information"))
  1275.             infoMenuItem.connect("activate", self.open_information)
  1276.             visibleColumnsMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_DIALOG_INFO)
  1277.             visibleColumnsMenuItem.set_use_stock(True)
  1278.             visibleColumnsMenuItem.set_label(_("Visible columns"))
  1279.             visibleColumnsMenu = Gtk.Menu()
  1280.             visibleColumnsMenuItem.set_submenu(visibleColumnsMenu)
  1281.  
  1282.             typeColumnMenuItem = Gtk.CheckMenuItem(_("Type"))
  1283.             typeColumnMenuItem.set_active(self.settings.get_boolean("show-type-column"))
  1284.             column7.set_visible(self.settings.get_boolean("show-type-column"))
  1285.             typeColumnMenuItem.connect("toggled", self.setVisibleColumn, column7, "show-type-column")
  1286.             visibleColumnsMenu.append(typeColumnMenuItem)
  1287.  
  1288.             levelColumnMenuItem = Gtk.CheckMenuItem(_("Level"))
  1289.             levelColumnMenuItem.set_active(self.settings.get_boolean("show-level-column"))
  1290.             column3.set_visible(self.settings.get_boolean("show-level-column"))
  1291.             levelColumnMenuItem.connect("toggled", self.setVisibleColumn, column3, "show-level-column")
  1292.             visibleColumnsMenu.append(levelColumnMenuItem)
  1293.  
  1294.             packageColumnMenuItem = Gtk.CheckMenuItem(_("Package"))
  1295.             packageColumnMenuItem.set_active(self.settings.get_boolean("show-package-column"))
  1296.             column2.set_visible(self.settings.get_boolean("show-package-column"))
  1297.             packageColumnMenuItem.connect("toggled", self.setVisibleColumn, column2, "show-package-column")
  1298.             visibleColumnsMenu.append(packageColumnMenuItem)
  1299.  
  1300.             oldVersionColumnMenuItem = Gtk.CheckMenuItem(_("Old version"))
  1301.             oldVersionColumnMenuItem.set_active(self.settings.get_boolean("show-old-version-column"))
  1302.             column4.set_visible(self.settings.get_boolean("show-old-version-column"))
  1303.             oldVersionColumnMenuItem.connect("toggled", self.setVisibleColumn, column4, "show-old-version-column")
  1304.             visibleColumnsMenu.append(oldVersionColumnMenuItem)
  1305.  
  1306.             newVersionColumnMenuItem = Gtk.CheckMenuItem(_("New version"))
  1307.             newVersionColumnMenuItem.set_active(self.settings.get_boolean("show-new-version-column"))
  1308.             column5.set_visible(self.settings.get_boolean("show-new-version-column"))
  1309.             newVersionColumnMenuItem.connect("toggled", self.setVisibleColumn, column5, "show-new-version-column")
  1310.             visibleColumnsMenu.append(newVersionColumnMenuItem)
  1311.  
  1312.             sizeColumnMenuItem = Gtk.CheckMenuItem(_("Size"))
  1313.             sizeColumnMenuItem.set_active(self.settings.get_boolean("show-size-column"))
  1314.             column6.set_visible(self.settings.get_boolean("show-size-column"))
  1315.             sizeColumnMenuItem.connect("toggled", self.setVisibleColumn, column6, "show-size-column")
  1316.             visibleColumnsMenu.append(sizeColumnMenuItem)
  1317.  
  1318.             sizeColumnMenuItem = Gtk.CheckMenuItem(_("Origin"))
  1319.             sizeColumnMenuItem.set_active(self.settings.get_boolean("show-origin-column"))
  1320.             column8.set_visible(self.settings.get_boolean("show-origin-column"))
  1321.             sizeColumnMenuItem.connect("toggled", self.setVisibleColumn, column8, "show-origin-column")
  1322.             visibleColumnsMenu.append(sizeColumnMenuItem)
  1323.  
  1324.             viewSubmenu.append(visibleColumnsMenuItem)
  1325.  
  1326.             descriptionsMenuItem = Gtk.CheckMenuItem(_("Show descriptions"))
  1327.             descriptionsMenuItem.set_active(self.settings.get_boolean("show-descriptions"))
  1328.             descriptionsMenuItem.connect("toggled", self.setVisibleDescriptions)
  1329.             viewSubmenu.append(descriptionsMenuItem)
  1330.  
  1331.             viewSubmenu.append(historyMenuItem)
  1332.  
  1333.             try:
  1334.                 # Only support kernel selection in Linux Mint (not LMDE)
  1335.                 if (subprocess.check_output("lsb_release -is", shell = True).strip() == b"LinuxMint" and float(subprocess.check_output("lsb_release -rs", shell = True).strip()) >= 13):
  1336.                     viewSubmenu.append(kernelMenuItem)
  1337.             except Exception as e:
  1338.                 print (e)
  1339.                 print(sys.exc_info()[0])
  1340.             viewSubmenu.append(infoMenuItem)
  1341.  
  1342.             helpMenu = Gtk.MenuItem.new_with_mnemonic(_("_Help"))
  1343.             helpSubmenu = Gtk.Menu()
  1344.             helpMenu.set_submenu(helpSubmenu)
  1345.             if os.path.exists("/usr/share/help/C/linuxmint"):
  1346.                 helpMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_HELP)
  1347.                 helpMenuItem.set_use_stock(True)
  1348.                 helpMenuItem.set_label(_("Contents"))
  1349.                 helpMenuItem.connect("activate", self.open_help)
  1350.                 key, mod = Gtk.accelerator_parse("F1")
  1351.                 helpMenuItem.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
  1352.                 helpSubmenu.append(helpMenuItem)
  1353.             aboutMenuItem = Gtk.ImageMenuItem(Gtk.STOCK_ABOUT)
  1354.             aboutMenuItem.set_use_stock(True)
  1355.             aboutMenuItem.set_label(_("About"))
  1356.             aboutMenuItem.connect("activate", self.open_about)
  1357.             helpSubmenu.append(aboutMenuItem)
  1358.  
  1359.             self.builder.get_object("menubar1").append(fileMenu)
  1360.             self.builder.get_object("menubar1").append(editMenu)
  1361.             self.builder.get_object("menubar1").append(viewMenu)
  1362.             self.builder.get_object("menubar1").append(helpMenu)
  1363.  
  1364.             if len(sys.argv) > 1:
  1365.                 showWindow = sys.argv[1]
  1366.                 if (showWindow == "show"):
  1367.                     self.window.show_all()
  1368.                     self.builder.get_object("paned1").set_position(self.settings.get_int('window-pane-position'))
  1369.                     self.app_hidden = False
  1370.  
  1371.             # Status pages
  1372.             status_updated_page = self.builder.get_object("status_updated")
  1373.             self.stack.add_named(status_updated_page, "status_updated")
  1374.  
  1375.             status_error_page = self.builder.get_object("status_error")
  1376.             self.stack.add_named(status_error_page, "status_error")
  1377.  
  1378.             self.stack.show_all()
  1379.             if self.settings.get_boolean("show-policy-configuration"):
  1380.                 self.show_configuration()
  1381.             else:
  1382.                 self.stack.set_visible_child_name("updates_available")
  1383.                 refresh = RefreshThread(self)
  1384.                 refresh.start()
  1385.  
  1386.             self.builder.get_object("notebook_details").set_current_page(0)
  1387.  
  1388.             self.window.resize(self.settings.get_int('window-width'), self.settings.get_int('window-height'))
  1389.             self.builder.get_object("paned1").set_position(self.settings.get_int('window-pane-position'))
  1390.  
  1391.             auto_refresh = AutomaticRefreshThread(self)
  1392.             auto_refresh.start()
  1393.  
  1394.             Gdk.threads_enter()
  1395.             Gtk.main()
  1396.             Gdk.threads_leave()
  1397.  
  1398.         except Exception as e:
  1399.             print (e)
  1400.             print(sys.exc_info()[0])
  1401.             self.logger.write_error("Exception occurred in main thread: " + str(sys.exc_info()[0]))
  1402.             self.logger.close()
  1403.  
  1404. ######### UTILITY FUNCTIONS #########
  1405.     def hide_window(self, widget, window):
  1406.         window.hide()
  1407.  
  1408.     def refresh(self):
  1409.         refresh = RefreshThread(self)
  1410.         refresh.start()
  1411.  
  1412.     def set_status_message(self, message):
  1413.         self.statusbar.push(self.context_id, message)
  1414.  
  1415.     def set_status(self, message, tooltip, icon, visible):
  1416.         self.set_status_message(message)
  1417.         self.statusIcon.set_from_icon_name(icon)
  1418.         self.statusIcon.set_tooltip_text(tooltip)
  1419.         self.statusIcon.set_visible(visible)
  1420.  
  1421. ######### WINDOW/STATUSICON ##########
  1422.  
  1423.     def close_window(self, window, event):
  1424.         window.hide()
  1425.         self.save_window_size()
  1426.         self.app_hidden = True
  1427.         return True
  1428.  
  1429.     def save_window_size(self):
  1430.         self.settings.set_int('window-width', self.window.get_size()[0])
  1431.         self.settings.set_int('window-height', self.window.get_size()[1])
  1432.         self.settings.set_int('window-pane-position', self.builder.get_object("paned1").get_position())
  1433.  
  1434. ######### MENU/TOOLBAR FUNCTIONS ################
  1435.  
  1436.     def hide_main_window(self, widget):
  1437.         self.window.hide()
  1438.         self.app_hidden = True
  1439.  
  1440.     def setVisibleColumn(self, checkmenuitem, column, key):
  1441.         self.settings.set_boolean(key, checkmenuitem.get_active())
  1442.         column.set_visible(checkmenuitem.get_active())
  1443.  
  1444.     def setVisibleDescriptions(self, checkmenuitem):
  1445.         self.settings.set_boolean("show-descriptions", checkmenuitem.get_active())
  1446.         refresh = RefreshThread(self)
  1447.         refresh.start()
  1448.  
  1449.     def clear(self, widget):
  1450.         model = self.treeview.get_model()
  1451.         iter = model.get_iter_first()
  1452.         while (iter != None):
  1453.             model.set_value(iter, 0, "false")
  1454.             iter = model.iter_next(iter)
  1455.         self.set_status_message(_("No updates selected"))
  1456.  
  1457.     def select_all(self, widget):
  1458.         self.select_updates()
  1459.  
  1460.     def select_level1(self, widget):
  1461.         self.select_updates(1)
  1462.  
  1463.     def select_level2(self, widget):
  1464.         self.select_updates(2)
  1465.  
  1466.     def select_level3(self, widget):
  1467.         self.select_updates(3)
  1468.  
  1469.     def select_level4(self, widget):
  1470.         self.select_updates(4)
  1471.  
  1472.     def select_security_updates(self, widget):
  1473.         self.select_updates(level=None, security=True, kernel=False)
  1474.  
  1475.     def select_kernel_updates(self, widget):
  1476.         self.select_updates(level=None, security=False, kernel=True)
  1477.  
  1478.     def select_updates(self, level=None, security=False, kernel=False):
  1479.         model = self.treeview.get_model()
  1480.         iter = model.get_iter_first()
  1481.         while (iter != None):
  1482.             update =  model.get_value(iter, UPDATE_OBJ)
  1483.             if level is not None:
  1484.                 if level == update.level:
  1485.                     model.set_value(iter, UPDATE_CHECKED, "true")
  1486.             elif security:
  1487.                 if update.type == "security":
  1488.                     model.set_value(iter, UPDATE_CHECKED, "true")
  1489.             elif kernel:
  1490.                 if update.type == "kernel":
  1491.                     model.set_value(iter, UPDATE_CHECKED, "true")
  1492.             else:
  1493.                 model.set_value(iter, UPDATE_CHECKED, "true")
  1494.             iter = model.iter_next(iter)
  1495.         iter = model.get_iter_first()
  1496.         download_size = 0
  1497.         num_selected = 0
  1498.         while (iter != None):
  1499.             checked = model.get_value(iter, UPDATE_CHECKED)
  1500.             if (checked == "true"):
  1501.                 size = model.get_value(iter, UPDATE_SIZE)
  1502.                 download_size = download_size + size
  1503.                 num_selected = num_selected + 1
  1504.             iter = model.iter_next(iter)
  1505.         if num_selected == 0:
  1506.             self.set_status_message(_("No updates selected"))
  1507.         elif num_selected == 1:
  1508.             self.set_status_message(_("%(selected)d update selected (%(size)s)") % {'selected':num_selected, 'size':size_to_string(download_size)})
  1509.         else:
  1510.             self.set_status_message(_("%(selected)d updates selected (%(size)s)") % {'selected':num_selected, 'size':size_to_string(download_size)})
  1511.  
  1512.     def force_refresh(self, widget):
  1513.         refresh = RefreshThread(self, root_mode=True)
  1514.         refresh.start()
  1515.  
  1516.     def install(self, widget):
  1517.         install = InstallThread(self)
  1518.         install.start()
  1519.  
  1520. ######### CONFIGURE PAGE FUNCTIONS #######
  1521.  
  1522.     def on_configure_finished(self, button):
  1523.         self.settings.set_boolean("show-policy-configuration", False)
  1524.  
  1525.         if (self.builder.get_object("radiobutton_policy_1").get_active()):
  1526.             self.settings.set_boolean("level3-is-visible", False)
  1527.             self.settings.set_boolean("level4-is-visible", False)
  1528.             self.settings.set_boolean("level3-is-safe", False)
  1529.             self.settings.set_boolean("level4-is-safe", False)
  1530.             self.settings.set_boolean("security-updates-are-safe", False)
  1531.             self.settings.set_boolean("kernel-updates-are-safe", False)
  1532.         elif (self.builder.get_object("radiobutton_policy_2").get_active()):
  1533.             self.settings.set_boolean("level3-is-visible", True)
  1534.             self.settings.set_boolean("level4-is-visible", True)
  1535.             self.settings.set_boolean("level3-is-safe", False)
  1536.             self.settings.set_boolean("level4-is-safe", False)
  1537.             self.settings.set_boolean("security-updates-are-safe", True)
  1538.             self.settings.set_boolean("kernel-updates-are-safe", False)
  1539.         elif (self.builder.get_object("radiobutton_policy_3").get_active()):
  1540.             self.settings.set_boolean("level3-is-visible", True)
  1541.             self.settings.set_boolean("level4-is-visible", True)
  1542.             self.settings.set_boolean("level3-is-safe", True)
  1543.             self.settings.set_boolean("level4-is-safe", True)
  1544.             self.settings.set_boolean("security-updates-are-safe", True)
  1545.             self.settings.set_boolean("kernel-updates-are-safe", True)
  1546.  
  1547.         # Common to all policies
  1548.         self.settings.set_boolean("level1-is-visible", True)
  1549.         self.settings.set_boolean("level2-is-visible", True)
  1550.         self.settings.set_boolean("level5-is-visible", False)
  1551.         self.settings.set_boolean("level1-is-safe", True)
  1552.         self.settings.set_boolean("level2-is-safe", True)
  1553.         self.settings.set_boolean("level5-is-safe", False)
  1554.         self.settings.set_boolean("security-updates-are-visible", True)
  1555.         self.settings.set_boolean("kernel-updates-are-visible", True)
  1556.  
  1557.         self.builder.get_object("toolbar1").set_visible(True)
  1558.         self.builder.get_object("toolbar1").set_sensitive(True)
  1559.         self.builder.get_object("menubar1").set_visible(True)
  1560.         self.builder.get_object("menubar1").set_sensitive(True)
  1561.         self.updates_inhibited = False
  1562.         refresh = RefreshThread(self)
  1563.         refresh.start()
  1564.  
  1565.     def on_configure_help(self, button):
  1566.         os.system("yelp help:mintupdate/index &")
  1567.  
  1568.     def show_configuration(self, widget=None):
  1569.         self.updates_inhibited = True
  1570.         policy = "radiobutton_policy_1"
  1571.         if (self.settings.get_boolean("security-updates-are-safe")):
  1572.             policy = "radiobutton_policy_2"
  1573.         if (self.settings.get_boolean("level4-is-safe")):
  1574.             policy = "radiobutton_policy_3"
  1575.         self.builder.get_object(policy).set_active(True)
  1576.         self.stack.set_visible_child_name("configure")
  1577.         self.set_status(_("Please choose an update policy."), _("Please choose an update policy."), "mintupdate-updates-available", True)
  1578.         self.set_status_message("")
  1579.         self.builder.get_object("toolbar1").set_sensitive(False)
  1580.         self.builder.get_object("toolbar1").set_visible(False)
  1581.         self.builder.get_object("menubar1").set_sensitive(False)
  1582.         self.builder.get_object("menubar1").set_visible(False)
  1583.  
  1584. ######### TREEVIEW/SELECTION FUNCTIONS #######
  1585.  
  1586.     def celldatafunction_checkbox(self, column, cell, model, iter, data):
  1587.         cell.set_property("activatable", True)
  1588.         checked = model.get_value(iter, UPDATE_CHECKED)
  1589.         if (checked == "true"):
  1590.             cell.set_property("active", True)
  1591.         else:
  1592.             cell.set_property("active", False)
  1593.  
  1594.     def treeview_row_activated(self, treeview, path, view_column):
  1595.         self.toggled(None, path)
  1596.  
  1597.     def toggled(self, renderer, path):
  1598.         model = self.treeview.get_model()
  1599.         iter = model.get_iter(path)
  1600.         if (iter != None):
  1601.             checked = model.get_value(iter, UPDATE_CHECKED)
  1602.             if (checked == "true"):
  1603.                 model.set_value(iter, UPDATE_CHECKED, "false")
  1604.             else:
  1605.                 model.set_value(iter, UPDATE_CHECKED, "true")
  1606.  
  1607.         iter = model.get_iter_first()
  1608.         download_size = 0
  1609.         num_selected = 0
  1610.         while (iter != None):
  1611.             checked = model.get_value(iter, UPDATE_CHECKED)
  1612.             if (checked == "true"):
  1613.                 size = model.get_value(iter, UPDATE_SIZE)
  1614.                 download_size = download_size + size
  1615.                 num_selected = num_selected + 1
  1616.             iter = model.iter_next(iter)
  1617.         if num_selected == 0:
  1618.             self.set_status_message(_("No updates selected"))
  1619.         elif num_selected == 1:
  1620.             self.set_status_message(_("%(selected)d update selected (%(size)s)") % {'selected':num_selected, 'size':size_to_string(download_size)})
  1621.         else:
  1622.             self.set_status_message(_("%(selected)d updates selected (%(size)s)") % {'selected':num_selected, 'size':size_to_string(download_size)})
  1623.  
  1624.     def display_selected_package(self, selection):
  1625.         try:
  1626.             self.builder.get_object("textview_description").get_buffer().set_text("")
  1627.             self.builder.get_object("textview_changes").get_buffer().set_text("")
  1628.             (model, iter) = selection.get_selected()
  1629.             if (iter != None):
  1630.                 package_update = model.get_value(iter, UPDATE_OBJ)
  1631.                 self.display_package_description(package_update)
  1632.                 if self.builder.get_object("notebook_details").get_current_page() == 0:
  1633.                     # Description tab
  1634.                     self.changelog_retriever_started = False
  1635.                 else:
  1636.                     # Changelog tab
  1637.                     retriever = ChangelogRetriever(package_update, self)
  1638.                     retriever.start()
  1639.                     self.changelog_retriever_started = True
  1640.         except Exception as e:
  1641.             print (e)
  1642.             print(sys.exc_info()[0])
  1643.  
  1644.     def switch_page(self, notebook, page, page_num):
  1645.         selection = self.treeview.get_selection()
  1646.         (model, iter) = selection.get_selected()
  1647.         if (iter != None):
  1648.             if (page_num == 1 and not self.changelog_retriever_started):
  1649.                 # Changelog tab
  1650.                 package_update = model.get_value(iter, UPDATE_OBJ)
  1651.                 retriever = ChangelogRetriever(package_update, self)
  1652.                 retriever.start()
  1653.                 self.changelog_retriever_started = True
  1654.  
  1655.     def display_package_description(self, package_update):
  1656.         description = package_update.description
  1657.         description = description.split("\\n")
  1658.         for line in description:
  1659.             self.buffer.insert(self.buffer.get_end_iter(), line)
  1660.             self.buffer.insert(self.buffer.get_end_iter(), "\n")
  1661.  
  1662.         if (len(package_update.package_names) > 1):
  1663.             dimmed_description = "\n%s %s" % (_("This update contains %d packages: ") % len(package_update.package_names), " ".join(sorted(package_update.package_names)))
  1664.             self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(), dimmed_description, "dimmed")
  1665.         elif (package_update.package_names[0] != package_update.display_name):
  1666.             dimmed_description = "\n%s %s" % (_("This update contains 1 package: "), package_update.package_names[0])
  1667.             self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(), dimmed_description, "dimmed")
  1668.  
  1669.     def treeview_right_clicked(self, widget, event):
  1670.         if event.button == 3:
  1671.             (model, iter) = widget.get_selection().get_selected()
  1672.             if (iter != None):
  1673.                 package_update = model.get_value(iter, UPDATE_OBJ)
  1674.                 menu = Gtk.Menu()
  1675.                 menuItem = Gtk.MenuItem.new_with_mnemonic(_("Ignore updates for this package"))
  1676.                 menuItem.connect("activate", self.add_to_ignore_list, package_update.source_name)
  1677.                 menu.append(menuItem)
  1678.                 menu.attach_to_widget (widget, None)
  1679.                 menu.show_all()
  1680.                 menu.popup(None, None, None, None, event.button, event.time)
  1681.  
  1682.     def add_to_ignore_list(self, widget, pkg):
  1683.         blacklist = self.settings.get_strv("blacklisted-packages")
  1684.         blacklist.append(pkg)
  1685.         self.settings.set_strv("blacklisted-packages", blacklist)
  1686.         refresh = RefreshThread(self)
  1687.         refresh.start()
  1688.  
  1689.  
  1690. ######### SYSTRAY ####################
  1691.  
  1692.     def show_statusicon_menu(self, icon, button, time, menu):
  1693.         menu.show_all()
  1694.         menu.popup(None, None, None, None, button, time)
  1695.  
  1696.     def on_statusicon_clicked(self, widget):
  1697.         if (self.app_hidden):
  1698.             self.window.show_all()
  1699.         else:
  1700.             self.window.hide()
  1701.             self.save_window_size()
  1702.         self.app_hidden = not self.app_hidden
  1703.  
  1704.     def quit_from_systray(self, widget, data = None):
  1705.         if data:
  1706.             data.set_visible(False)
  1707.         try:
  1708.             self.logger.write("Exiting - requested by user")
  1709.             self.logger.close()
  1710.             self.save_window_size()
  1711.         except:
  1712.             pass # cause log might already been closed
  1713.         # Whatever works best heh :)
  1714.         os.system("kill -9 %s &" % os.getpid())
  1715.  
  1716. ######### INFORMATION SCREEN #########
  1717.  
  1718.     def open_information(self, widget):
  1719.         gladefile = "/usr/share/linuxmint/mintupdate/information.ui"
  1720.         builder = Gtk.Builder()
  1721.         builder.add_from_file(gladefile)
  1722.         window = builder.get_object("main_window")
  1723.         window.set_title(_("Information") + " - " + _("Update Manager"))
  1724.         window.set_icon_name("mintupdate")
  1725.         builder.get_object("close_button").connect("clicked", self.hide_window, window)
  1726.         builder.get_object("label4").set_text(_("Process ID:"))
  1727.         builder.get_object("label5").set_text(_("Log file:"))
  1728.         builder.get_object("processid_label").set_text(str(os.getpid()))
  1729.         builder.get_object("log_filename").set_text(str(self.logger.log.name))
  1730.         txtbuffer = Gtk.TextBuffer()
  1731.         txtbuffer.set_text(subprocess.check_output("cat " + self.logger.log.name, shell = True).decode("utf-8"))
  1732.         builder.get_object("log_textview").set_buffer(txtbuffer)
  1733.  
  1734. ######### HISTORY SCREEN #########
  1735.  
  1736.     def open_history(self, widget):
  1737.         gladefile = "/usr/share/linuxmint/mintupdate/history.ui"
  1738.         builder = Gtk.Builder()
  1739.         builder.add_from_file(gladefile)
  1740.         window = builder.get_object("main_window")
  1741.         window.set_icon_name("mintupdate")
  1742.         window.set_title(_("History of updates") + " - " + _("Update Manager"))
  1743.  
  1744.         treeview = builder.get_object("treeview_history")
  1745.         column1 = Gtk.TreeViewColumn(_("Date"), Gtk.CellRendererText(), text=1)
  1746.         column1.set_sort_column_id(1)
  1747.         column1.set_resizable(True)
  1748.         column2 = Gtk.TreeViewColumn(_("Package"), Gtk.CellRendererText(), text=0)
  1749.         column2.set_sort_column_id(0)
  1750.         column2.set_resizable(True)
  1751.         column3 = Gtk.TreeViewColumn(_("Old version"), Gtk.CellRendererText(), text=2)
  1752.         column3.set_sort_column_id(2)
  1753.         column3.set_resizable(True)
  1754.         column4 = Gtk.TreeViewColumn(_("New version"), Gtk.CellRendererText(), text=3)
  1755.         column4.set_sort_column_id(3)
  1756.         column4.set_resizable(True)
  1757.         treeview.append_column(column1)
  1758.         treeview.append_column(column2)
  1759.         treeview.append_column(column3)
  1760.         treeview.append_column(column4)
  1761.         treeview.set_headers_clickable(True)
  1762.         treeview.set_reorderable(False)
  1763.         treeview.set_search_column(0)
  1764.         treeview.set_enable_search(True)
  1765.         treeview.show()
  1766.  
  1767.         model = Gtk.TreeStore(str, str, str, str) # (packageName, date, oldVersion, newVersion)
  1768.         if (os.path.exists("/var/log/dpkg.log")):
  1769.             updates = subprocess.check_output("cat /var/log/dpkg.log /var/log/dpkg.log.? 2>/dev/null | egrep \"upgrade\"", shell = True).decode("utf-8")
  1770.             updates = updates.split("\n")
  1771.             for pkg in updates:
  1772.                 values = pkg.split(" ")
  1773.                 if len(values) == 6:
  1774.                     (date, time, action, package, oldVersion, newVersion) = values
  1775.                     if action != "upgrade" or oldVersion == newVersion:
  1776.                         continue
  1777.                     if ":" in package:
  1778.                         package = package.split(":")[0]
  1779.  
  1780.                     iter = model.insert_before(None, None)
  1781.                     model.set_value(iter, 0, package)
  1782.                     model.row_changed(model.get_path(iter), iter)
  1783.                     model.set_value(iter, 1, "%s - %s" % (date, time))
  1784.                     model.set_value(iter, 2, oldVersion)
  1785.                     model.set_value(iter, 3, newVersion)
  1786.  
  1787.         model.set_sort_column_id( 1, Gtk.SortType.DESCENDING )
  1788.         treeview.set_model(model)
  1789.         del model
  1790.         builder.get_object("button_close").connect("clicked", self.hide_window, window)
  1791.  
  1792. ######### HELP/ABOUT/SOURCES SCREEN #########
  1793.  
  1794.     def open_help(self, widget):
  1795.         os.system("yelp help:mintupdate/index &")
  1796.  
  1797.     def open_rel_upgrade(self, widget):
  1798.         os.system("/usr/bin/mint-release-upgrade &")
  1799.  
  1800.     def open_about(self, widget):
  1801.         dlg = Gtk.AboutDialog()
  1802.         dlg.set_title(_("About") + " - " + _("Update Manager"))
  1803.         dlg.set_program_name("mintUpdate")
  1804.         dlg.set_comments(_("Update Manager"))
  1805.         try:
  1806.             h = open('/usr/share/common-licenses/GPL','r')
  1807.             s = h.readlines()
  1808.             gpl = ""
  1809.             for line in s:
  1810.                 gpl += line
  1811.             h.close()
  1812.             dlg.set_license(gpl)
  1813.         except Exception as e:
  1814.             print (e)
  1815.             print(sys.exc_info()[0])
  1816.  
  1817.         try:
  1818.             version = subprocess.getoutput("/usr/lib/linuxmint/common/version.py mintupdate")
  1819.             dlg.set_version(version)
  1820.         except Exception as e:
  1821.             print (e)
  1822.             print(sys.exc_info()[0])
  1823.  
  1824.         dlg.set_icon_name("mintupdate")
  1825.         dlg.set_logo_icon_name("mintupdate")
  1826.         dlg.set_website("http://www.github.com/linuxmint/mintupdate")
  1827.         def close(w, res):
  1828.             if res == Gtk.ResponseType.CANCEL or res == Gtk.ResponseType.DELETE_EVENT:
  1829.                 w.hide()
  1830.         dlg.connect("response", close)
  1831.         dlg.show()
  1832.  
  1833.     def open_repositories(self, widget):
  1834.         if os.path.exists("/usr/bin/software-sources"):
  1835.             os.system("/usr/bin/software-sources &")
  1836.         elif os.path.exists("/usr/bin/software-properties-gtk"):
  1837.             os.system("/usr/bin/software-properties-gtk &")
  1838.         elif os.path.exists("/usr/bin/software-properties-kde"):
  1839.             os.system("/usr/bin/software-properties-kde &")
  1840.  
  1841. ######### PREFERENCES SCREEN #########
  1842.  
  1843.     def open_preferences(self, widget):
  1844.         gladefile = "/usr/share/linuxmint/mintupdate/preferences.ui"
  1845.         builder = Gtk.Builder()
  1846.         builder.add_from_file(gladefile)
  1847.         window = builder.get_object("main_window")
  1848.         window.set_title(_("Preferences") + " - " + _("Update Manager"))
  1849.         window.set_icon_name("mintupdate")
  1850.  
  1851.         switch_container = builder.get_object("switch_container")
  1852.         stack = Gtk.Stack()
  1853.         stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
  1854.         stack.set_transition_duration(150)
  1855.         stack_switcher = Gtk.StackSwitcher()
  1856.         stack_switcher.set_stack(stack)
  1857.         switch_container.pack_start(stack_switcher, True, True, 0)
  1858.         stack_switcher.set_halign(Gtk.Align.CENTER)
  1859.  
  1860.         page_holder = builder.get_object("page_container")
  1861.         page_holder.add(stack)
  1862.  
  1863.         stack.add_titled(builder.get_object("page_options"), "page_options", _("Options"))
  1864.         stack.add_titled(builder.get_object("page_levels"), "page_levels", _("Levels"))
  1865.         stack.add_titled(builder.get_object("page_refresh"), "page_refresh", _("Auto-refresh"))
  1866.         stack.add_titled(builder.get_object("page_blacklist"), "page_blacklist", _("Blacklist"))
  1867.  
  1868.         #l10n
  1869.         builder.get_object("label39").set_markup("<b>" + _("Impact level") + "</b>")
  1870.         builder.get_object("label_recommandation").set_markup("<b>" + _("Description") + "</b>")
  1871.         builder.get_object("label41").set_markup("<b>" + _("Selected") + "</b>")
  1872.         builder.get_object("label42").set_markup("<b>" + _("Visible") + "</b>")
  1873.  
  1874.         builder.get_object("label_level_1").set_text(_("Minimal"))
  1875.         builder.get_object("label_level_2").set_text(_("Normal"))
  1876.         builder.get_object("label_level_3").set_text(_("Large"))
  1877.         builder.get_object("label_level_4").set_text(_("Sensitive"))
  1878.         builder.get_object("label_level_5").set_text(_("Dangerous"))
  1879.  
  1880.         builder.get_object("label_impact_1").set_text(_("No impact on the system or other applications."))
  1881.         builder.get_object("label_impact_2").set_text(_("Default level. Usually low impact on the system."))
  1882.         builder.get_object("label_impact_3").set_text(_("Apply with caution. Impact on multiple applications."))
  1883.         builder.get_object("label_impact_4").set_text(_("Apply one by one. Impact on sensitive parts of the system."))
  1884.         builder.get_object("label_impact_5").set_text(_("Very rare. Not recommended. Known to create issues."))
  1885.  
  1886.         builder.get_object("label_refresh").set_text(_("First, refresh the list of updates after:"))
  1887.         builder.get_object("label_autorefresh").set_text(_("Then, refresh the list of updates every:"))
  1888.         builder.get_object("label82").set_text("<i>" + _("Note: The list only gets refreshed while the update manager window is closed (system tray mode).") + "</i>")
  1889.         builder.get_object("label82").set_use_markup(True)
  1890.         builder.get_object("checkbutton_dist_upgrade").set_label(_("Include updates which require the installation of new packages or the removal of installed packages"))
  1891.         builder.get_object("checkbutton_hide_window_after_update").set_label(_("Hide the update manager after applying updates"))
  1892.         builder.get_object("checkbutton_hide_systray").set_label(_("Only show a tray icon when updates are available or in case of errors"))
  1893.         builder.get_object("checkbutton_default_repo_is_ok").set_label(_("Don't suggest to switch to a local mirror"))
  1894.         builder.get_object("checkbutton_security_visible").set_label(_("Always show security updates"))
  1895.         builder.get_object("checkbutton_security_safe").set_label(_("Always select security updates"))
  1896.         builder.get_object("checkbutton_kernel_visible").set_label(_("Always show kernel updates"))
  1897.         builder.get_object("checkbutton_kernel_safe").set_label(_("Always select kernel updates"))
  1898.         builder.get_object("label_minutes").set_text(_("minutes"))
  1899.         builder.get_object("label_hours").set_text(_("hours"))
  1900.         builder.get_object("label_days").set_text(_("days"))
  1901.         builder.get_object("pref_button_cancel").set_label(_("Cancel"))
  1902.         builder.get_object("pref_button_apply").set_label(_("Apply"))
  1903.  
  1904.         builder.get_object("visible1").set_active(self.settings.get_boolean("level1-is-visible"))
  1905.         builder.get_object("visible2").set_active(self.settings.get_boolean("level2-is-visible"))
  1906.         builder.get_object("visible3").set_active(self.settings.get_boolean("level3-is-visible"))
  1907.         builder.get_object("visible4").set_active(self.settings.get_boolean("level4-is-visible"))
  1908.         builder.get_object("visible5").set_active(self.settings.get_boolean("level5-is-visible"))
  1909.         builder.get_object("safe1").set_active(self.settings.get_boolean("level1-is-safe"))
  1910.         builder.get_object("safe2").set_active(self.settings.get_boolean("level2-is-safe"))
  1911.         builder.get_object("safe3").set_active(self.settings.get_boolean("level3-is-safe"))
  1912.         builder.get_object("safe4").set_active(self.settings.get_boolean("level4-is-safe"))
  1913.         builder.get_object("safe5").set_active(self.settings.get_boolean("level5-is-safe"))
  1914.         builder.get_object("checkbutton_security_visible").set_active(self.settings.get_boolean("security-updates-are-visible"))
  1915.         builder.get_object("checkbutton_security_safe").set_active(self.settings.get_boolean("security-updates-are-safe"))
  1916.         builder.get_object("checkbutton_kernel_visible").set_active(self.settings.get_boolean("kernel-updates-are-visible"))
  1917.         builder.get_object("checkbutton_kernel_safe").set_active(self.settings.get_boolean("kernel-updates-are-safe"))
  1918.         builder.get_object("checkbutton_dist_upgrade").set_active(self.settings.get_boolean("dist-upgrade"))
  1919.         builder.get_object("checkbutton_hide_window_after_update").set_active(self.settings.get_boolean("hide-window-after-update"))
  1920.         builder.get_object("checkbutton_hide_systray").set_active(self.settings.get_boolean("hide-systray"))
  1921.         builder.get_object("checkbutton_default_repo_is_ok").set_active(self.settings.get_boolean("default-repo-is-ok"))
  1922.  
  1923.         builder.get_object("refresh_days").set_range(0, 365)
  1924.         builder.get_object("refresh_days").set_increments(1, 10)
  1925.         builder.get_object("refresh_days").set_value(self.settings.get_int("refresh-days"))
  1926.         builder.get_object("refresh_hours").set_range(0, 59)
  1927.         builder.get_object("refresh_hours").set_increments(1, 5)
  1928.         builder.get_object("refresh_hours").set_value(self.settings.get_int("refresh-hours"))
  1929.         builder.get_object("refresh_minutes").set_range(0, 59)
  1930.         builder.get_object("refresh_minutes").set_increments(1, 5)
  1931.         builder.get_object("refresh_minutes").set_value(self.settings.get_int("refresh-minutes"))
  1932.         builder.get_object("autorefresh_days").set_range(0, 365)
  1933.         builder.get_object("autorefresh_days").set_increments(1, 10)
  1934.         builder.get_object("autorefresh_days").set_value(self.settings.get_int("autorefresh-days"))
  1935.         builder.get_object("autorefresh_hours").set_range(0, 59)
  1936.         builder.get_object("autorefresh_hours").set_increments(1, 5)
  1937.         builder.get_object("autorefresh_hours").set_value(self.settings.get_int("autorefresh-hours"))
  1938.         builder.get_object("autorefresh_minutes").set_range(0, 59)
  1939.         builder.get_object("autorefresh_minutes").set_increments(1, 5)
  1940.         builder.get_object("autorefresh_minutes").set_value(self.settings.get_int("autorefresh-minutes"))
  1941.  
  1942.         treeview_blacklist = builder.get_object("treeview_blacklist")
  1943.         column1 = Gtk.TreeViewColumn(_("Ignored updates"), Gtk.CellRendererText(), text=0)
  1944.         column1.set_sort_column_id(0)
  1945.         column1.set_resizable(True)
  1946.         treeview_blacklist.append_column(column1)
  1947.         treeview_blacklist.set_headers_clickable(True)
  1948.         treeview_blacklist.set_reorderable(False)
  1949.         treeview_blacklist.show()
  1950.         model = Gtk.TreeStore(str)
  1951.         model.set_sort_column_id( 0, Gtk.SortType.ASCENDING )
  1952.         treeview_blacklist.set_model(model)
  1953.         blacklist = self.settings.get_strv("blacklisted-packages")
  1954.         for ignored_pkg in blacklist:
  1955.             iter = model.insert_before(None, None)
  1956.             model.set_value(iter, 0, ignored_pkg)
  1957.  
  1958.         builder.get_object("pref_button_cancel").connect("clicked", self.hide_window, window)
  1959.         builder.get_object("pref_button_apply").connect("clicked", self.save_preferences, builder)
  1960.         builder.get_object("button_add").connect("clicked", self.add_blacklisted_package, treeview_blacklist)
  1961.         builder.get_object("button_remove").connect("clicked", self.remove_blacklisted_package, treeview_blacklist)
  1962.         builder.get_object("button_add").set_always_show_image(True)
  1963.         builder.get_object("button_remove").set_always_show_image(True)
  1964.  
  1965.         window.show_all()
  1966.  
  1967.     def save_preferences(self, widget, builder):
  1968.         self.settings.set_boolean('hide-window-after-update', builder.get_object("checkbutton_hide_window_after_update").get_active())
  1969.         self.settings.set_boolean('hide-systray', builder.get_object("checkbutton_hide_systray").get_active())
  1970.         self.settings.set_boolean('default-repo-is-ok', builder.get_object("checkbutton_default_repo_is_ok").get_active())
  1971.         self.settings.set_boolean('level1-is-visible', builder.get_object("visible1").get_active())
  1972.         self.settings.set_boolean('level2-is-visible', builder.get_object("visible2").get_active())
  1973.         self.settings.set_boolean('level3-is-visible', builder.get_object("visible3").get_active())
  1974.         self.settings.set_boolean('level4-is-visible', builder.get_object("visible4").get_active())
  1975.         self.settings.set_boolean('level5-is-visible', builder.get_object("visible5").get_active())
  1976.         self.settings.set_boolean('level1-is-safe', builder.get_object("safe1").get_active())
  1977.         self.settings.set_boolean('level2-is-safe', builder.get_object("safe2").get_active())
  1978.         self.settings.set_boolean('level3-is-safe', builder.get_object("safe3").get_active())
  1979.         self.settings.set_boolean('level4-is-safe', builder.get_object("safe4").get_active())
  1980.         self.settings.set_boolean('level5-is-safe', builder.get_object("safe5").get_active())
  1981.         self.settings.set_boolean('security-updates-are-visible', builder.get_object("checkbutton_security_visible").get_active())
  1982.         self.settings.set_boolean('security-updates-are-safe', builder.get_object("checkbutton_security_safe").get_active())
  1983.         self.settings.set_boolean('kernel-updates-are-visible', builder.get_object("checkbutton_kernel_visible").get_active())
  1984.         self.settings.set_boolean('kernel-updates-are-safe', builder.get_object("checkbutton_kernel_safe").get_active())
  1985.         self.settings.set_int('refresh-days', int(builder.get_object("refresh_days").get_value()))
  1986.         self.settings.set_int('refresh-hours', int(builder.get_object("refresh_hours").get_value()))
  1987.         self.settings.set_int('refresh-minutes', int(builder.get_object("refresh_minutes").get_value()))
  1988.         self.settings.set_int('autorefresh-days', int(builder.get_object("autorefresh_days").get_value()))
  1989.         self.settings.set_int('autorefresh-hours', int(builder.get_object("autorefresh_hours").get_value()))
  1990.         self.settings.set_int('autorefresh-minutes', int(builder.get_object("autorefresh_minutes").get_value()))
  1991.         self.settings.set_boolean('dist-upgrade', builder.get_object("checkbutton_dist_upgrade").get_active())
  1992.         blacklist = []
  1993.         treeview_blacklist = builder.get_object("treeview_blacklist")
  1994.         model = treeview_blacklist.get_model()
  1995.         iter = model.get_iter_first()
  1996.         while iter is not None:
  1997.             pkg = model.get_value(iter, UPDATE_CHECKED)
  1998.             iter = model.iter_next(iter)
  1999.             blacklist.append(pkg)
  2000.         self.settings.set_strv("blacklisted-packages", blacklist)
  2001.         builder.get_object("main_window").hide()
  2002.         self.refresh()
  2003.  
  2004.     def add_blacklisted_package(self, widget, treeview_blacklist):
  2005.         dialog = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK, None)
  2006.         dialog.set_markup("<b>" + _("Please specify the name of the update to ignore:") + "</b>")
  2007.         dialog.set_title(_("Ignore an update"))
  2008.         dialog.set_icon_name("mintupdate")
  2009.         entry = Gtk.Entry()
  2010.         hbox = Gtk.HBox()
  2011.         hbox.pack_start(Gtk.Label(_("Name:")), False, 5, 5)
  2012.         hbox.pack_end(entry, True, True, 0)
  2013.         dialog.vbox.pack_end(hbox, True, True, 0)
  2014.         dialog.show_all()
  2015.         if dialog.run() == Gtk.ResponseType.OK:
  2016.             name = entry.get_text()
  2017.             pkg = name.strip()
  2018.             if pkg != '':
  2019.                 model = treeview_blacklist.get_model()
  2020.                 iter = model.insert_before(None, None)
  2021.                 model.set_value(iter, 0, pkg)
  2022.         dialog.destroy()
  2023.  
  2024.     def remove_blacklisted_package(self, widget, treeview_blacklist):
  2025.         selection = treeview_blacklist.get_selection()
  2026.         (model, iter) = selection.get_selected()
  2027.         if (iter != None):
  2028.             pkg = model.get_value(iter, UPDATE_CHECKED)
  2029.             model.remove(iter)
  2030.  
  2031. ###### KERNEL FEATURES #####################################
  2032.  
  2033.     def open_kernels(self, widget):
  2034.         kernel_window = KernelWindow(self)
  2035.  
  2036. if __name__ == "__main__":
  2037.     MintUpdate()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top