diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/debian/bzr-builder.manifest ukuu-16.12~57~ubuntu16.10.1/debian/bzr-builder.manifest --- ukuu-16.11.1~47~ubuntu16.10.1/debian/bzr-builder.manifest 2016-11-27 05:46:28.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/debian/bzr-builder.manifest 2016-12-07 16:47:11.000000000 +0000 @@ -1,2 +1,2 @@ -# bzr-builder format 0.3 deb-version {debupstream}~47 -lp:ukuu revid:tony.george.kol@gmail.com-20161127052315-wv82wvev2fcj83tg +# bzr-builder format 0.3 deb-version {debupstream}~57 +lp:ukuu revid:tony.george.kol@gmail.com-20161207163741-mmkegfa6t9tki5br diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/debian/changelog ukuu-16.12~57~ubuntu16.10.1/debian/changelog --- ukuu-16.11.1~47~ubuntu16.10.1/debian/changelog 2016-11-27 05:46:28.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/debian/changelog 2016-12-07 16:47:11.000000000 +0000 @@ -1,9 +1,26 @@ -ukuu (16.11.1~47~ubuntu16.10.1) yakkety; urgency=low +ukuu (16.12~57~ubuntu16.10.1) yakkety; urgency=low * Auto build. - -- Tony George Sun, 27 Nov 2016 05:46:28 +0000 + -- Tony George Wed, 07 Dec 2016 16:47:11 +0000 +ukuu (16.12) trusty; urgency=medium + + * Fixed an issue with update check. User would sometimes be prompted + to install an older version. + + * Fixed an issue where the update notification script would cause + high CPU usage if internet connection was not active. + + * Fixed an issue where the application would quit while refreshing + the cache + + * Cache refresh is now much faster. Uses aria2 for running parallel + downloads. + + -- Tony George Wed, 7 Dec 2016 10:00:00 +0530 + + ukuu (16.11.1) trusty; urgency=medium * Fixed build for xenial: Added dependency for 'valac' diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/po/ukuu-sv.po ukuu-16.12~57~ubuntu16.10.1/po/ukuu-sv.po --- ukuu-16.11.1~47~ubuntu16.10.1/po/ukuu-sv.po 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/po/ukuu-sv.po 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,486 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Tony George (teejeetech@gmail.com) +# This file is distributed under the same license as the ukuu package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ukuu 2.2\n" +"Report-Msgid-Bugs-To: teejeetech@gmail.com\n" +"POT-Creation-Date: 2016-11-04 19:19+0100\n" +"PO-Revision-Date: 2016-11-08 10:22+0100\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.7.1\n" +"Last-Translator: Åke Engelbrektson \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: sv\n" + +#: Gtk/MainWindow.vala:461 +msgid "About" +msgstr "Om" + +#: Console/AppConsole.vala:98 +msgid "Admin access is required for running this application." +msgstr "Root-åtkomst krävs för att köra detta program." + +#: Gtk/AboutWindow.vala:324 +#, c-format +msgid "Artists" +msgstr "Artister" + +#: Gtk/AboutWindow.vala:316 +#, c-format +msgid "Authors" +msgstr "Utvecklare" + +#: Common/LinuxKernel.vala:1059 +msgid "Available Kernels" +msgstr "Tillgängliga kärnor" + +#: Gtk/AboutWindow.vala:285 +msgid "Back" +msgstr "Tillbaka" + +#: Gtk/UpdateNotificationWindow.vala:177 Gtk/ProgressWindow.vala:139 +#: Gtk/TerminalWindow.vala:167 +msgid "Cancel" +msgstr "Avbryt" + +#: Gtk/MainWindow.vala:417 +msgid "Changes" +msgstr "Ändringar" + +#: Gtk/SettingsDialog.vala:120 +msgid "Check every" +msgstr "Kontrollera varje" + +#: Console/AppConsole.vala:84 +msgid "Check for kernel updates" +msgstr "Sök efter kärnuppdateringar" + +#: Gtk/TerminalWindow.vala:177 Gtk/AboutWindow.vala:295 +msgid "Close" +msgstr "Stäng" + +#: Common/Main.vala:105 +msgid "Commands listed below are not available on this system" +msgstr "Kommandon listade nedan, finns inte tillgängliga i detta system." + +#: Gtk/MainWindow.vala:95 Console/AppConsole.vala:200 +msgid "Could not find requested version" +msgstr "Kunde inte hitta efterfrågad version" + +#: Gtk/AboutWindow.vala:272 Gtk/AboutWindow.vala:289 +msgid "Credits" +msgstr "Tack" + +#: Common/CronTab.vala:65 +msgid "Cron job added" +msgstr "Cron-jobb tillagt" + +#: Common/CronTab.vala:115 +msgid "Cron job removed" +msgstr "Cron-jobb borttaget" + +#: Gtk/SettingsDialog.vala:153 +msgid "Day(s)" +msgstr "Dag(ar)" + +#: Gtk/DonationWindow.vala:55 +msgid "" +"Did you find this software useful?\n" +"\n" +"You can buy me a coffee or make a donation via PayPal to show your support. " +"Or just drop me an email and say Hi. This application is completely free and " +"will continue to remain that way. Your contributions will help in keeping " +"this project alive and improving it further.\n" +"\n" +"Feel free to send me an email if you find any issues in this application or " +"if you need any changes. Suggestions and feedback are always welcome.\n" +"\n" +"Thanks,\n" +"Tony George\n" +"(teejeetech@gmail.com)" +msgstr "" +"Tycker du att detta program är användbart?\n" +"\n" +"Du kan bjuda mig på en kopp kaffe eller donera via PayPal för att visa ditt " +"stöd. Eller bara skicka ett e-postmeddelande och säga Hej! Programmet är " +"helt gratis och kommer att fortsätta vara så. Ditt bidrag hjälper mig att " +"hålla projektet levande och att utveckla det vidare.\n" +"\n" +"Skicka gärna ett e-postmeddelande om du stöter på några problem med " +"programmet eller behöver några ändringar. Förslag och återkoppling är alltid " +"välkommet.\n" +"\n" +"Tack!\n" +"Tony George\n" +"(teejeetech@gmail.com)" + +#: Common/Utility.vala:428 +msgid "Dir not found" +msgstr "Mappen kan inte hittas" + +#: Gtk/SettingsDialog.vala:160 +msgid "Display" +msgstr "Visa" + +#: Common/LinuxKernel.vala:88 +msgid "Distribution" +msgstr "Distribution" + +#: Gtk/AboutWindow.vala:348 +#, c-format +msgid "Documenters" +msgstr "Dokumentalister" + +#: Gtk/MainWindow.vala:449 Gtk/DonationWindow.vala:36 +msgid "Donate" +msgstr "Donera" + +#: Gtk/DonationWindow.vala:75 +msgid "Donate with Google Wallet" +msgstr "Donera med Google Wallet" + +#: Gtk/DonationWindow.vala:68 +msgid "Donate with PayPal" +msgstr "Donera med PayPal" + +#: Gtk/AboutWindow.vala:356 +#, c-format +msgid "Donations" +msgstr "Donationer" + +#: Console/AppConsole.vala:89 +msgid "Download packages for specified kernel" +msgstr "Ladda ner paket för specificerad kärna" + +#: Common/LinuxKernel.vala:1097 +#, c-format +msgid "Downloading" +msgstr "Laddar ner" + +#: Common/Utility.vala:100 +msgid "E" +msgstr "F" + +#: Common/LinuxKernel.vala:1120 +#, c-format +msgid "ERROR" +msgstr "FEL" + +#: Gtk/GtkHelper.vala:18 +msgid "Error" +msgstr "Fel" + +#: Common/CronTab.vala:61 +msgid "Failed to add cron job" +msgstr "Kunde inte lägga till Cron-jobb" + +#: Common/Utility.vala:257 +msgid "Failed to copy file" +msgstr "Kunde inte kopiera filen" + +#: Common/Utility.vala:336 +msgid "Failed to create dir" +msgstr "Kunde inte skapa mappen" + +#: Common/Utility.vala:196 +msgid "Failed to delete file" +msgstr "Kunde inte ta bort filen" + +#: Common/Utility.vala:276 +msgid "Failed to move file" +msgstr "Kunde inte flytta filen" + +#: Common/CronTab.vala:18 +msgid "Failed to read cron tab" +msgstr "Kunde inte läsa cron-fliken" + +#: Common/Utility.vala:214 +msgid "Failed to read file" +msgstr "Kunde inte läsa filen" + +#: Common/CronTab.vala:111 +msgid "Failed to remove cron job" +msgstr "Kunde inte ta bort cron-jobbet" + +#: Common/Utility.vala:241 +msgid "Failed to write file" +msgstr "Kunde inte skriva filen" + +#: Common/LinuxKernel.vala:954 +#, c-format +msgid "Fetching changelog for" +msgstr "Hämtar ändringslogg för" + +#: Common/LinuxKernel.vala:912 +#, c-format +msgid "Fetching index for" +msgstr "Hämtar index för" + +#: Common/LinuxKernel.vala:348 +msgid "Fetching index from kernel.ubuntu.com..." +msgstr "Hämtar index från kernel.ubuntu.com ..." + +#: Common/Utility.vala:574 Common/Utility.vala:623 +msgid "File is missing" +msgstr "Filen saknas" + +#: Common/LinuxKernel.vala:968 Common/DownloadManager.vala:346 +#: Common/Utility.vala:271 Common/Utility.vala:457 +msgid "File not found" +msgstr "Filen kan inte hittas" + +#: Common/Package.vala:133 Common/Package.vala:195 +#, c-format +msgid "File not found: %s" +msgstr "Filen kunde inte hittas: %s" + +#: Gtk/SettingsDialog.vala:178 +msgid "Hide kernels older than 4.0" +msgstr "Dölj kärnor, äldre än 4.0" + +#: Gtk/SettingsDialog.vala:167 +msgid "Hide unstable and RC releases" +msgstr "Dölj instabila- och RC-publiceringar" + +#: Gtk/SettingsDialog.vala:151 +msgid "Hour(s)" +msgstr "Timma(r)" + +#: Gtk/UpdateNotificationWindow.vala:178 +msgid "Ignore this update" +msgstr "Undanta denna uppdatering" + +#: Common/LinuxKernel.vala:251 +msgid "Index is fresh" +msgstr "Index är uppdaterat" + +#: Common/LinuxKernel.vala:248 +msgid "Index is stale" +msgstr "Index är inaktuellt" + +#: Gtk/MainWindow.vala:370 Gtk/UpdateNotificationWindow.vala:145 +msgid "Install" +msgstr "Installera" + +#: Console/AppConsole.vala:87 +msgid "Install specified mainline kernel" +msgstr "Installera specificerad kärna" + +#: Gtk/UpdateNotificationWindow.vala:146 +msgid "Install this kernel" +msgstr "Installera denna kärna" + +#: Common/LinuxKernel.vala:1165 +msgid "Installation completed with errors" +msgstr "Installation slutförd med fel" + +#: Common/LinuxKernel.vala:1162 +msgid "Installation completed. A reboot is required to use the new kernel." +msgstr "Installation slutförd. Omstart krävs för att tillämpa den nya kärnan." + +#: Gtk/MainWindow.vala:221 Common/LinuxKernel.vala:1076 +msgid "Installed" +msgstr "Installerad" + +#: Gtk/MainWindow.vala:505 Console/AppConsole.vala:340 +msgid "Internet connection is not active" +msgstr "Internetuppkopplingen är inte aktiv" + +#: Gtk/MainWindow.vala:133 +msgid "Kernel" +msgstr "Kärna" + +#: Gtk/MainWindow.vala:489 +msgid "Kernel upgrade utility for Ubuntu-based distributions" +msgstr "Kärnuppgraderingsverktyg för Ubuntu-baserade distributioner" + +#: Console/AppConsole.vala:86 +msgid "List all available mainline kernels" +msgstr "Lista alla tillgängliga kärnor" + +#: Gtk/GtkHelper.vala:169 +msgid "Missing Icon" +msgstr "Saknad ikon" + +#: Console/AppConsole.vala:334 +msgid "No updates found" +msgstr "Inga uppdateringar hittades" + +#: Gtk/SettingsDialog.vala:67 +msgid "Notification" +msgstr "Avisering" + +#: Gtk/SettingsDialog.vala:73 +msgid "Notify if a major release is available" +msgstr "Meddela om en ny (stor) uppdatering finns tillgänglig" + +#: Gtk/SettingsDialog.vala:84 +msgid "Notify if a point release is available" +msgstr "Meddela om en ny (mindre) uppdatering finns tillgänglig" + +#: Console/AppConsole.vala:85 +msgid "Notify if kernel update is available" +msgstr "Meddela om en kärnuppdatering finns tillgänglig" + +#: Gtk/DonationWindow.vala:96 Common/LinuxKernel.vala:1112 +#, c-format +msgid "OK" +msgstr "OK" + +#: Gtk/UpdateNotificationWindow.vala:162 +msgid "Open" +msgstr "Öppna" + +#: Gtk/UpdateNotificationWindow.vala:163 +msgid "Open Ukuu" +msgstr "Öppna Ukuu" + +#: Gtk/AppGtk.vala:179 Console/AppConsole.vala:82 +msgid "Options" +msgstr "Alternativ" + +#: Common/Main.vala:106 +msgid "Please install required packages and try again" +msgstr "Installera nödvändiga paket och försök igen" + +#: Gtk/AppGtk.vala:181 +msgid "Print debug information" +msgstr "Skriv ut felsökningsinformation" + +#: Gtk/MainWindow.vala:509 +msgid "Refreshing..." +msgstr "Uppdaterar ..." + +#: Gtk/MainWindow.vala:381 +msgid "Remove" +msgstr "Ta bort" + +#: Console/AppConsole.vala:91 +msgid "Remove files from application cache" +msgstr "Ta bort filer från program-cachen" + +#: Console/AppConsole.vala:88 +msgid "Remove specified mainline kernel" +msgstr "Ta bort specificerad kärna" + +#: Gtk/AppGtk.vala:105 +msgid "Root Access Required" +msgstr "Root-åtkomst krävs" + +#: Gtk/AppGtk.vala:103 +msgid "Root access is required for running this application." +msgstr "Root-åtkomst krävs för att använda det här programmet" + +#: Console/AppConsole.vala:204 +msgid "Run 'ukuu --list' and use the version string listed in first column" +msgstr "" +"Kör \"ukuu --list\" och använd den versionssträng som listas i första " +"kolumnen" + +#: Gtk/AppGtk.vala:104 Console/AppConsole.vala:99 +msgid "Run the application as root or using gksu/sudo." +msgstr "Kör programmet som root, eller använd gksu/sudo." + +#: Gtk/MainWindow.vala:221 Common/LinuxKernel.vala:1076 +msgid "Running" +msgstr "Körs" + +#: Gtk/DonationWindow.vala:82 +msgid "Send Email" +msgstr "Skicka e-post" + +#: Gtk/MainWindow.vala:428 Gtk/SettingsDialog.vala:57 +msgid "Settings" +msgstr "Inställningar" + +#: Gtk/AppGtk.vala:182 +msgid "Show all options" +msgstr "Visa alla alternativ" + +#: Gtk/SettingsDialog.vala:95 +msgid "Show notification bubble on desktop" +msgstr "Visa aviseringsruta på skrivbordet" + +#: Gtk/SettingsDialog.vala:106 +msgid "Show notification dialog" +msgstr "Visa aviseringsdialog" + +#: Gtk/MainWindow.vala:209 +msgid "Status" +msgstr "Status" + +#: Common/Utility.vala:1232 +msgid "Stopped" +msgstr "Stoppad" + +#: Gtk/AppGtk.vala:177 Console/AppConsole.vala:80 +msgid "Syntax" +msgstr "Syntax" + +#: Common/LinuxKernel.vala:102 +msgid "System architecture" +msgstr "Systemarkitektur" + +#: Gtk/AboutWindow.vala:340 +#, c-format +msgid "Third Party Tools & Software" +msgstr "Tredjepartsverktyg & mjukvara" + +#: Gtk/MainWindow.vala:602 Common/LinuxKernel.vala:1134 +msgid "This kernel is already installed." +msgstr "Denna kärna är redan installerad" + +#: Common/LinuxKernel.vala:1179 +msgid "" +"This kernel is currently running and cannot be removed.\n" +" Install another kernel before removing this one." +msgstr "" +"Denna kärna används för tillfället och kan inte tas bort.\n" +"Installera en annan kärna innan du tar bort den här." + +#: Gtk/AboutWindow.vala:332 +#, c-format +msgid "Translators" +msgstr "Översättare" + +#: Common/LinuxKernel.vala:1219 +msgid "Un-install completed" +msgstr "Avinstallation slutförd" + +#: Common/LinuxKernel.vala:1222 +msgid "Un-install completed with errors" +msgstr "Avinstallation slutförd med fel" + +#: Gtk/AppGtk.vala:165 Console/AppConsole.vala:239 +msgid "Unknown option" +msgstr "Okänt alternativ" + +#: Console/AppConsole.vala:90 +msgid "Use specified user's cache directory" +msgstr "Använd specificerad användares cache-mapp" + +#: Gtk/AppGtk.vala:113 Gtk/AppGtk.vala:131 Console/AppConsole.vala:140 +msgid "Using cache directory" +msgstr "Använder cache-mapp" + +#: Gtk/MainWindow.vala:182 +msgid "Version" +msgstr "Version" + +#: Gtk/DonationWindow.vala:89 +msgid "Visit Website" +msgstr "Besök hemsidan" + +#: Common/Utility.vala:100 +msgid "W" +msgstr "V" + +#: Gtk/SettingsDialog.vala:155 +msgid "Week(s)" +msgstr "Veckor" diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/CronTab.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/CronTab.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/CronTab.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/CronTab.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ - -using TeeJee.Logging; -using TeeJee.FileSystem; -//using TeeJee.JSON; -using TeeJee.ProcessManagement; -//using TeeJee.Multimedia; -//using TeeJee.System; -using TeeJee.Misc; - -public class CronTab : GLib.Object { - - private static string crontab_read_all(){ - string std_out, std_err; - var cmd = "crontab -l"; - int ret_val = exec_sync(cmd, out std_out, out std_err); - - if (ret_val != 0){ - log_debug(_("Failed to read cron tab")); - return ""; - } - else{ - return std_out; - } - } - - public static bool add_job(string entry){ - // read crontab file - string tab = crontab_read_all(); - var lines = new Gee.ArrayList(); - foreach(string line in tab.split("\n")){ - lines.add(line); - } - - // check if entry exists - foreach(string line in lines){ - if (line == entry){ - return true; // return - } - } - - // append entry - lines.add(entry); - - // create new tab - string tab_new = ""; - foreach(string line in lines){ - if (line.length > 0){ - tab_new += "%s\n".printf(line); - } - } - - // write temp crontab file - string temp_file = get_temp_file_path(); - file_write(temp_file, tab_new); - - // install crontab file - var cmd = "crontab \"%s\"".printf(temp_file); - int status = exec_sync(cmd); - - if (status != 0){ - log_error(_("Failed to add cron job") + ": %s".printf(entry)); - return false; - } - else{ - log_msg(_("Cron job added") + ": %s".printf(entry)); - return true; - } - } - - public static bool remove_job(string entry){ - // read crontab file - string tab = crontab_read_all(); - var lines = new Gee.ArrayList(); - foreach(string line in tab.split("\n")){ - lines.add(line); - } - - // check if entry exists - bool found = false; - for(int i=0; i < lines.size; i++){ - string line = lines[i]; - if (line != null){ - line = line.strip(); - } - if (line == entry){ - lines.remove(line); - found = true; - } - } - if (!found){ - return true; - } - - // create new tab - string tab_new = ""; - foreach(string line in lines){ - if (line.length > 0){ - tab_new += "%s\n".printf(line); - } - } - - // write temp crontab file - string temp_file = get_temp_file_path(); - file_write(temp_file, tab_new); - - // install crontab file - var cmd = "crontab \"%s\"".printf(temp_file); - int status = exec_sync(cmd); - - if (status != 0){ - log_error(_("Failed to remove cron job") + ": %s".printf(entry)); - return false; - } - else{ - log_msg(_("Cron job removed") + ": %s".printf(entry)); - return true; - } - } -} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/DownloadManager.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/DownloadManager.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/DownloadManager.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/DownloadManager.vala 2016-12-07 16:47:10.000000000 +0000 @@ -1,13 +1,11 @@ using TeeJee.Logging; using TeeJee.FileSystem; -//using TeeJee.JSON; -using TeeJee.ProcessManagement; -//using TeeJee.Multimedia; -//using TeeJee.System; +using TeeJee.ProcessHelper; using TeeJee.Misc; -public class DownloadManager : GLib.Object{ + +public class DownloadTask : AsyncTask{ public string name = ""; public string file_name = ""; public string download_dir = ""; @@ -15,80 +13,65 @@ public string source_uri = ""; public int64 size = 0; public int64 download_rate = 0; + public string md5hash = ""; + + // settings + public bool status_in_kb = false; public int connect_timeout_secs = 60; public int timeout_secs = 60; - public string md5hash = ""; - public Status status = Status.PENDING; + public int concurrent_downloads = 20; - public Gee.ArrayList stdout_lines; - public Gee.ArrayList stderr_lines; - - public Pid proc_id; - public DataInputStream dis_out; - public DataInputStream dis_err; - public int64 progress_count = 0; - public int64 progress_total = 0; - public double progress_percent = 0.0; - public string eta = ""; - - public bool is_running = false; - public string temp_dir = ""; - public string command = ""; - public string err_line = ""; - public string out_line = ""; - public string status_line = ""; + public Gee.ArrayList downloads; - private static int _download_count = 0; + private Gee.HashMap regex = null; - // settings - public bool status_in_kb = false; - - // exit status - public int status_code = 0; - public string status_message = ""; - - private Regex regex = null; - private MatchInfo match; + public DownloadTask(){ - Pid child_pid; - int input_fd; - int output_fd; - int error_fd; - - public signal void download_complete(); - - public enum Status{ - PENDING, - STARTED, - FINISHED, - ERROR - } - - public DownloadManager( - string _file_name, - string _download_dir, - string? _partial_dir , - string _source_uri){ - - file_name = _file_name; - download_dir = _download_dir; - partial_dir = (_partial_dir == null) ? create_temp_subdir() : _partial_dir; - source_uri = _source_uri; - name = _file_name.split("_")[0]; + base(); + + downloads = new Gee.ArrayList(); + regex = new Gee.HashMap(); + try { //Sample: //[#4df0c7 19283968B/45095814B(42%) CN:1 DL:105404B ETA:4m4s] - regex = new Regex("""^[^ \t]+[ \t]+([0-9]+)B\/([0-9]+)B\(([0-9]+)%\)[ \t]+[^ \t]+[ \t]+DL\:([0-9]+)B[ \t]+ETA\:([^ \]]+)]"""); + regex["file-progress"] = new Regex("""^[^ \t]+[ \t]+([0-9]+)B\/([0-9]+)B\(([0-9]+)%\)[ \t]+[^ \t]+[ \t]+DL\:([0-9]+)B[ \t]+ETA\:([^ \]]+)]"""); + + //12/03 21:15:33 [NOTICE] Download complete: /home/teejee/.cache/ukuu/v4.7.8/CHANGES + regex["file-complete"] = new Regex("""[0-9A-Z\/: ]*\[NOTICE\] Download complete\: (.*)"""); + + //8ae3a3|OK | 16KiB/s|/home/teejee/.cache/ukuu/v4.0.7-wily/index.html + //bea740|OK | n/a|/home/teejee/.cache/ukuu/v4.0.9-wily/CHANGES + regex["file-status"] = new Regex("""^([0-9A-Za-z]+)\|(OK|ERR)[ ]*\|[ ]*(n\/a|[0-9.]+[A-Za-z\/]+)\|(.*)"""); } catch (Error e) { log_error (e.message); } } + + // execution ---------------------------- - private string build_command_string(){ - string cmd = ""; + public void execute() { + + prepare(); + + begin(); + + if (status == AppStatus.RUNNING){ + + + } + } + public void prepare() { + string script_text = build_script(); + save_bash_script_temp(script_text, script_file); + } + + private string build_script() { + string cmd = ""; + var command = "wget"; var cmd_path = get_cmd_path ("aria2c"); if ((cmd_path != null) && (cmd_path.length > 0)) { @@ -96,309 +79,177 @@ } if (command == "aria2c"){ + + string list = ""; + string list_file = path_combine(working_dir, "download.list"); + foreach(var item in downloads){ + list += "%s\n".printf(item.source_uri); + list += " dir=%s\n".printf(item.download_dir); + list += " out=%s\n".printf(item.file_name); + dir_create(item.download_dir); + } + file_write(list_file, list); + cmd += "aria2c"; - cmd += " -d '%s'".printf(partial_dir); - cmd += " -o '%s'".printf(file_name); + cmd += " -i '%s'".printf(escape_single_quote(list_file)); cmd += " --show-console-readout=false"; cmd += " --summary-interval=1"; + cmd += " --auto-save-interval=1"; // save aria2 control file every sec cmd += " --human-readable=false"; + cmd += " --enable-color=false"; // enabling color breaks the output parsing cmd += " --allow-overwrite"; cmd += " --connect-timeout=%d".printf(connect_timeout_secs); cmd += " --timeout=%d".printf(timeout_secs); - //cmd += " --direct-file-mapping=false"; - cmd += " '%s'".printf(source_uri); + cmd += " --max-concurrent-downloads=%d".printf(concurrent_downloads); + //cmd += " --continue"; // never use - this is for continuing files downloaded sequentially by web browser and other programs + //cmd += " --optimize-concurrent-downloads=true"; // not supported by all versions + //cmd += " -l download.log"; // too much logging + //cmd += " --direct-file-mapping=false"; // not required + //cmd += " --dry-run"; } log_debug(cmd); - //cmd = "apt-get update"; - return cmd; } - private string save_script(string cmd){ - var script = new StringBuilder(); - script.append ("#!/bin/bash\n"); - script.append ("\n"); - script.append ("LANG=C\n"); - script.append ("\n"); - script.append ("%s\n".printf(cmd)); - script.append ("\n\nexitCode=$?\n"); - script.append ("echo ${exitCode} > ${exitCode}\n"); - script.append ("echo ${exitCode} > status\n"); - - temp_dir = "%s/%s%ld".printf(TEMP_DIR, timestamp_for_path(), GLib.Random.next_int()); - - var script_file = temp_dir + "/script.sh"; - //log_msg("%s: %s".printf(name,script_file)); - dir_create (temp_dir); - - try { - // create new script file - var file = File.new_for_path(script_file); - var file_stream = file.create(FileCreateFlags.REPLACE_DESTINATION); - var data_stream = new DataOutputStream(file_stream); - data_stream.put_string(script.str); - data_stream.close(); - data_stream = null; - - //set execute permission - chmod(script_file, "u+x"); + public override void parse_stdout_line(string out_line){ + if (is_terminated) { + return; } - catch (Error e) { - log_error (e.message); + + update_progress_parse_console_output(out_line); + } + + public override void parse_stderr_line(string err_line){ + if (is_terminated) { + return; } - - return script_file; + + update_progress_parse_console_output(err_line); } - public bool download_begin() { - - lock (_download_count) { - _download_count++; + public bool update_progress_parse_console_output (string line) { + if ((line == null) || (line.length == 0)) { + return true; } - status = DownloadManager.Status.STARTED; + //log_msg(line); - dir_create(partial_dir); - dir_create(download_dir); - - string src_path = "%s/%s".printf(partial_dir,file_name); - string dst_path = "%s/%s".printf(download_dir,file_name); + MatchInfo match; - if (file_exists(src_path)){ - file_delete(src_path); - } - - if (file_exists(dst_path)){ - file_delete(dst_path); + if (regex["file-complete"].match(line, 0, out match)) { + //log_msg("match: file-complete: " + line); + prg_count++; + } + else if (regex["file-status"].match(line, 0, out match)) { + + // always display + //log_msg(line); + + string hash = match.fetch(1).strip(); + string status = match.fetch(2).strip(); + //string rate = match.fetch(3).strip(); + string file = match.fetch(4).strip(); + foreach(var item in downloads){ + if (item.file_path == file){ + item.hash = hash; + item.status = status; + break; + } + } } - - string[] argv = new string[1]; - string cmd = build_command_string(); - argv[0] = save_script(cmd); + else if (regex["file-progress"].match(line, 0, out match)) { - progress_count = 0; - progress_total = size; - - try { - //execute script file - Process.spawn_async_with_pipes( - temp_dir, //working dir - argv, //argv - null, //environment - SpawnFlags.SEARCH_PATH, - null, // child_setup - out child_pid, - out input_fd, - out output_fd, - out error_fd); + //log_msg("match: file-status: " + line); - is_running = true; + // Note: HTML files don't have content length, so byte count will be 0 - //create stream readers - UnixInputStream uis_out = new UnixInputStream(output_fd, false); - UnixInputStream uis_err = new UnixInputStream(error_fd, false); - dis_out = new DataInputStream(uis_out); - dis_err = new DataInputStream(uis_err); - dis_out.newline_type = DataStreamNewlineType.ANY; - dis_err.newline_type = DataStreamNewlineType.ANY; - - //progress_count = 0; - stdout_lines = new Gee.ArrayList(); - stderr_lines = new Gee.ArrayList(); - - try { - //start thread for reading output stream - Thread.create (read_output_line, true); - } catch (Error e) { - log_error (e.message); - } - - try { - //start thread for reading error stream - Thread.create (read_error_line, true); - } catch (Error e) { - log_error (e.message); - } - - return true; - } - catch (Error e) { - log_error (e.message); - return false; - } - } - - private void read_error_line() { - try { - err_line = dis_err.read_line (null); - while (err_line != null) { - if (err_line.length > 0){ - //stderr_lines.add(err_line); - //status_line = err_line; - log_msg("E: %s".printf(err_line)); + if (downloads.size == 1){ + prg_count = long.parse(match.fetch(1).strip()); + size = long.parse(match.fetch(2).strip()); + percent = double.parse(match.fetch(3).strip()); + download_rate = long.parse(match.fetch(4).strip()); + eta = match.fetch(5).strip(); + + if (status_in_kb){ + status_line = "%s / %s, %s/s (%s)".printf( + format_file_size(prg_count, false, "", true, 1), + format_file_size(size, false, "", true, 1), + format_file_size(download_rate, false, "", true, 1), + eta).replace("\n",""); + } + else{ + status_line = "%s / %s, %s/s (%s)".printf( + format_file_size(prg_count), + format_file_size(size), + format_file_size(download_rate), + eta).replace("\n",""); } - err_line = dis_err.read_line (null); //read next } - - // dispose stderr - dis_err.close(); - dis_err = null; - GLib.FileUtils.close(error_fd); + + //log_msg(status_line); } - catch (Error e) { - log_error (e.message); + else { + //log_msg("unmatched: '%s'".printf(line)); } + + return true; } - private void read_output_line() { - try { - out_line = dis_out.read_line (null); - while (out_line != null) { - if (out_line.length > 0){ - //log_msg("%s".printf(out_line)); - parse_output(); - } - out_line = dis_out.read_line (null); //read next - } - - //log_msg("exit thread"); - - progress_count = size; - progress_percent = 100; - - // cleanup ----------------- - - // dispose stdout - GLib.FileUtils.close(output_fd); - dis_out.close(); - dis_out = null; - - // dispose stdin - GLib.FileUtils.close(input_fd); - - // dispose child process - Process.close_pid(child_pid); //required on Windows, doesn't do anything on Unix + protected override void finish_task(){ + + verify(); - // finish ------------------ - - verify_and_copy(); - } - catch (Error e) { - log_error (e.message); - } + dir_delete(working_dir); } - public void parse_output() { - if (status != Status.STARTED){ - return; - } - if ((out_line == null) || (out_line.length == 0)){ - return; - } - - if (regex.match(out_line, 0, out match)) { - progress_count = long.parse(match.fetch(1).strip()); - size = long.parse(match.fetch(2).strip()); - progress_percent = double.parse(match.fetch(3).strip()); - download_rate = long.parse(match.fetch(4).strip()); - eta = match.fetch(5).strip(); - - if (status_in_kb){ - status_line = "%s / %s, %s/s (%s)".printf( - format_file_size(progress_count, false, true), - format_file_size(size, false, true), - format_file_size(download_rate, false, true), - eta).replace("\n",""); + private void verify() { + foreach(var item in downloads){ + if (item.status != "OK"){ + file_delete(item.file_path); } - else{ - status_line = "%s / %s, %s/s (%s)".printf( - format_file_size(progress_count), - format_file_size(size), - format_file_size(download_rate), - eta).replace("\n",""); - } - - //log_msg(status_line); } } public int read_status(){ - var path = temp_dir + "/status"; - var f = File.new_for_path(path); + var status_file = working_dir + "/status"; + var f = File.new_for_path(status_file); if (f.query_exists()){ - var txt = file_read(path); + var txt = file_read(status_file); return int.parse(txt); } return -1; } +} - private void verify_and_copy() { - status_code = read_status(); - - if (status_code == 0){ - string src_path = "%s/%s".printf(partial_dir,file_name); - string dst_path = "%s/%s".printf(download_dir,file_name); - if (file_exists(src_path)){ - file_move(src_path,dst_path); - } - else{ - log_error("Download Manager: " + _("File not found") + ": '%s'".printf(src_path)); - } - - //log_debug("\nMoving '%s' to '%s'".printf(src_path, dst_path)); - status_line = "OK"; - status = DownloadManager.Status.FINISHED; - } - else{ - //leave the partial file - switch(status_code){ - case 1: - status_line = "ERROR: Unknown"; - break; - case 2: - status_line = "ERROR: Network Time-out"; - break; - case 3: - status_line = "ERROR: 404 Not Found"; - break; - case 6: - status_line = "ERROR: Network Problem"; - break; - default: - status_line = "ERROR: Unknown"; - break; - } - - status = DownloadManager.Status.ERROR; - } - - status_message = status_line; - - lock (_download_count) { - _download_count--; - } - - download_complete(); //signal - is_running = false; - } +public class DownloadItem : GLib.Object +{ + public string file_name = ""; + public string download_dir = ""; + public string partial_dir = ""; + public string source_uri = ""; + public int64 size = 0; + public int64 downloaded_bytes = 0; + public string hash = ""; + public string status = ""; - public static int download_count{ - get { - int count = 0; - lock (_download_count) { - count = _download_count; - } - return count; + public string file_path{ + owned get{ + return path_combine(download_dir, file_name); } } - - public static void reset_counter(){ - lock (_download_count) { - _download_count = 0; - } + + public DownloadItem( + string _source_uri, + string _download_dir, + string _file_name + ){ + + file_name = _file_name; + download_dir = _download_dir; + partial_dir = create_temp_subdir(); + source_uri = _source_uri; } } - diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/LinuxKernel.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/LinuxKernel.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/LinuxKernel.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/LinuxKernel.vala 2016-12-07 16:47:10.000000000 +0000 @@ -1,7 +1,7 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.System; using TeeJee.Misc; @@ -14,9 +14,9 @@ public string type = ""; public string page_uri = ""; - public int version_maj; - public int version_min; - public int version_point; + public int version_maj = -1; + public int version_min = -1; + public int version_point = -1; public Gee.HashMap deb_list = new Gee.HashMap(); public Gee.HashMap apt_pkg_list = new Gee.HashMap(); @@ -59,8 +59,8 @@ // global progress ------------ public static string status_line = ""; - public static int progress_total = 0; - public static int progress_count = 0; + public static int64 progress_total = 0; + public static int64 progress_count = 0; public static bool cancelled = false; public static bool task_is_running = false; public static bool _temp_refresh = false; @@ -202,8 +202,10 @@ is_mainline = _is_mainline; } - public LinuxKernel.from_version(string version){ - + public LinuxKernel.from_version(string _version){ + + version = _version; + name = "v" + version; split_version_string(version, out version_main, out version_extra); @@ -238,7 +240,7 @@ log_debug("query: skip_older: %s".printf(skip_older.to_string())); log_debug("query: skip_unstable: %s".printf(skip_unstable.to_string())); - DownloadManager.reset_counter(); + //DownloadManager.reset_counter(); bool refresh = false; var one_hour_before = (new DateTime.now_local()).add_hours(-1); @@ -273,10 +275,14 @@ } if (kern.is_valid && !kern.cached_page_exists){ - progress_total++; + progress_total += 2; } } + + var downloads = new Gee.ArrayList(); + var kernels_to_update = new Gee.ArrayList(); + foreach(var kern in kernel_list){ if (cancelled){ break; @@ -304,21 +310,43 @@ } if (!kern.cached_page_exists){ - while (DownloadManager.download_count > 20){ - sleep(100); // wait for counter to decrease - } - kern.download_cached_page(false); - progress_count++; + + var item = new DownloadItem( + kern.cached_page_uri, + file_parent(kern.cached_page), + file_basename(kern.cached_page)); + + downloads.add(item); + + item = new DownloadItem( + kern.changes_file_uri, + file_parent(kern.changes_file), + file_basename(kern.changes_file)); + + downloads.add(item); + + kernels_to_update.add(kern); } } - // No need to wait for downloads to complete - // Cached index files will be loaded once downloads is complete + if (downloads.size > 0){ + + var mgr = new DownloadTask(); + mgr.downloads = downloads; + mgr.status_in_kb = true; + mgr.prg_count_total = progress_total; + mgr.execute(); + + while (mgr.is_running()){ + progress_count = mgr.prg_count; + sleep(300); + } - if (DownloadManager.download_count > 0){ - sleep(1000); // wait a sec + foreach(var kern in kernels_to_update){ + kern.load_cached_page(); + } } - + check_installed(); check_updates(); @@ -337,20 +365,19 @@ if (file_exists(index_page)){ file_delete(index_page); } - - var mgr = new DownloadManager( - "index.html", - CACHE_DIR, - create_temp_subdir(), - URI_KERNEL_UBUNTU_MAINLINE); + + var item = new DownloadItem(URI_KERNEL_UBUNTU_MAINLINE, CACHE_DIR, "index.html"); + var mgr = new DownloadTask(); + mgr.downloads.add(item); + mgr.status_in_kb = true; + mgr.execute(); - mgr.download_begin(); var msg = _("Fetching index from kernel.ubuntu.com..."); log_msg(msg); status_line = msg.strip(); - while (mgr.is_running){ + while (mgr.is_running()){ sleep(500); } @@ -581,6 +608,11 @@ continue; } + if (kernel_latest_stable == null){ + kernel_latest_stable = kern; + log_debug("latest stable kernel -> %s".printf(kern.version_main)); + } + // skip installed if (kern.is_installed){ continue; @@ -588,26 +620,18 @@ //log_msg("check: %s".printf(kern.version_main)); - if (kernel_latest_stable == null){ - kernel_latest_stable = kern; - log_debug("latest stable kernel -> %s".printf(kern.version_main)); - } - bool major_available = false; bool minor_available = false; - string[] arr = kern.version_main.split_set (".-"); - string[] arr_r = kern_running.version_main.split_set (".-"); - - if (arr[0] > arr_r[0]){ + if (kern.version_maj > kern_running.version_maj){ major_available = true; } - else if (arr[0] == arr_r[0]){ - if (arr[1] > arr_r[1]){ + else if (kern.version_maj == kern_running.version_maj){ + if (kern.version_min > kern_running.version_min){ major_available = true; } - else if (arr[1] == arr_r[1]){ - if (arr[2] > arr_r[2]){ + else if (kern.version_min == kern_running.version_min){ + if (kern.version_point > kern_running.version_point){ minor_available = true; } } @@ -657,10 +681,19 @@ ver_main = ver_main[1:ver_main.length]; } + version_maj = int.parse(ver_main); + // append all numbers which are 3 digits or less while (i < arr.length){ if (is_numeric(arr[i]) && (arr[i].length <= 3)){ - ver_main += ".%s".printf(arr[i++]); + ver_main += ".%s".printf(arr[i]); + if (version_min == -1){ + version_min = int.parse(arr[i]); + } + else if (version_point == -1){ + version_point = int.parse(arr[i]); + } + i++; } else{ break; @@ -703,7 +736,7 @@ } } - //log_debug("split: %s, version_main: %s".printf(version_string, ver_main)); + //log_debug("split: %s, version_main: %s, maj/min/point: %d,%d,%d".printf(version_string, ver_main, version_maj, version_min, version_point)); } public int compare_to(LinuxKernel b){ @@ -837,11 +870,23 @@ } } + public string cached_page_uri{ + owned get { + return page_uri; + } + } + public string changes_file{ owned get { return "%s/CHANGES".printf(cache_subdir); } } + + public string changes_file_uri{ + owned get { + return "%s%s".printf(page_uri, "CHANGES"); + } + } public bool cached_page_exists{ get { @@ -869,100 +914,10 @@ } } - // download - - private bool download_cached_page(bool wait){ - - // fetch index-.html -------------------------------------- - - dir_create(file_parent(cached_page)); - - if (file_exists(cached_page)){ - return true; // do not download again - } - else if (!is_valid){ - return true; - } - - var mgr = new DownloadManager( - file_basename(cached_page), - cache_subdir, - create_temp_subdir(), - page_uri); - - mgr.download_complete.connect(() => { - if (mgr.status_code == 0){ - load_cached_page(); - download_changes_file(); - } - else if (mgr.status_code == 3){ - file_write("%s/index.html.404".printf(cache_subdir), ""); - mark_invalid(); - } - else{ - file_write("%s/index.html.%d".printf(cache_subdir, mgr.status_code), ""); - mark_invalid(); - } - }); - - mgr.connect_timeout_secs = 10; - mgr.timeout_secs = 10; - - mgr.download_begin(); - - var msg = "%-60s".printf(_("Fetching index for") + " '%s'... ".printf(name)); - log_msg(msg); - status_line = "> Linux %s".printf(name); - - return true; - } - - private bool download_changes_file(){ - - // fetch file -------------------------------------- - - dir_create(file_parent(changes_file)); - - if (file_exists(changes_file)){ - return true; // do not download again - } - - var mgr = new DownloadManager( - file_basename(changes_file), - file_parent(changes_file), - create_temp_subdir(), - "%s%s".printf(page_uri, "CHANGES")); - - mgr.download_complete.connect(() => { - if (mgr.status_code == 0){ - // do nothing - } - else if (mgr.status_code == 3){ - file_write("%s.%s".printf(changes_file, "404"), ""); - mark_invalid(); - } - else{ - file_write("%s.%d".printf(changes_file, mgr.status_code), ""); - mark_invalid(); - } - }); - - mgr.connect_timeout_secs = 10; - mgr.timeout_secs = 10; - - mgr.download_begin(); - - var msg = "%-60s".printf(_("Fetching changelog for") + " '%s'... ".printf(name)); - log_msg(msg); - status_line = "> Linux %s".printf(name); - - return true; - } - // load private void load_cached_page(){ - + var list = new Gee.HashMap(); if (!file_exists(cached_page)){ @@ -1021,7 +976,8 @@ catch (Error e) { log_error (e.message); } - + + deb_list = list; } @@ -1089,7 +1045,7 @@ foreach(string file_name in deb_list.keys){ string file_path = "%s/%s/%s".printf(cache_subdir, NATIVE_ARCH, file_name); - if (file_exists(file_path)){ + if (file_exists(file_path) && !file_exists(file_path + ".aria2c")){ continue; } @@ -1097,12 +1053,14 @@ stdout.printf("\n" + _("Downloading") + ": '%s'... \n".printf(file_name)); stdout.flush(); - - var mgr = new DownloadManager(file_basename(file_path), file_parent(file_path), TEMP_DIR, deb_list[file_name]); + + var item = new DownloadItem(deb_list[file_name], file_parent(file_path), file_basename(file_path)); + var mgr = new DownloadTask(); + mgr.downloads.add(item); mgr.status_in_kb = true; - mgr.download_begin(); + mgr.execute(); - while (mgr.is_running){ + while (mgr.is_running()){ sleep(200); stdout.printf("\r%-60s".printf(mgr.status_line.replace("\n",""))); @@ -1227,7 +1185,5 @@ return ok; } - - } diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Main.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/Main.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Main.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/Main.vala 2016-12-07 16:47:10.000000000 +0000 @@ -28,9 +28,8 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.Multimedia; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.System; using TeeJee.Misc; @@ -50,8 +49,8 @@ // global progress ---------------- public string status_line = ""; - public int progress_total = 0; - public int progress_count = 0; + public int64 progress_total = 0; + public int64 progress_count = 0; public bool cancelled = false; // state flags ---------- @@ -162,12 +161,12 @@ // change owner to current user so that ukuu can access in normal mode chown(APP_CONFIG_FILE, user_login, user_login); + update_notification_files(); + } + + public void update_notification_files(){ update_startup_script(); update_startup_desktop_file(); - - if (user_is_admin()){ - remove_cron_jobs(); - } } public void load_app_config(){ @@ -204,18 +203,6 @@ // begin ------------ - public void remove_cron_jobs(){ - CronTab.remove_job(get_crontab_entry_scheduled()); - CronTab.remove_job(get_crontab_entry_boot()); - } - - private string get_crontab_entry_scheduled(){ - return "@daily ukuu --notify"; - } - - private string get_crontab_entry_boot(){ - return "@reboot sleep %dm && ukuu --notify".printf(20); - } private void update_startup_script(){ @@ -242,7 +229,7 @@ txt += "sleep %ds\n".printf(startup_delay); txt += "while true\n"; txt += "do\n"; - txt += " ukuu --notify && sleep %d%s \n".printf(count, suffix); + txt += " ukuu --notify ; sleep %d%s \n".printf(count, suffix); txt += "done\n"; if (file_exists(STARTUP_SCRIPT_FILE)){ @@ -289,5 +276,24 @@ file_delete(STARTUP_DESKTOP_FILE); } } + + public void fix_startup_script_error(){ + + /* This fixes a critical issue with startup script in versions prior to Ukuu v16.12 */ + + if (!file_exists(STARTUP_SCRIPT_FILE)){ + return; + } + + if (!file_read(STARTUP_SCRIPT_FILE).contains("&&")){ + return; + } + + update_startup_script(); + + process_quit_by_name("sh", "ukuu-notify.sh", false); + + // don't start script again + } } diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Package.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/Package.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Package.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/Package.vala 2016-12-07 16:47:10.000000000 +0000 @@ -1,7 +1,7 @@ using TeeJee.Logging; using TeeJee.FileSystem; -//using TeeJee.JSON; -using TeeJee.ProcessManagement; +//using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; //using TeeJee.Multimedia; //using TeeJee.System; using TeeJee.Misc; diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Utility.vala ukuu-16.12~57~ubuntu16.10.1/src/Common/Utility.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Common/Utility.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Common/Utility.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,2823 +0,0 @@ -/* - * Utility.vala - * - * Copyright 2012 Tony George - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ - -using Gtk; -using Json; -using TeeJee.Logging; -using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.Multimedia; -using TeeJee.System; -using TeeJee.Misc; - -/* -extern void exit(int exit_code); -*/ - -namespace TeeJee.Logging{ - - /* Functions for logging messages to console and log files */ - - using TeeJee.Misc; - - public DataOutputStream dos_log; - public string err_log; - public bool LOG_ENABLE = true; - public bool LOG_TIMESTAMP = true; - public bool LOG_COLORS = true; - public bool LOG_DEBUG = false; - public bool LOG_COMMANDS = false; - - public void log_msg (string message, bool highlight = false){ - - if (!LOG_ENABLE) { return; } - - string msg = ""; - - if (highlight && LOG_COLORS){ - msg += "\033[1;38;5;34m"; - } - - if (LOG_TIMESTAMP){ - msg += "[" + timestamp() + "] "; - } - - msg += message; - - if (highlight && LOG_COLORS){ - msg += "\033[0m"; - } - - msg += "\n"; - - stdout.printf (msg); - stdout.flush(); - - try { - if (dos_log != null){ - dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); - } - } - catch (Error e) { - stdout.printf (e.message); - } - } - - public void log_error (string message, bool highlight = false, bool is_warning = false){ - if (!LOG_ENABLE) { return; } - - string msg = ""; - - if (highlight && LOG_COLORS){ - msg += "\033[1;38;5;160m"; - } - - if (LOG_TIMESTAMP){ - msg += "[" + timestamp() + "] "; - } - - string prefix = (is_warning) ? _("W") : _("E"); - - msg += prefix + ": " + message; - - if (highlight && LOG_COLORS){ - msg += "\033[0m"; - } - - msg += "\n"; - - stdout.printf (msg); - stdout.flush(); - - try { - string str = "[%s] %s: %s\n".printf(timestamp(), prefix, message); - - if (dos_log != null){ - dos_log.put_string (str); - } - - if (err_log != null){ - err_log += "%s\n".printf(message); - } - } - catch (Error e) { - stdout.printf (e.message); - } - } - - public void log_debug (string message){ - if (!LOG_ENABLE) { return; } - - if (LOG_DEBUG){ - log_msg ("D: " + message); - } - - try { - if (dos_log != null){ - dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); - } - } - catch (Error e) { - stdout.printf (e.message); - } - } - - public void log_draw_line(){ - log_msg(string.nfill(70,'=')); - } - - public void clear_err_log(){ - err_log = ""; - } - - public void disable_err_log(){ - err_log = null; - } -} - -namespace TeeJee.FileSystem{ - - /* Convenience functions for handling files and directories */ - - using TeeJee.Logging; - using TeeJee.ProcessManagement; - using TeeJee.Misc; - - // path helpers ---------------------------- - - public string file_parent(string file_path){ - return File.new_for_path(file_path).get_parent().get_path(); - } - - public string file_basename(string file_path){ - return File.new_for_path(file_path).get_basename(); - } - - // file helpers ----------------------------- - - public bool file_exists (string file_path){ - /* Check if file exists */ - return ( FileUtils.test(file_path, GLib.FileTest.EXISTS) && FileUtils.test(file_path, GLib.FileTest.IS_REGULAR)); - } - - public bool file_delete(string file_path){ - - /* Check and delete file */ - - try { - var file = File.new_for_path (file_path); - if (file.query_exists ()) { - file.delete (); - } - return true; - } catch (Error e) { - log_error (e.message); - log_error(_("Failed to delete file") + ": %s".printf(file_path)); - return false; - } - } - - public string? file_read (string file_path){ - - /* Reads text from file */ - - string txt; - size_t size; - - try{ - GLib.FileUtils.get_contents (file_path, out txt, out size); - return txt; - } - catch (Error e){ - log_error (e.message); - log_error(_("Failed to read file") + ": %s".printf(file_path)); - } - - return null; - } - - public bool file_write (string file_path, string contents){ - - /* Write text to file */ - - try{ - - dir_create(file_parent(file_path)); - - var file = File.new_for_path (file_path); - if (file.query_exists ()) { - file.delete (); - } - - var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); - var data_stream = new DataOutputStream (file_stream); - data_stream.put_string (contents); - data_stream.close(); - return true; - } - catch (Error e) { - log_error (e.message); - log_error(_("Failed to write file") + ": %s".printf(file_path)); - return false; - } - } - - public bool file_copy (string src_file, string dest_file){ - try{ - var file_src = File.new_for_path (src_file); - if (file_src.query_exists()) { - var file_dest = File.new_for_path (dest_file); - file_src.copy(file_dest,FileCopyFlags.OVERWRITE,null,null); - return true; - } - } - catch(Error e){ - log_error (e.message); - log_error(_("Failed to copy file") + ": '%s', '%s'".printf(src_file, dest_file)); - } - - return false; - } - - public void file_move (string src_file, string dest_file){ - try{ - var file_src = File.new_for_path (src_file); - if (file_src.query_exists()) { - var file_dest = File.new_for_path (dest_file); - file_src.move(file_dest,FileCopyFlags.OVERWRITE,null,null); - } - else{ - log_error(_("File not found") + ": '%s'".printf(src_file)); - } - } - catch(Error e){ - log_error (e.message); - log_error(_("Failed to move file") + ": '%s', '%s'".printf(src_file, dest_file)); - } - } - - - // file info ----------------- - - public int64 file_get_size(string file_path){ - try{ - File file = File.parse_name (file_path); - if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){ - if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR) - && !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){ - return file.query_info("standard::size",0).get_size(); - } - } - } - catch(Error e){ - log_error (e.message); - } - - return -1; - } - - public DateTime file_get_modified_date(string file_path){ - try{ - FileInfo info; - File file = File.parse_name (file_path); - if (file.query_exists()) { - info = file.query_info("%s".printf(FileAttribute.TIME_MODIFIED), 0); - return (new DateTime.from_timeval_utc(info.get_modification_time())).to_local(); - } - } - catch (Error e) { - log_error (e.message); - } - - return (new DateTime.from_unix_utc(0)); //1970 - } - - // dir helpers ---------------------- - - public bool dir_exists (string dir_path){ - /* Check if directory exists */ - return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR)); - } - - public bool dir_create (string dir_path){ - - /* Creates a directory along with parents */ - - try{ - var dir = File.parse_name (dir_path); - if (dir.query_exists () == false) { - dir.make_directory_with_parents (null); - } - return true; - } - catch (Error e) { - log_error (e.message); - log_error(_("Failed to create dir") + ": %s".printf(dir_path)); - return false; - } - } - - public bool dir_delete (string dir_path){ - - /* Recursively deletes directory along with contents */ - - string cmd = "rm -rf '%s'".printf(escape_single_quote(dir_path)); - log_debug(cmd); - int status = exec_sync(cmd); - return (status == 0); - } - - public bool dir_is_empty (string dir_path){ - - /* Check if directory is empty */ - - try{ - bool is_empty = true; - var dir = File.parse_name (dir_path); - if (dir.query_exists()) { - FileInfo info; - var enu = dir.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); - while ((info = enu.next_file()) != null) { - is_empty = false; - break; - } - } - return is_empty; - } - catch (Error e) { - log_error (e.message); - return false; - } - } - - - public Gee.ArrayList dir_list_names(string path){ - var list = new Gee.ArrayList(); - - try - { - File f_home = File.new_for_path (path); - FileEnumerator enumerator = f_home.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); - FileInfo file; - while ((file = enumerator.next_file ()) != null) { - string name = file.get_name(); - list.add(name); - } - } - catch (Error e) { - log_error (e.message); - } - - //sort the list - CompareDataFunc entry_compare = (a, b) => { - return strcmp(a,b); - }; - list.sort((owned) entry_compare); - - return list; - } - - public bool dir_tar (string src_dir, string tar_file, bool recursion = true){ - if (dir_exists(src_dir)) { - - if (file_exists(tar_file)){ - file_delete(tar_file); - } - - var src_parent = file_parent(src_dir); - var src_name = file_basename(src_dir); - - string cmd = "tar cvf '%s' --overwrite --%srecursion -C '%s' '%s'\n".printf( - escape_single_quote(tar_file), - (recursion ? "" : "no-"), - escape_single_quote(src_parent), - escape_single_quote(src_name)); - - log_debug(cmd); - - string stdout, stderr; - int status = exec_script_sync(cmd, out stdout, out stderr); - if (status == 0){ - return true; - } - else{ - log_msg(stderr); - } - } - else{ - log_error(_("Dir not found") + ": %s".printf(src_dir)); - } - - return false; - } - - public bool dir_untar (string tar_file, string dst_dir){ - if (file_exists(tar_file)) { - - if (!dir_exists(dst_dir)){ - dir_create(dst_dir); - } - - string cmd = "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf( - escape_single_quote(tar_file), - escape_single_quote(dst_dir)); - - log_debug(cmd); - - string stdout, stderr; - int status = exec_script_sync(cmd, out stdout, out stderr); - if (status == 0){ - return true; - } - else{ - log_msg(stderr); - } - } - else{ - log_error(_("File not found") + ": %s".printf(tar_file)); - } - - return false; - } - - public bool chown(string dir_path, string user, string group = user){ - string cmd = "chown %s:%s -R '%s'".printf(user, group, escape_single_quote(dir_path)); - int status = exec_sync(cmd, null, null); - log_debug(cmd); - return (status == 0); - } - - // dir info ------------------- - - // dep: find wc TODO: rewrite - public long dir_get_count(string path){ - - /* Return total count of files and directories */ - - string cmd = ""; - string std_out; - string std_err; - int ret_val; - - cmd = "find '%s' | wc -l".printf(escape_single_quote(path)); - ret_val = exec_script_sync(cmd, out std_out, out std_err); - return long.parse(std_out); - } - - // dep: du - public long dir_get_size_kb(string path){ - - /* Returns size of files and directories in KB*/ - - string cmd = "du -s '%s'".printf(escape_single_quote(path)); - string std_out, std_err; - exec_sync(cmd, out std_out, out std_err); - return long.parse(std_out.split("\t")[0]); - } - - // archiving and encryption ---------------- - - // dep: tar gzip gpg - public bool file_tar_encrypt (string src_file, string dst_file, string password){ - if (file_exists(src_file)) { - if (file_exists(dst_file)){ - file_delete(dst_file); - } - - var src_dir = file_parent(src_file); - var src_name = file_basename(src_file); - - var dst_dir = file_parent(dst_file); - var dst_name = file_basename(dst_file); - var tar_name = dst_name[0 : dst_name.index_of(".gpg")]; - var tar_file = "%s/%s".printf(dst_dir, tar_name); - - string cmd = "tar cvf '%s' --overwrite -C '%s' '%s'\n".printf( - escape_single_quote(tar_file), - escape_single_quote(src_dir), - escape_single_quote(src_name)); - - cmd += "gpg --passphrase '%s' -o '%s' --symmetric '%s'\n".printf( - password, - escape_single_quote(dst_file), - escape_single_quote(tar_file)); - - cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); - - log_debug(cmd); - - string stdout, stderr; - int status = exec_script_sync(cmd, out stdout, out stderr); - if (status == 0){ - return true; - } - else{ - log_msg(stderr); - } - } - - return false; - } - - // dep: tar gzip gpg - public string file_decrypt_untar_read (string src_file, string password){ - - if (file_exists(src_file)) { - - //var src_name = file_basename(src_file); - //var tar_name = src_name[0 : src_name.index_of(".gpg")]; - //var tar_file = "%s/%s".printf(TEMP_DIR, tar_name); - //var temp_file = "%s/%s".printf(TEMP_DIR, random_string()); - - string cmd = ""; - - cmd += "gpg --quiet --no-verbose --passphrase '%s' -o- --decrypt '%s'".printf( - password, - escape_single_quote(src_file)); - - cmd += " | tar xf - --to-stdout 2>/dev/null\n"; - cmd += "exit $?\n"; - - log_debug(cmd); - - string std_out, std_err; - int status = exec_script_sync(cmd, out std_out, out std_err); - if (status == 0){ - return std_out; - } - else{ - log_error(std_err); - return ""; - } - } - else{ - log_error(_("File is missing") + ": %s".printf(src_file)); - } - - return ""; - } - - // dep: tar gzip gpg - public bool decrypt_and_untar (string src_file, string dst_file, string password){ - if (file_exists(src_file)) { - if (file_exists(dst_file)){ - file_delete(dst_file); - } - - var src_dir = file_parent(src_file); - var src_name = file_basename(src_file); - var tar_name = src_name[0 : src_name.index_of(".gpg")]; - var tar_file = "%s/%s".printf(src_dir, tar_name); - - string cmd = ""; - - // gpg cannot overwrite - remove tar file if it exists - cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); - - cmd += "gpg --passphrase '%s' -o '%s' --decrypt '%s'\n".printf( - password, - escape_single_quote(tar_file), - escape_single_quote(src_file)); - - cmd += "status=$?; if [ $status -ne 0 ]; then exit $status; fi\n"; - - cmd += "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf( - escape_single_quote(tar_file), - escape_single_quote(file_parent(dst_file))); - - cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); - - log_debug(cmd); - - string stdout, stderr; - int status = exec_script_sync(cmd, out stdout, out stderr); - if (status == 0){ - return true; - } - else{ - log_error(stderr); - return false; - } - } - else{ - log_error(_("File is missing") + ": %s".printf(src_file)); - } - - return false; - } - - // hashing ----------- - - private string hash_md5(string path){ - Checksum checksum = new Checksum (ChecksumType.MD5); - FileStream stream = FileStream.open (path, "rb"); - - uint8 fbuf[100]; - size_t size; - while ((size = stream.read (fbuf)) > 0){ - checksum.update (fbuf, size); - } - - unowned string digest = checksum.get_string(); - - return digest; - } - - // misc -------------------- - - public string format_file_size (uint64 size, bool binary_units = false, bool size_kb = false){ - int64 KB = binary_units ? 1024 : 1000; - int64 MB = binary_units ? 1024 * KB : 1000 * KB; - int64 GB = binary_units ? 1024 * MB : 1000 * MB; - - if (size_kb){ - return "%'0.0f %sB".printf(size/(1.0*KB), (binary_units)?"Ki":"K"); - } - - if (size > GB){ - return "%'0.1f %sB".printf(size/(1.0*GB), (binary_units)?"Gi":"G"); - } - else if (size > MB){ - return "%'0.1f %sB".printf(size/(1.0*MB), (binary_units)?"Mi":"M"); - } - else if (size > KB){ - return "%'0.0f %sB".printf(size/(1.0*KB), (binary_units)?"Ki":"K"); - } - else{ - return "%'0lld B".printf(size); - } - } - - public string escape_single_quote(string file_path){ - return file_path.replace("'","'\\''"); - } - - - // dep: chmod - public int chmod (string file, string permission){ - - /* Change file permissions */ - string cmd = "chmod %s '%s'".printf(permission, escape_single_quote(file)); - return exec_sync (cmd, null, null); - } - - // dep: realpath - public string resolve_relative_path (string filePath){ - - /* Resolve the full path of given file using 'realpath' command */ - - string filePath2 = filePath; - if (filePath2.has_prefix ("~")){ - filePath2 = Environment.get_home_dir () + "/" + filePath2[2:filePath2.length]; - } - - try { - string output = ""; - string cmd = "realpath '%s'".printf(escape_single_quote(filePath2)); - Process.spawn_command_line_sync(cmd, out output); - output = output.strip (); - if (FileUtils.test(output, GLib.FileTest.EXISTS)){ - return output; - } - } - catch(Error e){ - log_error (e.message); - } - - return filePath2; - } - - public int rsync (string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){ - - /* Sync files with rsync */ - - string cmd = "rsync -avh"; - cmd += updateExisting ? "" : " --ignore-existing"; - cmd += deleteExtra ? " --delete" : ""; - cmd += " '%s'".printf(escape_single_quote(sourceDirectory) + "//"); - cmd += " '%s'".printf(escape_single_quote(destDirectory)); - return exec_sync (cmd, null, null); - } -} - -namespace TeeJee.JSON{ - - using TeeJee.Logging; - - /* Convenience functions for reading and writing JSON files */ - - public string json_get_string(Json.Object jobj, string member, string def_value){ - if (jobj.has_member(member)){ - return jobj.get_string_member(member); - } - else{ - log_error ("Member not found in JSON object: " + member, false, true); - return def_value; - } - } - - public bool json_get_bool(Json.Object jobj, string member, bool def_value){ - if (jobj.has_member(member)){ - return bool.parse(jobj.get_string_member(member)); - } - else{ - log_error ("Member not found in JSON object: " + member, false, true); - return def_value; - } - } - - public int json_get_int(Json.Object jobj, string member, int def_value){ - if (jobj.has_member(member)){ - return int.parse(jobj.get_string_member(member)); - } - else{ - log_error ("Member not found in JSON object: " + member, false, true); - return def_value; - } - } - - public Gee.ArrayList json_get_array( - Json.Object jobj, - string member, - Gee.ArrayList def_value){ - - if (jobj.has_member(member)){ - var jarray = jobj.get_array_member(member); - var list = new Gee.ArrayList(); - foreach(var node in jarray.get_elements()){ - list.add(node.get_string()); - } - return list; - } - else{ - log_error ("Member not found in JSON object: " + member, false, true); - return def_value; - } - } - -} - -namespace TeeJee.ProcessManagement{ - using TeeJee.Logging; - using TeeJee.FileSystem; - using TeeJee.Misc; - - public string TEMP_DIR; - - /* Convenience functions for executing commands and managing processes */ - - // execute process --------------------------------- - - public static void init_tmp(string subdir_name){ - string std_out, std_err; - - TEMP_DIR = Environment.get_tmp_dir() + "/" + subdir_name + "/" + random_string(); - dir_create(TEMP_DIR); - - exec_script_sync("echo 'ok'",out std_out,out std_err, true); - if ((std_out == null)||(std_out.strip() != "ok")){ - TEMP_DIR = Environment.get_home_dir() + "/.temp/" + subdir_name + "/" + random_string(); - exec_sync("rm -rf '%s'".printf(TEMP_DIR), null, null); - dir_create(TEMP_DIR); - } - - //log_debug("TEMP_DIR=" + TEMP_DIR); - } - - public string create_temp_subdir(){ - var temp = "%s/%s".printf(TEMP_DIR, random_string()); - dir_create(temp); - return temp; - } - - public int exec_sync (string cmd, out string? std_out = null, out string? std_err = null){ - - /* Executes single command synchronously. - * Pipes and multiple commands are not supported. - * std_out, std_err can be null. Output will be written to terminal if null. */ - - try { - int status; - Process.spawn_command_line_sync(cmd, out std_out, out std_err, out status); - return status; - } - catch (Error e){ - log_error (e.message); - return -1; - } - } - - public int exec_script_sync (string script, - out string? std_out = null, out string? std_err = null, - bool supress_errors = false, bool run_as_admin = false, - bool cleanup_tmp = true){ - - /* Executes commands synchronously. - * Pipes and multiple commands are fully supported. - * Commands are written to a temporary bash script and executed. - * std_out, std_err can be null. Output will be written to terminal if null. - * */ - - string sh_file = save_bash_script_temp(script, null, supress_errors); - string sh_file_main = ""; - if (run_as_admin){ - string script_main = "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY"; - script_main += " '%s'".printf(escape_single_quote(sh_file)); - string dir = file_parent(sh_file); - sh_file_main = GLib.Path.build_filename(dir,"script-admin.sh"); - save_bash_script_temp(script_main, sh_file_main); - } - - try { - string[] argv = new string[1]; - if (run_as_admin){ - argv[0] = sh_file_main; - } - else{ - argv[0] = sh_file; - } - - string[] env = Environ.get(); - - int exit_code; - - Process.spawn_sync ( - TEMP_DIR, //working dir - argv, //argv - env, //environment - SpawnFlags.SEARCH_PATH, - null, // child_setup - out std_out, - out std_err, - out exit_code - ); - - if (cleanup_tmp){ - file_delete(sh_file); - if (run_as_admin){ - file_delete(sh_file_main); - } - } - - return exit_code; - } - catch (Error e){ - if (!supress_errors){ - log_error (e.message); - } - return -1; - } - } - - public int exec_script_async (string script){ - - /* Executes commands synchronously. - * Pipes and multiple commands are fully supported. - * Commands are written to a temporary bash script and executed. - * Return value indicates if script was started successfully. - * */ - - try { - - string scriptfile = save_bash_script_temp (script); - - string[] argv = new string[1]; - argv[0] = scriptfile; - - string[] env = Environ.get(); - - Pid child_pid; - Process.spawn_async_with_pipes( - TEMP_DIR, //working dir - argv, //argv - env, //environment - SpawnFlags.SEARCH_PATH, - null, - out child_pid); - - return 0; - } - catch (Error e){ - log_error (e.message); - return 1; - } - } - - public string? save_bash_script_temp (string commands, string? script_path = null, - bool force_locale = true, bool supress_errors = false){ - - string sh_path = script_path; - - /* Creates a temporary bash script with given commands - * Returns the script file path */ - - var script = new StringBuilder(); - script.append ("#!/bin/bash\n"); - script.append ("\n"); - if (force_locale){ - script.append ("LANG=C\n"); - } - script.append ("\n"); - script.append ("%s\n".printf(commands)); - script.append ("\n\nexitCode=$?\n"); - script.append ("echo ${exitCode} > ${exitCode}\n"); - script.append ("echo ${exitCode} > status\n"); - - if ((sh_path == null) || (sh_path.length == 0)){ - sh_path = get_temp_file_path() + ".sh"; - } - - try{ - //write script file - var file = File.new_for_path (sh_path); - if (file.query_exists ()) { - file.delete (); - } - var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); - var data_stream = new DataOutputStream (file_stream); - data_stream.put_string (script.str); - data_stream.close(); - - // set execute permission - chmod (sh_path, "u+x"); - - return sh_path; - } - catch (Error e) { - if (!supress_errors){ - log_error (e.message); - } - } - - return null; - } - - public string get_temp_file_path(){ - - /* Generates temporary file path */ - - return TEMP_DIR + "/" + timestamp_numeric() + (new Rand()).next_int().to_string(); - } - - // find process ------------------------------- - - // dep: which - public string get_cmd_path (string cmd){ - - /* Returns the full path to a command */ - - try { - int exitCode; - string stdout, stderr; - Process.spawn_command_line_sync("which " + cmd, out stdout, out stderr, out exitCode); - return stdout; - } - catch (Error e){ - log_error (e.message); - return ""; - } - } - - // dep: pidof, TODO: Rewrite using /proc - public int get_pid_by_name (string name){ - - /* Get the process ID for a process with given name */ - - string std_out, std_err; - exec_sync("pidof \"%s\"".printf(name), out std_out, out std_err); - - if (std_out != null){ - string[] arr = std_out.split ("\n"); - if (arr.length > 0){ - return int.parse (arr[0]); - } - } - - return -1; - } - - public int get_pid_by_command(string cmdline){ - - /* Searches for process using the command line used to start the process. - * Returns the process id if found. - * */ - - try { - FileEnumerator enumerator; - FileInfo info; - File file = File.parse_name ("/proc"); - - enumerator = file.enumerate_children ("standard::name", 0); - while ((info = enumerator.next_file()) != null) { - try { - string io_stat_file_path = "/proc/%s/cmdline".printf(info.get_name()); - var io_stat_file = File.new_for_path(io_stat_file_path); - if (file.query_exists()){ - var dis = new DataInputStream (io_stat_file.read()); - - string line; - string text = ""; - size_t length; - while((line = dis.read_until ("\0", out length)) != null){ - text += " " + line; - } - - if ((text != null) && text.contains(cmdline)){ - return int.parse(info.get_name()); - } - } //stream closed - } - catch(Error e){ - // do not log - // some processes cannot be accessed by non-admin user - } - } - } - catch(Error e){ - log_error (e.message); - } - - return -1; - } - - public void get_proc_io_stats(int pid, out int64 read_bytes, out int64 write_bytes){ - - /* Returns the number of bytes read and written by a process to disk */ - - string io_stat_file_path = "/proc/%d/io".printf(pid); - var file = File.new_for_path(io_stat_file_path); - - read_bytes = 0; - write_bytes = 0; - - try { - if (file.query_exists()){ - var dis = new DataInputStream (file.read()); - string line; - while ((line = dis.read_line (null)) != null) { - if(line.has_prefix("rchar:")){ - read_bytes = int64.parse(line.replace("rchar:","").strip()); - } - else if(line.has_prefix("wchar:")){ - write_bytes = int64.parse(line.replace("wchar:","").strip()); - } - } - } //stream closed - } - catch(Error e){ - log_error (e.message); - } - } - - // dep: ps TODO: Rewrite using /proc - public bool process_is_running(long pid){ - - /* Checks if given process is running */ - - string cmd = ""; - string std_out; - string std_err; - int ret_val; - - try{ - cmd = "ps --pid %ld".printf(pid); - Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - } - catch (Error e) { - log_error (e.message); - return false; - } - - return (ret_val == 0); - } - - // dep: pgrep TODO: Rewrite using /proc - public bool process_is_running_by_name(string proc_name){ - - /* Checks if given process is running */ - - string cmd = ""; - string std_out; - string std_err; - int ret_val; - - try{ - cmd = "pgrep -f '%s'".printf(proc_name); - Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - } - catch (Error e) { - log_error (e.message); - return false; - } - - return (ret_val == 0); - } - - // dep: ps TODO: Rewrite using /proc - public int[] get_process_children (Pid parent_pid){ - - /* Returns the list of child processes spawned by given process */ - - string std_out, std_err; - exec_sync("ps --ppid %d".printf(parent_pid), out std_out, out std_err); - - int pid; - int[] procList = {}; - string[] arr; - - foreach (string line in std_out.split ("\n")){ - arr = line.strip().split (" "); - if (arr.length < 1) { continue; } - - pid = 0; - pid = int.parse (arr[0]); - - if (pid != 0){ - procList += pid; - } - } - return procList; - } - - // manage process --------------------------------- - - public void process_quit(Pid process_pid, bool killChildren = true){ - - /* Kills specified process and its children (optional). - * Sends signal SIGTERM to the process to allow it to quit gracefully. - * */ - - int[] child_pids = get_process_children (process_pid); - Posix.kill (process_pid, Posix.SIGTERM); - - if (killChildren){ - Pid childPid; - foreach (long pid in child_pids){ - childPid = (Pid) pid; - Posix.kill (childPid, Posix.SIGTERM); - } - } - } - - public void process_kill(Pid process_pid, bool killChildren = true){ - - /* Kills specified process and its children (optional). - * Sends signal SIGKILL to the process to kill it forcefully. - * It is recommended to use the function process_quit() instead. - * */ - - int[] child_pids = get_process_children (process_pid); - Posix.kill (process_pid, Posix.SIGKILL); - - if (killChildren){ - Pid childPid; - foreach (long pid in child_pids){ - childPid = (Pid) pid; - Posix.kill (childPid, Posix.SIGKILL); - } - } - } - - // dep: kill - public int process_pause (Pid procID){ - - /* Pause/Freeze a process */ - - return exec_sync ("kill -STOP %d".printf(procID), null, null); - } - - // dep: kill - public int process_resume (Pid procID){ - - /* Resume/Un-freeze a process*/ - - return exec_sync ("kill -CONT %d".printf(procID), null, null); - } - - // dep: ps TODO: Rewrite using /proc - public void process_quit_by_name(string cmd_name, string cmd_to_match, bool exact_match){ - - /* Kills a specific command */ - - string std_out, std_err; - exec_sync ("ps w -C '%s'".printf(cmd_name), out std_out, out std_err); - //use 'ps ew -C conky' for all users - - string pid = ""; - foreach(string line in std_out.split("\n")){ - if ((exact_match && line.has_suffix(" " + cmd_to_match)) - || (!exact_match && (line.index_of(cmd_to_match) != -1))){ - pid = line.strip().split(" ")[0]; - Posix.kill ((Pid) int.parse(pid), 15); - log_debug(_("Stopped") + ": [PID=" + pid + "] "); - } - } - } - - // process priority --------------------------------------- - - public void process_set_priority (Pid procID, int prio){ - - /* Set process priority */ - - if (Posix.getpriority (Posix.PRIO_PROCESS, procID) != prio) - Posix.setpriority (Posix.PRIO_PROCESS, procID, prio); - } - - public int process_get_priority (Pid procID){ - - /* Get process priority */ - - return Posix.getpriority (Posix.PRIO_PROCESS, procID); - } - - public void process_set_priority_normal (Pid procID){ - - /* Set normal priority for process */ - - process_set_priority (procID, 0); - } - - public void process_set_priority_low (Pid procID){ - - /* Set low priority for process */ - - process_set_priority (procID, 5); - } - -} - -namespace TeeJee.Multimedia{ - - using TeeJee.Logging; - - /* Functions for working with audio/video files */ - - public long get_file_duration(string filePath){ - - /* Returns the duration of an audio/video file using MediaInfo */ - - string output = "0"; - - try { - Process.spawn_command_line_sync("mediainfo \"--Inform=General;%Duration%\" \"" + filePath + "\"", out output); - } - catch(Error e){ - log_error (e.message); - } - - return long.parse(output); - } - - public string get_file_crop_params (string filePath){ - - /* Returns cropping parameters for a video file using avconv */ - - string output = ""; - string error = ""; - - try { - Process.spawn_command_line_sync("avconv -i \"%s\" -vf cropdetect=30 -ss 5 -t 5 -f matroska -an -y /dev/null".printf(filePath), out output, out error); - } - catch(Error e){ - log_error (e.message); - } - - int w=0,h=0,x=10000,y=10000; - int num=0; - string key,val; - string[] arr; - - foreach (string line in error.split ("\n")){ - if (line == null) { continue; } - if (line.index_of ("crop=") == -1) { continue; } - - foreach (string part in line.split (" ")){ - if (part == null || part.length == 0) { continue; } - - arr = part.split (":"); - if (arr.length != 2) { continue; } - - key = arr[0].strip (); - val = arr[1].strip (); - - switch (key){ - case "x": - num = int.parse (arr[1]); - if (num < x) { x = num; } - break; - case "y": - num = int.parse (arr[1]); - if (num < y) { y = num; } - break; - case "w": - num = int.parse (arr[1]); - if (num > w) { w = num; } - break; - case "h": - num = int.parse (arr[1]); - if (num > h) { h = num; } - break; - } - } - } - - if (x == 10000 || y == 10000) - return "%i:%i:%i:%i".printf(0,0,0,0); - else - return "%i:%i:%i:%i".printf(w,h,x,y); - } - - public string get_mediainfo (string filePath){ - - /* Returns the multimedia properties of an audio/video file using MediaInfo */ - - string output = ""; - - try { - Process.spawn_command_line_sync("mediainfo \"%s\"".printf(filePath), out output); - } - catch(Error e){ - log_error (e.message); - } - - return output; - } - -} - -namespace TeeJee.System{ - - using TeeJee.ProcessManagement; - using TeeJee.Logging; - - // user --------------------------------------------------- - - public bool user_is_admin (){ - - /* Check if current application is running with admin priviledges */ - - try{ - // create a process - string[] argv = { "sleep", "10" }; - Pid procId; - Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); - - // try changing the priority - Posix.setpriority (Posix.PRIO_PROCESS, procId, -5); - - // check if priority was changed successfully - if (Posix.getpriority (Posix.PRIO_PROCESS, procId) == -5) - return true; - else - return false; - } - catch (Error e) { - log_error (e.message); - return false; - } - } - - // dep: whoami - public string get_user_login(){ - /* - Returns Login ID of current user. - If running as 'sudo' it will return Login ID of the actual user. - */ - - string cmd = "echo ${SUDO_USER:-$(whoami)}"; - string std_out; - string std_err; - int ret_val; - ret_val = exec_script_sync(cmd, out std_out, out std_err); - - string user_name; - if ((std_out == null) || (std_out.length == 0)){ - user_name = "root"; - } - else{ - user_name = std_out.strip(); - } - - return user_name; - } - - public string get_user_home(string custom_user_login = ""){ - string user_login = get_user_login(); - - if (custom_user_login.length > 0){ - user_login = custom_user_login; - } - - if (user_login == "root"){ - return "/root"; - } - else{ - return "/home/%s".printf(user_login); - } - } - - // dep: id - public int get_user_id(string user_login){ - /* - Returns UID of specified user. - */ - - int uid = -1; - string cmd = "id %s -u".printf(user_login); - string std_out, std_err; - exec_sync(cmd, out std_out, out std_err); - if ((std_out != null) && (std_out.length > 0)){ - uid = int.parse(std_out); - } - - return uid; - } - - // application ----------------------------------------------- - - public string get_app_path(){ - - /* Get path of current process */ - - try{ - return GLib.FileUtils.read_link ("/proc/self/exe"); - } - catch (Error e){ - log_error (e.message); - return ""; - } - } - - public string get_app_dir(){ - - /* Get parent directory of current process */ - - try{ - return (File.new_for_path (GLib.FileUtils.read_link ("/proc/self/exe"))).get_parent ().get_path (); - } - catch (Error e){ - log_error (e.message); - return ""; - } - } - - // system ------------------------------------ - - // dep: cat TODO: rewrite - public double get_system_uptime_seconds(){ - - /* Returns the system up-time in seconds */ - - string cmd = ""; - string std_out; - string std_err; - int ret_val; - - try{ - cmd = "cat /proc/uptime"; - Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - string uptime = std_out.split(" ")[0]; - double secs = double.parse(uptime); - return secs; - } - catch(Error e){ - log_error (e.message); - return 0; - } - } - - public bool check_internet_connectivity(){ - bool connected = false; - connected = check_internet_connectivity_test1(); - - if (connected){ - return connected; - } - - if (!connected){ - connected = check_internet_connectivity_test2(); - } - - return connected; - } - - public bool check_internet_connectivity_test1(){ - int exit_code = -1; - string std_err; - string std_out; - - string cmd = "ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3`\n"; - cmd += "exit $?"; - exit_code = exec_script_sync(cmd, out std_out, out std_err, false); - - return (exit_code == 0); - } - - public bool check_internet_connectivity_test2(){ - int exit_code = -1; - string std_err; - string std_out; - - string cmd = "ping -q -w 1 -c 1 google.com\n"; - cmd += "exit $?"; - exit_code = exec_script_sync(cmd, out std_out, out std_err, false); - - return (exit_code == 0); - } - - public bool shutdown (){ - - /* Shutdown the system immediately */ - - try{ - string[] argv = { "shutdown", "-h", "now" }; - Pid procId; - Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); - return true; - } - catch (Error e) { - log_error (e.message); - return false; - } - } - - // open files ----------------------------------- - - public bool xdg_open (string file){ - string path = get_cmd_path ("xdg-open"); - if ((path != null)&&(path != "")){ - string cmd = "xdg-open '%s'".printf(escape_single_quote(file)); - int status = exec_script_async(cmd); - return (status == 0); - } - return false; - } - - public bool exo_open_folder (string dir_path, bool xdg_open_try_first = true){ - - /* Tries to open the given directory in a file manager */ - - /* - xdg-open is a desktop-independent tool for configuring the default applications of a user. - Inside a desktop environment (e.g. GNOME, KDE, Xfce), xdg-open simply passes the arguments - to that desktop environment's file-opener application (gvfs-open, kde-open, exo-open, respectively). - We will first try using xdg-open and then check for specific file managers if it fails. - */ - - string path; - int status; - - if (xdg_open_try_first){ - //try using xdg-open - path = get_cmd_path ("xdg-open"); - if ((path != null)&&(path != "")){ - string cmd = "xdg-open '%s'".printf(escape_single_quote(dir_path)); - status = exec_script_async (cmd); - return (status == 0); - } - } - - foreach(string app_name in - new string[]{ "nemo", "nautilus", "thunar", "pantheon-files", "marlin"}){ - - path = get_cmd_path (app_name); - if ((path != null)&&(path != "")){ - string cmd = "%s '%s'".printf(app_name, escape_single_quote(dir_path)); - status = exec_script_async (cmd); - return (status == 0); - } - } - - if (xdg_open_try_first == false){ - //try using xdg-open - path = get_cmd_path ("xdg-open"); - if ((path != null)&&(path != "")){ - string cmd = "xdg-open '%s'".printf(escape_single_quote(dir_path)); - status = exec_script_async (cmd); - return (status == 0); - } - } - - return false; - } - - public bool exo_open_textfile (string txt_file){ - - /* Tries to open the given text file in a text editor */ - - string path; - int status; - string cmd; - - path = get_cmd_path ("exo-open"); - if ((path != null)&&(path != "")){ - cmd = "exo-open '%s'".printf(escape_single_quote(txt_file)); - status = exec_script_async (cmd); - return (status == 0); - } - - path = get_cmd_path ("gedit"); - if ((path != null)&&(path != "")){ - cmd = "gedit --new-document '%s'".printf(escape_single_quote(txt_file)); - status = exec_script_async (cmd); - return (status == 0); - } - - return false; - } - - public bool exo_open_url (string url){ - - /* Tries to open the given text file in a text editor */ - - string path; - int status; - string cmd; - - path = get_cmd_path ("exo-open"); - if ((path != null)&&(path != "")){ - status = exec_script_async ("exo-open \"" + url + "\""); - return (status == 0); - } - - path = get_cmd_path ("firefox"); - if ((path != null)&&(path != "")){ - status = exec_script_async ("firefox \"" + url + "\""); - return (status == 0); - } - - path = get_cmd_path ("chromium-browser"); - if ((path != null)&&(path != "")){ - status = exec_script_async ("chromium-browser \"" + url + "\""); - return (status == 0); - } - - return false; - } - - // timers -------------------------------------------------- - - public GLib.Timer timer_start(){ - var timer = new GLib.Timer(); - timer.start(); - return timer; - } - - public ulong timer_elapsed(GLib.Timer timer, bool stop = true){ - ulong microseconds; - double seconds; - seconds = timer.elapsed (out microseconds); - if (stop){ - timer.stop(); - } - return (ulong)((seconds * 1000 ) + (microseconds / 1000)); - } - - public void sleep(int milliseconds){ - Thread.usleep ((ulong) milliseconds * 1000); - } - - public string timer_elapsed_string(GLib.Timer timer, bool stop = true){ - ulong microseconds; - double seconds; - seconds = timer.elapsed (out microseconds); - if (stop){ - timer.stop(); - } - return "%.0f ms".printf((seconds * 1000 ) + microseconds/1000); - } - - public void timer_elapsed_print(GLib.Timer timer, bool stop = true){ - ulong microseconds; - double seconds; - seconds = timer.elapsed (out microseconds); - if (stop){ - timer.stop(); - } - log_msg("%s %lu\n".printf(seconds.to_string(), microseconds)); - } - - public class LinuxDistro : GLib.Object{ - - /* Class for storing information about Linux distribution */ - - public string dist_id = ""; - public string description = ""; - public string release = ""; - public string codename = ""; - - public LinuxDistro(){ - dist_id = ""; - description = ""; - release = ""; - codename = ""; - } - - public string full_name(){ - if (dist_id == ""){ - return ""; - } - else{ - string val = ""; - val += dist_id; - val += (release.length > 0) ? " " + release : ""; - val += (codename.length > 0) ? " (" + codename + ")" : ""; - return val; - } - } - - public static LinuxDistro get_dist_info(string root_path){ - - /* Returns information about the Linux distribution - * installed at the given root path */ - - LinuxDistro info = new LinuxDistro(); - - string dist_file = root_path + "/etc/lsb-release"; - var f = File.new_for_path(dist_file); - if (f.query_exists()){ - - /* - DISTRIB_ID=Ubuntu - DISTRIB_RELEASE=13.04 - DISTRIB_CODENAME=raring - DISTRIB_DESCRIPTION="Ubuntu 13.04" - */ - - foreach(string line in file_read(dist_file).split("\n")){ - - if (line.split("=").length != 2){ continue; } - - string key = line.split("=")[0].strip(); - string val = line.split("=")[1].strip(); - - if (val.has_prefix("\"")){ - val = val[1:val.length]; - } - - if (val.has_suffix("\"")){ - val = val[0:val.length-1]; - } - - switch (key){ - case "DISTRIB_ID": - info.dist_id = val; - break; - case "DISTRIB_RELEASE": - info.release = val; - break; - case "DISTRIB_CODENAME": - info.codename = val; - break; - case "DISTRIB_DESCRIPTION": - info.description = val; - break; - } - } - } - else{ - - dist_file = root_path + "/etc/os-release"; - f = File.new_for_path(dist_file); - if (f.query_exists()){ - - /* - NAME="Ubuntu" - VERSION="13.04, Raring Ringtail" - ID=ubuntu - ID_LIKE=debian - PRETTY_NAME="Ubuntu 13.04" - VERSION_ID="13.04" - HOME_URL="http://www.ubuntu.com/" - SUPPORT_URL="http://help.ubuntu.com/" - BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" - */ - - foreach(string line in file_read(dist_file).split("\n")){ - - if (line.split("=").length != 2){ continue; } - - string key = line.split("=")[0].strip(); - string val = line.split("=")[1].strip(); - - switch (key){ - case "ID": - info.dist_id = val; - break; - case "VERSION_ID": - info.release = val; - break; - //case "DISTRIB_CODENAME": - //info.codename = val; - //break; - case "PRETTY_NAME": - info.description = val; - break; - } - } - } - } - - return info; - } - - public static string get_running_desktop_name(){ - - /* Return the names of the current Desktop environment */ - - int pid = -1; - - pid = get_pid_by_name("cinnamon"); - if (pid > 0){ - return "Cinnamon"; - } - - pid = get_pid_by_name("xfdesktop"); - if (pid > 0){ - return "Xfce"; - } - - pid = get_pid_by_name("lxsession"); - if (pid > 0){ - return "LXDE"; - } - - pid = get_pid_by_name("gnome-shell"); - if (pid > 0){ - return "Gnome"; - } - - pid = get_pid_by_name("wingpanel"); - if (pid > 0){ - return "Elementary"; - } - - pid = get_pid_by_name("unity-panel-service"); - if (pid > 0){ - return "Unity"; - } - - pid = get_pid_by_name("plasma-desktop"); - if (pid > 0){ - return "KDE"; - } - - return "Unknown"; - } - - } - - - // dep: notify-send - public class OSDNotify : GLib.Object { - private static DateTime dt_last_notification = null; - public static const int NOTIFICATION_INTERVAL = 3; - - public static int notify_send ( - string title, string message, int durationMillis, - string urgency = "low", // low, normal, critical - string dialog_type = "info" //error, info, warning - ){ - - /* Displays notification bubble on the desktop */ - - int retVal = 0; - - switch (dialog_type){ - case "error": - case "info": - case "warning": - //ok - break; - default: - dialog_type = "info"; - break; - } - - long seconds = 9999; - if (dt_last_notification != null){ - DateTime dt_end = new DateTime.now_local(); - TimeSpan elapsed = dt_end.difference(dt_last_notification); - seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND); - } - - if (seconds > NOTIFICATION_INTERVAL){ - string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\"".printf(durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message); - retVal = exec_sync (s, null, null); - dt_last_notification = new DateTime.now_local(); - } - - return retVal; - } - - public static bool is_supported(){ - string path = get_cmd_path ("notify-send"); - if ((path != null) && (path.length > 0)){ - return true; - } - else{ - return false; - } - } - } - - public class ProcStats : GLib.Object { - public double user = 0; - public double nice = 0; - public double system = 0; - public double idle = 0; - public double iowait = 0; - - public double user_delta = 0; - public double nice_delta = 0; - public double system_delta = 0; - public double idle_delta = 0; - public double iowait_delta = 0; - - public double usage_percent = 0; - - public static ProcStats stat_prev = null; - - public ProcStats(string line){ - string[] arr = line.split(" "); - int col = 0; - if (arr[col++] == "cpu"){ - if (arr[col].length == 0){ col++; }; - - user = double.parse(arr[col++]); - nice = double.parse(arr[col++]); - system = double.parse(arr[col++]); - idle = double.parse(arr[col++]); - iowait = double.parse(arr[col++]); - - if (ProcStats.stat_prev != null){ - user_delta = user - ProcStats.stat_prev.user; - nice_delta = nice - ProcStats.stat_prev.nice; - system_delta = system - ProcStats.stat_prev.system; - idle_delta = idle - ProcStats.stat_prev.idle; - iowait_delta = iowait - ProcStats.stat_prev.iowait; - - usage_percent = (user_delta + nice_delta + system_delta) * 100 / (user_delta + nice_delta + system_delta + idle_delta); - } - else{ - usage_percent = 0; - - } - - ProcStats.stat_prev = this; - } - } - - //returns 0 when it is called first time - public static double get_cpu_usage(){ - string txt = file_read("/proc/stat"); - foreach(string line in txt.split("\n")){ - string[] arr = line.split(" "); - if (arr[0] == "cpu"){ - ProcStats stat = new ProcStats(line); - return stat.usage_percent; - } - } - return 0; - } - } - - public class SystemUser : GLib.Object { - public string name = ""; - public string password = ""; - public int uid = -1; - public int gid = -1; - public string user_info = ""; - public string home_path = ""; - public string shell_path = ""; - - public string full_name = ""; - public string room_num = ""; - public string phone_work = ""; - public string phone_home = ""; - public string other_info = ""; - - //public string - public string shadow_line = ""; - public string pwd_hash = ""; - public string pwd_last_changed = ""; - public string pwd_age_min = ""; - public string pwd_age_max = ""; - public string pwd_warning_period = ""; - public string pwd_inactivity_period = ""; - public string pwd_expiraton_date = ""; - public string reserved_field = ""; - - public bool is_selected = false; - - public static Gee.HashMap all_users; - - public SystemUser(string name){ - this.name = name; - } - - public static void query_users(){ - all_users = read_users_from_file("/etc/passwd","/etc/shadow",""); - } - - public bool is_installed{ - get { - return SystemUser.all_users.has_key(name); - } - } - - public static Gee.HashMap read_users_from_file( - string passwd_file, string shadow_file, string password){ - - var list = new Gee.HashMap(); - - // read 'passwd' file --------------------------------- - - string txt = ""; - - if (passwd_file.has_suffix(".tar.gpg")){ - txt = file_decrypt_untar_read(passwd_file, password); - } - else{ - txt = file_read(passwd_file); - } - - if (txt.length == 0){ - return list; - } - - foreach(string line in txt.split("\n")){ - if ((line == null) || (line.length == 0)){ - continue; - } - var user = parse_line_passwd(line); - if (user != null){ - list[user.name] = user; - } - } - - - // read 'shadow' file --------------------------------- - - txt = ""; - - if (shadow_file.has_suffix(".tar.gpg")){ - txt = file_decrypt_untar_read(shadow_file, password); - } - else{ - txt = file_read(shadow_file); - } - - if (txt.length == 0){ - return list; - } - - foreach(string line in txt.split("\n")){ - if ((line == null) || (line.length == 0)){ - continue; - } - parse_line_shadow(line, list); - } - - return list; - } - - private static SystemUser? parse_line_passwd(string line){ - if ((line == null) || (line.length == 0)){ - return null; - } - - SystemUser user = null; - - //teejee:x:504:504:Tony George:/home/teejee:/bin/bash - string[] fields = line.split(":"); - - if (fields.length == 7){ - user = new SystemUser(fields[0].strip()); - user.password = fields[1].strip(); - user.uid = int.parse(fields[2].strip()); - user.gid = int.parse(fields[3].strip()); - user.user_info = fields[4].strip(); - user.home_path = fields[5].strip(); - user.shell_path = fields[6].strip(); - - string[] arr = user.user_info.split(","); - if (arr.length >= 1){ - user.full_name = arr[0]; - } - if (arr.length >= 2){ - user.room_num = arr[1]; - } - if (arr.length >= 3){ - user.phone_work = arr[2]; - } - if (arr.length >= 4){ - user.phone_home = arr[3]; - } - if (arr.length >= 5){ - user.other_info = arr[4]; - } - } - else{ - log_error("'passwd' file contains a record with non-standard fields" + ": %d".printf(fields.length)); - return null; - } - - return user; - } - - private static SystemUser? parse_line_shadow(string line, Gee.HashMap list){ - if ((line == null) || (line.length == 0)){ - return null; - } - - SystemUser user = null; - - //root:$1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1:15651:0:99999:7::: - //:$$$::::::: - - string[] fields = line.split(":"); - - if (fields.length == 9){ - string user_name = fields[0].strip(); - if (list.has_key(user_name)){ - user = list[user_name]; - user.shadow_line = line; - user.pwd_hash = fields[1].strip(); - user.pwd_last_changed = fields[2].strip(); - user.pwd_age_min = fields[3].strip(); - user.pwd_age_max = fields[4].strip(); - user.pwd_warning_period = fields[5].strip(); - user.pwd_inactivity_period = fields[6].strip(); - user.pwd_expiraton_date = fields[7].strip(); - user.reserved_field = fields[8].strip(); - return user; - } - else{ - log_error("user in file 'shadow' does not exist in file 'passwd'" + ": %s".printf(user_name)); - return null; - } - } - else{ - log_error("'shadow' file contains a record with non-standard fields" + ": %d".printf(fields.length)); - return null; - } - } - - public static int add_user(string user_name, bool system_account = false){ - string std_out, std_err; - string cmd = "adduser%s --gecos '' --disabled-login %s".printf((system_account ? " --system" : ""), user_name); - log_debug(cmd); - int status = exec_sync(cmd, out std_out, out std_err); - if (status != 0){ - log_error(std_err); - } - else{ - //log_msg(std_out); - } - return status; - } - - public int add(){ - return add_user(name, is_system); - } - - public bool is_system{ - get { - return (uid < 1000); - } - } - - public string group_names{ - owned get { - return ""; - } - } - - public bool update_passwd_file(){ - string file_path = "/etc/passwd"; - string txt = file_read(file_path); - - var txt_new = ""; - foreach(string line in txt.split("\n")){ - if (line.strip().length == 0) { - continue; - } - - string[] parts = line.split(":"); - - if (parts.length != 7){ - log_error("'passwd' file contains a record with non-standard fields" + ": %d".printf(parts.length)); - return false; - } - - if (parts[0].strip() == name){ - txt_new += get_passwd_line() + "\n"; - } - else{ - txt_new += line + "\n"; - } - } - - file_write(file_path, txt_new); - - log_msg("Updated user settings in /etc/passwd" + ": %s".printf(name)); - - return true; - } - - public string get_passwd_line(){ - string txt = ""; - txt += "%s".printf(name); - txt += ":%s".printf(password); - txt += ":%d".printf(uid); - txt += ":%d".printf(gid); - txt += ":%s".printf(user_info); - txt += ":%s".printf(home_path); - txt += ":%s".printf(shell_path); - return txt; - } - - public bool update_shadow_file(){ - string file_path = "/etc/shadow"; - string txt = file_read(file_path); - - var txt_new = ""; - foreach(string line in txt.split("\n")){ - if (line.strip().length == 0) { - continue; - } - - string[] parts = line.split(":"); - - if (parts.length != 9){ - log_error("'shadow' file contains a record with non-standard fields" + ": %d".printf(parts.length)); - return false; - } - - if (parts[0].strip() == name){ - txt_new += get_shadow_line() + "\n"; - } - else{ - txt_new += line + "\n"; - } - } - - file_write(file_path, txt_new); - - log_msg("Updated user settings in /etc/shadow" + ": %s".printf(name)); - - return true; - } - - public string get_shadow_line(){ - string txt = ""; - txt += "%s".printf(name); - txt += ":%s".printf(pwd_hash); - txt += ":%s".printf(pwd_last_changed); - txt += ":%s".printf(pwd_age_min); - txt += ":%s".printf(pwd_age_max); - txt += ":%s".printf(pwd_warning_period); - txt += ":%s".printf(pwd_inactivity_period); - txt += ":%s".printf(pwd_expiraton_date); - txt += ":%s".printf(reserved_field); - return txt; - } - } - - public class SystemGroup : GLib.Object { - public string name = ""; - public string password = ""; - public int gid = -1; - public string user_names = ""; - - public string shadow_line = ""; - public string password_hash = ""; - public string admin_list = ""; - public string member_list = ""; - - public bool is_selected = false; - public Gee.ArrayList users; - - public static Gee.HashMap all_groups; - - public SystemGroup(string name){ - this.name = name; - this.users = new Gee.ArrayList(); - } - - public static void query_groups(){ - all_groups = read_groups_from_file("/etc/group","/etc/gshadow", ""); - } - - public bool is_installed{ - get{ - return SystemGroup.all_groups.has_key(name); - } - } - - public static Gee.HashMap read_groups_from_file(string group_file, string gshadow_file, string password){ - var list = new Gee.HashMap(); - - // read 'group' file ------------------------------- - - string txt = ""; - - if (group_file.has_suffix(".tar.gpg")){ - txt = file_decrypt_untar_read(group_file, password); - } - else{ - txt = file_read(group_file); - } - - if (txt.length == 0){ - return list; - } - - foreach(string line in txt.split("\n")){ - if ((line == null) || (line.length == 0)){ - continue; - } - - var group = parse_line_group(line); - if (group != null){ - list[group.name] = group; - } - } - - // read 'gshadow' file ------------------------------- - - txt = ""; - - if (gshadow_file.has_suffix(".tar.gpg")){ - txt = file_decrypt_untar_read(gshadow_file, password); - } - else{ - txt = file_read(gshadow_file); - } - - if (txt.length == 0){ - return list; - } - - foreach(string line in txt.split("\n")){ - if ((line == null) || (line.length == 0)){ - continue; - } - - parse_line_gshadow(line, list); - } - - return list; - } - - private static SystemGroup? parse_line_group(string line){ - if ((line == null) || (line.length == 0)){ - return null; - } - - SystemGroup group = null; - - //cdrom:x:24:teejee,user2 - string[] fields = line.split(":"); - - if (fields.length == 4){ - group = new SystemGroup(fields[0].strip()); - group.password = fields[1].strip(); - group.gid = int.parse(fields[2].strip()); - group.user_names = fields[3].strip(); - foreach(string user_name in group.user_names.split(",")){ - group.users.add(user_name); - } - } - else{ - log_error("'group' file contains a record with non-standard fields" + ": %d".printf(fields.length)); - return null; - } - - return group; - } - - private static SystemGroup? parse_line_gshadow(string line, Gee.HashMap list){ - if ((line == null) || (line.length == 0)){ - return null; - } - - SystemGroup group = null; - - //adm:*::syslog,teejee - //::: - string[] fields = line.split(":"); - - if (fields.length == 4){ - string group_name = fields[0].strip(); - if (list.has_key(group_name)){ - group = list[group_name]; - group.shadow_line = line; - group.password_hash = fields[1].strip(); - group.admin_list = fields[2].strip(); - group.member_list = fields[3].strip(); - return group; - } - else{ - log_error("group in file 'gshadow' does not exist in file 'group'" + ": %s".printf(group_name)); - return null; - } - } - else{ - log_error("'gshadow' file contains a record with non-standard fields" + ": %d".printf(fields.length)); - return null; - } - } - - public static int add_group(string group_name, bool system_account = false){ - string std_out, std_err; - string cmd = "groupadd%s %s".printf((system_account)? " --system" : "", group_name); - int status = exec_sync(cmd, out std_out, out std_err); - if (status != 0){ - log_error(std_err); - } - else{ - //log_msg(std_out); - } - return status; - } - - public int add(){ - return add_group(name,is_system); - } - - public static int add_user_to_group(string user_name, string group_name){ - string std_out, std_err; - string cmd = "adduser %s %s".printf(user_name, group_name); - log_debug(cmd); - int status = exec_sync(cmd, out std_out, out std_err); - if (status != 0){ - log_error(std_err); - } - else{ - //log_msg(std_out); - } - return status; - } - - public int add_to_group(string user_name){ - return add_user_to_group(user_name, name); - } - - public bool is_system{ - get { - return (gid < 1000); - } - } - - public bool update_group_file(){ - string file_path = "/etc/group"; - string txt = file_read(file_path); - - var txt_new = ""; - foreach(string line in txt.split("\n")){ - if (line.strip().length == 0) { - continue; - } - - string[] parts = line.split(":"); - - if (parts.length != 4){ - log_error("'group' file contains a record with non-standard fields" + ": %d".printf(parts.length)); - return false; - } - - if (parts[0].strip() == name){ - txt_new += get_group_line() + "\n"; - } - else{ - txt_new += line + "\n"; - } - } - - file_write(file_path, txt_new); - - log_msg("Updated group settings in /etc/group" + ": %s".printf(name)); - - return true; - } - - public string get_group_line(){ - string txt = ""; - txt += "%s".printf(name); - txt += ":%s".printf(password); - txt += ":%d".printf(gid); - txt += ":%s".printf(user_names); - return txt; - } - - public bool update_gshadow_file(){ - string file_path = "/etc/gshadow"; - string txt = file_read(file_path); - - var txt_new = ""; - foreach(string line in txt.split("\n")){ - if (line.strip().length == 0) { - continue; - } - - string[] parts = line.split(":"); - - if (parts.length != 4){ - log_error("'gshadow' file contains a record with non-standard fields" + ": %d".printf(parts.length)); - return false; - } - - if (parts[0].strip() == name){ - txt_new += get_gshadow_line() + "\n"; - } - else{ - txt_new += line + "\n"; - } - } - - file_write(file_path, txt_new); - - log_msg("Updated group settings in /etc/gshadow" + ": %s".printf(name)); - - return true; - } - - public string get_gshadow_line(){ - string txt = ""; - txt += "%s".printf(name); - txt += ":%s".printf(password_hash); - txt += ":%s".printf(admin_list); - txt += ":%s".printf(member_list); - return txt; - } - } -} - -namespace TeeJee.Misc { - - /* Various utility functions */ - - using Gtk; - using TeeJee.Logging; - using TeeJee.FileSystem; - using TeeJee.ProcessManagement; - - // color format ------------------- - - public static Gdk.RGBA hex_to_rgba (string hex_color){ - - /* Converts the color in hex to RGBA */ - - string hex = hex_color.strip().down(); - if (hex.has_prefix("#") == false){ - hex = "#" + hex; - } - - Gdk.RGBA color = Gdk.RGBA(); - if(color.parse(hex) == false){ - color.parse("#000000"); - } - color.alpha = 255; - - return color; - } - - public static string rgba_to_hex (Gdk.RGBA color, bool alpha = false, bool prefix_hash = true){ - - /* Converts the color in RGBA to hex */ - - string hex = ""; - - if (alpha){ - hex = "%02x%02x%02x%02x".printf((uint)(Math.round(color.red*255)), - (uint)(Math.round(color.green*255)), - (uint)(Math.round(color.blue*255)), - (uint)(Math.round(color.alpha*255))) - .up(); - } - else { - hex = "%02x%02x%02x".printf((uint)(Math.round(color.red*255)), - (uint)(Math.round(color.green*255)), - (uint)(Math.round(color.blue*255))) - .up(); - } - - if (prefix_hash){ - hex = "#" + hex; - } - - return hex; - } - - // timestamp ---------------- - - public string timestamp (){ - - /* Returns a formatted timestamp string */ - - Time t = Time.local (time_t ()); - return t.format ("%H:%M:%S"); - } - - public string timestamp_numeric (){ - - /* Returns a numeric timestamp string */ - - return "%ld".printf((long) time_t ()); - } - - public string timestamp_for_path (){ - - /* Returns a formatted timestamp string */ - - Time t = Time.local (time_t ()); - return t.format ("%Y-%d-%m_%H-%M-%S"); - } - - // string formatting ------------------------------------------------- - - public string format_duration (long millis){ - - /* Converts time in milliseconds to format '00:00:00.0' */ - - double time = millis / 1000.0; // time in seconds - - double hr = Math.floor(time / (60.0 * 60)); - time = time - (hr * 60 * 60); - double min = Math.floor(time / 60.0); - time = time - (min * 60); - double sec = Math.floor(time); - - return "%02.0lf:%02.0lf:%02.0lf".printf (hr, min, sec); - } - - public double parse_time (string time){ - - /* Converts time in format '00:00:00.0' to milliseconds */ - - string[] arr = time.split (":"); - double millis = 0; - if (arr.length >= 3){ - millis += double.parse(arr[0]) * 60 * 60; - millis += double.parse(arr[1]) * 60; - millis += double.parse(arr[2]); - } - return millis; - } - - public string string_replace( - string str, string search, string replacement, int count = -1){ - - string[] arr = str.split(search); - string new_txt = ""; - bool first = true; - - foreach(string part in arr){ - if (first){ - new_txt += part; - } - else{ - if (count == 0){ - new_txt += search; - new_txt += part; - } - else{ - new_txt += replacement; - new_txt += part; - count--; - } - } - first = false; - } - - return new_txt; - } - - public string escape_html(string html){ - return html - .replace("&","&") - .replace("\"",""") - //.replace(" "," ") //pango markup throws an error with   - .replace("<","<") - .replace(">",">") - ; - } - - public string unescape_html(string html){ - return html - .replace("&","&") - .replace(""","\"") - //.replace(" "," ") //pango markup throws an error with   - .replace("<","<") - .replace(">",">") - ; - } - - public DateTime datetime_from_string (string date_time_string){ - - /* Converts date time string to DateTime - * - * Supported inputs: - * 'yyyy-MM-dd' - * 'yyyy-MM-dd HH' - * 'yyyy-MM-dd HH:mm' - * 'yyyy-MM-dd HH:mm:ss' - * */ - - string[] arr = date_time_string.replace(":"," ").replace("-"," ").strip().split(" "); - - int year = (arr.length >= 3) ? int.parse(arr[0]) : 0; - int month = (arr.length >= 3) ? int.parse(arr[1]) : 0; - int day = (arr.length >= 3) ? int.parse(arr[2]) : 0; - int hour = (arr.length >= 4) ? int.parse(arr[3]) : 0; - int min = (arr.length >= 5) ? int.parse(arr[4]) : 0; - int sec = (arr.length >= 6) ? int.parse(arr[5]) : 0; - - return new DateTime.utc(year,month,day,hour,min,sec); - } - - public string break_string_by_word(string input_text){ - string text = ""; - string line = ""; - foreach(string part in input_text.split(" ")){ - line += part + " "; - if (line.length > 50){ - text += line.strip() + "\n"; - line = ""; - } - } - if (line.length > 0){ - text += line; - } - if (text.has_suffix("\n")){ - text = text[0:text.length-1].strip(); - } - return text; - } - - public string[] array_concat(string[] a, string[] b){ - string[] c = {}; - foreach(string str in a){ c += str; } - foreach(string str in b){ c += str; } - return c; - } - - public string random_string( - int length = 8, - string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"){ - - string random = ""; - - for(int i=0;i= 1){ - txt += "%.0fm ".printf(mins); - } - txt += "%.0fs".printf(secs); - return txt; - } -} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Console/AppConsole.vala ukuu-16.12~57~ubuntu16.10.1/src/Console/AppConsole.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Console/AppConsole.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Console/AppConsole.vala 2016-12-07 16:47:10.000000000 +0000 @@ -29,16 +29,15 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.Multimedia; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.System; using TeeJee.Misc; public Main App; public const string AppName = "Ubuntu Kernel Update Utility"; public const string AppShortName = "ukuu"; -public const string AppVersion = "16.11.1"; +public const string AppVersion = "16.12"; public const string AppAuthor = "Tony George"; public const string AppAuthorEmail = "teejeetech@gmail.com"; @@ -64,6 +63,8 @@ bool is_success = console.parse_arguments(args); //App.exit_app(); + App.fix_startup_script_error(); + return (is_success) ? 0 : 1; } @@ -338,6 +339,7 @@ public void check_if_internet_is_active(){ if (!check_internet_connectivity()){ log_error(_("Internet connection is not active")); + App.fix_startup_script_error(); exit(1); } } diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/AboutWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/AboutWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/AboutWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/AboutWindow.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,423 +0,0 @@ -/* - * AboutWindow.vala - * - * Copyright 2016 Tony George - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ - -using Gtk; - -using TeeJee.Logging; -using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.GtkHelper; -using TeeJee.System; -using TeeJee.Misc; - -public class AboutWindow : Gtk.Dialog { - private Box vbox_main; - private Box vbox_logo; - private Box vbox_credits; - private Box vbox_lines; - private Box hbox_action; - private Button btn_credits; - private Button btn_close; - - private Gtk.Image img_logo; - private Label lbl_program_name; - private Label lbl_version; - private Label lbl_comments; - private LinkButton lbtn_website; - private Label lbl_copyright; - - private string[] _artists; - public string[] artists{ - get{ - return _artists; - } - set{ - _artists = value; - } - } - - private string[] _authors; - public string[] authors{ - get{ - return _authors; - } - set{ - _authors = value; - } - } - - private string _comments = ""; - public string comments{ - get{ - return _comments; - } - set{ - _comments = value; - } - } - - private string _copyright = ""; - public string copyright{ - get{ - return _copyright; - } - set{ - _copyright = value; - } - } - - private string[] _documenters; - public string[] documenters{ - get{ - return _documenters; - } - set{ - _documenters = value; - } - } - - private string[] _donations; - public string[] donations{ - get{ - return _donations; - } - set{ - _donations = value; - } - } - - private string _license = ""; - public string license{ - get{ - return _license; - } - set{ - _license = value; - } - } - - private Gdk.Pixbuf _logo; - public Gdk.Pixbuf logo{ - get{ - return _logo; - } - set{ - _logo = value; - } - } - - private string _program_name = ""; - public string program_name{ - get{ - return _program_name; - } - set{ - _program_name = value; - } - } - - private string[] _translators; - public string[] translators{ - get{ - return _translators; - } - set{ - _translators = value; - } - } - - private string[] _third_party; - public string[] third_party{ - get{ - return _third_party; - } - set{ - _third_party = value; - } - } - - private string _version = ""; - public string version{ - get{ - return _version; - } - set{ - _version = value; - } - } - - private string _website = ""; - public string website{ - get{ - return _website; - } - set{ - _website = value; - } - } - - private string _website_label = ""; - public string website_label{ - get{ - return _website_label; - } - set{ - _website_label = value; - } - } - - public AboutWindow() { - window_position = WindowPosition.CENTER_ON_PARENT; - set_destroy_with_parent (true); - set_modal (true); - skip_taskbar_hint = false; - set_default_size (450, 400); - - vbox_main = get_content_area(); - vbox_main.margin = 6; - vbox_main.spacing = 6; - - vbox_logo = new Box(Orientation.VERTICAL,0); - vbox_main.add(vbox_logo); - - vbox_credits = new Box(Orientation.VERTICAL,0); - vbox_credits.no_show_all = true; - vbox_main.add(vbox_credits); - - vbox_lines = new Box(Orientation.VERTICAL,0); - vbox_lines.margin_top = 10; - - //logo - img_logo = new Gtk.Image(); - img_logo.margin_top = 6; - img_logo.margin_bottom = 6; - vbox_logo.add(img_logo); - - //program_name - lbl_program_name = new Label(""); - lbl_program_name.set_use_markup(true); - vbox_logo.add(lbl_program_name); - - //version - lbl_version = new Label(""); - lbl_version.set_use_markup(true); - lbl_version.margin_top = 5; - vbox_logo.add(lbl_version); - - //comments - lbl_comments = new Label(""); - lbl_comments.set_use_markup(true); - lbl_comments.margin_top = 10; - vbox_logo.add(lbl_comments); - - //website - lbtn_website = new LinkButton(""); - lbtn_website.margin_top = 5; - vbox_logo.add(lbtn_website); - - lbtn_website.activate_link.connect(()=>{ - try{ - return Gtk.show_uri(null, lbtn_website.uri, Gdk.CURRENT_TIME); - } - catch(Error e){ - return false; - } - }); - - //copyright - lbl_copyright = new Label(""); - lbl_copyright.set_use_markup(true); - lbl_copyright.margin_top = 5; - vbox_logo.add(lbl_copyright); - - //spacer_bottom - var spacer_bottom = new Label(""); - spacer_bottom.margin_top = 20; - vbox_logo.add(spacer_bottom); - - //scroller - var sw_credits = new ScrolledWindow(null, null); - sw_credits.set_shadow_type(ShadowType.ETCHED_IN); - sw_credits.expand = true; - - vbox_credits.add(sw_credits); - sw_credits.add(vbox_lines); - - //hbox_commands -------------------------------------------------- - - hbox_action = (Box) get_action_area(); - - //btn_credits - btn_credits = new Button.with_label(" " + _("Credits")); - btn_credits.set_image (new Image.from_stock ("gtk-about", IconSize.MENU)); - hbox_action.add(btn_credits); - - btn_credits.clicked.connect(()=>{ - vbox_logo.visible = !(vbox_logo.visible); - vbox_credits.visible = !(vbox_credits.visible); - - if ((vbox_credits.visible)&&(!sw_credits.visible)){ - sw_credits.show_all(); - } - - if (vbox_credits.visible){ - btn_credits.label = " " + _("Back"); - btn_credits.set_image (new Image.from_stock ("gtk-go-back", IconSize.MENU)); - } - else{ - btn_credits.label = " " + _("Credits"); - btn_credits.set_image (new Image.from_stock ("gtk-about", IconSize.MENU)); - } - }); - - //btn_close - btn_close = new Button.with_label(" " + _("Close")); - btn_close.set_image (new Image.from_stock ("gtk-close", IconSize.MENU)); - hbox_action.add(btn_close); - - btn_close.clicked.connect(() => { - this.destroy(); - }); - } - - public void initialize() { - title = program_name; - img_logo.pixbuf = logo; - lbl_program_name.label = "%s".printf(program_name); - lbl_version.label = "v%s".printf(version); - lbl_comments.label = "%s".printf(comments); - lbtn_website.uri = website; - lbtn_website.label = website_label; - //lbl_copyright.label = "%s".printf(copyright); - lbl_copyright.label = "%s".printf(copyright); - - if (authors.length > 0){ - add_line("%s\n".printf(_("Authors"))); - foreach(string name in authors){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (artists.length > 0){ - add_line("%s\n".printf(_("Artists"))); - foreach(string name in artists){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (translators.length > 0){ - add_line("%s\n".printf(_("Translators"))); - foreach(string name in translators){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (third_party.length > 0){ - add_line("%s\n".printf(_("Third Party Tools & Software"))); - foreach(string name in third_party){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (documenters.length > 0){ - add_line("%s\n".printf(_("Documenters"))); - foreach(string name in documenters){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (donations.length > 0){ - add_line("%s\n".printf(_("Donations"))); - foreach(string name in donations){ - add_line("%s\n".printf(name)); - } - add_line("\n"); - } - - if (vbox_lines.get_children().length() == 0){ - btn_credits.visible = false; - } - } - - public void add_line(string text){ - if (text.split(":").length >= 2){ - var txt = break_string_by_word(text.split(":")[0].strip()); - var link = new LinkButton(txt); - vbox_lines.add(link); - - string val = text[text.index_of(":") + 1:text.length]; //break at first colon - if (val.contains("@")){ - link.uri = "mailto:" + val; - } - else if(val.has_prefix("http://") || val.has_prefix("https://")){ - link.uri = val; - } - else{ - link.uri = "http://" + val; - } - - link.activate_link.connect(()=>{ - try{ - return Gtk.show_uri(null, link.uri, Gdk.CURRENT_TIME); - } - catch(Error e){ - return false; - } - }); - } - else{ - var txt = break_string_by_word(text); - var lbl = new Label(txt); - lbl.set_use_markup(true); - lbl.valign = Align.START; - lbl.wrap = true; - lbl.wrap_mode = Pango.WrapMode.WORD; - vbox_lines.add(lbl); - } - } - - public string break_string_by_word(string input_text){ - string text = ""; - string line = ""; - foreach(string part in input_text.split(" ")){ - line += part + " "; - if (line.length > 50){ - text += line.strip() + "\n"; - line = ""; - } - } - if (line.length > 0){ - text += line; - } - if (text.has_suffix("\n")){ - text = text[0:text.length-1].strip(); - } - return text; - } -} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/AppGtk.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/AppGtk.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/AppGtk.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/AppGtk.vala 2016-12-07 16:47:10.000000000 +0000 @@ -28,17 +28,16 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; public Main App; public const string AppName = "Ubuntu Kernel Update Utility"; public const string AppShortName = "ukuu"; -public const string AppVersion = "16.11.1"; +public const string AppVersion = "16.12"; public const string AppAuthor = "Tony George"; public const string AppAuthorEmail = "teejeetech@gmail.com"; @@ -128,7 +127,7 @@ } } - log_msg(_("Using cache directory") + ": %s".printf(LinuxKernel.CACHE_DIR)); + //log_msg(_("Using cache directory") + ": %s".printf(LinuxKernel.CACHE_DIR)); for (int k = 1; k < args.length; k++) // Oth arg is app path { diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/CellRendererProgress2.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/CellRendererProgress2.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/CellRendererProgress2.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/CellRendererProgress2.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ - public class CellRendererProgress2 : Gtk.CellRendererProgress{ - public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { - if (text == "--") - return; - - int diff = (int) ((cell_area.height - height)/2); - - // Apply the new height into the bar, and center vertically: - Gdk.Rectangle new_area = Gdk.Rectangle() ; - new_area.x = cell_area.x; - new_area.y = cell_area.y + diff; - new_area.width = width - 5; - new_area.height = height; - - base.render(cr, widget, background_area, new_area, flags); - } - } - diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/CustomMessageDialog.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/CustomMessageDialog.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/CustomMessageDialog.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/CustomMessageDialog.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -/* - * CustomMessageDialog.vala - * - * Copyright 2015 Tony George - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ - - -using Gtk; -using Gee; - -using TeeJee.Logging; -using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.GtkHelper; -using TeeJee.Multimedia; -using TeeJee.System; -using TeeJee.Misc; - -public class CustomMessageDialog : Gtk.Dialog { - private Gtk.Box vbox_main; - private Gtk.Label lbl_msg; - private Gtk.ScrolledWindow sw_msg; - private Gtk.Button btn_ok; - - private string msg_title; - private string msg_body; - private Gtk.MessageType msg_type; - - public CustomMessageDialog(string _msg_title, string _msg_body, Gtk.MessageType _msg_type, Window? parent) { - set_transient_for(parent); - set_modal(true); - - msg_title = _msg_title; - msg_body = _msg_body; - msg_type = _msg_type; - - init_window(); - - show_all(); - - if (lbl_msg.get_allocated_height() > 400){ - sw_msg.vscrollbar_policy = PolicyType.AUTOMATIC; - sw_msg.set_size_request(-1,400); - lbl_msg.margin_right = 25; - } - else{ - sw_msg.vscrollbar_policy = PolicyType.NEVER; - } - } - - public void init_window () { - title = msg_title; - window_position = WindowPosition.CENTER_ON_PARENT; - icon = get_app_icon(16); - resizable = false; - deletable = false; - skip_taskbar_hint = true; - skip_pager_hint = true; - - //vbox_main - vbox_main = get_content_area () as Gtk.Box; - vbox_main.margin = 6; - - //hbox_contents - var hbox_contents = new Box (Orientation.HORIZONTAL, 6); - hbox_contents.margin = 6; - vbox_main.add (hbox_contents); - - string icon_name = "gtk-dialog-info"; - - switch(msg_type){ - case Gtk.MessageType.INFO: - icon_name = "gtk-dialog-info"; - break; - case Gtk.MessageType.WARNING: - icon_name = "gtk-dialog-warning"; - break; - case Gtk.MessageType.QUESTION: - icon_name = "gtk-dialog-question"; - break; - case Gtk.MessageType.ERROR: - icon_name = "gtk-dialog-error"; - break; - } - - //img - var img = new Image.from_icon_name(icon_name, Gtk.IconSize.DIALOG); - img.margin_right = 12; - hbox_contents.add(img); - - //lbl_msg - lbl_msg = new Gtk.Label(msg_body); - lbl_msg.xalign = (float) 0.0; - lbl_msg.max_width_chars = 70; - lbl_msg.wrap = true; - lbl_msg.wrap_mode = Pango.WrapMode.WORD; - //hbox_contents.add(lbl_msg); - - //sw_msg - sw_msg = new ScrolledWindow(null, null); - //sw_msg.set_shadow_type (ShadowType.ETCHED_IN); - sw_msg.add (lbl_msg); - sw_msg.expand = true; - sw_msg.hscrollbar_policy = PolicyType.NEVER; - sw_msg.vscrollbar_policy = PolicyType.AUTOMATIC; - //sw_msg.set_size_request(); - hbox_contents.add(sw_msg); - - //actions - btn_ok = (Gtk.Button) add_button ("_Ok", Gtk.ResponseType.OK); - btn_ok.clicked.connect(()=>{ - this.close(); - }); - //btn_cancel = (Gtk.Button) add_button ("_Cancel", Gtk.ResponseType.CANCEL); - } -} - - diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/DonationWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/DonationWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/DonationWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/DonationWindow.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* - * DonationWindow.vala - * - * Copyright 2012 Tony George - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ - -using Gtk; - -using TeeJee.Logging; -using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.GtkHelper; -using TeeJee.System; -using TeeJee.Misc; - -public class DonationWindow : Dialog { - public DonationWindow() { - set_title(_("Donate")); - window_position = WindowPosition.CENTER_ON_PARENT; - set_destroy_with_parent (true); - set_modal (true); - set_deletable(true); - set_skip_taskbar_hint(false); - - set_default_size (400, 20); - icon = get_app_icon(16); - - //vbox_main - Box vbox_main = get_content_area(); - vbox_main.margin = 6; - vbox_main.homogeneous = false; - - get_action_area().visible = false; - - //lbl_message - Label lbl_message = new Gtk.Label(""); - string msg = _("Did you find this software useful?\n\nYou can buy me a coffee or make a donation via PayPal to show your support. Or just drop me an email and say Hi. This application is completely free and will continue to remain that way. Your contributions will help in keeping this project alive and improving it further.\n\nFeel free to send me an email if you find any issues in this application or if you need any changes. Suggestions and feedback are always welcome.\n\nThanks,\nTony George\n(teejeetech@gmail.com)"); - lbl_message.label = msg; - lbl_message.wrap = true; - vbox_main.pack_start(lbl_message,true,true,0); - - //vbox_actions - Box vbox_actions = new Box (Orientation.VERTICAL, 6); - vbox_actions.margin_left = 50; - vbox_actions.margin_right = 50; - vbox_actions.margin_top = 20; - vbox_main.pack_start(vbox_actions,false,false,0); - - //btn_donate_paypal - Button btn_donate_paypal = new Button.with_label(" " + _("Donate with PayPal") + " "); - vbox_actions.add(btn_donate_paypal); - btn_donate_paypal.clicked.connect(()=>{ - xdg_open("https://www.paypal.com/cgi-bin/webscr?business=teejeetech@gmail.com&cmd=_xclick¤cy_code=USD&amount=10&item_name=Ukuu%20Donation"); - }); - - //btn_donate_wallet - Button btn_donate_wallet = new Button.with_label(" " + _("Donate with Google Wallet") + " "); - vbox_actions.add(btn_donate_wallet); - btn_donate_wallet.clicked.connect(()=>{ - xdg_open("https://support.google.com/mail/answer/3141103?hl=en"); - }); - - //btn_send_email - Button btn_send_email = new Button.with_label(" " + _("Send Email") + " "); - vbox_actions.add(btn_send_email); - btn_send_email.clicked.connect(()=>{ - xdg_open("mailto:teejeetech@gmail.com"); - }); - - //btn_visit - Button btn_visit = new Button.with_label(" " + _("Visit Website") + " "); - vbox_actions.add(btn_visit); - btn_visit.clicked.connect(()=>{ - xdg_open("http://www.teejeetech.in"); - }); - - //btn_exit - Button btn_exit = new Button.with_label(" " + _("OK") + " "); - vbox_actions.add(btn_exit); - btn_exit.clicked.connect(() => { - this.destroy(); - }); - } -} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/GtkHelper.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/GtkHelper.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/GtkHelper.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/GtkHelper.vala 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ - - -using TeeJee.Logging; -using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; -using TeeJee.System; -using TeeJee.Misc; - -namespace TeeJee.GtkHelper{ - - using Gtk; - - // messages ----------- - - public void show_err_log(Gtk.Window parent, bool disable_log = true){ - if ((err_log != null) && (err_log.length > 0)){ - gtk_messagebox(_("Error"), err_log, parent, true); - } - - if (disable_log){ - disable_err_log(); - } - } - - public void gtk_do_events (){ - - /* Do pending events */ - - while(Gtk.events_pending ()) - Gtk.main_iteration (); - } - - public void gtk_set_busy (bool busy, Gtk.Window win) { - - /* Show or hide busy cursor on window */ - - Gdk.Cursor? cursor = null; - - if (busy){ - cursor = new Gdk.Cursor(Gdk.CursorType.WATCH); - } - else{ - cursor = new Gdk.Cursor(Gdk.CursorType.ARROW); - } - - var window = win.get_window (); - - if (window != null) { - window.set_cursor (cursor); - } - - gtk_do_events (); - } - - public void gtk_messagebox(string title, string message, Gtk.Window? parent_win, bool is_error = false){ - - /* Shows a simple message box */ - - var type = Gtk.MessageType.INFO; - if (is_error){ - type = Gtk.MessageType.ERROR; - } - else{ - type = Gtk.MessageType.INFO; - } - - /*var dlg = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, type, Gtk.ButtonsType.OK, message); - dlg.title = title; - dlg.set_default_size (200, -1); - if (parent_win != null){ - dlg.set_transient_for(parent_win); - dlg.set_modal(true); - } - dlg.run(); - dlg.destroy();*/ - - var dlg = new CustomMessageDialog(title,message,type,parent_win); - dlg.run(); - } - - // combo --------- - - public bool gtk_combobox_set_value (ComboBox combo, int index, string val){ - - /* Conveniance function to set combobox value */ - - TreeIter iter; - string comboVal; - TreeModel model = (TreeModel) combo.model; - - bool iterExists = model.get_iter_first (out iter); - while (iterExists){ - model.get(iter, 1, out comboVal); - if (comboVal == val){ - combo.set_active_iter(iter); - return true; - } - iterExists = model.iter_next (ref iter); - } - - return false; - } - - public string gtk_combobox_get_value (ComboBox combo, int index, string default_value){ - - /* Conveniance function to get combobox value */ - - if ((combo.model == null) || (combo.active < 0)) { return default_value; } - - TreeIter iter; - string val = ""; - combo.get_active_iter (out iter); - TreeModel model = (TreeModel) combo.model; - model.get(iter, index, out val); - - return val; - } - - public int gtk_combobox_get_value_enum (ComboBox combo, int index, int default_value){ - - /* Conveniance function to get combobox value */ - - if ((combo.model == null) || (combo.active < 0)) { return default_value; } - - TreeIter iter; - int val; - combo.get_active_iter (out iter); - TreeModel model = (TreeModel) combo.model; - model.get(iter, index, out val); - - return val; - } - - // icon ------- - - public Gdk.Pixbuf? get_app_icon(int icon_size, string format = ".png"){ - var img_icon = get_shared_icon(AppShortName, AppShortName + format,icon_size,"pixmaps"); - if (img_icon != null){ - return img_icon.pixbuf; - } - else{ - return null; - } - } - - public Gtk.Image? get_shared_icon( - string icon_name, - string fallback_icon_file_name, - int icon_size, - string icon_directory = AppShortName + "/images"){ - - Gdk.Pixbuf pix_icon = null; - Gtk.Image img_icon = null; - - try { - Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default(); - - pix_icon = icon_theme.load_icon_for_scale ( - icon_name, Gtk.IconSize.MENU, icon_size, Gtk.IconLookupFlags.FORCE_SIZE); - - } catch (Error e) { - //log_error (e.message); - } - - string fallback_icon_file_path = "/usr/share/%s/%s".printf(icon_directory, fallback_icon_file_name); - - if (pix_icon == null){ - try { - pix_icon = new Gdk.Pixbuf.from_file_at_size (fallback_icon_file_path, icon_size, icon_size); - } catch (Error e) { - log_error (e.message); - } - } - - if (pix_icon == null){ - log_error (_("Missing Icon") + ": '%s', '%s'".printf(icon_name, fallback_icon_file_path)); - } - else{ - img_icon = new Gtk.Image.from_pixbuf(pix_icon); - } - - return img_icon; - } - - public Gdk.Pixbuf? get_shared_icon_pixbuf(string icon_name, - string fallback_file_name, - int icon_size, - string icon_directory = AppShortName + "/images"){ - - var img = get_shared_icon(icon_name, fallback_file_name, icon_size, icon_directory); - var pixbuf = (img == null) ? null : img.pixbuf; - return pixbuf; - } - - // treeview ----------------- - - public int gtk_treeview_model_count(TreeModel model){ - int count = 0; - TreeIter iter; - if (model.get_iter_first(out iter)){ - count++; - while(model.iter_next(ref iter)){ - count++; - } - } - return count; - } -} - diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/MainWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/MainWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/MainWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/MainWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -26,10 +26,9 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; @@ -490,7 +489,7 @@ }; dialog.translators = { - + "Åke Engelbrektson (Swedish):eson@svenskasprakfiler.se" }; dialog.documenters = null; @@ -546,8 +545,8 @@ App.progress_count = LinuxKernel.progress_count; ulong ms_elapsed = timer_elapsed(timer, false); - int remaining_count = App.progress_total - App.progress_count; - ulong ms_remaining = (ulong)((ms_elapsed * 1.0) / App.progress_count) * remaining_count; + int64 remaining_count = App.progress_total - App.progress_count; + int64 ms_remaining = (int64)((ms_elapsed * 1.0) / App.progress_count) * remaining_count; if ((count % 5) == 0){ msg_remaining = format_time_left(ms_remaining); @@ -555,7 +554,7 @@ if (App.progress_total > 0){ dlg.update_message( - message + " %ld/%ld (%s)".printf( + message + " %lld/%lld (%s)".printf( App.progress_count, App.progress_total, msg_remaining)); diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/ProgressWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/ProgressWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/ProgressWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/ProgressWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -27,10 +27,9 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/SettingsDialog.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/SettingsDialog.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/SettingsDialog.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/SettingsDialog.vala 2016-12-07 16:47:10.000000000 +0000 @@ -27,10 +27,9 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/TerminalWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/TerminalWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/TerminalWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/TerminalWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -27,10 +27,9 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/UpdateNotificationWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Gtk/UpdateNotificationWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Gtk/UpdateNotificationWindow.vala 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Gtk/UpdateNotificationWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -27,10 +27,9 @@ using TeeJee.Logging; using TeeJee.FileSystem; -using TeeJee.JSON; -using TeeJee.ProcessManagement; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; using TeeJee.GtkHelper; -using TeeJee.Multimedia; using TeeJee.System; using TeeJee.Misc; diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/makefile ukuu-16.12~57~ubuntu16.10.1/src/makefile --- ukuu-16.11.1~47~ubuntu16.10.1/src/makefile 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/makefile 2016-12-07 16:47:10.000000000 +0000 @@ -16,10 +16,10 @@ #build binaries #app-gtk - valac -X -D'GETTEXT_PACKAGE="${app_name}"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/${app_name}/libs ${define_symbols} --thread Common/*.vala Gtk/*.vala -o ${app_name}-gtk --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg json-glib-1.0 --pkg $(vte_version) + valac -X -D'GETTEXT_PACKAGE="${app_name}"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/${app_name}/libs ${define_symbols} --thread Common/*.vala Gtk/*.vala Utility/*.vala Utility/Gtk/*.vala -o ${app_name}-gtk --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg json-glib-1.0 --pkg $(vte_version) #app - valac -X -D'GETTEXT_PACKAGE="${app_name}"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/${app_name}/libs --thread Common/*.vala Console/*.vala Gtk/CustomMessageDialog.vala Gtk/UpdateNotificationWindow.vala Gtk/GtkHelper.vala -o ${app_name} --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg libsoup-2.4 --pkg json-glib-1.0 --pkg $(vte_version) + valac -X -D'GETTEXT_PACKAGE="${app_name}"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/${app_name}/libs --thread Common/*.vala Console/*.vala Utility/*.vala Utility/Gtk/*.vala Gtk/UpdateNotificationWindow.vala -o ${app_name} --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg libsoup-2.4 --pkg json-glib-1.0 --pkg $(vte_version) #update translation template find . -iname "*.vala" | xargs xgettext --language=C --keyword=_ --copyright-holder='Tony George (teejeetech@gmail.com)' --package-name='${app_name}' --package-version='2.2' --msgid-bugs-address='teejeetech@gmail.com' --escape --sort-output -o ../${app_name}.pot @@ -49,7 +49,7 @@ #polkit policy file #install -m 0644 ./share/polkit-1/actions/in.teejeetech.pkexec.ukuu-gtk.policy "$(DESTDIR)$(polkitdir)" - #rm -f "$(DESTDIR)$(polkitdir)/in.teejeetech.pkexec.ukuu-gtk.policy" + #rm -f "$(DESTDIR)$(polkitdir)/in.teejeetech.pkexec.ukuu-gtk.policy" #launcher install -m 0755 ${app_name}.desktop "$(DESTDIR)$(launcherdir)" @@ -58,9 +58,8 @@ install -m 0755 ./share/pixmaps/${app_name}.* "$(DESTDIR)$(sharedir)/pixmaps" #translations - #mkdir -p "$(DESTDIR)$(localedir)/ms/LC_MESSAGES" - #msgfmt --check --verbose -o "$(DESTDIR)$(localedir)/ms/LC_MESSAGES/${app_name}.mo" ../po/${app_name}-ms.po - + mkdir -p "$(DESTDIR)$(localedir)/sv/LC_MESSAGES" + msgfmt --check --verbose -o "$(DESTDIR)$(localedir)/sv/LC_MESSAGES/${app_name}.mo" ../po/${app_name}-sv.po uninstall: #binary @@ -80,4 +79,8 @@ rm -f "$(DESTDIR)$(sharedir)/pixmaps/${app_name}.png" #translations - #rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/${app_name}.mo + rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/${app_name}.mo + + #startup scripts + rm -f $(DESTDIR)/home/*/.config/ukuu-notify.sh + rm -f $(DESTDIR)/home/*/.config/autostart/ukuu.desktop diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/AppLock.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/AppLock.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/AppLock.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/AppLock.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,89 @@ + +/* + * AppLock.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.ProcessHelper; +using TeeJee.Misc; + +public class AppLock : GLib.Object { + public string lock_file = ""; + public string lock_message = ""; + + public bool create(string app_name, string message){ + + var lock_dir = "/var/run/lock/%s".printf(app_name); + dir_create(lock_dir); + lock_file = path_combine(lock_dir, "lock"); + + try{ + var file = File.new_for_path(lock_file); + if (file.query_exists()) { + + string txt = file_read(lock_file); + string process_id = txt.split(";")[0].strip(); + lock_message = txt.split(";")[1].strip(); + long pid = long.parse(process_id); + + if (process_is_running(pid)){ + log_msg(_("Another instance of this application is running") + + " (PID=%ld)".printf(pid)); + return false; + } + else{ + log_msg(_("[Warning] Deleted invalid lock")); + file.delete(); + write_lock_file(message); + return true; + } + } + else{ + write_lock_file(message); + return true; + } + } + catch (Error e) { + log_error (e.message); + return false; + } + } + + private void write_lock_file(string message){ + string current_pid = ((long) Posix.getpid()).to_string(); + file_write(lock_file, "%s;%s".printf(current_pid, message)); + } + + public void remove(){ + try{ + var file = File.new_for_path (lock_file); + if (file.query_exists()) { + file.delete(); + } + } + catch (Error e) { + log_error (e.message); + } + } + +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/ArchiveFile.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/ArchiveFile.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/ArchiveFile.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/ArchiveFile.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * ArchiveFile.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using GLib; +using Gtk; +using Gee; +using Json; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class ArchiveFile : FileItem { + + // additional properties + public int64 archive_size = 0; + public int64 archive_unpacked_size = 0; + public double compression_ratio = 0.0; + public string archive_type = ""; + public string archive_method = ""; + public bool archive_is_encrypted = false; + public bool archive_is_solid = false; + public int archive_blocks = 0; + public int64 archive_header_size = 0; + public DateTime archive_modified; + + public string password = ""; + public string keyfile = ""; + + // extraction + public Gee.ArrayList extract_list; + + // temp + public string temp_dir = ""; + public string script_file = ""; + public string log_file = ""; + + public ArchiveFile(string archive_file_path = "") { + base.from_path_and_type(archive_file_path, FileType.REGULAR); + is_archive = true; + + //this.tag = this; + + extract_list = new Gee.ArrayList(); + temp_dir = TEMP_DIR + "/" + timestamp_for_path(); + log_file = temp_dir + "/log.txt"; + script_file = temp_dir + "/convert.sh"; + dir_create (temp_dir); + } + + public void add_items(Gee.ArrayList item_list){ + if (item_list.size > 0){ + foreach(string item in item_list){ + add_child_from_disk(item); + } + } + } +} + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/AsyncTask.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/AsyncTask.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/AsyncTask.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/AsyncTask.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,541 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.System; +using TeeJee.Misc; + +public abstract class AsyncTask : GLib.Object{ + + private string err_line = ""; + private string out_line = ""; + private DataOutputStream dos_in; + private DataInputStream dis_out; + private DataInputStream dis_err; + protected DataOutputStream dos_log; + protected bool is_terminated = false; + + private bool stdout_is_open = false; + private bool stderr_is_open = false; + + protected Pid child_pid; + private int input_fd; + private int output_fd; + private int error_fd; + private bool finish_called = false; + + protected string script_file = ""; + protected string working_dir = ""; + protected string log_file = ""; + + public bool background_mode = false; + + // public + public AppStatus status; + public string status_line = ""; + public int exit_code = 0; + public string error_msg = ""; + public GLib.Timer timer; + public double progress = 0.0; + public double percent = 0.0; + public int64 prg_count = 0; + public int64 prg_count_total = 0; + public int64 prg_bytes = 0; + public int64 prg_bytes_total = 0; + public string eta = ""; + //public bool is_running = false; + + // signals + public signal void stdout_line_read(string line); + public signal void stderr_line_read(string line); + public signal void task_complete(); + + public AsyncTask(){ + working_dir = TEMP_DIR + "/" + timestamp_for_path(); + script_file = path_combine(working_dir, "script.sh"); + log_file = path_combine(working_dir, "task.log"); + + //regex = new Gee.HashMap(); // needs to be initialized again in instance constructor + + dir_create(working_dir); + } + + public bool begin(){ + + status = AppStatus.RUNNING; + + bool has_started = true; + is_terminated = false; + finish_called = false; + + prg_count = 0; + prg_bytes = 0; + error_msg = ""; + + string[] spawn_args = new string[1]; + spawn_args[0] = script_file; + + string[] spawn_env = Environ.get(); + + try { + // start timer + timer = new GLib.Timer(); + timer.start(); + + // execute script file + Process.spawn_async_with_pipes( + working_dir, // working dir + spawn_args, // argv + spawn_env, // environment + SpawnFlags.SEARCH_PATH, + null, // child_setup + out child_pid, + out input_fd, + out output_fd, + out error_fd); + + set_priority(); + + log_debug("AsyncTask: child_pid: %d".printf(child_pid)); + + // create stream readers + UnixOutputStream uos_in = new UnixOutputStream(input_fd, false); + UnixInputStream uis_out = new UnixInputStream(output_fd, false); + UnixInputStream uis_err = new UnixInputStream(error_fd, false); + dos_in = new DataOutputStream(uos_in); + dis_out = new DataInputStream(uis_out); + dis_err = new DataInputStream(uis_err); + dis_out.newline_type = DataStreamNewlineType.ANY; + dis_err.newline_type = DataStreamNewlineType.ANY; + + // create log file + if (log_file.length > 0){ + var file = File.new_for_path(log_file); + if (file.query_exists()){ + file.delete(); + } + var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); + dos_log = new DataOutputStream (file_stream); + } + + try { + //start thread for reading output stream + Thread.create (read_stdout, true); + } catch (Error e) { + log_error ("AsyncTask.begin():create_thread:read_stdout()"); + log_error (e.message); + } + + try { + //start thread for reading error stream + Thread.create (read_stderr, true); + } catch (Error e) { + log_error ("AsyncTask.begin():create_thread:read_stderr()"); + log_error (e.message); + } + } + catch (Error e) { + log_error ("AsyncTask.begin()"); + log_error(e.message); + has_started = false; + //status = AppStatus.FINISHED; + } + + return has_started; + } + + private void read_stdout() { + try { + stdout_is_open = true; + + out_line = dis_out.read_line (null); + while (out_line != null) { + //log_msg("O: " + out_line); + if (!is_terminated && (out_line.length > 0)){ + parse_stdout_line(out_line); + stdout_line_read(out_line); //signal + } + out_line = dis_out.read_line (null); //read next + } + + stdout_is_open = false; + + // dispose stdout + if ((dis_out != null) && !dis_out.is_closed()){ + dis_out.close(); + } + //dis_out.close(); + dis_out = null; + GLib.FileUtils.close(output_fd); + + // check if complete + if (!stdout_is_open && !stderr_is_open){ + finish(); + } + } + catch (Error e) { + log_error ("AsyncTask.read_stdout()"); + log_error (e.message); + } + } + + private void read_stderr() { + try { + stderr_is_open = true; + + err_line = dis_err.read_line (null); + while (err_line != null) { + if (!is_terminated && (err_line.length > 0)){ + error_msg += "%s\n".printf(err_line); + + parse_stderr_line(err_line); + stderr_line_read(err_line); //signal + } + err_line = dis_err.read_line (null); //read next + } + + stderr_is_open = false; + + // dispose stderr + if ((dis_err != null) && !dis_err.is_closed()){ + dis_err.close(); + } + //dis_err.close(); + dis_err = null; + GLib.FileUtils.close(error_fd); + + // check if complete + if (!stdout_is_open && !stderr_is_open){ + finish(); + } + } + catch (Error e) { + log_error ("AsyncTask.read_stderr()"); + log_error (e.message); + } + } + + public void write_stdin(string line){ + try{ + if (status == AppStatus.RUNNING){ + dos_in.put_string(line + "\n"); + } + else{ + log_error ("AsyncTask.write_stdin(): NOT RUNNING"); + } + } + catch(Error e){ + log_error ("AsyncTask.write_stdin(): %s".printf(line)); + log_error (e.message); + } + } + + protected abstract void parse_stdout_line(string out_line); + + protected abstract void parse_stderr_line(string err_line); + + private void finish(){ + // finish() gets called by 2 threads but should be executed only once + if (finish_called) { return; } + finish_called = true; + + log_debug("AsyncTask: finish(): enter"); + + // dispose stdin + try{ + if ((dos_in != null) && !dos_in.is_closed() && !dos_in.is_closing()){ + dos_in.close(); + } + } + catch(Error e){ + // ignore + //log_error ("AsyncTask.finish(): dos_in.close()"); + //log_error (e.message); + } + + dos_in = null; + GLib.FileUtils.close(input_fd); + + // dispose child process + Process.close_pid(child_pid); //required on Windows, doesn't do anything on Unix + + try{ + // dispose log + if ((dos_log != null) && !dos_log.is_closed() && !dos_log.is_closing()){ + dos_log.close(); + } + dos_log = null; + } + catch (Error e) { + // error can be ignored + // dos_log is closed automatically when the last reference is set to null + // there may be pending operations which may throw an error + } + + read_exit_code(); + + status_line = ""; + err_line = ""; + out_line = ""; + + timer.stop(); + + finish_task(); + + if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { + status = AppStatus.FINISHED; + } + + //dir_delete(working_dir); + + task_complete(); //signal + } + + protected abstract void finish_task(); + + protected int read_exit_code(){ + log_debug("read_exit_code: enter"); + exit_code = -1; + var status_file = file_parent(script_file) + "/status"; + if (file_exists(status_file)){ + var txt = file_read(status_file); + exit_code = int.parse(txt); + } + log_debug("exit_code: %d".printf(exit_code)); + return exit_code; + } + + public bool is_running(){ + return (status == AppStatus.RUNNING); + } + + // public actions -------------- + + public void pause() { + Pid sub_child_pid; + foreach (long pid in get_process_children(child_pid)) { + sub_child_pid = (Pid) pid; + process_pause(sub_child_pid); + } + + status = AppStatus.PAUSED; + } + + public void resume() { + Pid sub_child_pid; + foreach (long pid in get_process_children(child_pid)) { + sub_child_pid = (Pid) pid; + process_resume(sub_child_pid); + } + + status = AppStatus.RUNNING; + } + + public void stop(AppStatus status_to_update = AppStatus.CANCELLED) { + // we need to un-freeze the processes before we kill them + if (status == AppStatus.PAUSED) { + resume(); + } + + status = status_to_update; + + process_quit(child_pid); + + log_debug("process_quit: %d".printf(child_pid)); + } + + public void set_priority() { + if (background_mode){ + set_priority_value(5); + } + else{ + set_priority_value(0); + } + } + + public void set_priority_value(int prio) { + Pid app_pid = Posix.getpid(); + process_set_priority (app_pid, prio); + + if (status == AppStatus.RUNNING) { + process_set_priority (child_pid, prio); + + Pid sub_child_pid; + foreach (long pid in get_process_children (child_pid)) { + sub_child_pid = (Pid) pid; + process_set_priority (sub_child_pid, prio); + } + } + } + + public string stat_time_elapsed{ + owned get{ + long elapsed = (long) timer_elapsed(timer); + return format_duration(elapsed); + } + } + + public string stat_time_remaining{ + owned get{ + if (progress > 0){ + long elapsed = (long) timer_elapsed(timer); + long remaining = (long)((elapsed / progress) * (1.0 - progress)); + if (remaining < 0){ + remaining = 0; + } + return format_duration(remaining); + } + else{ + return "???"; + } + } + } + + public void print_app_status(){ + switch(status){ + case AppStatus.NOT_STARTED: + log_debug("status=%s".printf("NOT_STARTED")); + break; + case AppStatus.RUNNING: + log_debug("status=%s".printf("RUNNING")); + break; + case AppStatus.PAUSED: + log_debug("status=%s".printf("PAUSED")); + break; + case AppStatus.FINISHED: + log_debug("status=%s".printf("FINISHED")); + break; + case AppStatus.CANCELLED: + log_debug("status=%s".printf("CANCELLED")); + break; + case AppStatus.PASSWORD_REQUIRED: + log_debug("status=%s".printf("PASSWORD_REQUIRED")); + break; + } + } +} + +public enum AppStatus { + NOT_STARTED, + RUNNING, + PAUSED, + FINISHED, + CANCELLED, + PASSWORD_REQUIRED +} + +/* Sample Subclass: +public class RsyncTask : AsyncTask{ + + public bool delete_extra = true; + public string rsync_log_file = ""; + public string exclude_from_file = ""; + public string source_path = ""; + public string dest_path = ""; + public bool verbose = true; + + public RsyncTask(string _script_file, string _working_dir, string _log_file){ + working_dir = _working_dir; + script_file = _script_file; + log_file = _log_file; + } + + public void prepare() { + string script_text = build_script(); + save_bash_script_temp(script_text, script_file); + } + + private string build_script() { + var script = new StringBuilder(); + + var cmd = "rsync -ai"; + + if (verbose){ + cmd += " --verbose"; + } + else{ + cmd += " --quiet"; + } + + if (delete_extra){ + cmd += " --delete"; + } + + cmd += " --numeric-ids --stats --relative --delete-excluded"; + + if (rsync_log_file.length > 0){ + cmd += " --log-file='%s'".printf(escape_single_quote(rsync_log_file)); + } + + if (exclude_from_file.length > 0){ + cmd += " --exclude-from='%s'".printf(escape_single_quote(exclude_from_file)); + } + + source_path = remove_trailing_slash(source_path); + + dest_path = remove_trailing_slash(dest_path); + + cmd += " '%s/'".printf(escape_single_quote(source_path)); + + cmd += " '%s/'".printf(escape_single_quote(dest_path)); + + //cmd += " /. \"%s\"".printf(sync_path + "/localhost/"); + + return script.str; + } + + // execution ---------------------------- + + public void execute() { + + prepare(); + + begin(); + + if (status == AppStatus.RUNNING){ + + + } + } + + public override void parse_stdout_line(string out_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(out_line); + } + + public override void parse_stderr_line(string err_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(err_line); + } + + public bool update_progress_parse_console_output (string line) { + if ((line == null) || (line.length == 0)) { + return true; + } + + return true; + } + + protected override void finish_task(){ + if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { + status = AppStatus.FINISHED; + } + } + + public int read_status(){ + var status_file = working_dir + "/status"; + var f = File.new_for_path(status_file); + if (f.query_exists()){ + var txt = file_read(status_file); + return int.parse(txt); + } + return -1; + } +} +*/ diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Bash.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Bash.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Bash.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Bash.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Bash.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using GLib; +using Gtk; +using Gee; +using Json; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class Bash : AsyncTask { + + public Pid bash_pid = -1; + public int status_code = -1; + private static Gee.HashMap regex_list; + + public Bash() { + init_regular_expressions(); + } + + private static void init_regular_expressions(){ + if (regex_list != null){ + return; // already initialized + } + + regex_list = new Gee.HashMap(); + + try { + //Example: status=-1 + regex_list["status"] = new Regex("""status=([0-9\-]+)"""); + } + catch (Error e) { + log_error (e.message); + } + } + + // execution ---------------------------- + + public void start_shell() { + dir_create(working_dir); + + var sh = "bash -c 'pkexec bash'"; + save_bash_script_temp(sh, script_file); + begin(); + log_debug("Started bash shell"); + + if (status == AppStatus.RUNNING){ + bash_pid = -1; + while ((status == AppStatus.RUNNING) && (bash_pid == -1)) { + sleep(200); + var children = get_process_children(child_pid); + if (children.length > 0){ + bash_pid = children[0]; + } + } + + log_debug("script pid: %d".printf(child_pid)); + log_debug("bash shell pid: %d".printf(bash_pid)); + } + } + + public override void parse_stdout_line(string out_line){ + if ((out_line == null) || (out_line.length == 0)) { + return; + } + MatchInfo match; + if (regex_list["status"].match(out_line, 0, out match)) { + status_code = int.parse(match.fetch(1)); + } + stdout.printf(out_line + "\n"); + stdout.flush(); + } + + public override void parse_stderr_line(string err_line){ + stdout.printf(err_line + "\n"); + stdout.flush(); + } + + public int execute(string line){ + status_code = -1; + write_stdin(line); + write_stdin("echo status=$?"); + + while (status_code == -1){ + sleep(200); + gtk_do_events(); + } + + return status_code; + } + + protected override void finish_task(){ + log_debug("Bash: finish_task()"); + } + + public int read_status(){ + var status_file = working_dir + "/status"; + var f = File.new_for_path(status_file); + if (f.query_exists()){ + var txt = file_read(status_file); + return int.parse(txt); + } + return -1; + } + +} + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/CronTab.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/CronTab.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/CronTab.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/CronTab.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,220 @@ + +using TeeJee.Logging; +using TeeJee.FileSystem; +//using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +//using TeeJee.Multimedia; +//using TeeJee.System; +using TeeJee.Misc; + +public class CronTab : GLib.Object { + + public static string crontab_text = null; + + public static void clear_cached_text(){ + crontab_text = null; + } + + public static string crontab_read_all(string user_name = ""){ + string std_out, std_err; + + var cmd = "crontab -l"; + if (user_name.length > 0){ + cmd += " -u %s".printf(user_name); + } + + log_debug(cmd); + + int ret_val = exec_sync(cmd, out std_out, out std_err); + + if (ret_val != 0){ + log_debug(_("Failed to read cron tab")); + return ""; + } + else{ + return std_out; + } + } + + public static bool add_job(string entry, bool use_cached_text){ + + // read crontab file + string tab = ""; + if (use_cached_text && (crontab_text != null)){ + tab = crontab_text; + } + else{ + crontab_text = crontab_read_all(); + tab = crontab_text; + } + + var lines = new Gee.ArrayList(); + foreach(string line in tab.split("\n")){ + lines.add(line); + } + + // check if entry exists + foreach(string line in lines){ + if (line == entry){ + return true; // return + } + } + + // append entry + lines.add(entry); + + // create new tab + string tab_new = ""; + foreach(string line in lines){ + if (line.length > 0){ + tab_new += "%s\n".printf(line); + } + } + + // write temp crontab file + string temp_file = get_temp_file_path(); + file_write(temp_file, tab_new); + + // install crontab file + var cmd = "crontab \"%s\"".printf(temp_file); + int status = exec_sync(cmd); + + if (status != 0){ + log_error(_("Failed to add cron job") + ": %s".printf(entry)); + return false; + } + else{ + log_msg(_("Cron job added") + ": %s".printf(entry)); + return true; + } + } + + public static bool remove_job(string entry, bool use_regex, bool use_cached_text){ + + // read crontab file + string tab = ""; + if (use_cached_text && (crontab_text != null)){ + tab = crontab_text; + } + else{ + crontab_text = crontab_read_all(); + tab = crontab_text; + } + + var lines = new Gee.ArrayList(); + foreach(string line in tab.split("\n")){ + lines.add(line); + } + + Regex regex = null; + + if (use_regex){ + try { + regex = new Regex(entry); + } + catch (Error e) { + log_error (e.message); + } + } + + // check if entry exists + bool found = false; + for(int i=0; i < lines.size; i++){ + string line = lines[i]; + if (line != null){ + line = line.strip(); + } + + if (use_regex && (regex != null)){ + + MatchInfo match; + if (regex.match(line, 0, out match)) { + lines.remove(line); + found = true; + } + } + else{ + if (line == entry){ + lines.remove(line); + found = true; + } + } + } + if (!found){ + return true; + } + + // create new tab + string tab_new = ""; + foreach(string line in lines){ + if (line.length > 0){ + tab_new += "%s\n".printf(line); + } + } + + // write temp crontab file + string temp_file = get_temp_file_path(); + file_write(temp_file, tab_new); + + // install crontab file + var cmd = "crontab \"%s\"".printf(temp_file); + int status = exec_sync(cmd); + + if (status != 0){ + log_error(_("Failed to remove cron job") + ": %s".printf(entry)); + return false; + } + else{ + log_msg(_("Cron job removed") + ": %s".printf(entry)); + return true; + } + } + + public static bool install(string file_path, string user_name = ""){ + + if (!file_exists(file_path)){ + log_error(_("File not found") + ": %s".printf(file_path)); + return false; + } + + var cmd = "crontab"; + if (user_name.length > 0){ + cmd += " -u %s".printf(user_name); + } + cmd += " \"%s\"".printf(file_path); + + log_debug(cmd); + + int status = exec_sync(cmd); + + if (status != 0){ + log_error(_("Failed to install crontab file") + ": %s".printf(file_path)); + return false; + } + else{ + log_msg(_("crontab file installed") + ": %s".printf(file_path)); + return true; + } + } + + public static bool export(string file_path, string user_name = ""){ + if (file_exists(file_path)){ + file_delete(file_path); + } + + bool ok = file_write(file_path, crontab_read_all(user_name)); + + if (!ok){ + log_error(_("Failed to export crontab file") + ": %s".printf(file_path)); + return false; + } + else{ + log_msg(_("crontab file exported") + ": %s".printf(file_path)); + return true; + } + } + + public static bool import(string file_path, string user_name = ""){ + return install(file_path, user_name); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/CryptTabEntry.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/CryptTabEntry.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/CryptTabEntry.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/CryptTabEntry.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,148 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class CryptTabEntry : GLib.Object{ + public bool is_comment = false; + public bool is_empty_line = false; + + // fields + public string mapped_name = ""; + public string device_string = ""; + public string keyfile = "none"; + public string options = "luks,nofail"; + public string line = ""; + + public string device_uuid { + owned get{ + if (device_string.down().has_prefix("uuid=")){ + return device_string.replace("\"","").replace("'","").split("=")[1]; + } + else{ + return ""; + } + } + set { + device_string = "UUID=%s".printf(value); + } + } + + public static Gee.ArrayList read_file(string file_path){ + var list = new Gee.ArrayList(); + + if (!file_exists(file_path)){ return list; } + + string text = file_read(file_path); + string[] lines = text.split("\n"); + foreach(string line in lines){ + var entry = new CryptTabEntry(); + list.add(entry); + + entry.is_comment = line.strip().has_prefix("#"); + entry.is_empty_line = (line.strip().length == 0); + + if (entry.is_comment){ + entry.line = line; + } + else if (entry.is_empty_line){ + entry.line = ""; + } + else{ + entry.line = line; + + string[] parts = line.replace("\t"," ").split(" "); + int part_num = -1; + foreach(string part in parts){ + if (part.strip().length == 0) { continue; } + switch (++part_num){ + case 0: + entry.mapped_name = part.strip(); + break; + case 1: + entry.device_string = part.strip(); + break; + case 2: + entry.keyfile = part.strip(); + break; + case 3: + entry.options = part.strip(); + break; + } + } + } + } + + return list; + } + + public static string write_file( + Gee.ArrayList entries, string file_path, + bool keep_comments_and_empty_lines = true){ + + string text = ""; + foreach(var entry in entries){ + if (entry.is_comment || entry.is_empty_line){ + if (keep_comments_and_empty_lines){ + text += "%s\n".printf(entry.line); + } + } + else { + text += "%s\t%s\t%s\t%s\n".printf( + entry.mapped_name, entry.device_string, + entry.keyfile, entry.options); + } + } + + if (file_exists(file_path)){ + file_delete(file_path); + } + + file_write(file_path, text); + + return text; + } + + public void append_option(string option){ + + if (!options.contains(option)){ + options += ",%s".printf(option); + } + + if(options.has_prefix(",")){ + options = options[1:options.length]; + } + + options = options.strip(); + } + + public void remove_option(string option){ + + options = options.replace(option,"").strip(); + + if(options.has_prefix(",")){ + options = options[1:options.length]; + } + + if (options.has_suffix(",")){ + options = options[0:options.length - 1]; + } + + options = options.strip(); + } + + public static CryptTabEntry? find_entry_by_uuid( + Gee.ArrayList entries, string uuid){ + + foreach(var entry in entries){ + if (entry.device_uuid == uuid){ + return entry; + } + } + + return null; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/DeleteFileTask.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/DeleteFileTask.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/DeleteFileTask.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/DeleteFileTask.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,186 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class DeleteFileTask : AsyncTask{ + + // settings + public string dest_path = ""; + public bool verbose = true; + public bool io_nice = true; + public bool use_rsync = false; + + //private + private string source_path = ""; + + // regex + private Gee.HashMap regex_list; + + // status + public int64 status_line_count = 0; + public int64 total_size = 0; + public string status_message = ""; + public string time_remaining = ""; + + public DeleteFileTask(){ + init_regular_expressions(); + } + + private void init_regular_expressions(){ + if (regex_list != null){ + return; // already initialized + } + + regex_list = new Gee.HashMap(); + + try { + + regex_list["rsync-deleted"] = new Regex( + """\*deleting[ \t]+(.*)"""); + + } + catch (Error e) { + log_error (e.message); + } + } + + public void prepare() { + string script_text = build_script(); + log_debug(script_text); + save_bash_script_temp(script_text, script_file); + + log_debug("RsyncTask:prepare(): saved: %s".printf(script_file)); + + status_line_count = 0; + total_size = 0; + } + + private string build_script() { + var cmd = ""; + + if (io_nice){ + //cmd += "ionice -c2 -n7 "; + } + + if (use_rsync){ + + cmd += "rsync -aii"; + + if (verbose){ + cmd += " --verbose"; + } + else{ + cmd += " --quiet"; + } + + cmd += " --delete"; + + cmd += " --stats --relative"; + + source_path = "/tmp/%s_empty".printf(random_string()); + dir_create(source_path); + + source_path = remove_trailing_slash(source_path); + dest_path = remove_trailing_slash(dest_path); + + cmd += " '%s/'".printf(escape_single_quote(source_path)); + cmd += " '%s/'".printf(escape_single_quote(dest_path)); + } + else{ + cmd += "rm"; + + if (verbose){ + cmd += " -rfv"; + } + else{ + cmd += " -rf"; + } + + cmd += " '%s'".printf(escape_single_quote(dest_path)); + } + + return cmd; + } + + // execution ---------------------------- + + public void execute() { + + status = AppStatus.RUNNING; + + log_debug("RsyncTask:execute()"); + + prepare(); + + begin(); + + if (status == AppStatus.RUNNING){ + + + } + } + + public override void parse_stdout_line(string out_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(out_line); + } + + public override void parse_stderr_line(string err_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(err_line); + } + + public bool update_progress_parse_console_output (string line) { + if ((line == null) || (line.length == 0)) { + return true; + } + + status_line_count++; + + if (prg_count_total > 0){ + prg_count = status_line_count; + progress = (prg_count * 1.0) / prg_count_total; + } + + MatchInfo match; + if (regex_list["rsync-deleted"].match(line, 0, out match)) { + + //log_debug("matched: rsync-deleted:%s".printf(line)); + + status_line = match.fetch(1).split(" -> ")[0].strip(); + } + else { + + //log_debug("matched: else:%s".printf(line)); + + status_line = line.strip(); + } + + return true; + } + + protected override void finish_task(){ + if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { + status = AppStatus.FINISHED; + } + } + + public int read_status(){ + var status_file = working_dir + "/status"; + var f = File.new_for_path(status_file); + if (f.query_exists()){ + var txt = file_read(status_file); + return int.parse(txt); + } + return -1; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Device.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Device.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Device.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Device.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,1979 @@ + +/* + * Device.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +/* Functions and classes for handling disk partitions */ + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; + +public class Device : GLib.Object{ + + /* Class for storing disk information */ + + public static double KB = 1000; + public static double MB = 1000 * KB; + public static double GB = 1000 * MB; + + public static double KiB = 1024; + public static double MiB = 1024 * KiB; + public static double GiB = 1024 * MiB; + + public string device = ""; + public string kname = ""; + public string pkname = ""; + public string name = ""; + public string mapped_name = ""; + + public string type = ""; // disk, part, crypt, loop, rom, lvm + public string fstype = ""; // iso9660, ext4, btrfs, ... + + public string label = ""; + public string uuid = ""; + public int order = -1; + + public string vendor = ""; + public string model = ""; + public string serial = ""; + public string revision = ""; + + public bool removable = false; + public bool read_only = false; + + public int64 size_bytes = 0; + public int64 used_bytes = 0; + public int64 available_bytes = 0; + + public string used_percent = ""; + public string dist_info = ""; + public Gee.ArrayList mount_points; + public Gee.ArrayList symlinks; + + public Device parent = null; + public Gee.ArrayList children = null; + + private static string lsblk_version = ""; + private static bool lsblk_is_ancient = false; + + private static Gee.ArrayList device_list; + + public Device(){ + mount_points = new Gee.ArrayList(); + symlinks = new Gee.ArrayList(); + children = new Gee.ArrayList(); + + test_lsblk_version(); + } + + public static void test_lsblk_version(){ + + if ((lsblk_version != null) && (lsblk_version.length > 0)){ + return; + } + + string std_out, std_err; + int status = exec_sync("lsblk --bytes --pairs --output HOTPLUG,PKNAME,VENDOR,SERIAL,REV", out std_out, out std_err); + if (status == 0){ + lsblk_version = std_out; + lsblk_is_ancient = false; + } + else{ + lsblk_version = "ancient"; + lsblk_is_ancient = true; + } + } + + public int64 free_bytes{ + get{ + return (used_bytes == 0) ? 0 : (size_bytes - used_bytes); + } + } + + public string size{ + owned get{ + if (size_bytes < GB){ + return "%.1f MB".printf(size_bytes / MB); + } + else if (size_bytes > 0){ + return "%.1f GB".printf(size_bytes / GB); + } + else{ + return ""; + } + } + } + + public string used{ + owned get{ + return (used_bytes == 0) ? "" : "%.1f GB".printf(used_bytes / GB); + } + } + + public string free{ + owned get{ + return (free_bytes == 0) ? "" : "%.1f GB".printf(free_bytes / GB); + } + } + + public bool is_mounted{ + get{ + return (mount_points.size > 0); + } + } + + public bool has_linux_filesystem(){ + switch (fstype){ + case "ext2": + case "ext3": + case "ext4": + case "reiserfs": + case "reiser4": + case "xfs": + case "jfs": + case "btrfs": + case "lvm": + case "lvm2": + case "lvm2_member": + case "luks": + case "crypt": + case "crypto_luks": + return true; + default: + return false; + } + } + + public bool is_encrypted_partition(){ + return (type == "part") && fstype.down().contains("luks"); + } + + public bool is_on_encrypted_partition(){ + return (type == "crypt"); + } + + public bool is_lvm_partition(){ + return (type == "part") && fstype.down().contains("lvm2_member"); + } + + public bool has_children(){ + return (children.size > 0); + } + + public Device? first_linux_child(){ + + foreach(var child in children){ + if (child.has_linux_filesystem()){ + return child; + } + } + + return null; + } + + public bool has_parent(){ + return (parent != null); + } + + // static -------------------------------- + + public static Gee.ArrayList get_filesystems(bool get_space = true, bool get_mounts = true){ + + /* Returns list of block devices + Populates all fields in Device class */ + + var list = get_block_devices_using_lsblk(); + + if (get_space){ + //get used space for mounted filesystems + var list_df = get_disk_space_using_df(); + foreach(var dev_df in list_df){ + var dev = find_device_in_list_by_uuid(list, dev_df.uuid); + if (dev != null){ + dev.size_bytes = dev_df.size_bytes; + dev.used_bytes = dev_df.used_bytes; + dev.available_bytes = dev_df.available_bytes; + dev.used_percent = dev_df.used_percent; + } + } + } + + if (get_mounts){ + //get mount points + var list_mtab = get_mounted_filesystems_using_mtab(); + foreach(var dev_mtab in list_mtab){ + var dev = find_device_in_list_by_uuid(list, dev_mtab.uuid); + if (dev != null){ + dev.mount_points = dev_mtab.mount_points; + } + } + } + + //print_device_list(list); + + //print_device_mounts(list); + + log_debug("Device: get_filesystems(): %d".printf(list.size)); + + return list; + } + + private static void find_child_devices(Gee.ArrayList list, Device parent){ + if (lsblk_is_ancient && (parent.type == "disk")){ + foreach (var part in list){ + if ((part.kname != parent.kname) && part.kname.has_prefix(parent.kname)){ + parent.children.add(part); + part.parent = parent; + part.pkname = parent.kname; + log_debug("%s -> %s".printf(parent.kname, part.kname)); + } + } + } + else{ + foreach (var part in list){ + if (part.pkname == parent.kname){ + parent.children.add(part); + part.parent = parent; + } + } + } + } + + private static void find_child_devices_using_dmsetup(Gee.ArrayList list){ + + string std_out, std_err; + exec_sync("dmsetup deps -o blkdevname", out std_out, out std_err); + + /* + sdb3_crypt: 1 dependencies : (sdb3) + sda5_crypt: 1 dependencies : (sda5) + mmcblk0_crypt: 1 dependencies : (mmcblk0) + */ + + Regex rex; + MatchInfo match; + + foreach(string line in std_out.split("\n")){ + if (line.strip().length == 0) { continue; } + + try{ + + rex = new Regex("""([^:]*)\:.*\((.*)\)"""); + + if (rex.match (line, 0, out match)){ + + string child_name = match.fetch(1).strip(); + string parent_kname = match.fetch(2).strip(); + + Device parent = null; + foreach(var dev in list){ + if ((dev.kname == parent_kname)){ + parent = dev; + break; + } + } + + Device child = null; + foreach(var dev in list){ + if ((dev.mapped_name == child_name)){ + child = dev; + break; + } + } + + if ((parent != null) && (child != null)){ + child.pkname = parent.kname; + log_debug("%s -> %s".printf(parent.kname, child.kname)); + } + + } + else{ + log_debug("no-match: %s".printf(line)); + } + } + catch(Error e){ + log_error (e.message); + } + } + } + + public static Gee.ArrayList get_block_devices_using_lsblk(string dev_name = ""){ + + /* Returns list of mounted partitions using 'lsblk' command + Populates device, type, uuid, label */ + + test_lsblk_version(); + + var list = new Gee.ArrayList(); + + string std_out; + string std_err; + string cmd; + int ret_val; + Regex rex; + MatchInfo match; + + if (lsblk_is_ancient){ + cmd = "lsblk --bytes --pairs --output NAME,KNAME,LABEL,UUID,TYPE,FSTYPE,SIZE,MOUNTPOINT,MODEL,RO,RM"; + } + else{ + cmd = "lsblk --bytes --pairs --output NAME,KNAME,LABEL,UUID,TYPE,FSTYPE,SIZE,MOUNTPOINT,MODEL,RO,HOTPLUG,PKNAME,VENDOR,SERIAL,REV"; + } + + if (dev_name.length > 0){ + cmd += " %s".printf(dev_name); + } + + if (LOG_DEBUG){ + log_debug(""); + log_debug(cmd); + } + + ret_val = exec_sync(cmd, out std_out, out std_err); + + //if (ret_val != 0){ + // var msg = "lsblk: " + _("Failed to get partition list"); + // msg += (device_file.length > 0) ? ": " + device_file : ""; + // log_error (msg); + // return list; //return empty map + //} + + /* + sample output + ----------------- + NAME="sda" KNAME="sda" PKNAME="" LABEL="" UUID="" FSTYPE="" SIZE="119.2G" MOUNTPOINT="" HOTPLUG="0" + + NAME="sda1" KNAME="sda1" PKNAME="sda" LABEL="" UUID="5345-E139" FSTYPE="vfat" SIZE="47.7M" MOUNTPOINT="/boot/efi" HOTPLUG="0" + + NAME="mmcblk0p1" KNAME="mmcblk0p1" PKNAME="mmcblk0" LABEL="" UUID="3c0e4bbf" FSTYPE="crypto_LUKS" SIZE="60.4G" MOUNTPOINT="" HOTPLUG="1" + + NAME="luks-3c0" KNAME="dm-1" PKNAME="mmcblk0p1" LABEL="" UUID="f0d933c0-" FSTYPE="ext4" SIZE="60.4G" MOUNTPOINT="/mnt/sdcard" HOTPLUG="0" + */ + + /* + Note: Multiple loop devices can have same UUIDs. + Example: Loop devices created by mounting the same ISO multiple times. + */ + + //parse output and build filesystem map ------------- + + int index = -1; + + foreach(string line in std_out.split("\n")){ + if (line.strip().length == 0) { continue; } + + try{ + if (lsblk_is_ancient){ + rex = new Regex("""NAME="(.*)" KNAME="(.*)" LABEL="(.*)" UUID="(.*)" TYPE="(.*)" FSTYPE="(.*)" SIZE="(.*)" MOUNTPOINT="(.*)" MODEL="(.*)" RO="([0-9]+)" RM="([0-9]+)""""); + } + else{ + rex = new Regex("""NAME="(.*)" KNAME="(.*)" LABEL="(.*)" UUID="(.*)" TYPE="(.*)" FSTYPE="(.*)" SIZE="(.*)" MOUNTPOINT="(.*)" MODEL="(.*)" RO="([0-9]+)" HOTPLUG="([0-9]+)" PKNAME="(.*)" VENDOR="(.*)" SERIAL="(.*)" REV="(.*)""""); + } + + if (rex.match (line, 0, out match)){ + + Device pi = new Device(); + pi.name = match.fetch(1).strip(); + pi.kname = match.fetch(2).strip(); + pi.label = match.fetch(3); // do not strip - labels can have leading or trailing spaces + pi.uuid = match.fetch(4).strip(); + pi.type = match.fetch(5).strip().down(); + + pi.fstype = match.fetch(6).strip().down(); + pi.fstype = (pi.fstype == "crypto_luks") ? "luks" : pi.fstype; + pi.fstype = (pi.fstype == "lvm2_member") ? "lvm2" : pi.fstype; + + pi.size_bytes = int64.parse(match.fetch(7).strip()); + + var mp = match.fetch(8).strip(); + if (mp.length > 0){ + pi.mount_points.add(new MountEntry(pi,mp,"")); + } + + pi.model = match.fetch(9).strip(); + + pi.read_only = (match.fetch(10).strip() == "1"); + + pi.removable = (match.fetch(11).strip() == "1"); + + if (!lsblk_is_ancient){ + pi.pkname = match.fetch(12).strip(); + pi.vendor = match.fetch(13).strip(); + pi.serial = match.fetch(14).strip(); + pi.revision = match.fetch(15).strip(); + } + + pi.order = ++index; + pi.device = "/dev/%s".printf(pi.kname); + + //if ((pi.type == "crypt") && (pi.pkname.length > 0)){ + // pi.name = "%s (unlocked)".printf(pi.pkname); + //} + + //if ((pi.uuid.length > 0) && (pi.pkname.length > 0)){ + list.add(pi); + //} + } + else{ + log_debug("no-match: %s".printf(line)); + } + } + catch(Error e){ + log_error (e.message); + } + } + + // already sorted + /*list.sort((a,b)=>{ + return (a.order - b.order); + });*/ + + // add aliases from /dev/disk/by-uuid/ + + foreach(var dev in list){ + var dev_by_uuid = path_combine("/dev/disk/by-uuid/", dev.uuid); + if (file_exists(dev_by_uuid)){ + dev.symlinks.add(dev_by_uuid); + } + } + + // add aliases from /dev/mapper/ + + try + { + File f_dev_mapper = File.new_for_path ("/dev/mapper"); + + FileEnumerator enumerator = f_dev_mapper.enumerate_children ( + "%s,%s".printf( + FileAttribute.STANDARD_NAME, FileAttribute.STANDARD_SYMLINK_TARGET), + FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + + FileInfo info; + while ((info = enumerator.next_file ()) != null) { + + if (info.get_name() == "control") { continue; } + + File f_mapped = f_dev_mapper.resolve_relative_path(info.get_name()); + + string mapped_file = f_mapped.get_path(); + string mapped_device = info.get_symlink_target(); + mapped_device = mapped_device.replace("..","/dev"); + //log_debug("info.get_name(): %s".printf(info.get_name())); + //log_debug("info.get_symlink_target(): %s".printf(info.get_symlink_target())); + //log_debug("mapped_file: %s".printf(mapped_file)); + //log_debug("mapped_device: %s".printf(mapped_device)); + + foreach(var dev in list){ + if (dev.device == mapped_device){ + dev.mapped_name = mapped_file.replace("/dev/mapper/",""); + dev.symlinks.add(mapped_file); + log_debug("found link: %s -> %s".printf(mapped_file, dev.device)); + break; + } + } + } + } + catch (Error e) { + log_error (e.message); + } + + device_list = list; + + foreach (var part in list){ + find_child_devices(list, part); + } + + if (lsblk_is_ancient){ + find_child_devices_using_dmsetup(list); + } + + print_device_list(list); + + log_debug("Device: get_block_devices_using_lsblk(): %d".printf(list.size)); + + return list; + } + + // deprecated: use get_block_devices_using_lsblk() instead + public static Gee.ArrayList get_block_devices_using_blkid(string dev_name = ""){ + + /* Returns list of mounted partitions using 'blkid' command + Populates device, type, uuid, label */ + + var list = new Gee.ArrayList(); + + string std_out; + string std_err; + string cmd; + int ret_val; + Regex rex; + MatchInfo match; + + cmd = "/sbin/blkid" + ((dev_name.length > 0) ? " " + dev_name: ""); + + if (LOG_DEBUG){ + log_debug(cmd); + } + + ret_val = exec_script_sync(cmd, out std_out, out std_err); + if (ret_val != 0){ + var msg = "blkid: " + _("Failed to get partition list"); + msg += (dev_name.length > 0) ? ": " + dev_name : ""; + log_error(msg); + return list; //return empty list + } + + /* + sample output + ----------------- + /dev/sda1: LABEL="System Reserved" UUID="F476B08076B04560" TYPE="ntfs" + /dev/sda2: LABEL="windows" UUID="BE00B6DB00B69A3B" TYPE="ntfs" + /dev/sda3: UUID="03f3f35d-71fa-4dff-b740-9cca19e7555f" TYPE="ext4" + */ + + //parse output and build filesystem map ------------- + + foreach(string line in std_out.split("\n")){ + if (line.strip().length == 0) { continue; } + + Device pi = new Device(); + + pi.device = line.split(":")[0].strip(); + + if (pi.device.length == 0) { continue; } + + //exclude non-standard devices -------------------- + + if (!pi.device.has_prefix("/dev/")){ + continue; + } + + if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { + //ok + } + else if (pi.device.has_prefix("/dev/disk/by-uuid/")){ + //ok, get uuid + pi.uuid = pi.device.replace("/dev/disk/by-uuid/",""); + } + else{ + continue; //skip + } + + //parse & populate fields ------------------ + + try{ + rex = new Regex("""LABEL=\"([^\"]*)\""""); + if (rex.match (line, 0, out match)){ + pi.label = match.fetch(1); // do not strip - labels can have leading or trailing spaces + } + + rex = new Regex("""UUID=\"([^\"]*)\""""); + if (rex.match (line, 0, out match)){ + pi.uuid = match.fetch(1).strip(); + } + + rex = new Regex("""TYPE=\"([^\"]*)\""""); + if (rex.match (line, 0, out match)){ + pi.fstype = match.fetch(1).strip(); + } + } + catch(Error e){ + log_error (e.message); + } + + //add to map ------------------------- + + if (pi.uuid.length > 0){ + list.add(pi); + } + } + + log_debug("Device: get_block_devices_using_blkid(): %d".printf(list.size)); + + return list; + } + + public static Gee.ArrayList get_disk_space_using_df(string dev_name_or_mount_point = ""){ + + /* + Returns list of mounted partitions using 'df' command + Populates device, type, size, used and mount_point_list + */ + + var list = new Gee.ArrayList(); + + string std_out; + string std_err; + string cmd; + int ret_val; + + cmd = "df -T -B1"; + + if (dev_name_or_mount_point.length > 0){ + cmd += " '%s'".printf(escape_single_quote(dev_name_or_mount_point)); + } + + if (LOG_DEBUG){ + log_debug(cmd); + } + + ret_val = exec_sync(cmd, out std_out, out std_err); + //ret_val is not reliable, no need to check + + /* + sample output + ----------------- + Filesystem Type 1M-blocks Used Available Use% Mounted on + /dev/sda3 ext4 25070M 19508M 4282M 83% / + none tmpfs 1M 0M 1M 0% /sys/fs/cgroup + udev devtmpfs 3903M 1M 3903M 1% /dev + tmpfs tmpfs 789M 1M 788M 1% /run + none tmpfs 5M 0M 5M 0% /run/lock + /dev/sda3 ext4 25070M 19508M 4282M 83% /mnt/timeshift + */ + + string[] lines = std_out.split("\n"); + + int line_num = 0; + foreach(string line in lines){ + + if (++line_num == 1) { continue; } + if (line.strip().length == 0) { continue; } + + Device pi = new Device(); + + //parse & populate fields ------------------ + + int k = 1; + foreach(string val in line.split(" ")){ + + if (val.strip().length == 0){ continue; } + + switch(k++){ + case 1: + pi.device = val.strip(); + break; + case 2: + pi.fstype = val.strip(); + break; + case 3: + pi.size_bytes = int64.parse(val.strip()); + break; + case 4: + pi.used_bytes = int64.parse(val.strip()); + break; + case 5: + pi.available_bytes = int64.parse(val.strip()); + break; + case 6: + pi.used_percent = val.strip(); + break; + case 7: + //string mount_point = val.strip(); + //if (!pi.mount_point_list.contains(mount_point)){ + // pi.mount_point_list.add(mount_point); + //} + break; + } + } + + /* Note: + * The mount points displayed by 'df' are not reliable. + * For example, if same device is mounted at 2 locations, 'df' displays only the first location. + * Hence, we will not populate the 'mount_points' field in Device object + * Use get_mounted_filesystems_using_mtab() if mount info is required + * */ + + // resolve device name -------------------- + + pi.device = resolve_device_name(pi.device); + + // get uuid --------------------------- + + pi.uuid = get_device_uuid(pi.device); + + // add to map ------------------------- + + if (pi.uuid.length > 0){ + list.add(pi); + } + } + + log_debug("Device: get_disk_space_using_df(): %d".printf(list.size)); + + return list; + } + + public static Gee.ArrayList get_mounted_filesystems_using_mtab(){ + + /* Returns list of mounted partitions by reading /proc/mounts + Populates device, type and mount_point_list */ + + var list = new Gee.ArrayList(); + + string mtab_path = "/etc/mtab"; + string mtab_lines = ""; + + File f; + + // find mtab file ----------- + + mtab_path = "/proc/mounts"; + f = File.new_for_path(mtab_path); + if(!f.query_exists()){ + mtab_path = "/proc/self/mounts"; + f = File.new_for_path(mtab_path); + if(!f.query_exists()){ + mtab_path = "/etc/mtab"; + f = File.new_for_path(mtab_path); + if(!f.query_exists()){ + return list; //empty list + } + } + } + + /* Note: + * /etc/mtab represents what 'mount' passed to the kernel + * whereas /proc/mounts shows the data as seen inside the kernel + * Hence /proc/mounts is always up-to-date whereas /etc/mtab might not be + * */ + + //read ----------- + + mtab_lines = file_read(mtab_path); + + /* + sample mtab + ----------------- + /dev/sda3 / ext4 rw,errors=remount-ro 0 0 + proc /proc proc rw,noexec,nosuid,nodev 0 0 + sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0 + none /sys/fs/cgroup tmpfs rw 0 0 + none /sys/fs/fuse/connections fusectl rw 0 0 + none /sys/kernel/debug debugfs rw 0 0 + none /sys/kernel/security securityfs rw 0 0 + udev /dev devtmpfs rw,mode=0755 0 0 + + device - the device or remote filesystem that is mounted. + mountpoint - the place in the filesystem the device was mounted. + filesystemtype - the type of filesystem mounted. + options - the mount options for the filesystem + dump - used by dump to decide if the filesystem needs dumping. + fsckorder - used by fsck to detrmine the fsck pass to use. + */ + + /* Note: + * We are interested only in the last device that was mounted at a given mount point + * Hence the lines must be parsed in reverse order (from last to first) + * */ + + //parse ------------ + + string[] lines = mtab_lines.split("\n"); + var mount_list = new Gee.ArrayList(); + + for (int i = lines.length - 1; i >= 0; i--){ + + string line = lines[i].strip(); + if (line.length == 0) { continue; } + + var pi = new Device(); + + var mp = new MountEntry(pi,"",""); + + //parse & populate fields ------------------ + + int k = 1; + foreach(string val in line.split(" ")){ + if (val.strip().length == 0){ continue; } + switch(k++){ + case 1: //device + pi.device = val.strip(); + break; + case 2: //mountpoint + mp.mount_point = val.strip().replace("""\040"""," "); // replace space. TODO: other chars? + if (!mount_list.contains(mp.mount_point)){ + mount_list.add(mp.mount_point); + pi.mount_points.add(mp); + } + break; + case 3: //filesystemtype + pi.fstype = val.strip(); + break; + case 4: //options + mp.mount_options = val.strip(); + break; + default: + //ignore + break; + } + } + + // resolve device names ---------------- + + pi.device = resolve_device_name(pi.device); + + // get uuid --------------------------- + + pi.uuid = get_device_uuid(pi.device); + + // add to map ------------------------- + + if (pi.uuid.length > 0){ + var dev = find_device_in_list_by_uuid(list, pi.uuid); + if (dev == null){ + list.add(pi); + } + else{ + // add mount points to existing device + foreach(var item in pi.mount_points){ + dev.mount_points.add(item); + } + } + } + } + + log_debug("Device: get_mounted_filesystems_using_mtab(): %d".printf(list.size)); + + return list; + } + + // helpers ---------------------------------- + + public static Device? find_device_in_list_by_name(Gee.ArrayList list, string dev_name){ + + foreach(var dev in list){ + if (dev.device == dev_name){ + return dev; + } + } + + return null; + } + + public static Device? find_device_in_list_by_uuid(Gee.ArrayList list, string dev_uuid){ + + foreach(var dev in list){ + if (dev.uuid == dev_uuid){ + return dev; + } + } + + return null; + } + + public static Device? get_device_by_uuid(string uuid){ + foreach(var dev in device_list){ + if (dev.uuid == uuid){ + return dev; + } + } + + return null; + } + + public static Device? get_device_by_name(string file_name){ + + var device_name = resolve_device_name(file_name); + + foreach(var dev in device_list){ + if (dev.device == device_name){ + return dev; + } + } + + return null; + } + + public static Device? get_device_by_path(string path_to_check){ + var list = Device.get_disk_space_using_df(path_to_check); + if (list.size > 0){ + return list[0]; + } + return null; + } + + public static string get_device_uuid(string device){ + if (device_list == null){ + device_list = get_block_devices_using_lsblk(); + } + foreach(Device dev in device_list){ + if (dev.device == device){ + return dev.uuid; + } + } + return ""; + } + + public static Gee.ArrayList get_device_mount_points(string dev_name_or_uuid){ + string device = ""; + string uuid = ""; + + if (dev_name_or_uuid.has_prefix("/dev")){ + device = dev_name_or_uuid; + uuid = get_device_uuid(dev_name_or_uuid); + } + else{ + uuid = dev_name_or_uuid; + device = "/dev/disk/by-uuid/%s".printf(uuid); + device = resolve_device_name(device); + } + + var list_mtab = get_mounted_filesystems_using_mtab(); + + var dev = find_device_in_list_by_uuid(list_mtab, uuid); + + if (dev != null){ + return dev.mount_points; + } + else{ + return (new Gee.ArrayList()); + } + } + + public static bool device_is_mounted(string dev_name_or_uuid){ + + var mps = Device.get_device_mount_points(dev_name_or_uuid); + if (mps.size > 0){ + return true; + } + + return false; + } + + public static bool mount_point_in_use(string mount_point){ + var list = Device.get_mounted_filesystems_using_mtab(); + foreach (var dev in list){ + foreach(var mp in dev.mount_points){ + if (mp.mount_point.has_prefix(mount_point)){ + // check for any mount point at or under the given mount_point + return true; + } + } + } + return false; + } + + public static string resolve_device_name(string dev_alias){ + + string resolved = dev_alias; + + if (dev_alias.has_prefix("/dev/mapper/")){ + var link_path = file_get_symlink_target(dev_alias); + if (link_path.has_prefix("../")){ + resolved = link_path.replace("../","/dev/"); + } + } + + if (dev_alias.has_prefix("/dev/disk/")){ + var link_path = file_get_symlink_target(dev_alias); + if (link_path.has_prefix("../../")){ + resolved = link_path.replace("../../","/dev/"); + } + } + + if (dev_alias != resolved){ + //log_msg("resolved '%s' to '%s'".printf(dev_alias, resolved)); + } + + return resolved; + } + + public void copy_fields_from(Device dev2){ + + this.device = dev2.device; + this.name = dev2.name; + this.kname = dev2.kname; + this.pkname = dev2.pkname; + this.label = dev2.label; + this.uuid = dev2.uuid; + this.mapped_name = dev2.mapped_name; + + this.type = dev2.type; + this.fstype = dev2.fstype; + + this.size_bytes = dev2.size_bytes; + this.used_bytes = dev2.used_bytes; + this.available_bytes = dev2.available_bytes; + + this.mount_points = dev2.mount_points; + this.symlinks = dev2.symlinks; + this.parent = dev2.parent; + this.children = dev2.children; + + this.vendor = dev2.vendor; + this.model = dev2.model; + this.serial = dev2.serial; + this.revision = dev2.revision; + + this.removable = dev2.removable; + this.read_only = dev2.read_only; + } + + public Device? query_changes(){ + + Device dev_new = null; + + foreach (var dev in get_block_devices_using_lsblk()){ + if (uuid.length > 0){ + if (dev.uuid == uuid){ + dev_new = dev; + break; + } + } + else{ + if (dev.device == device){ + dev_new = dev; + break; + } + } + } + + return dev_new; + } + + public void query_disk_space(){ + + /* Updates disk space info and returns the given Device object */ + + var list_df = get_disk_space_using_df(device); + + var dev_df = find_device_in_list_by_uuid(list_df, uuid); + + if (dev_df != null){ + // update dev fields + size_bytes = dev_df.size_bytes; + used_bytes = dev_df.used_bytes; + available_bytes = dev_df.available_bytes; + used_percent = dev_df.used_percent; + } + } + + // mounting --------------------------------- + + public static bool automount_udisks(string dev_name_or_uuid, Gtk.Window? parent_window){ + + if (dev_name_or_uuid.length == 0){ + log_error(_("Device name is empty!")); + return false; + } + + var cmd = "udisksctl mount -b '%s'".printf(dev_name_or_uuid); + log_debug(cmd); + int status = Posix.system(cmd); + + if (status != 0){ + if (parent_window != null){ + string msg = "Failed to mount: %s".printf(dev_name_or_uuid); + gtk_messagebox("Error", msg, parent_window, true); + } + } + + return (status == 0); + } + + public static bool automount_udisks_iso(string iso_file_path, out string loop_device, Gtk.Window? parent_window){ + + loop_device = ""; + + if (!file_exists(iso_file_path)){ + string msg = "%s: %s".printf(_("Could not find file"), iso_file_path); + log_error(msg); + return false; + } + + var cmd = "udisksctl loop-setup -r -f '%s'".printf( + escape_single_quote(iso_file_path)); + + log_debug(cmd); + string std_out, std_err; + int exit_code = exec_sync(cmd, out std_out, out std_err); + + if (exit_code == 0){ + log_msg("%s".printf(std_out)); + //log_msg("%s".printf(std_err)); + + if (!std_out.contains(" as ")){ + log_error("Could not determine loop device"); + return false; + } + + loop_device = std_out.split(" as ")[1].replace(".","").strip(); + log_msg("loop_device: %s".printf(loop_device)); + + var list = get_block_devices_using_lsblk(); + foreach(var dev in list){ + if ((dev.pkname == loop_device.replace("/dev/","")) && (dev.fstype == "iso9660")){ + loop_device = dev.device; + return automount_udisks(dev.device, parent_window); + } + } + } + + return false; + } + + public static bool unmount_udisks(string dev_name_or_uuid, Gtk.Window? parent_window){ + + if (dev_name_or_uuid.length == 0){ + log_error(_("Device name is empty!")); + return false; + } + + var cmd = "udisksctl unmount -b '%s'".printf(dev_name_or_uuid); + log_debug(cmd); + int status = Posix.system(cmd); + + if (status != 0){ + if (parent_window != null){ + string msg = "Failed to unmount: %s".printf(dev_name_or_uuid); + gtk_messagebox("Error", msg, parent_window, true); + } + } + + return (status == 0); + } + + public static Device? luks_unlock( + Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window, + out string message, out string details){ + + /* Unlocks a LUKS device using provided passphrase. + * Prompts the user for passphrase if empty. + * Displays a GTK prompt if parent_window is not null + * Otherwise prompts user on terminal with a timeout of 20 secsonds + * */ + + Device unlocked_device = null; + string std_out = "", std_err = ""; + + // check if not encrypted + if (!luks_device.fstype.contains("luks") && !luks_device.fstype.contains("crypt")){ + message = _("This device is not encrypted"); + details = _("Failed to unlock device"); + return null; + } + + // check if already unlocked + var list = get_block_devices_using_lsblk(); + foreach(var part in list){ + if (part.pkname == luks_device.kname){ + unlocked_device = part; + message = _("Device is unlocked"); + details = _("Unlocked device is mapped to '%s'").printf(part.mapped_name); + return part; + } + } + + string luks_pass = passphrase; + string luks_name = mapped_name; + + if ((luks_name == null) || (luks_name.length == 0)){ + luks_name = "%s_crypt".printf(luks_device.kname); + } + + if (parent_window == null){ + + // console mode + + if ((luks_pass == null) || (luks_pass.length == 0)){ + + // prompt user on terminal and unlock, else timeout after 20 secs + + var counter = new TimeoutCounter(); + counter.kill_process_on_timeout("cryptsetup", 20, true); + string cmd = "cryptsetup luksOpen '%s' '%s'".printf(luks_device.device, luks_name); + + log_debug(cmd); + Posix.system(cmd); + counter.stop(); + log_msg(""); + + } + else{ + + // use password to unlock + + var cmd = "echo -n -e '%s' | cryptsetup luksOpen --key-file - '%s' '%s'\n".printf( + luks_pass, luks_device.device, luks_name); + + log_debug(cmd.replace(luks_pass, "**PASSWORD**")); + + int status = exec_script_sync(cmd, out std_out, out std_err, false, true); + + switch (status){ + case 512: // invalid passphrase + message = _("Wrong password"); + details = _("Failed to unlock device"); + log_error(message); + log_error(details); + break; + } + } + + } + else{ + + // gui mode + + if ((luks_pass == null) || (luks_pass.length == 0)){ + + // show input prompt + + log_debug("Prompting user for passphrase.."); + + luks_pass = gtk_inputbox( + _("Encrypted Device"), + _("Enter passphrase to unlock '%s'").printf(luks_device.name), + parent_window, true); + + if (luks_pass == null){ + // cancelled by user + message = _("Failed to unlock device"); + details = _("User cancelled the password prompt"); + log_debug("User cancelled the password prompt"); + return null; + } + } + + if ((luks_pass != null) && (luks_pass.length > 0)){ + + // use password to unlock + + var cmd = "echo -n -e '%s' | cryptsetup luksOpen --key-file - '%s' '%s'\n".printf( + luks_pass, luks_device.device, luks_name); + + log_debug(cmd.replace(luks_pass, "**PASSWORD**")); + + int status = exec_script_sync(cmd, out std_out, out std_err, false, true); + + switch (status){ + case 512: // invalid passphrase + message = _("Wrong password"); + details = _("Failed to unlock device"); + log_error(message); + log_error(details); + break; + } + } + + } + + // find unlocked device + list = get_block_devices_using_lsblk(); + foreach(var part in list){ + if (part.pkname == luks_device.kname){ + unlocked_device = part; + break; + } + } + + bool is_error = false; + if (unlocked_device == null){ + message = _("Failed to unlock device") + " '%s'".printf(luks_device.device); + details = std_err; + is_error = true; + } + else{ + message = _("Unlocked successfully"); + details = _("Unlocked device is mapped to '%s'").printf(unlocked_device.mapped_name); + } + + if (parent_window != null){ + gtk_messagebox(message, details, parent_window, is_error); + } + + return unlocked_device; + } + + public static bool luks_lock(string kname, Gtk.Window? parent_window){ + var cmd = "cryptsetup luksClose %s".printf(kname); + + log_debug(cmd); + + string std_out, std_err; + int status = exec_script_sync(cmd, out std_out, out std_err, false, true); + log_msg(std_out); + log_msg(std_err); + + if (status != 0){ + if (parent_window != null){ + string msg = "Failed to lock device: %s".printf(kname); + gtk_messagebox("Error", msg, parent_window, true); + } + } + + return (status == 0); + + /*log_debug(cmd); + + if (bash_admin_shell != null){ + int status = bash_admin_shell.execute(cmd); + return (status == 0); + } + else{ + int status = exec_script_sync(cmd,null,null,false,true); + return (status == 0); + }*/ + } + + public static bool mount( + string dev_name_or_uuid, string mount_point, string mount_options = "", bool silent = false){ + + /* + * Mounts specified device at specified mount point. + * + * */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + string device = ""; + string uuid = ""; + + if (dev_name_or_uuid.has_prefix("/dev")){ + device = dev_name_or_uuid; + uuid = get_device_uuid(dev_name_or_uuid); + } + else{ + uuid = dev_name_or_uuid; + device = "/dev/disk/by-uuid/%s".printf(uuid); + device = resolve_device_name(device); + } + + if (dir_exists(mount_point)){ + dir_create(mount_point); + } + + // check if already mounted ------------------ + + var mps = Device.get_device_mount_points(dev_name_or_uuid); + foreach(var mp in mps){ + if (mp.mount_point.contains(mount_point) && mp.mount_options.contains(mount_options)){ + if (!silent){ + string msg = ""; + msg += "%s: %s %s".printf(_("Mounted"), _("device"), dev_name_or_uuid); + if (mp.mount_options.length > 0){ + msg += ", %s".printf(mp.mount_options); + } + msg += " at '%s'".printf(mount_point); + } + return true; + } + } + + + try{ + // check and create mount point ------------- + + File file = File.new_for_path(mount_point); + if (!file.query_exists()){ + file.make_directory_with_parents(); + } + + // mount the device ----------------------------- + + if (mount_options.length > 0){ + cmd = "mount -o %s \"%s\" \"%s\"".printf(mount_options, device, mount_point); + } + else{ + cmd = "mount \"%s\" \"%s\"".printf(device, mount_point); + } + + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); + + if (ret_val != 0){ + log_error ("Failed to mount device '%s' at mount point '%s'".printf(device, mount_point)); + log_error (std_err); + return false; + } + else{ + if (!silent){ + Device dev = get_device_by_name(device); + log_msg ("Mounted '%s'%s at '%s'".printf( + (dev == null) ? device : dev.device_name_with_parent, + (mount_options.length > 0) ? " (%s)".printf(mount_options) : "", + mount_point)); + } + return true; + } + } + catch(Error e){ + log_error (e.message); + return false; + } + + // check if mounted successfully ------------------ + + /*mps = Device.get_device_mount_points(dev_name_or_uuid); + if (mps.contains(mount_point)){ + log_msg("Device '%s' is mounted at '%s'".printf(dev_name_or_uuid, mount_point)); + return true; + } + else{ + return false; + }*/ + } + + public static string automount( + string dev_name_or_uuid, string mount_options = "", string mount_prefix = "/mnt"){ + + /* Returns the mount point of specified device. + * If unmounted, mounts the device to /mnt/ and returns the mount point. + * */ + + string device = ""; + string uuid = ""; + + // get uuid ----------------------------- + + if (dev_name_or_uuid.has_prefix("/dev")){ + device = dev_name_or_uuid; + uuid = Device.get_device_uuid(dev_name_or_uuid); + } + else{ + uuid = dev_name_or_uuid; + device = "/dev/disk/by-uuid/%s".printf(uuid); + device = resolve_device_name(device); + } + + // check if already mounted and return mount point ------------- + + var list = Device.get_block_devices_using_lsblk(); + var dev = find_device_in_list_by_uuid(list, uuid); + if (dev != null){ + return dev.mount_points[0].mount_point; + } + + // check and create mount point ------------------- + + string mount_point = "%s/%s".printf(mount_prefix, uuid); + + try{ + File file = File.new_for_path(mount_point); + if (!file.query_exists()){ + file.make_directory_with_parents(); + } + } + catch(Error e){ + log_error (e.message); + return ""; + } + + // mount the device and return mount_point -------------------- + + if (mount(uuid, mount_point, mount_options)){ + return mount_point; + } + else{ + return ""; + } + } + + public static bool unmount(string mount_point){ + + /* Recursively unmounts all devices at given mount_point and subdirectories + * */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + // check if mount point is in use + if (!Device.mount_point_in_use(mount_point)) { + return true; + } + + // try to unmount ------------------ + + try{ + + string cmd_unmount = "cat /proc/mounts | awk '{print $2}' | grep '%s' | sort -r | xargs umount".printf(mount_point); + + log_debug(_("Unmounting from") + ": '%s'".printf(mount_point)); + + //sync before unmount + cmd = "sync"; + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); + //ignore success/failure + + //unmount + ret_val = exec_script_sync(cmd_unmount, out std_out, out std_err); + + if (ret_val != 0){ + log_error (_("Failed to unmount")); + log_error (std_err); + } + } + catch(Error e){ + log_error (e.message); + return false; + } + + // check if mount point is in use + if (!Device.mount_point_in_use(mount_point)) { + return true; + } + else{ + return false; + } + } + + // description helpers + + public string full_name_with_alias{ + owned get{ + string text = device; + if (mapped_name.length > 0){ + text += " (%s)".printf(mapped_name); + } + return text; + } + } + + public string full_name_with_parent{ + owned get{ + return device_name_with_parent; + } + } + + public string short_name_with_alias{ + owned get{ + string text = kname; + if (mapped_name.length > 0){ + text += " (%s)".printf(mapped_name); + } + return text; + } + } + + public string short_name_with_parent{ + owned get{ + string text = kname; + + if (has_parent() && (parent.type == "part")){ + text += " (%s)".printf(pkname); + } + + return text; + } + } + + public string device_name_with_parent{ + owned get{ + string text = device; + + if (has_parent() && (parent.type == "part")){ + text += " (%s)".printf(parent.kname); + } + + return text; + } + } + + public string description(){ + return description_formatted().replace("","").replace("",""); + } + + public string description_formatted(){ + string s = ""; + + if (type == "disk"){ + s += "" + kname + " ~"; + if (vendor.length > 0){ + s += " " + vendor; + } + if (model.length > 0){ + s += " " + model; + } + if (size_bytes > 0) { + s += " (%s)".printf(format_file_size(size_bytes, false, "", true, 0)); + } + } + else{ + s += "" + short_name_with_parent + "" ; + s += (label.length > 0) ? " (" + label + ")": ""; + s += (fstype.length > 0) ? " ~ " + fstype : ""; + if (size_bytes > 0) { + s += " (%s)".printf(format_file_size(size_bytes, false, "", true, 0)); + } + } + + return s.strip(); + } + + public string description_simple(){ + return description_simple_formatted().replace("","").replace("",""); + } + + public string description_simple_formatted(){ + + string s = ""; + + if (type == "disk"){ + if (vendor.length > 0){ + s += " " + vendor; + } + if (model.length > 0){ + s += " " + model; + } + if (size_bytes > 0) { + if (s.strip().length == 0){ + s += "%s Device".printf(format_file_size(size_bytes, false, "", true, 0)); + } + else{ + s += " (%s)".printf(format_file_size(size_bytes, false, "", true, 0)); + } + } + } + else{ + s += "" + short_name_with_parent + "" ; + s += (label.length > 0) ? " (" + label + ")": ""; + s += (fstype.length > 0) ? " ~ " + fstype : ""; + if (size_bytes > 0) { + s += " (%s)".printf(format_file_size(size_bytes, false, "", true, 0)); + } + } + + return s.strip(); + } + + public string description_full_free(){ + string s = ""; + + if (type == "disk"){ + s += "%s %s".printf(model, vendor).strip(); + if (s.length == 0){ + s = "%s Disk".printf(format_file_size(size_bytes)); + } + else{ + s += " (%s Disk)".printf(format_file_size(size_bytes)); + } + } + else{ + s += kname; + if (label.length > 0){ + s += " (%s)".printf(label); + } + if (fstype.length > 0){ + s += " ~ %s".printf(fstype); + } + if (free_bytes > 0){ + s += " ~ %s".printf(description_free()); + } + } + + return s; + } + + public string description_full(){ + string s = ""; + s += device; + s += (label.length > 0) ? " (" + label + ")": ""; + s += (uuid.length > 0) ? " ~ " + uuid : ""; + s += (fstype.length > 0) ? " ~ " + fstype : ""; + s += (used.length > 0) ? " ~ " + used + " / " + size + " GB used (" + used_percent + ")" : ""; + + return s; + } + + public string description_usage(){ + if (used.length > 0){ + return used + " / " + size + " used (" + used_percent + ")"; + } + else{ + return ""; + } + } + + public string description_free(){ + if (used.length > 0){ + return format_file_size(free_bytes, false, "g", false) + + " / " + format_file_size(size_bytes, false, "g", true) + " free"; + } + else{ + return ""; + } + } + + public string tooltip_text(){ + string tt = ""; + + if (type == "disk"){ + tt += "%-15s: %s\n".printf(_("Device"), device); + tt += "%-15s: %s\n".printf(_("Vendor"), vendor); + tt += "%-15s: %s\n".printf(_("Model"), model); + tt += "%-15s: %s\n".printf(_("Serial"), serial); + tt += "%-15s: %s\n".printf(_("Revision"), revision); + + tt += "%-15s: %s\n".printf( _("Size"), + (size_bytes > 0) ? format_file_size(size_bytes) : "N/A"); + } + else{ + tt += "%-15s: %s\n".printf(_("Device"), + (mapped_name.length > 0) ? "%s → %s".printf(device, mapped_name) : device); + + if (has_parent()){ + tt += "%-15s: %s\n".printf(_("Parent Device"), parent.device); + } + tt += "%-15s: %s\n".printf(_("UUID"),uuid); + tt += "%-15s: %s\n".printf(_("Type"),type); + tt += "%-15s: %s\n".printf(_("Filesystem"),fstype); + tt += "%-15s: %s\n".printf(_("Label"),label); + + tt += "%-15s: %s\n".printf(_("Size"), + (size_bytes > 0) ? format_file_size(size_bytes) : "N/A"); + + tt += "%-15s: %s\n".printf(_("Used"), + (used_bytes > 0) ? format_file_size(used_bytes) : "N/A"); + + tt += "%-15s: %s\n".printf(_("System"),dist_info); + } + + return "%s".printf(tt); + } + + private string display_name(bool short_name = true, bool show_label = true, bool show_parent = true, bool show_alias = false){ + + string txt = ""; + + if (short_name){ + txt += kname; + } + else{ + txt += device; + } + + if (type == "disk"){ + if (vendor.length > 0){ + txt += " " + vendor; + } + if (model.length > 0){ + txt += " " + model; + } + if (size_bytes > 0) { + if (txt.strip().length == 0){ + txt += "%s Device".printf(format_file_size(size_bytes, false, "", true, 0)); + } + else{ + txt += " (%s)".printf(format_file_size(size_bytes, false, "", true, 0)); + } + } + } + else{ + if (show_label && (label.length > 0)){ + txt += "(%s)".printf(label); + } + if (show_parent && has_parent() && (parent.type == "part")){ // TODO: if parent is crypt (like lvm on luks) + txt += "(%s)".printf(pkname); + } + if (show_alias && (mapped_name.length > 0)){ + txt += "(%s)".printf(mapped_name); + } + } + + return txt; + } + + // testing ----------------------------------- + + public static void test_all(){ + var list = get_block_devices_using_lsblk(); + log_msg("\n> get_block_devices_using_lsblk()"); + print_device_list(list); + + log_msg(""); + + //list = get_block_devices_using_blkid(); + //log_msg("\nget_block_devices_using_blkid()\n"); + //print_device_list(list); + + list = get_mounted_filesystems_using_mtab(); + log_msg("\n> get_mounted_filesystems_using_mtab()"); + print_device_mounts(list); + + log_msg(""); + + list = get_disk_space_using_df(); + log_msg("\n> get_disk_space_using_df()"); + print_device_disk_space(list); + + log_msg(""); + + list = get_filesystems(); + log_msg("\n> get_filesystems()"); + print_device_list(list); + print_device_mounts(list); + print_device_disk_space(list); + + log_msg(""); + } + + public static void print_device_list(Gee.ArrayList list){ + + log_debug(""); + + log_debug("%-12s ,%-5s ,%-5s ,%-36s ,%s".printf( + "device", + "pkname", + "kname", + "uuid", + "mapped_name")); + + log_debug(string.nfill(100, '-')); + + foreach(var dev in list){ + log_debug("%-12s ,%-5s ,%-5s ,%-36s ,%s".printf( + dev.device , + dev.pkname, + dev.kname, + dev.uuid, + dev.mapped_name + )); + } + + log_debug(""); + + /* + log_debug("%-20s %-20s %s %s %s %s".printf( + "device", + "label", + "vendor", + "model", + "serial", + "rev")); + + log_debug(string.nfill(100, '-')); + + foreach(var dev in list){ + log_debug("%-20s %-20s %s %s %s %s".printf( + dev.device, + dev.label, + dev.vendor, + dev.model, + dev.serial, + dev.revision + )); + } + + log_debug(""); + */ + + /*log_debug("%-20s %-10s %-15s %-3s %-3s %15s %15s".printf( + "device", + "type", + "fstype", + "REM", + "RO", + "size", + "used")); + + log_debug(string.nfill(100, '-')); + + foreach(var dev in list){ + log_debug("%-20s %-10s %-15s %-3s %-3s %15s %15s".printf( + dev.device, + dev.type, + dev.fstype, + dev.removable ? "1" : "0", + dev.read_only ? "1" : "0", + format_file_size(dev.size_bytes, true), + format_file_size(dev.used_bytes, true) + )); + }*/ + + //log_debug(""); + } + + public static void print_device_mounts(Gee.ArrayList list){ + + log_debug(""); + + log_debug("%-15s %s".printf( + "device", + //"fstype", + "> mount_points (mount_options)" + )); + + log_debug(string.nfill(100, '-')); + + foreach(var dev in list){ + + string mps = ""; + foreach(var mp in dev.mount_points){ + mps += "\n %s -> ".printf(mp.mount_point); + if (mp.mount_options.length > 0){ + mps += " %s".printf(mp.mount_options); + } + } + + log_debug("%-15s %s".printf( + dev.device, + //dev.fstype, + mps + )); + + } + + log_debug(""); + } + + public static void print_device_disk_space(Gee.ArrayList list){ + log_debug(""); + + log_debug("%-15s %-12s %15s %15s %15s %10s".printf( + "device", + "fstype", + "size", + "used", + "available", + "used_percent" + )); + + log_debug(string.nfill(100, '-')); + + foreach(var dev in list){ + log_debug("%-15s %-12s %15s %15s %15s %10s".printf( + dev.device, + dev.fstype, + format_file_size(dev.size_bytes, true), + format_file_size(dev.used_bytes, true), + format_file_size(dev.available_bytes, true), + dev.used_percent + )); + } + + log_debug(""); + } +} + + + + + + + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/FileItem.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/FileItem.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/FileItem.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/FileItem.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,661 @@ +/* + * FileItem.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using GLib; +using Gtk; +using Gee; +using Json; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class FileItem : GLib.Object,Gee.Comparable { + public string file_name = ""; + public string file_location = ""; + public string file_path = ""; + public string file_path_prefix = ""; + public FileType file_type = FileType.REGULAR; + public DateTime modified; + public string permissions = ""; + public string owner_user = ""; + public string owner_group = ""; + public string content_type = ""; + public string file_status = ""; + + public bool is_selected = false; + public bool is_symlink = false; + public string symlink_target = ""; + public bool is_archive = false; + public bool is_stale = false; + + public FileItem parent; + public Gee.HashMap children = new Gee.HashMap(); + public FileItem? source_archive; + + public GLib.Object? tag; + //public Gtk.TreeIter? treeiter; + + public long file_count = 0; + public long dir_count = 0; + private int64 _size = 0; + private int64 _size_compressed = 0; + + public long file_count_total = 0; + public long dir_count_total = 0; + + //public string icon_name = "gtk-file"; + public GLib.Icon icon; + + public bool is_dummy = false; + + public static string[] archive_extensions = { + ".tar", + ".tar.gz", ".tgz", + ".tar.bzip2", ".tar.bz2", ".tbz", ".tbz2", ".tb2", + ".tar.lzma", ".tar.lz", ".tlz", + ".tar.xz", ".txz", + ".tar.7z", + ".tar.zip", + ".7z", ".lzma", + ".bz2", ".bzip2", + ".gz", ".gzip", + ".zip", ".rar", ".cab", ".arj", ".z", ".taz", ".cpio", + ".rpm", ".deb", + ".lzh", ".lha", + ".chm", ".chw", ".hxs", + ".iso", ".dmg", ".xar", ".hfs", ".ntfs", ".fat", ".vhd", ".mbr", + ".wim", ".swm", ".squashfs", ".cramfs", ".scap" + }; + + + // contructors ------------------------------- + + public FileItem(string name = "New Archive") { + file_name = name; + } + + public FileItem.dummy(FileType _file_type) { + is_dummy = true; + file_type = _file_type; + } + + public FileItem.dummy_root() { + file_name = "dummy"; + file_location = ""; + } + + public FileItem.from_path_and_type(string _file_path, FileType _file_type) { + file_path = _file_path; + file_name = file_basename(_file_path); + file_location = file_parent(_file_path); + file_type = _file_type; + } + + // properties -------------------------------------- + + public int64 size { + get{ + return _size; + } + } + + public int64 size_compressed { + get{ + return _size_compressed; + } + } + + // helpers --------------- + + public int compare_to(FileItem b){ + if (this.file_type != b.file_type) { + if (this.file_type == FileType.DIRECTORY) { + return -1; + } + else { + return +1; + } + } + else { + //if (view.sort_column_desc) { + return strcmp(this.file_name.down(), b.file_name.down()); + //} + //else { + //return -1 * strcmp(a.file_name.down(), b.file_name.down()); + //} + } + } + + // instance methods ------------------------------------------ + + public FileItem add_child_from_disk(string item_file_path, int depth = -1) { + FileItem item = null; + + //log_debug("add_child_from_disk: %02d: %s".printf(depth, item_file_path)); + + try { + FileEnumerator enumerator; + FileInfo info; + File file = File.parse_name (item_file_path); + + if (file.query_exists()) { + + // query file type + var item_file_type = file.query_file_type(FileQueryInfoFlags.NONE); + + //add item + item = this.add_child(item_file_path, item_file_type, 0, 0, true); + + if ((item.file_type == FileType.DIRECTORY) && !item.is_symlink) { + if (depth != 0){ + //recurse children + enumerator = file.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); + while ((info = enumerator.next_file()) != null) { + string child_path = "%s/%s".printf(item_file_path, info.get_name()); + item.add_child_from_disk(child_path, depth - 1); + } + } + } + } + } + catch (Error e) { + log_error (e.message); + } + + return item; + } + + public FileItem add_descendant( + string _file_path, + FileType ? _file_type, + int64 item_size, + int64 item_size_compressed) { + + //log_debug("add_descendant=%s".printf(_file_path)); + + string item_path = _file_path.strip(); + FileType item_type = (_file_type == null) ? FileType.REGULAR : _file_type; + + if (item_path.has_suffix("/")) { + item_path = item_path[0:item_path.length - 1]; + item_type = FileType.DIRECTORY; + } + + if (item_path.has_prefix("/")) { + item_path = item_path[1:item_path.length]; + } + + string dir_name = ""; + string dir_path = ""; + + //create dirs and find parent dir + FileItem current_dir = this; + string[] arr = item_path.split("/"); + for (int i = 0; i < arr.length - 1; i++) { + //get dir name + dir_name = arr[i]; + + //add dir + if (!current_dir.children.keys.contains(dir_name)) { + if ((current_dir == this) && current_dir.is_archive){ + dir_path = ""; + } + else { + dir_path = current_dir.file_path + "/"; + } + dir_path = "%s%s".printf(dir_path, dir_name); + current_dir.add_child(dir_path, FileType.DIRECTORY, 0, 0, false); + } + + current_dir = current_dir.children[dir_name]; + } + + //get item name + string item_name = arr[arr.length - 1]; + + //add item + if (!current_dir.children.keys.contains(item_name)) { + + //log_debug("add_descendant: add_child()"); + + current_dir.add_child( + item_path, item_type, item_size, item_size_compressed, false); + } + + //log_debug("add_descendant: finished: %s".printf(item_path)); + + return current_dir.children[item_name]; + } + + public FileItem add_child( + string item_file_path, + FileType item_file_type, + int64 item_size, + int64 item_size_compressed, + bool item_query_file_info){ + + // create new item ------------------------------ + + //log_debug("add_child: %s".printf(item_file_path)); + + FileItem item = new FileItem.from_path_and_type(item_file_path, item_file_type); + //item.tag = this.tag; + + foreach(var ext in archive_extensions){ + if (item_file_path.has_suffix(ext)) { + item = new ArchiveFile(item_file_path); + item.is_archive = true; + break; + } + } + + // check existing ---------------------------- + + bool existing_file = false; + if (!children.has_key(item.file_name)){ + children[item.file_name] = item; + + //set parent + item.parent = this; + } + else{ + existing_file = true; + item = this.children[item.file_name]; + + // mark as fresh + item.is_stale = false; + } + + // copy prefix from parent + item.file_path_prefix = this.file_path_prefix; + + // query file properties + if (item_query_file_info){ + //log_debug("add_child: query_file_info()"); + item.query_file_info(); + } + + if (item_file_type == FileType.REGULAR) { + + //log_debug("add_child: regular file"); + + // set file sizes + if (item_size > 0) { + item._size = item_size; + } + if (item_size_compressed > 0) { + item._size_compressed = item_size_compressed; + } + + // update file counts + if (!existing_file){ + this.file_count++; + this.file_count_total++; + this._size += item_size; + this._size_compressed += item_size_compressed; + + // update file count and size of parent dirs + var temp = this; + while (temp.parent != null) { + temp.parent.file_count_total++; + temp.parent._size += item_size; + temp.parent._size_compressed += item_size_compressed; + temp = temp.parent; + } + } + } + else if (item_file_type == FileType.DIRECTORY) { + + //log_debug("add_child: directory"); + + if (!existing_file){ + + // update dir counts + this.dir_count++; + this.dir_count_total++; + //this.size += _size; + //size will be updated when children are added + + // update dir count of parent dirs + var temp = this; + while (temp.parent != null) { + temp.parent.dir_count_total++; + temp = temp.parent; + } + } + } + + //log_debug("add_child: finished: fc=%lld dc=%lld path=%s".printf( + // file_count, dir_count, item_file_path)); + + return item; + } + + public void query_file_info() { + + try { + FileInfo info; + File file = File.parse_name (file_path); + + if (file.query_exists()) { + + // get type without following symlinks + + info = file.query_info("%s,%s,%s".printf( + FileAttribute.STANDARD_TYPE, + FileAttribute.STANDARD_ICON, + FileAttribute.STANDARD_SYMLINK_TARGET), + FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + + var item_file_type = info.get_file_type(); + + this.icon = info.get_icon(); + + if (item_file_type == FileType.SYMBOLIC_LINK) { + //this.icon = GLib.Icon.new_for_string("emblem-symbolic-link"); + this.is_symlink = true; + this.symlink_target = info.get_symlink_target(); + } + else { + + this.is_symlink = false; + this.symlink_target = ""; + + if (item_file_type == FileType.REGULAR){ + //log_msg(file_basename(file_path) + " (gicon): " + icon.to_string()); + + /*var themed_icon = (GLib.ThemedIcon) icon; + + string txt = "-> "; + foreach(var name in themed_icon.names){ + txt += ", " + name; + } + log_msg(txt);*/ + } + } + + // get file info - follow symlinks + + info = file.query_info("%s,%s,%s,%s,%s,%s,%s,%s".printf( + FileAttribute.STANDARD_TYPE, + FileAttribute.STANDARD_SIZE, + FileAttribute.STANDARD_ICON, + FileAttribute.STANDARD_CONTENT_TYPE, + FileAttribute.TIME_MODIFIED, + FileAttribute.OWNER_USER, + FileAttribute.OWNER_GROUP, + FileAttribute.FILESYSTEM_FREE + ), 0); + + if (this.is_symlink){ + // get icon for the resolved file + this.icon = info.get_icon(); + } + + // file type resolved + this.file_type = info.get_file_type(); + + // content type + this.content_type = info.get_content_type(); + + // size + if (!this.is_symlink && (this.file_type == FileType.REGULAR)) { + this._size = info.get_size(); + } + + // modified + this.modified = (new DateTime.from_timeval_utc(info.get_modification_time())).to_local(); + + // owner_user + this.owner_user = info.get_attribute_string(FileAttribute.OWNER_USER); + + // owner_group + this.owner_group = info.get_attribute_string(FileAttribute.OWNER_GROUP); + + } + } + catch (Error e) { + log_error (e.message); + } + } + + public void query_children(int depth = -1) { + FileEnumerator enumerator; + FileInfo info; + File file = File.parse_name (file_path); + + if (!file.query_exists()) { + return; + } + + if (file_type == FileType.DIRECTORY) { + if (depth == 0){ + return; + } + + try{ + // mark existing children as stale + foreach(var child in children.values){ + child.is_stale = true; + } + + // recurse children + enumerator = file.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); + while ((info = enumerator.next_file()) != null) { + string child_name = info.get_name(); + string child_path = GLib.Path.build_filename(file_path, child_name); + this.add_child_from_disk(child_path, depth - 1); + } + + // remove stale children + var list = new Gee.ArrayList(); + foreach(var key in children.keys){ + if (children[key].is_stale){ + list.add(key); + } + } + foreach(var key in list){ + //log_debug("Unset:%s".printf(key)); + children.unset(key); + } + } + catch (Error e) { + log_error (e.message); + } + } + } + + public void clear_children() { + this.children.clear(); + } + + public FileItem remove_child(string child_name) { + FileItem child = null; + + if (this.children.has_key(child_name)) { + child = this.children[child_name]; + this.children.unset(child_name); + + if (child.file_type == FileType.REGULAR) { + //update file counts + this.file_count--; + this.file_count_total--; + + //subtract child size + this._size -= child.size; + this._size_compressed -= child.size_compressed; + + //update file count and size of parent dirs + var temp = this; + while (temp.parent != null) { + temp.parent.file_count_total--; + + temp.parent._size -= child.size; + temp.parent._size_compressed -= child.size_compressed; + + temp = temp.parent; + } + } + else { + //update dir counts + this.dir_count--; + this.dir_count_total--; + + //subtract child counts + this.file_count_total -= child.file_count_total; + this.dir_count_total -= child.dir_count_total; + this._size -= child.size; + this._size_compressed -= child.size_compressed; + + //update dir count of parent dirs + var temp = this; + while (temp.parent != null) { + temp.parent.dir_count_total--; + + temp.parent.file_count_total -= child.file_count_total; + temp.parent.dir_count_total -= child.dir_count_total; + temp.parent._size -= child.size; + temp.parent._size_compressed -= child.size_compressed; + + temp = temp.parent; + } + } + } + + //log_debug("%3ld %3ld %s".printf(file_count, dir_count, file_path)); + + return child; + } + + public FileItem? find_descendant(string path){ + var child = this; + + foreach(var part in path.split("/")){ + + // query children if needed + if (child.children.size == 0){ + child.query_children(1); + if (child.children.size == 0){ + break; + } + } + + if (child.children.has_key(part)){ + child = child.children[part]; + } + } + + if (child.file_path == path){ + return child; + } + else{ + return null; + } + } + + public void set_file_path_prefix(string prefix){ + file_path_prefix = prefix; + foreach(var child in this.children.values){ + child.set_file_path_prefix(prefix); + } + } + + public void print(int level) { + + if (level == 0) { + stdout.printf("\n"); + stdout.flush(); + } + + stdout.printf("%s%s\n".printf(string.nfill(level * 2, ' '), file_name)); + stdout.flush(); + + foreach (var key in this.children.keys) { + this.children[key].print(level + 1); + } + } + + public Gee.ArrayList get_children_sorted(){ + var list = new Gee.ArrayList(); + + foreach(string key in children.keys) { + var item = children[key]; + list.add(item); + } + + list.sort((a, b) => { + if ((a.file_type == FileType.DIRECTORY) && (b.file_type != FileType.DIRECTORY)){ + return -1; + } + else if ((a.file_type != FileType.DIRECTORY) && (b.file_type == FileType.DIRECTORY)){ + return 1; + } + else{ + return strcmp(a.file_name.down(), b.file_name.down()); + } + }); + + return list; + } + /*public Gtk.Image get_icon_image(){ + + log_debug("FileItem.get_icon_image()"); + + var image = get_shared_icon("gtk-directory","gtk-directory.png",16); + + if (is_archive) { + image.icon_name = "gnome-mime-application-x-archive"; + } + else{ + if ((content_type.length == 0) && (icon == null)){ + query_file_info(); + } + + if ((icon != null) && file_path.has_prefix("/")) { + image.gicon = icon; + log_debug("using gicon for: %s".printf(file_name)); + } + //else if (item.is_symlink) { + // (cell as Gtk.CellRendererPixbuf).icon_name = "emblem-symbolic-link"; + //} + else if (file_type == FileType.DIRECTORY) { + image.icon_name = "gtk-directory"; + } + else{ + image.icon_name = "gtk-file"; + } + } + + // TODO: use ThemedIcon? + + return image; + }*/ +} + + + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/FsTabEntry.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/FsTabEntry.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/FsTabEntry.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/FsTabEntry.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,259 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class FsTabEntry : GLib.Object{ + public bool is_comment = false; + public bool is_empty_line = false; + + public string device_string = ""; + public string mount_point = ""; + public string type = ""; + public string options = "defaults"; + public string dump = "0"; + public string pass = "0"; + public string line = ""; + + public string device_uuid { + owned get{ + if (device_string.down().has_prefix("uuid=")){ + return device_string.replace("\"","").replace("'","").split("=")[1]; + } + else{ + return ""; + } + } + set { + device_string = "UUID=%s".printf(value); + } + } + + public static Gee.ArrayList read_file(string file_path){ + var list = new Gee.ArrayList(); + + if (!file_exists(file_path)){ return list; } + + string text = file_read(file_path); + string[] lines = text.split("\n"); + foreach(string line in lines){ + var entry = new FsTabEntry(); + list.add(entry); + + entry.is_comment = line.strip().has_prefix("#"); + entry.is_empty_line = (line.strip().length == 0); + + if (entry.is_comment){ + entry.line = line; + } + else if (entry.is_empty_line){ + entry.line = ""; + } + else{ + entry.line = line; + + string[] parts = line.replace("\t"," ").split(" "); + int part_num = -1; + foreach(string part in parts){ + if (part.strip().length == 0) { continue; } + switch (++part_num){ + case 0: + entry.device_string = part.strip(); + break; + case 1: + entry.mount_point = part.strip(); + break; + case 2: + entry.type = part.strip(); + break; + case 3: + entry.options = part.strip(); + break; + case 4: + entry.dump = part.strip(); + break; + case 5: + entry.pass = part.strip(); + break; + } + } + } + } + + return list; + } + + public static string write_file( + Gee.ArrayList entries, string file_path, + bool keep_comments_and_empty_lines = false){ + + string text = ""; + + if (!keep_comments_and_empty_lines){ + text += "# \n\n"; + } + + foreach(var entry in entries){ + if (entry.is_comment || entry.is_empty_line){ + if (keep_comments_and_empty_lines){ + text += "%s\n".printf(entry.line); + } + } + else { + text += "%s\t%s\t%s\t%s\t%s\t%s\n".printf( + entry.device_string, entry.mount_point, entry.type, + entry.options, entry.dump, entry.pass); + } + } + + // sort the entries based on mount path + // this is required to ensure that base paths are mounted before child paths + + entries.sort((a, b)=>{ + return strcmp(a.mount_point, b.mount_point); + }); + + if (file_exists(file_path)){ + file_delete(file_path); + } + + file_write(file_path, text); + + return text; + } + + public string subvolume_name(){ + if (options.contains("subvol=")){ + return options.split("subvol=")[1].split(",")[0].strip(); + } + else{ + return ""; + } + } + + public bool is_for_system_directory(){ + + if (mount_point.has_prefix("/mnt") + || mount_point.has_prefix("/mount") + || mount_point.has_prefix("/sdcard") + || mount_point.has_prefix("/cdrom") + || mount_point.has_prefix("/media") + || (mount_point == "none") + || !mount_point.has_prefix("/") + || (!device_string.has_prefix("/dev/") && !device_string.down().has_prefix("uuid="))){ + + return false; + } + else{ + return true; + } + } + + public static FsTabEntry? find_entry_by_mount_point( + Gee.ArrayList entries, string mount_path){ + + foreach(var entry in entries){ + if (entry.mount_point == mount_path){ + return entry; + } + } + return null; + } + + + public Device? resolve_device(Gee.ArrayList crypttab, Gtk.Window parent_window){ + Device dev_fstab = null; + if (device_uuid.length > 0){ + dev_fstab = Device.get_device_by_uuid(device_uuid); + } + else{ + dev_fstab = Device.get_device_by_name(device_string); + } + + if (dev_fstab == null){ + + /* + Check if the device mentioned in fstab entry is a mapped device. + If it is, then try finding the parent device which may be available on the current system. + Prompt user to unlock it if found. + + Note: + Mapped name may be different on running system, or it may be same. + Since it is not reliable, we will try to identify the parent intead of the mapped device. + */ + + if (device_string.has_prefix("/dev/mapper/")){ + + string mapped_name = device_string.replace("/dev/mapper/",""); + + foreach(var item in crypttab){ + + if (item.mapped_name == mapped_name){ + + // we found the entry for the mapped device + device_string = item.device_string; + + if (device_uuid.length > 0){ + + // we have the parent's uuid. get the luks device and prompt user to unlock it. + var dev_luks = Device.get_device_by_uuid(device_uuid); + + if (dev_luks != null){ + + string msg_out, msg_err; + var dev_unlocked = Device.luks_unlock( + dev_luks, "", "", parent_window, out msg_out, out msg_err); + + if (dev_unlocked != null){ + dev_fstab = dev_unlocked; + } + else{ + dev_fstab = dev_luks; // map to parent + } + } + } + else{ + // nothing to do: we don't have the parent's uuid + } + + break; + } + } + } + } + + return dev_fstab; + } + + + public void append_option(string option){ + + if (!options.contains(option)){ + options += ",%s".printf(option); + } + + if(options.has_prefix(",")){ + options = options[1:options.length]; + } + + options = options.strip(); + } + + public void remove_option(string option){ + + options = options.replace(option,"").strip(); + + if(options.has_prefix(",")){ + options = options[1:options.length]; + } + + if (options.has_suffix(",")){ + options = options[0:options.length - 1]; + } + + options = options.strip(); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/AboutWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/AboutWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/AboutWindow.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/AboutWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,428 @@ +/* + * AboutWindow.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using Gtk; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class AboutWindow : Dialog { + private Box vbox_main; + private Box vbox_logo; + private Box vbox_credits; + private Box vbox_lines; + private Box hbox_action; + private Button btn_credits; + private Button btn_close; + + private Gtk.Image img_logo; + private Label lbl_program_name; + private Label lbl_version; + private Label lbl_comments; + private LinkButton lbtn_website; + private Label lbl_copyright; + + private string[] _artists; + public string[] artists{ + get{ + return _artists; + } + set{ + _artists = value; + } + } + + private string[] _authors; + public string[] authors{ + get{ + return _authors; + } + set{ + _authors = value; + } + } + + private string[] _contributors; + public string[] contributors{ + get{ + return _contributors; + } + set{ + _contributors = value; + } + } + + private string _comments = ""; + public string comments{ + get{ + return _comments; + } + set{ + _comments = value; + } + } + + private string _copyright = ""; + public string copyright{ + get{ + return _copyright; + } + set{ + _copyright = value; + } + } + + private string[] _documenters; + public string[] documenters{ + get{ + return _documenters; + } + set{ + _documenters = value; + } + } + + private string[] _donations; + public string[] donations{ + get{ + return _donations; + } + set{ + _donations = value; + } + } + + private string _license = ""; + public string license{ + get{ + return _license; + } + set{ + _license = value; + } + } + + private Gdk.Pixbuf _logo; + public Gdk.Pixbuf logo{ + get{ + return _logo; + } + set{ + _logo = value; + } + } + + private string _program_name = ""; + public string program_name{ + get{ + return _program_name; + } + set{ + _program_name = value; + } + } + + private string[] _translators; + public string[] translators{ + get{ + return _translators; + } + set{ + _translators = value; + } + } + + private string[] _third_party; + public string[] third_party{ + get{ + return _third_party; + } + set{ + _third_party = value; + } + } + + private string _version = ""; + public string version{ + get{ + return _version; + } + set{ + _version = value; + } + } + + private string _website = ""; + public string website{ + get{ + return _website; + } + set{ + _website = value; + } + } + + private string _website_label = ""; + public string website_label{ + get{ + return _website_label; + } + set{ + _website_label = value; + } + } + + public AboutWindow() { + window_position = WindowPosition.CENTER_ON_PARENT; + set_destroy_with_parent (true); + set_modal (true); + skip_taskbar_hint = false; + set_default_size (450, 400); + + vbox_main = get_content_area(); + vbox_main.margin = 6; + vbox_main.spacing = 6; + + vbox_logo = new Box(Orientation.VERTICAL,0); + vbox_main.add(vbox_logo); + + vbox_credits = new Box(Orientation.VERTICAL,0); + vbox_credits.no_show_all = true; + vbox_main.add(vbox_credits); + + vbox_lines = new Box(Orientation.VERTICAL,0); + vbox_lines.margin_top = 10; + + //logo + img_logo = new Gtk.Image(); + img_logo.margin_top = 6; + img_logo.margin_bottom = 6; + vbox_logo.add(img_logo); + + //program_name + lbl_program_name = new Label(""); + lbl_program_name.set_use_markup(true); + vbox_logo.add(lbl_program_name); + + //version + lbl_version = new Label(""); + lbl_version.set_use_markup(true); + lbl_version.margin_top = 5; + vbox_logo.add(lbl_version); + + //comments + lbl_comments = new Label(""); + lbl_comments.set_use_markup(true); + lbl_comments.margin_top = 10; + vbox_logo.add(lbl_comments); + + //website + lbtn_website = new LinkButton(""); + lbtn_website.margin_top = 5; + vbox_logo.add(lbtn_website); + + lbtn_website.activate_link.connect(()=>{ + try{ + return Gtk.show_uri(null, lbtn_website.uri, Gdk.CURRENT_TIME); + } + catch(Error e){ + return false; + } + }); + + //copyright + lbl_copyright = new Label(""); + lbl_copyright.set_use_markup(true); + lbl_copyright.margin_top = 5; + vbox_logo.add(lbl_copyright); + + //spacer_bottom + var spacer_bottom = new Label(""); + spacer_bottom.margin_top = 20; + vbox_logo.add(spacer_bottom); + + //scroller + var sw_credits = new ScrolledWindow(null, null); + sw_credits.set_shadow_type(ShadowType.ETCHED_IN); + sw_credits.expand = true; + + vbox_credits.add(sw_credits); + sw_credits.add(vbox_lines); + + //hbox_commands -------------------------------------------------- + + hbox_action = (Box) get_action_area(); + + //btn_credits + btn_credits = new Button.with_label(" " + _("Credits")); + btn_credits.set_image (new Image.from_stock ("gtk-about", IconSize.MENU)); + hbox_action.add(btn_credits); + + btn_credits.clicked.connect(()=>{ + vbox_logo.visible = !(vbox_logo.visible); + vbox_credits.visible = !(vbox_credits.visible); + + if ((vbox_credits.visible)&&(!sw_credits.visible)){ + sw_credits.show_all(); + } + + if (vbox_credits.visible){ + btn_credits.label = " " + _("Back"); + btn_credits.set_image (new Image.from_stock ("gtk-go-back", IconSize.MENU)); + } + else{ + btn_credits.label = " " + _("Credits"); + btn_credits.set_image (new Image.from_stock ("gtk-about", IconSize.MENU)); + } + }); + + //btn_close + btn_close = new Button.with_label(" " + _("Close")); + btn_close.set_image (new Image.from_stock ("gtk-close", IconSize.MENU)); + hbox_action.add(btn_close); + + btn_close.clicked.connect(()=>{ this.destroy(); }); + } + + public void initialize() { + title = program_name; + img_logo.pixbuf = logo.scale_simple(128,128,Gdk.InterpType.HYPER); + lbl_program_name.label = "%s".printf(program_name); + lbl_version.label = "v%s".printf(version); + lbl_comments.label = "%s".printf(comments); + lbtn_website.uri = website; + lbtn_website.label = website_label; + //lbl_copyright.label = "%s".printf(copyright); + lbl_copyright.label = "%s".printf(copyright); + + if (authors.length > 0){ + add_header("%s\n".printf(_("Authors"))); + foreach(string name in authors){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (contributors.length > 0){ + add_header("%s\n".printf(_("Contributions"))); + foreach(string name in contributors){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (third_party.length > 0){ + add_header("%s\n".printf(_("Third Party Tools"))); + foreach(string name in third_party){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (artists.length > 0){ + add_header("%s\n".printf(_("Artists"))); + foreach(string name in artists){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (translators.length > 0){ + add_header("%s\n".printf(_("Translators"))); + foreach(string name in translators){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (documenters.length > 0){ + add_header("%s\n".printf(_("Documenters"))); + foreach(string name in documenters){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (donations.length > 0){ + add_header("%s\n".printf(_("Donations"))); + foreach(string name in donations){ + add_line("%s\n".printf(name)); + } + add_line("\n"); + } + + if (vbox_lines.get_children().length() == 0){ + btn_credits.visible = false; + } + } + + public void add_line(string text, bool escape_html_chars = true){ + + if (text.split(":").length >= 2){ + var link = new LinkButton(escape_html(text.split(":")[0])); + vbox_lines.add(link); + + string val = text[text.index_of(":") + 1:text.length]; + if (val.contains("@")){ + link.uri = "mailto:" + val; + } + else if(val.has_prefix("http://")){ + link.uri = val; + } + else{ + link.uri = "http://" + val; + } + + link.activate_link.connect(()=>{ + try{ + return Gtk.show_uri(null, link.uri, Gdk.CURRENT_TIME); + } + catch(Error e){ + return false; + } + }); + } + else{ + var txt = text; + if (escape_html_chars){ + txt = escape_html(text); + } + + var lbl = new Label(txt); + lbl.set_use_markup(true); + lbl.valign = Align.START; + lbl.wrap = true; + lbl.wrap_mode = Pango.WrapMode.WORD; + vbox_lines.add(lbl); + } + } + + public void add_header(string text){ + add_line(text, false); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/CellRendererProgress2.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/CellRendererProgress2.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/CellRendererProgress2.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/CellRendererProgress2.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,18 @@ + public class CellRendererProgress2 : Gtk.CellRendererProgress{ + public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { + if (text == "--") + return; + + int diff = (int) ((cell_area.height - height)/2); + + // Apply the new height into the bar, and center vertically: + Gdk.Rectangle new_area = Gdk.Rectangle() ; + new_area.x = cell_area.x; + new_area.y = cell_area.y + diff; + new_area.width = width - 5; + new_area.height = height; + + base.render(cr, widget, background_area, new_area, flags); + } + } + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/CustomMessageDialog.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/CustomMessageDialog.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/CustomMessageDialog.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/CustomMessageDialog.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,135 @@ +/* + * CustomMessageDialog.vala + * + * Copyright 2015 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + + +using Gtk; +using Gee; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class CustomMessageDialog : Gtk.Dialog { + private Gtk.Box vbox_main; + private Gtk.Label lbl_msg; + private Gtk.ScrolledWindow sw_msg; + private Gtk.Button btn_ok; + + private string msg_title; + private string msg_body; + private Gtk.MessageType msg_type; + + public CustomMessageDialog(string _msg_title, string _msg_body, Gtk.MessageType _msg_type, Window? parent) { + set_transient_for(parent); + set_modal(true); + + msg_title = _msg_title; + msg_body = _msg_body; + msg_type = _msg_type; + + init_window(); + + show_all(); + + if (lbl_msg.get_allocated_height() > 400){ + sw_msg.vscrollbar_policy = PolicyType.AUTOMATIC; + sw_msg.set_size_request(-1,400); + lbl_msg.margin_right = 25; + } + else{ + sw_msg.vscrollbar_policy = PolicyType.NEVER; + } + } + + public void init_window () { + title = msg_title; + window_position = WindowPosition.CENTER_ON_PARENT; + icon = get_app_icon(16); + resizable = false; + deletable = false; + skip_taskbar_hint = true; + skip_pager_hint = true; + + //vbox_main + vbox_main = get_content_area () as Gtk.Box; + vbox_main.margin = 6; + + //hbox_contents + var hbox_contents = new Box (Orientation.HORIZONTAL, 6); + hbox_contents.margin = 6; + vbox_main.add (hbox_contents); + + string icon_name = "gtk-dialog-info"; + + switch(msg_type){ + case Gtk.MessageType.INFO: + icon_name = "gtk-dialog-info"; + break; + case Gtk.MessageType.WARNING: + icon_name = "gtk-dialog-warning"; + break; + case Gtk.MessageType.QUESTION: + icon_name = "gtk-dialog-question"; + break; + case Gtk.MessageType.ERROR: + icon_name = "gtk-dialog-error"; + break; + } + + //img + var img = new Image.from_icon_name(icon_name, Gtk.IconSize.DIALOG); + img.margin_right = 12; + hbox_contents.add(img); + + //lbl_msg + lbl_msg = new Gtk.Label(msg_body); + lbl_msg.xalign = (float) 0.0; + lbl_msg.max_width_chars = 70; + lbl_msg.wrap = true; + lbl_msg.wrap_mode = Pango.WrapMode.WORD; + //hbox_contents.add(lbl_msg); + + //sw_msg + sw_msg = new ScrolledWindow(null, null); + //sw_msg.set_shadow_type (ShadowType.ETCHED_IN); + sw_msg.add (lbl_msg); + sw_msg.expand = true; + sw_msg.hscrollbar_policy = PolicyType.NEVER; + sw_msg.vscrollbar_policy = PolicyType.AUTOMATIC; + //sw_msg.set_size_request(); + hbox_contents.add(sw_msg); + + //actions + btn_ok = (Gtk.Button) add_button ("_Ok", Gtk.ResponseType.OK); + btn_ok.clicked.connect(()=>{ + this.close(); + }); + //btn_cancel = (Gtk.Button) add_button ("_Cancel", Gtk.ResponseType.CANCEL); + } +} + + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/DonationWindow.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/DonationWindow.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/Gtk/DonationWindow.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/Gtk/DonationWindow.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * DonationWindow.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using Gtk; + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class DonationWindow : Dialog { + public DonationWindow() { + set_title(_("Donate")); + window_position = WindowPosition.CENTER_ON_PARENT; + set_destroy_with_parent (true); + set_modal (true); + set_deletable(true); + set_skip_taskbar_hint(false); + set_default_size (400, 20); + icon = get_app_icon(16); + + //vbox_main + Box vbox_main = get_content_area(); + vbox_main.margin = 6; + vbox_main.homogeneous = false; + + get_action_area().visible = false; + + //lbl_message + Label lbl_message = new Gtk.Label(""); + string msg = _("Did you find this software useful?\n\nYou can buy me a coffee or make a donation via PayPal to show your support. Or just drop me an email and say Hi. This application is completely free and will continue to remain that way. Your contributions will help in keeping this project alive and improving it further.\n\nFeel free to send me an email if you find any issues in this application or if you need any changes. Suggestions and feedback are always welcome.\n\nThanks,\nTony George\n(teejeetech@gmail.com)"); + lbl_message.label = msg; + lbl_message.wrap = true; + vbox_main.pack_start(lbl_message,true,true,0); + + //vbox_actions + Box vbox_actions = new Box (Orientation.VERTICAL, 6); + vbox_actions.margin_left = 50; + vbox_actions.margin_right = 50; + vbox_actions.margin_top = 20; + vbox_main.pack_start(vbox_actions,false,false,0); + + //btn_donate_paypal + Button btn_donate_paypal = new Button.with_label(" " + _("Donate with PayPal") + " "); + vbox_actions.add(btn_donate_paypal); + btn_donate_paypal.clicked.connect(()=>{ + xdg_open("https://www.paypal.com/cgi-bin/webscr?business=teejeetech@gmail.com&cmd=_xclick¤cy_code=USD&amount=10&item_name=Timeshift%20Donation"); + }); + + //btn_donate_wallet + Button btn_donate_wallet = new Button.with_label(" " + _("Donate with Google Wallet") + " "); + vbox_actions.add(btn_donate_wallet); + btn_donate_wallet.clicked.connect(()=>{ + xdg_open("https://support.google.com/mail/answer/3141103?hl=en"); + }); + + //btn_send_email + Button btn_send_email = new Button.with_label(" " + _("Send Email") + " "); + vbox_actions.add(btn_send_email); + btn_send_email.clicked.connect(()=>{ + xdg_open("mailto:teejeetech@gmail.com"); + }); + + //btn_visit + Button btn_visit = new Button.with_label(" " + _("Visit Website") + " "); + vbox_actions.add(btn_visit); + btn_visit.clicked.connect(()=>{ + xdg_open("http://www.teejeetech.in"); + }); + + //btn_exit + Button btn_exit = new Button.with_label(" " + _("OK") + " "); + vbox_actions.add(btn_exit); + btn_exit.clicked.connect(() => { + this.destroy(); + }); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/GtkHelper.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/GtkHelper.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/GtkHelper.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/GtkHelper.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,897 @@ + + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.System; +using TeeJee.Misc; + +namespace TeeJee.GtkHelper{ + + using Gtk; + + // messages ----------- + + public void show_err_log(Gtk.Window parent, bool disable_log = true){ + if ((err_log != null) && (err_log.length > 0)){ + gtk_messagebox(_("Error"), err_log, parent, true); + } + + if (disable_log){ + err_log_disable(); + } + } + + public void gtk_do_events (){ + + /* Do pending events */ + + while(Gtk.events_pending ()) + Gtk.main_iteration (); + } + + public void gtk_set_busy (bool busy, Gtk.Window win) { + + /* Show or hide busy cursor on window */ + + Gdk.Cursor? cursor = null; + + if (busy){ + cursor = new Gdk.Cursor(Gdk.CursorType.WATCH); + } + else{ + cursor = new Gdk.Cursor(Gdk.CursorType.ARROW); + } + + var window = win.get_window (); + + if (window != null) { + window.set_cursor (cursor); + } + + gtk_do_events (); + } + + public void gtk_messagebox( + string title, string message, Gtk.Window? parent_win, bool is_error = false){ + + /* Shows a simple message box */ + + var type = Gtk.MessageType.INFO; + if (is_error){ + type = Gtk.MessageType.ERROR; + } + else{ + type = Gtk.MessageType.INFO; + } + + /*var dlg = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, type, Gtk.ButtonsType.OK, message); + dlg.title = title; + dlg.set_default_size (200, -1); + if (parent_win != null){ + dlg.set_transient_for(parent_win); + dlg.set_modal(true); + } + dlg.run(); + dlg.destroy();*/ + + var dlg = new CustomMessageDialog(title,message,type,parent_win); + dlg.run(); + dlg.destroy(); + } + + public string? gtk_inputbox( + string title, string message, Gtk.Window? parent_win, bool mask_password = false){ + + /* Shows a simple input prompt */ + + //vbox_main + Gtk.Box vbox_main = new Box (Orientation.VERTICAL, 0); + vbox_main.margin = 0; + + //lbl_input + Gtk.Label lbl_input = new Gtk.Label(title); + lbl_input.xalign = (float) 0.0; + lbl_input.label = message; + + //txt_input + Gtk.Entry txt_input = new Gtk.Entry(); + txt_input.margin_top = 3; + txt_input.set_visibility(!mask_password); + + //create dialog + var dlg = new Gtk.Dialog.with_buttons(title, parent_win, DialogFlags.MODAL); + dlg.title = title; + dlg.set_default_size (300, -1); + if (parent_win != null){ + dlg.set_transient_for(parent_win); + dlg.set_modal(true); + } + + //add widgets + var content = (Box) dlg.get_content_area (); + vbox_main.pack_start (lbl_input, false, true, 0); + vbox_main.pack_start (txt_input, false, true, 0); + content.add(vbox_main); + content.margin = 6; + + //add buttons + var actions = (Box) dlg.get_action_area (); + dlg.add_button(_("OK"),Gtk.ResponseType.OK); + dlg.add_button(_("Cancel"),Gtk.ResponseType.CANCEL); + //actions.margin = 6; + actions.margin_top = 12; + + //keyboard shortcuts + txt_input.key_press_event.connect ((w, event) => { + if (event.keyval == 65293) { + dlg.response(Gtk.ResponseType.OK); + return true; + } + return false; + }); + + dlg.show_all(); + int response = dlg.run(); + string input_text = txt_input.text; + dlg.destroy(); + + if (response == Gtk.ResponseType.CANCEL){ + return null; + } + else{ + return input_text; + } + } + + + // combo --------- + + public bool gtk_combobox_set_value (ComboBox combo, int index, string val){ + + /* Conveniance function to set combobox value */ + + TreeIter iter; + string comboVal; + TreeModel model = (TreeModel) combo.model; + + bool iterExists = model.get_iter_first (out iter); + while (iterExists){ + model.get(iter, 1, out comboVal); + if (comboVal == val){ + combo.set_active_iter(iter); + return true; + } + iterExists = model.iter_next (ref iter); + } + + return false; + } + + public string gtk_combobox_get_value (ComboBox combo, int index, string default_value){ + + /* Conveniance function to get combobox value */ + + if ((combo.model == null) || (combo.active < 0)) { return default_value; } + + TreeIter iter; + string val = ""; + combo.get_active_iter (out iter); + TreeModel model = (TreeModel) combo.model; + model.get(iter, index, out val); + + return val; + } + + public GLib.Object gtk_combobox_get_selected_object ( + ComboBox combo, + int index, + GLib.Object default_value){ + + /* Conveniance function to get combobox value */ + + if ((combo.model == null) || (combo.active < 0)) { return default_value; } + + TreeIter iter; + GLib.Object val = null; + combo.get_active_iter (out iter); + TreeModel model = (TreeModel) combo.model; + model.get(iter, index, out val); + + return val; + } + + public int gtk_combobox_get_value_enum (ComboBox combo, int index, int default_value){ + + /* Conveniance function to get combobox value */ + + if ((combo.model == null) || (combo.active < 0)) { return default_value; } + + TreeIter iter; + int val; + combo.get_active_iter (out iter); + TreeModel model = (TreeModel) combo.model; + model.get(iter, index, out val); + + return val; + } + + // icon ------- + + public Gdk.Pixbuf? get_app_icon(int icon_size, string format = ".png"){ + var img_icon = get_shared_icon(AppShortName, AppShortName + format,icon_size,"pixmaps"); + if (img_icon != null){ + return img_icon.pixbuf; + } + else{ + return null; + } + } + + public Gtk.Image? get_shared_icon( + string icon_name, + string fallback_icon_file_name, + int icon_size, + string icon_directory = AppShortName + "/images"){ + + Gdk.Pixbuf pix_icon = null; + Gtk.Image img_icon = null; + + try { + Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default(); + + pix_icon = icon_theme.load_icon_for_scale ( + icon_name, Gtk.IconSize.MENU, icon_size, Gtk.IconLookupFlags.FORCE_SIZE); + + } catch (Error e) { + //log_error (e.message); + } + + string fallback_icon_file_path = "/usr/share/%s/%s".printf(icon_directory, fallback_icon_file_name); + + if (pix_icon == null){ + try { + pix_icon = new Gdk.Pixbuf.from_file_at_size (fallback_icon_file_path, icon_size, icon_size); + } catch (Error e) { + log_error (e.message); + } + } + + if (pix_icon == null){ + log_error (_("Missing Icon") + ": '%s', '%s'".printf(icon_name, fallback_icon_file_path)); + } + else{ + img_icon = new Gtk.Image.from_pixbuf(pix_icon); + } + + return img_icon; + } + + public Gdk.Pixbuf? get_shared_icon_pixbuf(string icon_name, + string fallback_file_name, + int icon_size, + string icon_directory = AppShortName + "/images"){ + + var img = get_shared_icon(icon_name, fallback_file_name, icon_size, icon_directory); + var pixbuf = (img == null) ? null : img.pixbuf; + return pixbuf; + } + + // styles ---------------- + + public static int CSS_AUTO_CLASS_INDEX = 0; + public static void gtk_apply_css(Gtk.Widget[] widgets, string css_style){ + var css_provider = new Gtk.CssProvider(); + var css = ".style_%d { %s }".printf(++CSS_AUTO_CLASS_INDEX, css_style); + try { + css_provider.load_from_data(css,-1); + } catch (GLib.Error e) { + warning(e.message); + } + + foreach(var widget in widgets){ + + widget.get_style_context().add_provider( + css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + + widget.get_style_context().add_class("style_%d".printf(CSS_AUTO_CLASS_INDEX)); + } + } + + // treeview ----------------- + + public int gtk_treeview_model_count(TreeModel model){ + int count = 0; + TreeIter iter; + if (model.get_iter_first(out iter)){ + count++; + while(model.iter_next(ref iter)){ + count++; + } + } + return count; + } + + public void gtk_stripe_row( + Gtk.CellRenderer cell, + bool odd_row, + string odd_color = "#F4F6F7", + string even_color = "#FFFFFF"){ + + if (cell is Gtk.CellRendererText){ + (cell as Gtk.CellRendererText).background = odd_row ? odd_color : even_color; + } + else if (cell is Gtk.CellRendererPixbuf){ + (cell as Gtk.CellRendererPixbuf).cell_background = odd_row ? odd_color : even_color; + } + } + + public void gtk_treeview_redraw(Gtk.TreeView treeview){ + var model = treeview.model; + treeview.model = null; + treeview.model = model; + } + + // menu + + public void gtk_menu_add_separator(Gtk.Menu menu){ + Gdk.RGBA gray = Gdk.RGBA(); + gray.parse ("rgba(200,200,200,1)"); + + // separator + var menu_item = new Gtk.SeparatorMenuItem(); + menu_item.override_color (StateFlags.NORMAL, gray); + menu.append(menu_item); + } + + public Gtk.MenuItem gtk_menu_add_item( + Gtk.Menu menu, + string label, + string tooltip, + Gtk.Image? icon_image, + Gtk.SizeGroup? sg_icon = null, + Gtk.SizeGroup? sg_label = null){ + + var menu_item = new Gtk.MenuItem(); + menu.append(menu_item); + + var box = new Gtk.Box(Orientation.HORIZONTAL, 3); + menu_item.add(box); + + // add icon + + if (icon_image == null){ + var dummy = new Gtk.Label(""); + box.add(dummy); + + if (sg_icon != null){ + sg_icon.add_widget(dummy); + } + } + else{ + box.add(icon_image); + + if (sg_icon != null){ + sg_icon.add_widget(icon_image); + } + } + + // add label + + var lbl = new Gtk.Label(label); + lbl.xalign = (float) 0.0; + lbl.margin_right = 6; + box.add(lbl); + + if (sg_label != null){ + sg_label.add_widget(lbl); + } + + box.set_tooltip_text(tooltip); + + return menu_item; + } + + // build ui + + public Gtk.Label gtk_box_add_header(Gtk.Box box, string text){ + var label = new Gtk.Label("" + text + ""); + label.set_use_markup(true); + label.xalign = (float) 0.0; + label.margin_bottom = 6; + box.add(label); + + return label; + } + + // misc + + public bool gtk_container_has_child(Gtk.Container container, Gtk.Widget widget){ + foreach(var child in container.get_children()){ + if (child == widget){ + return true; + } + } + return false; + } + + + private void text_view_append(Gtk.TextView view, string text){ + TextIter iter; + view.buffer.get_end_iter(out iter); + view.buffer.insert(ref iter, text, text.length); + } + + private void text_view_prepend(Gtk.TextView view, string text){ + TextIter iter; + view.buffer.get_start_iter(out iter); + view.buffer.insert(ref iter, text, text.length); + } + + private void text_view_scroll_to_end(Gtk.TextView view){ + TextIter iter; + view.buffer.get_end_iter(out iter); + view.scroll_to_iter(iter, 0.0, false, 0.0, 0.0); + } + + private void text_view_scroll_to_start(Gtk.TextView view){ + TextIter iter; + view.buffer.get_start_iter(out iter); + view.scroll_to_iter(iter, 0.0, false, 0.0, 0.0); + } + + // file chooser ---------------- + + public Gtk.FileFilter create_file_filter(string group_name, string[] patterns) { + var filter = new Gtk.FileFilter (); + filter.set_filter_name(group_name); + foreach(string pattern in patterns) { + filter.add_pattern (pattern); + } + return filter; + } + + // utility ------------------ + + // add_notebook + private Gtk.Notebook add_notebook( + Gtk.Box box, bool show_tabs = true, bool show_border = true){ + + // notebook + var book = new Gtk.Notebook(); + book.margin = 0; + book.show_tabs = show_tabs; + book.show_border = show_border; + + box.pack_start(book, true, true, 0); + + return book; + } + + // add_tab + private Gtk.Box add_tab( + Gtk.Notebook book, string title, int margin = 12, int spacing = 6){ + + // label + var label = new Gtk.Label(title); + + // vbox + var vbox = new Box (Gtk.Orientation.VERTICAL, spacing); + vbox.margin = margin; + book.append_page (vbox, label); + + return vbox; + } + + // add_treeview + private Gtk.TreeView add_treeview(Gtk.Box box, + Gtk.SelectionMode selection_mode = Gtk.SelectionMode.SINGLE){ + + // TreeView + var treeview = new TreeView(); + treeview.get_selection().mode = selection_mode; + treeview.set_rules_hint (true); + treeview.show_expanders = true; + treeview.enable_tree_lines = true; + + // ScrolledWindow + var scrollwin = new ScrolledWindow(null, null); + scrollwin.set_shadow_type (ShadowType.ETCHED_IN); + scrollwin.add (treeview); + scrollwin.expand = true; + box.add(scrollwin); + + return treeview; + } + + // add_column_text + private Gtk.TreeViewColumn add_column_text( + Gtk.TreeView treeview, string title, out Gtk.CellRendererText cell){ + + // TreeViewColumn + var col = new Gtk.TreeViewColumn(); + col.title = title; + + cell = new Gtk.CellRendererText(); + cell.xalign = (float) 0.0; + col.pack_start (cell, false); + treeview.append_column(col); + + return col; + } + + + // add_column_icon + private Gtk.TreeViewColumn add_column_icon( + Gtk.TreeView treeview, string title, out Gtk.CellRendererPixbuf cell){ + + // TreeViewColumn + var col = new Gtk.TreeViewColumn(); + col.title = title; + + cell = new Gtk.CellRendererPixbuf(); + cell.xpad = 2; + col.pack_start (cell, false); + treeview.append_column(col); + + return col; + } + + // add_column_icon_and_text + private Gtk.TreeViewColumn add_column_icon_and_text( + Gtk.TreeView treeview, string title, + out Gtk.CellRendererPixbuf cell_pix, out Gtk.CellRendererText cell_text){ + + // TreeViewColumn + var col = new Gtk.TreeViewColumn(); + col.title = title; + + cell_pix = new Gtk.CellRendererPixbuf(); + cell_pix.xpad = 2; + col.pack_start (cell_pix, false); + + cell_text = new Gtk.CellRendererText(); + cell_text.xalign = (float) 0.0; + col.pack_start (cell_text, false); + treeview.append_column(col); + + return col; + } + + // add_column_radio_and_text + private Gtk.TreeViewColumn add_column_radio_and_text( + Gtk.TreeView treeview, string title, + out Gtk.CellRendererToggle cell_radio, out Gtk.CellRendererText cell_text){ + + // TreeViewColumn + var col = new Gtk.TreeViewColumn(); + col.title = title; + + cell_radio = new Gtk.CellRendererToggle(); + cell_radio.xpad = 2; + cell_radio.radio = true; + cell_radio.activatable = true; + col.pack_start (cell_radio, false); + + cell_text = new Gtk.CellRendererText(); + cell_text.xalign = (float) 0.0; + col.pack_start (cell_text, false); + treeview.append_column(col); + + return col; + } + + // add_column_icon_radio_text + private Gtk.TreeViewColumn add_column_icon_radio_text( + Gtk.TreeView treeview, string title, + out Gtk.CellRendererPixbuf cell_pix, + out Gtk.CellRendererToggle cell_radio, + out Gtk.CellRendererText cell_text){ + + // TreeViewColumn + var col = new Gtk.TreeViewColumn(); + col.title = title; + + cell_pix = new Gtk.CellRendererPixbuf(); + cell_pix.xpad = 2; + col.pack_start (cell_pix, false); + + cell_radio = new Gtk.CellRendererToggle(); + cell_radio.xpad = 2; + cell_radio.radio = true; + cell_radio.activatable = true; + col.pack_start (cell_radio, false); + + cell_text = new Gtk.CellRendererText(); + cell_text.xalign = (float) 0.0; + col.pack_start (cell_text, false); + treeview.append_column(col); + + return col; + } + + // add_label_scrolled + private Gtk.Label add_label_scrolled( + Gtk.Box box, string text, + bool show_border = false, bool wrap = false, int ellipsize_chars = 40){ + + // ScrolledWindow + var scroll = new Gtk.ScrolledWindow(null, null); + scroll.hscrollbar_policy = PolicyType.NEVER; + scroll.vscrollbar_policy = PolicyType.ALWAYS; + scroll.expand = true; + box.add(scroll); + + var label = new Gtk.Label(text); + label.xalign = (float) 0.0; + label.yalign = (float) 0.0; + label.margin = 6; + label.set_use_markup(true); + scroll.add(label); + + if (wrap){ + label.wrap = true; + label.wrap_mode = Pango.WrapMode.WORD; + } + else { + label.wrap = false; + label.ellipsize = Pango.EllipsizeMode.MIDDLE; + label.max_width_chars = ellipsize_chars; + } + + if (show_border){ + scroll.set_shadow_type (ShadowType.ETCHED_IN); + } + else{ + label.margin_left = 0; + } + + return label; + } + + // add_text_view + private Gtk.TextView add_text_view( + Gtk.Box box, string text){ + + // ScrolledWindow + var scrolled = new Gtk.ScrolledWindow(null, null); + scrolled.hscrollbar_policy = PolicyType.NEVER; + scrolled.vscrollbar_policy = PolicyType.ALWAYS; + scrolled.expand = true; + box.add(scrolled); + + var view = new Gtk.TextView(); + view.wrap_mode = Gtk.WrapMode.WORD_CHAR; + view.accepts_tab = false; + view.editable = false; + view.cursor_visible = false; + view.buffer.text = text; + view.sensitive = false; + scrolled.add (view); + + return view; + } + + // add_label + private Gtk.Label add_label( + Gtk.Box box, string text, bool bold = false, + bool italic = false, bool large = false){ + + string msg = "%s".printf( + (bold ? " weight=\"bold\"" : ""), + (italic ? " style=\"italic\"" : ""), + (large ? " size=\"x-large\"" : ""), + text); + + var label = new Gtk.Label(msg); + label.set_use_markup(true); + label.xalign = (float) 0.0; + label.wrap = true; + label.wrap_mode = Pango.WrapMode.WORD; + box.add(label); + return label; + } + + private string format_text( + string text, + bool bold = false, bool italic = false, bool large = false){ + + string msg = "%s".printf( + (bold ? " weight=\"bold\"" : ""), + (italic ? " style=\"italic\"" : ""), + (large ? " size=\"x-large\"" : ""), + escape_html(text)); + + return msg; + } + + // add_label_header + private Gtk.Label add_label_header( + Gtk.Box box, string text, bool large_heading = false){ + + var label = add_label(box, escape_html(text), true, false, large_heading); + label.margin_bottom = 12; + return label; + } + + // add_label_subnote + private Gtk.Label add_label_subnote( + Gtk.Box box, string text){ + + var label = add_label(box, text, false, true); + label.margin_left = 6; + return label; + } + + // add_radio + private Gtk.RadioButton add_radio( + Gtk.Box box, string text, Gtk.RadioButton? another_radio_in_group){ + + Gtk.RadioButton radio = null; + + if (another_radio_in_group == null){ + radio = new Gtk.RadioButton(null); + } + else{ + radio = new Gtk.RadioButton.from_widget(another_radio_in_group); + } + + radio.label = text; + + box.add(radio); + + foreach(var child in radio.get_children()){ + if (child is Gtk.Label){ + var label = (Gtk.Label) child; + label.use_markup = true; + break; + } + } + + return radio; + } + + // add_checkbox + private Gtk.CheckButton add_checkbox( + Gtk.Box box, string text){ + + var chk = new Gtk.CheckButton.with_label(text); + chk.label = text; + box.add(chk); + + foreach(var child in chk.get_children()){ + if (child is Gtk.Label){ + var label = (Gtk.Label) child; + label.use_markup = true; + break; + } + } + + /* + chk.toggled.connect(()=>{ + chk.active; + }); + */ + + return chk; + } + + // add_spin + private Gtk.SpinButton add_spin( + Gtk.Box box, double min, double max, double val, + int digits = 0, double step = 1, double step_page = 1){ + + var adj = new Gtk.Adjustment(val, min, max, step, step_page, 0); + var spin = new Gtk.SpinButton(adj, step, digits); + spin.xalign = (float) 0.5; + box.add(spin); + + /* + spin.value_changed.connect(()=>{ + label.sensitive = spin.sensitive; + }); + */ + + return spin; + } + + // add_button + private Gtk.Button add_button( + Gtk.Box box, string text, string tooltip, + ref Gtk.SizeGroup? size_group, + Gtk.Image? icon = null){ + + var button = new Gtk.Button(); + box.add(button); + + button.set_label(text); + button.set_tooltip_text(tooltip); + + if (icon != null){ + button.set_image(icon); + button.set_always_show_image(true); + } + + if (size_group == null){ + size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); + } + + size_group.add_widget(button); + + return button; + } + + // add_toggle_button + private Gtk.ToggleButton add_toggle_button( + Gtk.Box box, string text, string tooltip, + ref Gtk.SizeGroup? size_group, + Gtk.Image? icon = null){ + + var button = new Gtk.ToggleButton(); + box.add(button); + + button.set_label(text); + button.set_tooltip_text(tooltip); + + if (icon != null){ + button.set_image(icon); + button.set_always_show_image(true); + } + + if (size_group == null){ + size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); + } + + size_group.add_widget(button); + + return button; + } + + // add_directory_chooser + private Gtk.Entry add_directory_chooser( + Gtk.Box box, string selected_directory, Gtk.Window parent_window){ + + // Entry + var entry = new Gtk.Entry(); + entry.hexpand = true; + //entry.margin_left = 6; + entry.secondary_icon_stock = "gtk-open"; + entry.placeholder_text = _("Enter path or browse for directory"); + box.add (entry); + + if ((selected_directory != null) && dir_exists(selected_directory)){ + entry.text = selected_directory; + } + + entry.icon_release.connect((p0, p1) => { + //chooser + var chooser = new Gtk.FileChooserDialog( + _("Select Path"), + parent_window, + FileChooserAction.SELECT_FOLDER, + "_Cancel", + Gtk.ResponseType.CANCEL, + "_Open", + Gtk.ResponseType.ACCEPT + ); + + chooser.select_multiple = false; + chooser.set_filename(selected_directory); + + if (chooser.run() == Gtk.ResponseType.ACCEPT) { + entry.text = chooser.get_filename(); + + //App.repo = new SnapshotRepo.from_path(entry.text, this); + //check_backup_location(); + } + + chooser.destroy(); + }); + + return entry; + } + + +} + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/LinuxDistro.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/LinuxDistro.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/LinuxDistro.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/LinuxDistro.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,218 @@ + +/* + * ProcStats.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.ProcessHelper; + +public class LinuxDistro : GLib.Object{ + + /* Class for storing information about Linux distribution */ + + public string dist_id = ""; + public string description = ""; + public string release = ""; + public string codename = ""; + + public LinuxDistro(){ + dist_id = ""; + description = ""; + release = ""; + codename = ""; + } + + public string full_name(){ + if (dist_id == ""){ + return ""; + } + else{ + string val = ""; + val += dist_id; + val += (release.length > 0) ? " " + release : ""; + val += (codename.length > 0) ? " (" + codename + ")" : ""; + return val; + } + } + + public static LinuxDistro get_dist_info(string root_path){ + + /* Returns information about the Linux distribution + * installed at the given root path */ + + LinuxDistro info = new LinuxDistro(); + + string dist_file = root_path + "/etc/lsb-release"; + var f = File.new_for_path(dist_file); + if (f.query_exists()){ + + /* + DISTRIB_ID=Ubuntu + DISTRIB_RELEASE=13.04 + DISTRIB_CODENAME=raring + DISTRIB_DESCRIPTION="Ubuntu 13.04" + */ + + foreach(string line in file_read(dist_file).split("\n")){ + + if (line.split("=").length != 2){ continue; } + + string key = line.split("=")[0].strip(); + string val = line.split("=")[1].strip(); + + if (val.has_prefix("\"")){ + val = val[1:val.length]; + } + + if (val.has_suffix("\"")){ + val = val[0:val.length-1]; + } + + switch (key){ + case "DISTRIB_ID": + info.dist_id = val; + break; + case "DISTRIB_RELEASE": + info.release = val; + break; + case "DISTRIB_CODENAME": + info.codename = val; + break; + case "DISTRIB_DESCRIPTION": + info.description = val; + break; + } + } + } + else{ + + dist_file = root_path + "/etc/os-release"; + f = File.new_for_path(dist_file); + if (f.query_exists()){ + + /* + NAME="Ubuntu" + VERSION="13.04, Raring Ringtail" + ID=ubuntu + ID_LIKE=debian + PRETTY_NAME="Ubuntu 13.04" + VERSION_ID="13.04" + HOME_URL="http://www.ubuntu.com/" + SUPPORT_URL="http://help.ubuntu.com/" + BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" + */ + + foreach(string line in file_read(dist_file).split("\n")){ + + if (line.split("=").length != 2){ continue; } + + string key = line.split("=")[0].strip(); + string val = line.split("=")[1].strip(); + + switch (key){ + case "ID": + info.dist_id = val; + break; + case "VERSION_ID": + info.release = val; + break; + //case "DISTRIB_CODENAME": + //info.codename = val; + //break; + case "PRETTY_NAME": + info.description = val; + break; + } + } + } + } + + return info; + } + + public static string get_running_desktop_name(){ + + /* Return the names of the current Desktop environment */ + + int pid = -1; + + pid = get_pid_by_name("cinnamon"); + if (pid > 0){ + return "Cinnamon"; + } + + pid = get_pid_by_name("xfdesktop"); + if (pid > 0){ + return "Xfce"; + } + + pid = get_pid_by_name("lxsession"); + if (pid > 0){ + return "LXDE"; + } + + pid = get_pid_by_name("gnome-shell"); + if (pid > 0){ + return "Gnome"; + } + + pid = get_pid_by_name("wingpanel"); + if (pid > 0){ + return "Elementary"; + } + + pid = get_pid_by_name("unity-panel-service"); + if (pid > 0){ + return "Unity"; + } + + pid = get_pid_by_name("plasma-desktop"); + if (pid > 0){ + return "KDE"; + } + + return "Unknown"; + } + + public string dist_type { + + owned get{ + + if (dist_id == "fedora"){ + return "redhat"; + } + else if (dist_id.down().contains("manjaro") || dist_id.down().contains("arch")){ + return "arch"; + } + else if (dist_id.down().contains("ubuntu") || dist_id.down().contains("debian")){ + return "debian"; + } + else{ + return ""; + } + + } + } +} + + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/MountEntry.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/MountEntry.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/MountEntry.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/MountEntry.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,49 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.GtkHelper; +using TeeJee.System; +using TeeJee.Misc; +using Json; + +public class MountEntry : GLib.Object{ + public Device device = null; + public string mount_point = ""; + public string mount_options = ""; + + public MountEntry(Device? device, string mount_point, string mount_options){ + this.device = device; + this.mount_point = mount_point; + this.mount_options = mount_options; + } + + public string subvolume_name(){ + if (mount_options.contains("subvol=")){ + return mount_options.split("subvol=")[1].split(",")[0].strip(); + } + else{ + return ""; + } + } + + public string lvm_name(){ + if ((device != null) && (device.type == "lvm") && (device.mapped_name.length > 0)){ + return device.mapped_name.strip(); + } + else{ + return ""; + } + } + + public static MountEntry? find_entry_by_mount_point( + Gee.ArrayList entries, string mount_path){ + + foreach(var entry in entries){ + if (entry.mount_point == mount_path){ + return entry; + } + } + return null; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/OSDNotify.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/OSDNotify.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/OSDNotify.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/OSDNotify.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,80 @@ + +/* + * ProcStats.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.ProcessHelper; + +// dep: notify-send +public class OSDNotify : GLib.Object { + private static DateTime dt_last_notification = null; + public const int NOTIFICATION_INTERVAL = 3; + + public static int notify_send ( + string title, string message, int durationMillis, + string urgency = "low", // low, normal, critical + string dialog_type = "info" //error, info, warning + ){ + + /* Displays notification bubble on the desktop */ + + int retVal = 0; + + switch (dialog_type){ + case "error": + case "info": + case "warning": + //ok + break; + default: + dialog_type = "info"; + break; + } + + long seconds = 9999; + if (dt_last_notification != null){ + DateTime dt_end = new DateTime.now_local(); + TimeSpan elapsed = dt_end.difference(dt_last_notification); + seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND); + } + + if (seconds > NOTIFICATION_INTERVAL){ + string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\"".printf(durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message); + retVal = exec_sync (s, null, null); + dt_last_notification = new DateTime.now_local(); + } + + return retVal; + } + + public static bool is_supported(){ + string path = get_cmd_path ("notify-send"); + if ((path != null) && (path.length > 0)){ + return true; + } + else{ + return false; + } + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/ProcStats.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/ProcStats.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/ProcStats.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/ProcStats.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,89 @@ + +/* + * ProcStats.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.ProcessHelper; + +public class ProcStats : GLib.Object { + public double user = 0; + public double nice = 0; + public double system = 0; + public double idle = 0; + public double iowait = 0; + + public double user_delta = 0; + public double nice_delta = 0; + public double system_delta = 0; + public double idle_delta = 0; + public double iowait_delta = 0; + + public double usage_percent = 0; + + public static ProcStats stat_prev = null; + + public ProcStats(string line){ + string[] arr = line.split(" "); + int col = 0; + if (arr[col++] == "cpu"){ + if (arr[col].length == 0){ col++; }; + + user = double.parse(arr[col++]); + nice = double.parse(arr[col++]); + system = double.parse(arr[col++]); + idle = double.parse(arr[col++]); + iowait = double.parse(arr[col++]); + + if (ProcStats.stat_prev != null){ + user_delta = user - ProcStats.stat_prev.user; + nice_delta = nice - ProcStats.stat_prev.nice; + system_delta = system - ProcStats.stat_prev.system; + idle_delta = idle - ProcStats.stat_prev.idle; + iowait_delta = iowait - ProcStats.stat_prev.iowait; + + usage_percent = (user_delta + nice_delta + system_delta) * 100 / (user_delta + nice_delta + system_delta + idle_delta); + } + else{ + usage_percent = 0; + + } + + ProcStats.stat_prev = this; + } + } + + //returns 0 when it is called first time + public static double get_cpu_usage(){ + string txt = file_read("/proc/stat"); + foreach(string line in txt.split("\n")){ + string[] arr = line.split(" "); + if (arr[0] == "cpu"){ + ProcStats stat = new ProcStats(line); + return stat.usage_percent; + } + } + return 0; + } + } + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/RsyncTask.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/RsyncTask.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/RsyncTask.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/RsyncTask.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,481 @@ +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.JsonHelper; +using TeeJee.ProcessHelper; +using TeeJee.System; +using TeeJee.Misc; + +public class RsyncTask : AsyncTask{ + + // settings + public bool delete_extra = true; + public bool delete_after = false; + public bool delete_excluded = false; + public bool relative = false; + + public string rsync_log_file = ""; + public string exclude_from_file = ""; + public string link_from_path = ""; + public string source_path = ""; + public string dest_path = ""; + public bool verbose = true; + public bool io_nice = true; + + // regex + private Gee.HashMap regex_list; + + // status + public GLib.Queue status_lines; + public int64 status_line_count = 0; + public int64 total_size = 0; + + public int64 count_created; + public int64 count_deleted; + public int64 count_modified; + public int64 count_checksum; + public int64 count_size; + public int64 count_timestamp; + public int64 count_permissions; + public int64 count_owner; + public int64 count_group; + public int64 count_unchanged; + + public RsyncTask(){ + init_regular_expressions(); + status_lines = new GLib.Queue(); + } + + private void init_regular_expressions(){ + if (regex_list != null){ + return; // already initialized + } + + regex_list = new Gee.HashMap(); + + try { + //Example: status=-1 + regex_list["status"] = new Regex( + """(.)(.)(c|\+|\.| )(s|\+|\.| )(t|\+|\.| )(p|\+|\.| )(o|\+|\.| )(g|\+|\.| )(u|\+|\.| )(a|\+|\.| )(x|\+|\.| ) (.*)"""); + + regex_list["created"] = new Regex( + """(.)(.)\+\+\+\+\+\+\+\+\+ (.*)"""); + + regex_list["log-created"] = new Regex( + """[0-9/]+ [0-9:.]+ \[[0-9]+\] (.)(.)\+\+\+\+\+\+\+\+\+ (.*)"""); + + regex_list["deleted"] = new Regex( + """\*deleting[ \t]+(.*)"""); + + regex_list["log-deleted"] = new Regex( + """[0-9/]+ [0-9:.]+ \[[0-9]+\] \*deleting[ \t]+(.*)"""); + + regex_list["modified"] = new Regex( + """(.)(.)(c|\+|\.| )(s|\+|\.| )(t|\+|\.| )(p|\+|\.| )(o|\+|\.| )(g|\+|\.| )(u|\+|\.| )(a|\+|\.| )(x|\+|\.) (.*)"""); + + regex_list["log-modified"] = new Regex( + """[0-9/]+ [0-9:.]+ \[[0-9]+\] (.)(.)(c|\+|\.| )(s|\+|\.| )(t|\+|\.| )(p|\+|\.| )(o|\+|\.| )(g|\+|\.| )(u|\+|\.| )(a|\+|\.| )(x|\+|\.) (.*)"""); + + regex_list["unchanged"] = new Regex( + """(.)(.) (.*)"""); + + regex_list["log-unchanged"] = new Regex( + """[0-9/]+ [0-9:.]+ \[[0-9]+\] (.)(.)\+\+\+\+\+\+\+\+\+ (.*)"""); + + regex_list["total-size"] = new Regex( + """total size is ([0-9,]+)[ \t]+speedup is [0-9.]+"""); + + } + catch (Error e) { + log_error (e.message); + } + } + + public void prepare() { + string script_text = build_script(); + + log_debug(script_text); + + save_bash_script_temp(script_text, script_file); + log_debug("RsyncTask:prepare(): saved: %s".printf(script_file)); + + //status_lines = new GLib.Queue(); + status_line_count = 0; + total_size = 0; + + count_created = 0; + count_deleted = 0; + count_modified = 0; + count_checksum = 0; + count_size = 0; + count_timestamp = 0; + count_permissions = 0; + count_owner = 0; + count_group = 0; + count_unchanged = 0; + } + + private string build_script() { + var cmd = ""; + + if (io_nice){ + //cmd += "ionice -c2 -n7 "; + } + + cmd += "rsync -aii --recursive"; + + if (verbose){ + cmd += " --verbose"; + } + else{ + cmd += " --quiet"; + } + + if (delete_extra){ + cmd += " --delete"; + } + + if (delete_after){ + cmd += " --delete-after"; + } + + cmd += " --force"; // allow deletion of non-empty directories + + //cmd += " --numeric-ids"; + + cmd += " --stats"; + + //if (relative){ + // cmd += " --relative"; + //} + + if (delete_excluded){ + cmd += " --delete-excluded"; + } + + if (link_from_path.length > 0){ + if (!link_from_path.has_suffix("/")){ + link_from_path = "%s/".printf(link_from_path); + } + + cmd += " --link-dest='%s'".printf(escape_single_quote(link_from_path)); + } + + if (rsync_log_file.length > 0){ + cmd += " --log-file='%s'".printf(escape_single_quote(rsync_log_file)); + } + + if (exclude_from_file.length > 0){ + cmd += " --exclude-from='%s'".printf(escape_single_quote(exclude_from_file)); + + if (delete_extra && delete_excluded){ + cmd += " --delete-excluded"; + } + } + + source_path = remove_trailing_slash(source_path); + + dest_path = remove_trailing_slash(dest_path); + + cmd += " '%s/'".printf(escape_single_quote(source_path)); + + cmd += " '%s/'".printf(escape_single_quote(dest_path)); + + return cmd; + } + + public FileItem parse_log(string log_file_path){ + var root = new FileItem.dummy_root(); + + string log_file = log_file_path; + DataOutputStream dos_changes = null; + + if (!log_file.has_suffix("-changes")){ + + string log_file_changes = log_file_path + "-changes"; + + if (file_exists(log_file_changes)){ + // use it + log_file = log_file_changes; + } + else{ + // create one by initializing dos_changes + try { + var file = File.new_for_path(log_file_changes); + if (file.query_exists()){ + file.delete(); + } + var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); + dos_changes = new DataOutputStream (file_stream); + } + catch (Error e) { + log_error (e.message); + } + } + } + + log_debug("RsyncTask: parse_log()"); + log_debug("log_file = %s".printf(log_file)); + + prg_count = 0; + prg_count_total = file_line_count(log_file); + + try { + string line; + var file = File.new_for_path(log_file); + if (!file.query_exists ()) { + log_error(_("File not found") + ": %s".printf(log_file)); + return root; + } + + var dis = new DataInputStream (file.read()); + while ((line = dis.read_line (null)) != null) { + + prg_count++; + + if (line.strip().length == 0) { continue; } + + string item_path = ""; + var item_type = FileType.REGULAR; + string item_status = ""; + bool item_is_symlink = false; + + MatchInfo match; + if (regex_list["log-created"].match(line, 0, out match)) { + + if (dos_changes != null){ + dos_changes.put_string("%s\n".printf(line)); + } + + //log_debug("matched: created:%s".printf(line)); + + item_path = match.fetch(3).split(" -> ")[0].strip(); + item_type = FileType.REGULAR; + if (match.fetch(2) == "d"){ + item_type = FileType.DIRECTORY; + } + else if (match.fetch(2) == "L"){ + item_is_symlink = true; + } + item_status = "created"; + } + else if (regex_list["log-deleted"].match(line, 0, out match)) { + + //log_debug("matched: deleted:%s".printf(line)); + + if (dos_changes != null){ + dos_changes.put_string("%s\n".printf(line)); + } + + item_path = match.fetch(1).split(" -> ")[0].strip(); + item_type = item_path.has_suffix("/") ? FileType.DIRECTORY : FileType.REGULAR; + item_status = "deleted"; + } + else if (regex_list["log-modified"].match(line, 0, out match)) { + + //log_debug("matched: modified:%s".printf(line)); + + if (dos_changes != null){ + dos_changes.put_string("%s\n".printf(line)); + } + + item_path = match.fetch(12).split(" -> ")[0].strip(); + + if (match.fetch(2) == "d"){ + item_type = FileType.DIRECTORY; + } + else if (match.fetch(2) == "L"){ + item_is_symlink = true; + } + + if (match.fetch(3) == "c"){ + item_status = "checksum"; + } + else if (match.fetch(4) == "s"){ + item_status = "size"; + } + else if (match.fetch(5) == "t"){ + item_status = "timestamp"; + } + else if (match.fetch(6) == "p"){ + item_status = "permissions"; + } + else if (match.fetch(7) == "o"){ + item_status = "owner"; + } + else if (match.fetch(8) == "g"){ + item_status = "group"; + } + } + else{ + //log_debug("not-matched: %s".printf(line)); + } + + if ((item_path.length > 0) && (item_path != "/./") && (item_path != "./") + //&& ((item_type == FileType.REGULAR)||(item_status == "created")) + ){ + + int64 item_size = 0;//int64.parse(size); + string item_disk_path = path_combine(file_parent(log_file_path),"localhost"); + item_disk_path = path_combine(item_disk_path, item_path); + item_size = file_get_size(item_disk_path); + if (item_size == -1){ + item_size = 0; + } + + var item = root.add_descendant(item_path, item_type, item_size, 0); + item.file_status = item_status; + item.is_symlink = item_is_symlink; + //log_debug("added: %s".printf(item_path)); + } + + } + } + catch (Error e) { + log_error (e.message); + } + + if (dos_changes != null){ + // archive the raw log file + file_gzip(log_file_path); + } + + log_debug("RsyncTask: parse_log(): exit"); + + return root; + } + + // execution ---------------------------- + + public void execute() { + log_debug("RsyncTask:execute()"); + + prepare(); + + /*log_debug(string.nfill(70,'=')); + log_debug(script_file); + log_debug(string.nfill(70,'=')); + log_debug(file_read(script_file)); + log_debug(string.nfill(70,'='));*/ + + begin(); + + if (status == AppStatus.RUNNING){ + + + } + } + + public override void parse_stdout_line(string out_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(out_line); + } + + public override void parse_stderr_line(string err_line){ + if (is_terminated) { + return; + } + + update_progress_parse_console_output(err_line); + } + + public bool update_progress_parse_console_output (string line) { + if ((line == null) || (line.length == 0)) { + return true; + } + + status_line_count++; + + if (prg_count_total > 0){ + prg_count = status_line_count; + progress = (prg_count * 1.0) / prg_count_total; + } + + //MatchInfo match; + //if (regex_list["status"].match(line, 0, out match)) { + // status_line = match.fetch(12); + + //status_lines.push_tail(status_line); + //if (status_lines.get_length() > 15){ + // status_lines.pop_head(); + //} + //} + MatchInfo match; + if (regex_list["created"].match(line, 0, out match)) { + + //log_debug("matched: created:%s".printf(line)); + + count_created++; + status_line = match.fetch(3).split(" -> ")[0].strip(); + } + else if (regex_list["deleted"].match(line, 0, out match)) { + + //log_debug("matched: deleted:%s".printf(line)); + + count_deleted++; + status_line = match.fetch(1).split(" -> ")[0].strip(); + } + else if (regex_list["unchanged"].match(line, 0, out match)) { + + //log_debug("matched: deleted:%s".printf(line)); + + count_unchanged++; + status_line = match.fetch(3).split(" -> ")[0].strip(); + } + else if (regex_list["modified"].match(line, 0, out match)) { + + //log_debug("matched: modified:%s".printf(line)); + + count_modified++; + status_line = match.fetch(12).split(" -> ")[0].strip(); + + if (match.fetch(3) == "c"){ + count_checksum++; + } + else if (match.fetch(4) == "s"){ + count_size++; + } + else if (match.fetch(5) == "t"){ + count_timestamp++; + } + else if (match.fetch(6) == "p"){ + count_permissions++; + } + else if (match.fetch(7) == "o"){ + count_owner++; + } + else if (match.fetch(8) == "g"){ + count_group++; + } + else{ + count_unchanged++; + } + } + else if (regex_list["total-size"].match(line, 0, out match)) { + total_size = int64.parse(match.fetch(1).replace(",","")); + } + else{ + //log_debug("not-matched: %s".printf(line)); + } + + return true; + } + + protected override void finish_task(){ + if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { + status = AppStatus.FINISHED; + } + } + + public int read_status(){ + var status_file = working_dir + "/status"; + var f = File.new_for_path(status_file); + if (f.query_exists()){ + var txt = file_read(status_file); + return int.parse(txt); + } + return -1; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.FileSystem.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.FileSystem.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.FileSystem.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.FileSystem.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,771 @@ + +/* + * TeeJee.FileSystem.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +namespace TeeJee.FileSystem{ + + /* Convenience functions for handling files and directories */ + + using TeeJee.Logging; + using TeeJee.ProcessHelper; + using TeeJee.Misc; + + + public const int64 KB = 1000; + public const int64 MB = 1000 * KB; + public const int64 GB = 1000 * MB; + public const int64 TB = 1000 * GB; + public const int64 KiB = 1024; + public const int64 MiB = 1024 * KiB; + public const int64 GiB = 1024 * MiB; + public const int64 TiB = 1024 * GiB; + + // path helpers ---------------------------- + + public string file_parent(string file_path){ + return File.new_for_path(file_path).get_parent().get_path(); + } + + public string file_basename(string file_path){ + return File.new_for_path(file_path).get_basename(); + } + + public string path_combine(string path1, string path2){ + return GLib.Path.build_path("/", path1, path2); + } + + public string remove_trailing_slash(string path){ + if (path.has_suffix("/")){ + return path[0:path.length - 1]; + } + else{ + return path; + } + } + + // file helpers ----------------------------- + + public bool file_or_dir_exists(string item_path){ + + /* check if item exists on disk*/ + + var item = File.parse_name(item_path); + return item.query_exists(); + } + + public bool file_exists (string file_path){ + /* Check if file exists */ + return (FileUtils.test(file_path, GLib.FileTest.EXISTS) + && !FileUtils.test(file_path, GLib.FileTest.IS_DIR)); + } + + public bool file_exists_regular (string file_path){ + /* Check if file exists */ + return ( FileUtils.test(file_path, GLib.FileTest.EXISTS) + && FileUtils.test(file_path, GLib.FileTest.IS_REGULAR)); + } + + public bool file_delete(string file_path){ + + /* Check and delete file */ + + try { + var file = File.new_for_path (file_path); + if (file.query_exists ()) { + file.delete (); + } + return true; + } catch (Error e) { + log_error (e.message); + log_error(_("Failed to delete file") + ": %s".printf(file_path)); + return false; + } + } + + public bool file_move_to_trash(string file_path){ + + /* Check and delete file */ + + var file = File.new_for_path (file_path); + if (file.query_exists ()) { + Posix.system("gvfs-trash '%s'".printf(escape_single_quote(file_path))); + } + return true; + } + + public bool file_shred(string file_path){ + + /* Check and delete file */ + + var file = File.new_for_path (file_path); + if (file.query_exists ()) { + Posix.system("shred -u '%s'".printf(escape_single_quote(file_path))); + } + return true; + } + + public int64 file_line_count (string file_path){ + /* Count number of lines in text file */ + string cmd = "wc -l '%s'".printf(escape_single_quote(file_path)); + string std_out, std_err; + exec_sync(cmd, out std_out, out std_err); + return long.parse(std_out.split("\t")[0]); + } + + public string? file_read (string file_path){ + + /* Reads text from file */ + + string txt; + size_t size; + + try{ + GLib.FileUtils.get_contents (file_path, out txt, out size); + return txt; + } + catch (Error e){ + log_error (e.message); + log_error(_("Failed to read file") + ": %s".printf(file_path)); + } + + return null; + } + + public bool file_write (string file_path, string contents){ + + /* Write text to file */ + + try{ + + dir_create(file_parent(file_path)); + + var file = File.new_for_path (file_path); + if (file.query_exists ()) { + file.delete (); + } + + var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); + var data_stream = new DataOutputStream (file_stream); + data_stream.put_string (contents); + data_stream.close(); + return true; + } + catch (Error e) { + log_error (e.message); + log_error(_("Failed to write file") + ": %s".printf(file_path)); + return false; + } + } + + public bool file_copy (string src_file, string dest_file){ + try{ + var file_src = File.new_for_path (src_file); + if (file_src.query_exists()) { + var file_dest = File.new_for_path (dest_file); + file_src.copy(file_dest,FileCopyFlags.OVERWRITE,null,null); + return true; + } + } + catch(Error e){ + log_error (e.message); + log_error(_("Failed to copy file") + ": '%s', '%s'".printf(src_file, dest_file)); + } + + return false; + } + + public void file_move (string src_file, string dest_file){ + try{ + var file_src = File.new_for_path (src_file); + if (file_src.query_exists()) { + var file_dest = File.new_for_path (dest_file); + file_src.move(file_dest,FileCopyFlags.OVERWRITE,null,null); + } + else{ + log_error(_("File not found") + ": '%s'".printf(src_file)); + } + } + catch(Error e){ + log_error (e.message); + log_error(_("Failed to move file") + ": '%s', '%s'".printf(src_file, dest_file)); + } + } + + public bool file_gzip (string src_file){ + + string dst_file = src_file + ".gz"; + file_delete(dst_file); + + string cmd = "gzip '%s'".printf(escape_single_quote(src_file)); + string std_out, std_err; + exec_sync(cmd, out std_out, out std_err); + + return file_exists(dst_file); + } + + public bool file_gunzip (string src_file){ + + string dst_file = src_file; + file_delete(dst_file); + + string cmd = "gunzip '%s'".printf(escape_single_quote(src_file)); + string std_out, std_err; + exec_sync(cmd, out std_out, out std_err); + + return file_exists(dst_file); + } + + + // file info ----------------- + + public int64 file_get_size(string file_path){ + try{ + File file = File.parse_name (file_path); + if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){ + if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR) + && !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){ + return file.query_info("standard::size",0).get_size(); + } + } + } + catch(Error e){ + log_error (e.message); + } + + return -1; + } + + public DateTime file_get_modified_date(string file_path){ + try{ + FileInfo info; + File file = File.parse_name (file_path); + if (file.query_exists()) { + info = file.query_info("%s".printf(FileAttribute.TIME_MODIFIED), 0); + return (new DateTime.from_timeval_utc(info.get_modification_time())).to_local(); + } + } + catch (Error e) { + log_error (e.message); + } + + return (new DateTime.from_unix_utc(0)); //1970 + } + + public string file_get_symlink_target(string file_path){ + try{ + FileInfo info; + File file = File.parse_name (file_path); + if (file.query_exists()) { + info = file.query_info("%s".printf(FileAttribute.STANDARD_SYMLINK_TARGET), 0); + return info.get_symlink_target(); + } + } + catch (Error e) { + log_error (e.message); + } + + return ""; + } + + // directory helpers ---------------------- + + public bool dir_exists (string dir_path){ + /* Check if directory exists */ + return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR)); + } + + public bool dir_create (string dir_path){ + + /* Creates a directory along with parents */ + + try{ + var dir = File.parse_name (dir_path); + if (dir.query_exists () == false) { + dir.make_directory_with_parents (null); + } + return true; + } + catch (Error e) { + log_error (e.message); + log_error(_("Failed to create dir") + ": %s".printf(dir_path)); + return false; + } + } + + public bool dir_delete (string dir_path){ + + /* Recursively deletes directory along with contents */ + + string cmd = "rm -rf '%s'".printf(escape_single_quote(dir_path)); + int status = exec_sync(cmd); + return (status == 0); + } + + public bool dir_move_to_trash (string dir_path){ + return file_move_to_trash(dir_path); + } + + public bool dir_is_empty (string dir_path){ + + /* Check if directory is empty */ + + try{ + bool is_empty = true; + var dir = File.parse_name (dir_path); + if (dir.query_exists()) { + FileInfo info; + var enu = dir.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); + while ((info = enu.next_file()) != null) { + is_empty = false; + break; + } + } + return is_empty; + } + catch (Error e) { + log_error (e.message); + return false; + } + } + + public bool filesystem_supports_hardlinks(string path, out bool is_readonly){ + bool supports_hardlinks = false; + is_readonly = false; + + var test_file = path_combine(path, random_string() + "~"); + + if (file_write(test_file,"")){ + + var test_file2 = path_combine(path, random_string() + "~"); + + var cmd = "ln '%s' '%s'".printf( + escape_single_quote(test_file), + escape_single_quote(test_file2)); + + log_debug(cmd); + + int status = exec_sync(cmd); + + cmd = "stat --printf '%%h' '%s'".printf( + escape_single_quote(test_file)); + + log_debug(cmd); + + string std_out, std_err; + status = exec_sync(cmd, out std_out, out std_err); + log_debug("stdout: %s".printf(std_out)); + + int64 count = 0; + if (int64.try_parse(std_out, out count)){ + if (count > 1){ + supports_hardlinks = true; + } + } + + file_delete(test_file2); // delete if exists + file_delete(test_file); + } + else{ + is_readonly = true; + } + + return supports_hardlinks; + } + + public Gee.ArrayList dir_list_names(string path){ + var list = new Gee.ArrayList(); + + try + { + File f_home = File.new_for_path (path); + FileEnumerator enumerator = f_home.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); + FileInfo file; + while ((file = enumerator.next_file ()) != null) { + string name = file.get_name(); + list.add(name); + } + } + catch (Error e) { + log_error (e.message); + } + + //sort the list + CompareDataFunc entry_compare = (a, b) => { + return strcmp(a,b); + }; + list.sort((owned) entry_compare); + + return list; + } + + public bool dir_tar (string src_dir, string tar_file, bool recursion = true){ + if (dir_exists(src_dir)) { + + if (file_exists(tar_file)){ + file_delete(tar_file); + } + + var src_parent = file_parent(src_dir); + var src_name = file_basename(src_dir); + + string cmd = "tar cvf '%s' --overwrite --%srecursion -C '%s' '%s'\n".printf( + escape_single_quote(tar_file), + (recursion ? "" : "no-"), + escape_single_quote(src_parent), + escape_single_quote(src_name)); + + log_debug(cmd); + + string stdout, stderr; + int status = exec_script_sync(cmd, out stdout, out stderr); + if (status == 0){ + return true; + } + else{ + log_msg(stderr); + } + } + else{ + log_error(_("Dir not found") + ": %s".printf(src_dir)); + } + + return false; + } + + public bool dir_untar (string tar_file, string dst_dir){ + if (file_exists(tar_file)) { + + if (!dir_exists(dst_dir)){ + dir_create(dst_dir); + } + + string cmd = "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf( + escape_single_quote(tar_file), + escape_single_quote(dst_dir)); + + log_debug(cmd); + + string stdout, stderr; + int status = exec_script_sync(cmd, out stdout, out stderr); + if (status == 0){ + return true; + } + else{ + log_msg(stderr); + } + } + else{ + log_error(_("File not found") + ": %s".printf(tar_file)); + } + + return false; + } + + public bool chown(string dir_path, string user, string group = user){ + string cmd = "chown %s:%s -R '%s'".printf(user, group, escape_single_quote(dir_path)); + int status = exec_sync(cmd, null, null); + return (status == 0); + } + + // dir info ------------------- + + // dep: find wc TODO: rewrite + public long dir_count(string path){ + + /* Return total count of files and directories */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + cmd = "find '%s' | wc -l".printf(escape_single_quote(path)); + ret_val = exec_script_sync(cmd, out std_out, out std_err); + return long.parse(std_out); + } + + // dep: du + public long dir_size(string path){ + + /* Returns size of files and directories in KB*/ + + string cmd = "du -s -b '%s'".printf(escape_single_quote(path)); + string std_out, std_err; + exec_sync(cmd, out std_out, out std_err); + return long.parse(std_out.split("\t")[0]); + } + + // dep: du + public long dir_size_kb(string path){ + + /* Returns size of files and directories in KB*/ + + return (long)(dir_size(path) / 1024.0); + } + + // archiving and encryption ---------------- + + // dep: tar gzip gpg + public bool file_tar_encrypt (string src_file, string dst_file, string password){ + if (file_exists(src_file)) { + if (file_exists(dst_file)){ + file_delete(dst_file); + } + + var src_dir = file_parent(src_file); + var src_name = file_basename(src_file); + + var dst_dir = file_parent(dst_file); + var dst_name = file_basename(dst_file); + var tar_name = dst_name[0 : dst_name.index_of(".gpg")]; + var tar_file = "%s/%s".printf(dst_dir, tar_name); + + string cmd = "tar cvf '%s' --overwrite -C '%s' '%s'\n".printf( + escape_single_quote(tar_file), + escape_single_quote(src_dir), + escape_single_quote(src_name)); + + cmd += "gpg --passphrase '%s' -o '%s' --symmetric '%s'\n".printf( + password, + escape_single_quote(dst_file), + escape_single_quote(tar_file)); + + cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); + + log_debug(cmd); + + string stdout, stderr; + int status = exec_script_sync(cmd, out stdout, out stderr); + if (status == 0){ + return true; + } + else{ + log_msg(stderr); + } + } + + return false; + } + + // dep: tar gzip gpg + public string file_decrypt_untar_read (string src_file, string password){ + + if (file_exists(src_file)) { + + //var src_name = file_basename(src_file); + //var tar_name = src_name[0 : src_name.index_of(".gpg")]; + //var tar_file = "%s/%s".printf(TEMP_DIR, tar_name); + //var temp_file = "%s/%s".printf(TEMP_DIR, random_string()); + + string cmd = ""; + + cmd += "gpg --quiet --no-verbose --passphrase '%s' -o- --decrypt '%s'".printf( + password, + escape_single_quote(src_file)); + + cmd += " | tar xf - --to-stdout 2>/dev/null\n"; + cmd += "exit $?\n"; + + log_debug(cmd); + + string std_out, std_err; + int status = exec_script_sync(cmd, out std_out, out std_err); + if (status == 0){ + return std_out; + } + else{ + log_error(std_err); + return ""; + } + } + else{ + log_error(_("File is missing") + ": %s".printf(src_file)); + } + + return ""; + } + + // dep: tar gzip gpg + public bool decrypt_and_untar (string src_file, string dst_file, string password){ + if (file_exists(src_file)) { + if (file_exists(dst_file)){ + file_delete(dst_file); + } + + var src_dir = file_parent(src_file); + var src_name = file_basename(src_file); + var tar_name = src_name[0 : src_name.index_of(".gpg")]; + var tar_file = "%s/%s".printf(src_dir, tar_name); + + string cmd = ""; + + // gpg cannot overwrite - remove tar file if it exists + cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); + + cmd += "gpg --passphrase '%s' -o '%s' --decrypt '%s'\n".printf( + password, + escape_single_quote(tar_file), + escape_single_quote(src_file)); + + cmd += "status=$?; if [ $status -ne 0 ]; then exit $status; fi\n"; + + cmd += "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf( + escape_single_quote(tar_file), + escape_single_quote(file_parent(dst_file))); + + cmd += "rm -f '%s'\n".printf(escape_single_quote(tar_file)); + + log_debug(cmd); + + string stdout, stderr; + int status = exec_script_sync(cmd, out stdout, out stderr); + if (status == 0){ + return true; + } + else{ + log_error(stderr); + return false; + } + } + else{ + log_error(_("File is missing") + ": %s".printf(src_file)); + } + + return false; + } + + // hashing ----------- + + private string hash_md5(string path){ + Checksum checksum = new Checksum (ChecksumType.MD5); + FileStream stream = FileStream.open (path, "rb"); + + uint8 fbuf[100]; + size_t size; + while ((size = stream.read (fbuf)) > 0){ + checksum.update (fbuf, size); + } + + unowned string digest = checksum.get_string(); + + return digest; + } + + // misc -------------------- + + public string format_file_size ( + uint64 size, bool binary_units = false, + string unit = "", bool show_units = true, int decimals = 1){ + + int64 unit_k = binary_units ? 1024 : 1000; + int64 unit_m = binary_units ? 1024 * unit_k : 1000 * unit_k; + int64 unit_g = binary_units ? 1024 * unit_m : 1000 * unit_m; + int64 unit_t = binary_units ? 1024 * unit_g : 1000 * unit_g; + + string txt = ""; + + if ((size > unit_t) && ((unit.length == 0) || (unit == "t"))){ + txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_t)); + if (show_units){ + txt += " %sB".printf(binary_units ? "Ti" : "T"); + } + } + else if ((size > unit_g) && ((unit.length == 0) || (unit == "g"))){ + txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_g)); + if (show_units){ + txt += " %sB".printf(binary_units ? "Gi" : "G"); + } + } + else if ((size > unit_m) && ((unit.length == 0) || (unit == "m"))){ + txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_m)); + if (show_units){ + txt += " %sB".printf(binary_units ? "Mi" : "M"); + } + } + else if ((size > unit_k) && ((unit.length == 0) || (unit == "k"))){ + txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_k)); + if (show_units){ + txt += " %sB".printf(binary_units ? "Ki" : "K"); + } + } + else{ + txt += "%'0lld".printf(size); + if (show_units){ + txt += " B"; + } + } + + return txt; + } + + public string escape_single_quote(string file_path){ + return file_path.replace("'","'\\''"); + } + + + // dep: chmod + public int chmod (string file, string permission){ + + /* Change file permissions */ + string cmd = "chmod %s '%s'".printf(permission, escape_single_quote(file)); + return exec_sync (cmd, null, null); + } + + // dep: realpath + public string resolve_relative_path (string filePath){ + + /* Resolve the full path of given file using 'realpath' command */ + + string filePath2 = filePath; + if (filePath2.has_prefix ("~")){ + filePath2 = Environment.get_home_dir () + "/" + filePath2[2:filePath2.length]; + } + + try { + string output = ""; + string cmd = "realpath '%s'".printf(escape_single_quote(filePath2)); + Process.spawn_command_line_sync(cmd, out output); + output = output.strip (); + if (FileUtils.test(output, GLib.FileTest.EXISTS)){ + return output; + } + } + catch(Error e){ + log_error (e.message); + } + + return filePath2; + } + + public int rsync (string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){ + + /* Sync files with rsync */ + + string cmd = "rsync -avh"; + cmd += updateExisting ? "" : " --ignore-existing"; + cmd += deleteExtra ? " --delete" : ""; + cmd += " '%s'".printf(escape_single_quote(sourceDirectory) + "//"); + cmd += " '%s'".printf(escape_single_quote(destDirectory)); + return exec_sync (cmd, null, null); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Json.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Json.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Json.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Json.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,103 @@ + +/* + * TeeJee.JsonHelper.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +using Json; + +namespace TeeJee.JsonHelper{ + + using TeeJee.Logging; + + /* Convenience functions for reading and writing JSON files */ + + public string json_get_string(Json.Object jobj, string member, string def_value){ + if (jobj.has_member(member)){ + return jobj.get_string_member(member); + } + else{ + log_debug ("Member not found in JSON object: " + member); + return def_value; + } + } + + public double json_get_double(Json.Object jobj, string member, double def_value){ + var text = json_get_string(jobj, member, def_value.to_string()); + double double_value; + if (double.try_parse(text, out double_value)){ + return double_value; + } + else{ + return def_value; + } + } + + public bool json_get_bool(Json.Object jobj, string member, bool def_value){ + if (jobj.has_member(member)){ + return bool.parse(jobj.get_string_member(member)); + } + else{ + log_debug ("Member not found in JSON object: " + member); + return def_value; + } + } + + public int json_get_int(Json.Object jobj, string member, int def_value){ + if (jobj.has_member(member)){ + return int.parse(jobj.get_string_member(member)); + } + else{ + log_debug ("Member not found in JSON object: " + member); + return def_value; + } + } + + public int64 json_get_int64(Json.Object jobj, string member, int64 def_value){ + if (jobj.has_member(member)){ + return int64.parse(jobj.get_string_member(member)); + } + else{ + log_debug ("Member not found in JSON object: " + member); + return def_value; + } + } + + public Gee.ArrayList json_get_array( + Json.Object jobj, + string member, + Gee.ArrayList def_value){ + + if (jobj.has_member(member)){ + var jarray = jobj.get_array_member(member); + var list = new Gee.ArrayList(); + foreach(var node in jarray.get_elements()){ + list.add(node.get_string()); + } + return list; + } + else{ + log_debug ("Member not found in JSON object: " + member); + return def_value; + } + } + +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Logging.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Logging.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Logging.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Logging.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,167 @@ + +/* + * TeeJee.Logging.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +namespace TeeJee.Logging{ + + /* Functions for logging messages to console and log files */ + + using TeeJee.Misc; + + public DataOutputStream dos_log; + public string err_log; + public bool LOG_ENABLE = true; + public bool LOG_TIMESTAMP = false; + public bool LOG_COLORS = true; + public bool LOG_DEBUG = false; + public bool LOG_COMMANDS = false; + + public void log_msg (string message, bool highlight = false){ + + if (!LOG_ENABLE) { return; } + + string msg = ""; + + if (highlight && LOG_COLORS){ + msg += "\033[1;38;5;34m"; + } + + if (LOG_TIMESTAMP){ + msg += "[" + timestamp(true) + "] "; + } + + msg += message; + + if (highlight && LOG_COLORS){ + msg += "\033[0m"; + } + + msg += "\n"; + + stdout.printf (msg); + stdout.flush(); + + try { + if (dos_log != null){ + dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); + } + } + catch (Error e) { + stdout.printf (e.message); + } + } + + public void log_error (string message, bool highlight = false, + bool is_warning = false){ + + if (!LOG_ENABLE) { return; } + + string msg = ""; + + if (highlight && LOG_COLORS){ + msg += "\033[1;38;5;160m"; + } + + if (LOG_TIMESTAMP){ + msg += "[" + timestamp(true) + "] "; + } + + string prefix = (is_warning) ? _("W") : _("E"); + + msg += prefix + ": " + message; + + if (highlight && LOG_COLORS){ + msg += "\033[0m"; + } + + msg += "\n"; + + stdout.printf (msg); + stdout.flush(); + + try { + string str = "[%s] %s: %s\n".printf(timestamp(), prefix, message); + + if (dos_log != null){ + dos_log.put_string (str); + } + + if (err_log != null){ + err_log += "%s\n".printf(message); + } + } + catch (Error e) { + stdout.printf (e.message); + } + } + + public void log_debug (string message){ + if (!LOG_ENABLE) { return; } + + if (LOG_DEBUG){ + log_msg ("D: " + message); + } + + try { + if (dos_log != null){ + dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); + } + } + catch (Error e) { + stdout.printf (e.message); + } + } + + public void log_to_file (string message, bool highlight = false){ + try { + if (dos_log != null){ + dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); + } + } + catch (Error e) { + stdout.printf (e.message); + } + } + + public void log_draw_line(){ + log_msg(string.nfill(70,'=')); + } + + public void show_err_log(Gtk.Window parent, bool disable_log = true){ + if ((err_log != null) && (err_log.length > 0)){ + //gtk_messagebox(_("Error"), err_log, parent, true); + } + + if (disable_log){ + err_log_disable(); + } + } + + public void err_log_clear(){ + err_log = ""; + } + + public void err_log_disable(){ + err_log = null; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Misc.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Misc.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Misc.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Misc.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,351 @@ + +/* + * TeeJee.Misc.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +namespace TeeJee.Misc { + + /* Various utility functions */ + + using Gtk; + using TeeJee.Logging; + using TeeJee.FileSystem; + using TeeJee.ProcessHelper; + + // color format ------------------- + + public static Gdk.RGBA hex_to_rgba (string hex_color){ + + /* Converts the color in hex to RGBA */ + + string hex = hex_color.strip().down(); + if (hex.has_prefix("#") == false){ + hex = "#" + hex; + } + + Gdk.RGBA color = Gdk.RGBA(); + if(color.parse(hex) == false){ + color.parse("#000000"); + } + color.alpha = 255; + + return color; + } + + public static string rgba_to_hex (Gdk.RGBA color, bool alpha = false, bool prefix_hash = true){ + + /* Converts the color in RGBA to hex */ + + string hex = ""; + + if (alpha){ + hex = "%02x%02x%02x%02x".printf((uint)(Math.round(color.red*255)), + (uint)(Math.round(color.green*255)), + (uint)(Math.round(color.blue*255)), + (uint)(Math.round(color.alpha*255))) + .up(); + } + else { + hex = "%02x%02x%02x".printf((uint)(Math.round(color.red*255)), + (uint)(Math.round(color.green*255)), + (uint)(Math.round(color.blue*255))) + .up(); + } + + if (prefix_hash){ + hex = "#" + hex; + } + + return hex; + } + + // localization -------------------- + + public void set_numeric_locale(string type){ + Intl.setlocale(GLib.LocaleCategory.NUMERIC, type); + Intl.setlocale(GLib.LocaleCategory.COLLATE, type); + Intl.setlocale(GLib.LocaleCategory.TIME, type); + } + + // timestamp ---------------- + + public string timestamp (bool show_millis = false){ + + /* Returns a formatted timestamp string */ + + // NOTE: format() does not support milliseconds + + DateTime now = new GLib.DateTime.now_local(); + + if (show_millis){ + var msec = now.get_microsecond () / 1000; + return "%s.%03d".printf(now.format("%H:%M:%S"), msec); + } + else{ + return now.format ("%H:%M:%S"); + } + } + + public string timestamp_numeric (){ + + /* Returns a numeric timestamp string */ + + return "%ld".printf((long) time_t ()); + } + + public string timestamp_for_path (){ + + /* Returns a formatted timestamp string */ + + Time t = Time.local (time_t ()); + return t.format ("%Y-%d-%m_%H-%M-%S"); + } + + // string formatting ------------------------------------------------- + + public string format_date(DateTime date){ + return date.format ("%Y-%m-%d %H:%M"); + } + + public string format_duration (long millis){ + + /* Converts time in milliseconds to format '00:00:00.0' */ + + double time = millis / 1000.0; // time in seconds + + double hr = Math.floor(time / (60.0 * 60)); + time = time - (hr * 60 * 60); + double min = Math.floor(time / 60.0); + time = time - (min * 60); + double sec = Math.floor(time); + + return "%02.0lf:%02.0lf:%02.0lf".printf (hr, min, sec); + } + + public string format_time_left(int64 millis){ + double mins = (millis * 1.0) / 60000; + double secs = ((millis * 1.0) % 60000) / 1000; + string txt = ""; + if (mins >= 1){ + txt += "%.0fm ".printf(mins); + } + txt += "%.0fs".printf(secs); + return txt; + } + + public double parse_time (string time){ + + /* Converts time in format '00:00:00.0' to milliseconds */ + + string[] arr = time.split (":"); + double millis = 0; + if (arr.length >= 3){ + millis += double.parse(arr[0]) * 60 * 60; + millis += double.parse(arr[1]) * 60; + millis += double.parse(arr[2]); + } + return millis; + } + + public string string_replace(string str, string search, string replacement, int count = -1){ + string[] arr = str.split(search); + string new_txt = ""; + bool first = true; + + foreach(string part in arr){ + if (first){ + new_txt += part; + } + else{ + if (count == 0){ + new_txt += search; + new_txt += part; + } + else{ + new_txt += replacement; + new_txt += part; + count--; + } + } + first = false; + } + + return new_txt; + } + + public string escape_html(string html, bool pango_markup = true){ + string txt = html; + + if (pango_markup){ + txt = txt + .replace("\\u00", "") + .replace("\\x" , ""); + } + else{ + txt = txt + .replace(" ", " "); //pango markup throws an error with   + } + + txt = txt + .replace("&" , "&") + .replace("\"", """) + .replace("<" , "<") + .replace(">" , ">") + ; + + return txt; + } + + public string unescape_html(string html){ + return html + .replace("&","&") + .replace(""","\"") + //.replace(" "," ") //pango markup throws an error with   + .replace("<","<") + .replace(">",">") + ; + } + + public string uri_encode(string path, bool encode_forward_slash){ + string uri = Uri.escape_string(path); + if (!encode_forward_slash){ + uri = uri.replace("%2F","/"); + } + return uri; + } + + public string uri_decode(string path){ + return Uri.unescape_string(path); + } + + public DateTime datetime_from_string (string date_time_string){ + + /* Converts date time string to DateTime + * + * Supported inputs: + * 'yyyy-MM-dd' + * 'yyyy-MM-dd HH' + * 'yyyy-MM-dd HH:mm' + * 'yyyy-MM-dd HH:mm:ss' + * */ + + string[] arr = date_time_string.replace(":"," ").replace("-"," ").strip().split(" "); + + int year = (arr.length >= 3) ? int.parse(arr[0]) : 0; + int month = (arr.length >= 3) ? int.parse(arr[1]) : 0; + int day = (arr.length >= 3) ? int.parse(arr[2]) : 0; + int hour = (arr.length >= 4) ? int.parse(arr[3]) : 0; + int min = (arr.length >= 5) ? int.parse(arr[4]) : 0; + int sec = (arr.length >= 6) ? int.parse(arr[5]) : 0; + + return new DateTime.utc(year,month,day,hour,min,sec); + } + + public string break_string_by_word(string input_text){ + string text = ""; + string line = ""; + foreach(string part in input_text.split(" ")){ + line += part + " "; + if (line.length > 50){ + text += line.strip() + "\n"; + line = ""; + } + } + if (line.length > 0){ + text += line; + } + if (text.has_suffix("\n")){ + text = text[0:text.length-1].strip(); + } + return text; + } + + public string[] array_concat(string[] a, string[] b){ + string[] c = {}; + foreach(string str in a){ c += str; } + foreach(string str in b){ c += str; } + return c; + } + + public string random_string(int length = 8, string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"){ + string random = ""; + + for(int i=0;i 0){ + sequence = string.nfill(max_length - sequence.length, pad_char) + sequence; + } + output += sequence; + sequence = ""; + seq_started = false; + } + + output += character; + } + } + + //append remaining characters in sequence + if (sequence.length > 0){ + if ((max_length - sequence.length) > 0){ + sequence = string.nfill(max_length - sequence.length, pad_char) + sequence; + } + output += sequence; + sequence = ""; + } + + return output; + } + + public bool is_numeric(string text){ + for (int i = 0; i < text.length; i++){ + if (!text[i].isdigit()){ + return false; + } + } + return true; + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Process.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Process.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.Process.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.Process.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,546 @@ + +/* + * TeeJee.ProcessHelper.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +namespace TeeJee.ProcessHelper{ + using TeeJee.Logging; + using TeeJee.FileSystem; + using TeeJee.Misc; + + public string TEMP_DIR; + + /* Convenience functions for executing commands and managing processes */ + + // execute process --------------------------------- + + public static void init_tmp(string subdir_name){ + string std_out, std_err; + + TEMP_DIR = Environment.get_tmp_dir() + "/" + subdir_name + "/" + random_string(); + dir_create(TEMP_DIR); + + exec_script_sync("echo 'ok'",out std_out,out std_err, true); + if ((std_out == null)||(std_out.strip() != "ok")){ + TEMP_DIR = Environment.get_home_dir() + "/.temp/" + subdir_name + "/" + random_string(); + exec_sync("rm -rf '%s'".printf(TEMP_DIR), null, null); + dir_create(TEMP_DIR); + } + + //log_debug("TEMP_DIR=" + TEMP_DIR); + } + + public string create_temp_subdir(){ + var temp = "%s/%s".printf(TEMP_DIR, random_string()); + dir_create(temp); + return temp; + } + + public int exec_sync (string cmd, out string? std_out = null, out string? std_err = null){ + + /* Executes single command synchronously. + * Pipes and multiple commands are not supported. + * std_out, std_err can be null. Output will be written to terminal if null. */ + + try { + int status; + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out status); + return status; + } + catch (Error e){ + log_error (e.message); + return -1; + } + } + + public int exec_script_sync (string script, + out string? std_out = null, out string? std_err = null, + bool supress_errors = false, bool run_as_admin = false, + bool cleanup_tmp = true, bool print_to_terminal = false){ + + /* Executes commands synchronously. + * Pipes and multiple commands are fully supported. + * Commands are written to a temporary bash script and executed. + * std_out, std_err can be null. Output will be written to terminal if null. + * */ + + string sh_file = save_bash_script_temp(script, null, true, supress_errors); + string sh_file_admin = ""; + + if (run_as_admin){ + + var script_admin = "#!/bin/bash\n"; + script_admin += "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY"; + script_admin += " '%s'".printf(escape_single_quote(sh_file)); + + sh_file_admin = GLib.Path.build_filename(file_parent(sh_file),"script-admin.sh"); + + save_bash_script_temp(script_admin, sh_file_admin, true, supress_errors); + } + + try { + string[] argv = new string[1]; + if (run_as_admin){ + argv[0] = sh_file_admin; + } + else{ + argv[0] = sh_file; + } + + string[] env = Environ.get(); + + int exit_code; + + if (print_to_terminal){ + + Process.spawn_sync ( + TEMP_DIR, //working dir + argv, //argv + env, //environment + SpawnFlags.SEARCH_PATH, + null, // child_setup + null, + null, + out exit_code + ); + } + else{ + + Process.spawn_sync ( + TEMP_DIR, //working dir + argv, //argv + env, //environment + SpawnFlags.SEARCH_PATH, + null, // child_setup + out std_out, + out std_err, + out exit_code + ); + } + + if (cleanup_tmp){ + file_delete(sh_file); + if (run_as_admin){ + file_delete(sh_file_admin); + } + } + + return exit_code; + } + catch (Error e){ + if (!supress_errors){ + log_error (e.message); + } + return -1; + } + } + + public int exec_script_async (string script){ + + /* Executes commands synchronously. + * Pipes and multiple commands are fully supported. + * Commands are written to a temporary bash script and executed. + * Return value indicates if script was started successfully. + * */ + + try { + + string scriptfile = save_bash_script_temp (script); + + string[] argv = new string[1]; + argv[0] = scriptfile; + + string[] env = Environ.get(); + + Pid child_pid; + Process.spawn_async_with_pipes( + TEMP_DIR, //working dir + argv, //argv + env, //environment + SpawnFlags.SEARCH_PATH, + null, + out child_pid); + + return 0; + } + catch (Error e){ + log_error (e.message); + return 1; + } + } + + public string? save_bash_script_temp (string commands, string? script_path = null, + bool force_locale = true, bool supress_errors = false){ + + string sh_path = script_path; + + /* Creates a temporary bash script with given commands + * Returns the script file path */ + + var script = new StringBuilder(); + script.append ("#!/bin/bash\n"); + script.append ("\n"); + if (force_locale){ + script.append ("LANG=C\n"); + } + script.append ("\n"); + script.append ("%s\n".printf(commands)); + script.append ("\n\nexitCode=$?\n"); + script.append ("echo ${exitCode} > ${exitCode}\n"); + script.append ("echo ${exitCode} > status\n"); + + if ((sh_path == null) || (sh_path.length == 0)){ + sh_path = get_temp_file_path() + ".sh"; + } + + try{ + //write script file + var file = File.new_for_path (sh_path); + if (file.query_exists ()) { + file.delete (); + } + var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); + var data_stream = new DataOutputStream (file_stream); + data_stream.put_string (script.str); + data_stream.close(); + + // set execute permission + chmod (sh_path, "u+x"); + + return sh_path; + } + catch (Error e) { + if (!supress_errors){ + log_error (e.message); + } + } + + return null; + } + + public string get_temp_file_path(){ + + /* Generates temporary file path */ + + return TEMP_DIR + "/" + timestamp_numeric() + (new Rand()).next_int().to_string(); + } + + public void exec_process_new_session(string command){ + exec_script_async("setsid %s &".printf(command)); + } + + // find process ------------------------------- + + // dep: which + public string get_cmd_path (string cmd_tool){ + + /* Returns the full path to a command */ + + try { + int exitCode; + string stdout, stderr; + Process.spawn_command_line_sync("which " + cmd_tool, out stdout, out stderr, out exitCode); + return stdout; + } + catch (Error e){ + log_error (e.message); + return ""; + } + } + + public bool cmd_exists(string cmd_tool){ + string path = get_cmd_path (cmd_tool); + if ((path == null) || (path.length == 0)){ + return false; + } + else{ + return true; + } + } + + // dep: pidof, TODO: Rewrite using /proc + public int get_pid_by_name (string name){ + + /* Get the process ID for a process with given name */ + + string std_out, std_err; + exec_sync("pidof \"%s\"".printf(name), out std_out, out std_err); + + if (std_out != null){ + string[] arr = std_out.split ("\n"); + if (arr.length > 0){ + return int.parse (arr[0]); + } + } + + return -1; + } + + public int get_pid_by_command(string cmdline){ + + /* Searches for process using the command line used to start the process. + * Returns the process id if found. + * */ + + try { + FileEnumerator enumerator; + FileInfo info; + File file = File.parse_name ("/proc"); + + enumerator = file.enumerate_children ("standard::name", 0); + while ((info = enumerator.next_file()) != null) { + try { + string io_stat_file_path = "/proc/%s/cmdline".printf(info.get_name()); + var io_stat_file = File.new_for_path(io_stat_file_path); + if (file.query_exists()){ + var dis = new DataInputStream (io_stat_file.read()); + + string line; + string text = ""; + size_t length; + while((line = dis.read_until ("\0", out length)) != null){ + text += " " + line; + } + + if ((text != null) && text.contains(cmdline)){ + return int.parse(info.get_name()); + } + } //stream closed + } + catch(Error e){ + // do not log + // some processes cannot be accessed by non-admin user + } + } + } + catch(Error e){ + log_error (e.message); + } + + return -1; + } + + public void get_proc_io_stats(int pid, out int64 read_bytes, out int64 write_bytes){ + + /* Returns the number of bytes read and written by a process to disk */ + + string io_stat_file_path = "/proc/%d/io".printf(pid); + var file = File.new_for_path(io_stat_file_path); + + read_bytes = 0; + write_bytes = 0; + + try { + if (file.query_exists()){ + var dis = new DataInputStream (file.read()); + string line; + while ((line = dis.read_line (null)) != null) { + if(line.has_prefix("rchar:")){ + read_bytes = int64.parse(line.replace("rchar:","").strip()); + } + else if(line.has_prefix("wchar:")){ + write_bytes = int64.parse(line.replace("wchar:","").strip()); + } + } + } //stream closed + } + catch(Error e){ + log_error (e.message); + } + } + + // dep: ps TODO: Rewrite using /proc + public bool process_is_running(long pid){ + + /* Checks if given process is running */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + try{ + cmd = "ps --pid %ld".printf(pid); + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); + } + catch (Error e) { + log_error (e.message); + return false; + } + + return (ret_val == 0); + } + + // dep: pgrep TODO: Rewrite using /proc + public bool process_is_running_by_name(string proc_name){ + + /* Checks if given process is running */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + try{ + cmd = "pgrep -f '%s'".printf(proc_name); + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); + } + catch (Error e) { + log_error (e.message); + return false; + } + + return (ret_val == 0); + } + + // dep: ps TODO: Rewrite using /proc + public int[] get_process_children (Pid parent_pid){ + + /* Returns the list of child processes spawned by given process */ + + string std_out, std_err; + exec_sync("ps --ppid %d".printf(parent_pid), out std_out, out std_err); + + int pid; + int[] procList = {}; + string[] arr; + + foreach (string line in std_out.split ("\n")){ + arr = line.strip().split (" "); + if (arr.length < 1) { continue; } + + pid = 0; + pid = int.parse (arr[0]); + + if (pid != 0){ + procList += pid; + } + } + return procList; + } + + // manage process --------------------------------- + + public void process_quit(Pid process_pid, bool killChildren = true){ + + /* Kills specified process and its children (optional). + * Sends signal SIGTERM to the process to allow it to quit gracefully. + * */ + + int[] child_pids = get_process_children (process_pid); + Posix.kill (process_pid, Posix.SIGTERM); + + if (killChildren){ + Pid childPid; + foreach (long pid in child_pids){ + childPid = (Pid) pid; + Posix.kill (childPid, Posix.SIGTERM); + } + } + } + + public void process_kill(Pid process_pid, bool killChildren = true){ + + /* Kills specified process and its children (optional). + * Sends signal SIGKILL to the process to kill it forcefully. + * It is recommended to use the function process_quit() instead. + * */ + + int[] child_pids = get_process_children (process_pid); + Posix.kill (process_pid, Posix.SIGKILL); + + if (killChildren){ + Pid childPid; + foreach (long pid in child_pids){ + childPid = (Pid) pid; + Posix.kill (childPid, Posix.SIGKILL); + } + } + } + + // dep: kill + public int process_pause (Pid procID){ + + /* Pause/Freeze a process */ + + return exec_sync ("kill -STOP %d".printf(procID), null, null); + } + + // dep: kill + public int process_resume (Pid procID){ + + /* Resume/Un-freeze a process*/ + + return exec_sync ("kill -CONT %d".printf(procID), null, null); + } + + // dep: ps TODO: Rewrite using /proc + public void process_quit_by_name(string cmd_name, string cmd_to_match, bool exact_match){ + + /* Kills a specific command */ + + string std_out, std_err; + exec_sync ("ps w -C '%s'".printf(cmd_name), out std_out, out std_err); + //use 'ps ew -C conky' for all users + + string pid = ""; + foreach(string line in std_out.split("\n")){ + if ((exact_match && line.has_suffix(" " + cmd_to_match)) + || (!exact_match && (line.index_of(cmd_to_match) != -1))){ + pid = line.strip().split(" ")[0]; + Posix.kill ((Pid) int.parse(pid), 15); + log_debug(_("Stopped") + ": [PID=" + pid + "] "); + } + } + } + + // process priority --------------------------------------- + + public void process_set_priority (Pid procID, int prio){ + + /* Set process priority */ + + if (Posix.getpriority (Posix.PRIO_PROCESS, procID) != prio) + Posix.setpriority (Posix.PRIO_PROCESS, procID, prio); + } + + public int process_get_priority (Pid procID){ + + /* Get process priority */ + + return Posix.getpriority (Posix.PRIO_PROCESS, procID); + } + + public void process_set_priority_normal (Pid procID){ + + /* Set normal priority for process */ + + process_set_priority (procID, 0); + } + + public void process_set_priority_low (Pid procID){ + + /* Set low priority for process */ + + process_set_priority (procID, 5); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.System.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.System.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TeeJee.System.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TeeJee.System.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,516 @@ + +/* + * TeeJee.System.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +namespace TeeJee.System{ + + using TeeJee.ProcessHelper; + using TeeJee.Logging; + using TeeJee.Misc; + using TeeJee.FileSystem; + + // user --------------------------------------------------- + + public bool user_is_admin (){ + + /* Check if current application is running with admin priviledges */ + + try{ + // create a process + string[] argv = { "sleep", "10" }; + Pid procId; + Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); + + // try changing the priority + Posix.setpriority (Posix.PRIO_PROCESS, procId, -5); + + // check if priority was changed successfully + if (Posix.getpriority (Posix.PRIO_PROCESS, procId) == -5) + return true; + else + return false; + } + catch (Error e) { + log_error (e.message); + return false; + } + } + + // dep: whoami + public string get_user_login(){ + /* + Returns Login ID of current user. + If running as 'sudo' it will return Login ID of the actual user. + */ + + string cmd = "echo ${SUDO_USER:-$(whoami)}"; + string std_out; + string std_err; + int ret_val; + ret_val = exec_script_sync(cmd, out std_out, out std_err); + + string user_name; + if ((std_out == null) || (std_out.length == 0)){ + user_name = "root"; + } + else{ + user_name = std_out.strip(); + } + + return user_name; + } + + // dep: id + public int get_user_id(string user_login){ + /* + Returns UID of specified user. + */ + + int uid = -1; + string cmd = "id %s -u".printf(user_login); + string std_out, std_err; + exec_sync(cmd, out std_out, out std_err); + if ((std_out != null) && (std_out.length > 0)){ + uid = int.parse(std_out); + } + + return uid; + } + + public string get_user_home(string custom_user_login = ""){ + string user_login = get_user_login(); + + if (custom_user_login.length > 0){ + user_login = custom_user_login; + } + + if (user_login == "root"){ + return "/root"; + } + else{ + return "/home/%s".printf(user_login); + } + } + + // application ----------------------------------------------- + + public string get_app_path(){ + + /* Get path of current process */ + + try{ + return GLib.FileUtils.read_link ("/proc/self/exe"); + } + catch (Error e){ + log_error (e.message); + return ""; + } + } + + public string get_app_dir(){ + + /* Get parent directory of current process */ + + try{ + return (File.new_for_path (GLib.FileUtils.read_link ("/proc/self/exe"))).get_parent ().get_path (); + } + catch (Error e){ + log_error (e.message); + return ""; + } + } + + // system ------------------------------------ + + // dep: cat TODO: rewrite + public double get_system_uptime_seconds(){ + + /* Returns the system up-time in seconds */ + + string cmd = ""; + string std_out; + string std_err; + int ret_val; + + try{ + cmd = "cat /proc/uptime"; + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); + string uptime = std_out.split(" ")[0]; + double secs = double.parse(uptime); + return secs; + } + catch(Error e){ + log_error (e.message); + return 0; + } + } + + public string get_desktop_name(){ + + /* Return the names of the current Desktop environment */ + + int pid = -1; + + pid = get_pid_by_name("cinnamon"); + if (pid > 0){ + return "Cinnamon"; + } + + pid = get_pid_by_name("xfdesktop"); + if (pid > 0){ + return "Xfce"; + } + + pid = get_pid_by_name("lxsession"); + if (pid > 0){ + return "LXDE"; + } + + pid = get_pid_by_name("gnome-shell"); + if (pid > 0){ + return "Gnome"; + } + + pid = get_pid_by_name("wingpanel"); + if (pid > 0){ + return "Elementary"; + } + + pid = get_pid_by_name("unity-panel-service"); + if (pid > 0){ + return "Unity"; + } + + pid = get_pid_by_name("plasma-desktop"); + if (pid > 0){ + return "KDE"; + } + + return "Unknown"; + } + + public Gee.ArrayList list_dir_names(string path){ + var list = new Gee.ArrayList(); + + try + { + File f_home = File.new_for_path (path); + FileEnumerator enumerator = f_home.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0); + FileInfo file; + while ((file = enumerator.next_file ()) != null) { + string name = file.get_name(); + //string item = path + "/" + name; + list.add(name); + } + } + catch (Error e) { + log_error (e.message); + } + + //sort the list + CompareDataFunc entry_compare = (a, b) => { + return strcmp(a,b); + }; + list.sort((owned) entry_compare); + + return list; + } + + public int get_display_width(){ + return Gdk.Screen.get_default().get_width(); + } + + public int get_display_height(){ + return Gdk.Screen.get_default().get_height(); + } + + // internet helpers ---------------------- + + public bool check_internet_connectivity(){ + bool connected = false; + connected = check_internet_connectivity_test1(); + + if (connected){ + return connected; + } + + if (!connected){ + connected = check_internet_connectivity_test2(); + } + + return connected; + } + + public bool check_internet_connectivity_test1(){ + int exit_code = -1; + string std_err; + string std_out; + + string cmd = "ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3`\n"; + cmd += "exit $?"; + exit_code = exec_script_sync(cmd, out std_out, out std_err, false); + + return (exit_code == 0); + } + + public bool check_internet_connectivity_test2(){ + int exit_code = -1; + string std_err; + string std_out; + + string cmd = "ping -q -w 1 -c 1 google.com\n"; + cmd += "exit $?"; + exit_code = exec_script_sync(cmd, out std_out, out std_err, false); + + return (exit_code == 0); + } + + public bool shutdown (){ + + /* Shutdown the system immediately */ + + try{ + string[] argv = { "shutdown", "-h", "now" }; + Pid procId; + Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); + return true; + } + catch (Error e) { + log_error (e.message); + return false; + } + } + + public bool command_exists(string command){ + string path = get_cmd_path(command); + return ((path != null) && (path.length > 0)); + } + + // open ----------------------------- + + public bool xdg_open (string file){ + string path = get_cmd_path ("xdg-open"); + if ((path != null)&&(path != "")){ + string cmd = "xdg-open '%s'".printf(escape_single_quote(file)); + int status = exec_script_async(cmd); + return (status == 0); + } + return false; + } + + public bool exo_open_folder (string dir_path, bool xdg_open_try_first = true){ + + /* Tries to open the given directory in a file manager */ + + /* + xdg-open is a desktop-independent tool for configuring the default applications of a user. + Inside a desktop environment (e.g. GNOME, KDE, Xfce), xdg-open simply passes the arguments + to that desktop environment's file-opener application (gvfs-open, kde-open, exo-open, respectively). + We will first try using xdg-open and then check for specific file managers if it fails. + */ + + string path; + int status; + + if (xdg_open_try_first){ + //try using xdg-open + path = get_cmd_path ("xdg-open"); + if ((path != null)&&(path != "")){ + string cmd = "xdg-open '%s'".printf(escape_single_quote(dir_path)); + status = exec_script_async (cmd); + return (status == 0); + } + } + + foreach(string app_name in + new string[]{ "nemo", "nautilus", "thunar", "pantheon-files", "marlin"}){ + + path = get_cmd_path (app_name); + if ((path != null)&&(path != "")){ + string cmd = "%s '%s'".printf(app_name, escape_single_quote(dir_path)); + status = exec_script_async (cmd); + return (status == 0); + } + } + + if (xdg_open_try_first == false){ + //try using xdg-open + path = get_cmd_path ("xdg-open"); + if ((path != null)&&(path != "")){ + string cmd = "xdg-open '%s'".printf(escape_single_quote(dir_path)); + status = exec_script_async (cmd); + return (status == 0); + } + } + + return false; + } + + public bool exo_open_textfile (string txt_file){ + + /* Tries to open the given text file in a text editor */ + + string path; + int status; + string cmd; + + path = get_cmd_path ("exo-open"); + if ((path != null)&&(path != "")){ + cmd = "exo-open '%s'".printf(escape_single_quote(txt_file)); + status = exec_script_async (cmd); + return (status == 0); + } + + path = get_cmd_path ("gedit"); + if ((path != null)&&(path != "")){ + cmd = "gedit --new-document '%s'".printf(escape_single_quote(txt_file)); + status = exec_script_async (cmd); + return (status == 0); + } + + return false; + } + + public bool exo_open_url (string url){ + + /* Tries to open the given text file in a text editor */ + + string path; + int status; + //string cmd; + + path = get_cmd_path ("exo-open"); + if ((path != null)&&(path != "")){ + status = exec_script_async ("exo-open \"" + url + "\""); + return (status == 0); + } + + path = get_cmd_path ("firefox"); + if ((path != null)&&(path != "")){ + status = exec_script_async ("firefox \"" + url + "\""); + return (status == 0); + } + + path = get_cmd_path ("chromium-browser"); + if ((path != null)&&(path != "")){ + status = exec_script_async ("chromium-browser \"" + url + "\""); + return (status == 0); + } + + return false; + } + + public bool using_efi_boot(){ + + /* Returns true if the system was booted in EFI mode + * and false for BIOS mode */ + + return dir_exists("/sys/firmware/efi"); + } + + public void open_terminal_window( + string terminal_emulator, + string working_dir, + string script_file_to_execute, + bool run_as_admin){ + + string cmd = ""; + if (run_as_admin){ + cmd += "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY "; + } + + string term = terminal_emulator; + if (!command_exists(term)){ + term = "gnome-terminal"; + if (!command_exists(term)){ + term = "xfce4-terminal"; + } + } + + cmd += term; + + switch (term){ + case "gnome-terminal": + case "xfce4-terminal": + if (working_dir.length > 0){ + cmd += " --working-directory='%s'".printf(escape_single_quote(working_dir)); + } + if (script_file_to_execute.length > 0){ + cmd += " -e '%s\n; echo Press ENTER to exit... ; read dummy;'".printf(escape_single_quote(script_file_to_execute)); + } + break; + } + + log_debug(cmd); + exec_script_async(cmd); + } + + // timers -------------------------------------------------- + + public GLib.Timer timer_start(){ + var timer = new GLib.Timer(); + timer.start(); + return timer; + } + + public ulong timer_elapsed(GLib.Timer timer, bool stop = true){ + ulong microseconds; + double seconds; + seconds = timer.elapsed (out microseconds); + if (stop){ + timer.stop(); + } + return (ulong)((seconds * 1000 ) + (microseconds / 1000)); + } + + public void sleep(int milliseconds){ + Thread.usleep ((ulong) milliseconds * 1000); + } + + public string timer_elapsed_string(GLib.Timer timer, bool stop = true){ + ulong microseconds; + double seconds; + seconds = timer.elapsed (out microseconds); + if (stop){ + timer.stop(); + } + return "%.0f ms".printf((seconds * 1000 ) + microseconds/1000); + } + + public void timer_elapsed_print(GLib.Timer timer, bool stop = true){ + ulong microseconds; + double seconds; + seconds = timer.elapsed (out microseconds); + if (stop){ + timer.stop(); + } + log_msg("%s %lu\n".printf(seconds.to_string(), microseconds)); + } + + + public void set_numeric_locale(string type){ + Intl.setlocale(GLib.LocaleCategory.NUMERIC, type); + Intl.setlocale(GLib.LocaleCategory.COLLATE, type); + Intl.setlocale(GLib.LocaleCategory.TIME, type); + } +} diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TimeoutCounter.vala ukuu-16.12~57~ubuntu16.10.1/src/Utility/TimeoutCounter.vala --- ukuu-16.11.1~47~ubuntu16.10.1/src/Utility/TimeoutCounter.vala 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/src/Utility/TimeoutCounter.vala 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,96 @@ + +/* + * TimeoutCounter.vala + * + * Copyright 2016 Tony George + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + + +using TeeJee.Logging; +using TeeJee.FileSystem; +using TeeJee.Misc; + +public class TimeoutCounter : GLib.Object { + + public bool active = false; + public string process_to_kill = ""; + public const int DEFAULT_SECONDS_TO_WAIT = 60; + public int seconds_to_wait = 60; + public bool exit_app = false; + + public void kill_process_on_timeout( + string process_to_kill, int seconds_to_wait = DEFAULT_SECONDS_TO_WAIT, bool exit_app = false){ + + this.process_to_kill = process_to_kill; + this.seconds_to_wait = seconds_to_wait; + this.exit_app = exit_app; + + try { + active = true; + Thread.create (start_counter_thread, true); + } + catch (Error e) { + log_error (e.message); + } + } + + public void exit_on_timeout(int seconds_to_wait = DEFAULT_SECONDS_TO_WAIT){ + this.process_to_kill = ""; + this.seconds_to_wait = seconds_to_wait; + this.exit_app = true; + + try { + active = true; + Thread.create (start_counter_thread, true); + } + catch (Error e) { + log_error (e.message); + } + } + + public void stop(){ + active = false; + } + + public void start_counter_thread(){ + int secs = 0; + + while (active && (secs < seconds_to_wait)){ + Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 1000); + secs += 1; + } + + if (active){ + active = false; + stdout.printf("\n"); + + if (process_to_kill.length > 0){ + Posix.system("killall " + process_to_kill); + log_debug("[timeout] Killed process" + ": %s".printf(process_to_kill)); + } + + if (exit_app){ + log_debug("[timeout] Exit application"); + exit(0); + } + } + } +} + diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/txt ukuu-16.12~57~ubuntu16.10.1/txt --- ukuu-16.11.1~47~ubuntu16.10.1/txt 1970-01-01 00:00:00.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/txt 2016-12-07 16:47:10.000000000 +0000 @@ -0,0 +1,12 @@ +cd src; make all +make[1]: Entering directory '/mnt/sdcard/Dropbox/projects/linux/ukuu/src' +#build binaries +#app-gtk +valac -X -D'GETTEXT_PACKAGE="ukuu"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/ukuu/libs -D VTE_291 --thread Common/*.vala Gtk/*.vala -o ukuu-gtk --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg json-glib-1.0 --pkg vte-2.91 +Compilation succeeded - 9 warning(s) +#app +valac -X -D'GETTEXT_PACKAGE="ukuu"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/ukuu/libs --thread Common/*.vala Console/*.vala Gtk/CustomMessageDialog.vala Gtk/UpdateNotificationWindow.vala Gtk/GtkHelper.vala -o ukuu --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg libsoup-2.4 --pkg json-glib-1.0 --pkg vte-2.91 +Compilation succeeded - 12 warning(s) +#update translation template +find . -iname "*.vala" | xargs xgettext --language=C --keyword=_ --copyright-holder='Tony George (teejeetech@gmail.com)' --package-name='ukuu' --package-version='2.2' --msgid-bugs-address='teejeetech@gmail.com' --escape --sort-output -o ../ukuu.pot +make[1]: Leaving directory '/mnt/sdcard/Dropbox/projects/linux/ukuu/src' diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/ukuu.geany ukuu-16.12~57~ubuntu16.10.1/ukuu.geany --- ukuu-16.11.1~47~ubuntu16.10.1/ukuu.geany 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/ukuu.geany 2016-12-07 16:47:10.000000000 +0000 @@ -17,29 +17,42 @@ long_line_column=80 [files] -current_page=3 -FILE_NAME_0=3141;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FMain.vala;0;4 -FILE_NAME_1=1201;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FConsole%2FAppConsole.vala;0;4 -FILE_NAME_2=8925;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FAboutWindow.vala;0;4 -FILE_NAME_3=1207;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FAppGtk.vala;0;4 -FILE_NAME_4=813;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FCustomMessageDialog.vala;0;4 -FILE_NAME_5=2700;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FDonationWindow.vala;0;4 -FILE_NAME_6=15377;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FMainWindow.vala;0;4 -FILE_NAME_7=2035;Make;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2Fmakefile;0;4 -FILE_NAME_8=2820;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FDownloadManager.vala;0;4 -FILE_NAME_9=7781;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FUtility.vala;0;4 -FILE_NAME_10=3766;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FPackage.vala;0;4 -FILE_NAME_11=25197;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FLinuxKernel.vala;0;4 -FILE_NAME_12=2437;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FTerminalWindow.vala;0;4 -FILE_NAME_13=1696;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FProgressWindow.vala;0;4 -FILE_NAME_14=5;Make;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fmakefile;0;4 -FILE_NAME_15=2038;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FSettingsDialog.vala;0;4 -FILE_NAME_16=1900;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FCronTab.vala;0;4 -FILE_NAME_17=4442;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FGtkHelper.vala;0;4 -FILE_NAME_18=71;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2Fukuu.desktop;0;4 -FILE_NAME_19=4634;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FUpdateNotificationWindow.vala;0;4 -FILE_NAME_20=822;None;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fdebian%2Fchangelog;0;4 -FILE_NAME_21=341;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fdebian%2Fcontrol;0;4 +current_page=0 +FILE_NAME_0=2068;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FMain.vala;0;4 +FILE_NAME_1=1472;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FConsole%2FAppConsole.vala;0;4 +FILE_NAME_2=3144;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FAppGtk.vala;0;4 +FILE_NAME_3=13011;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FMainWindow.vala;0;4 +FILE_NAME_4=1033;Make;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2Fmakefile;0;4 +FILE_NAME_5=5272;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FDownloadManager.vala;0;4 +FILE_NAME_6=49;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FPackage.vala;0;4 +FILE_NAME_7=14697;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FCommon%2FLinuxKernel.vala;0;4 +FILE_NAME_8=964;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FTerminalWindow.vala;0;4 +FILE_NAME_9=964;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FProgressWindow.vala;0;4 +FILE_NAME_10=5;Make;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fmakefile;0;4 +FILE_NAME_11=972;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FSettingsDialog.vala;0;4 +FILE_NAME_12=71;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2Fukuu.desktop;0;4 +FILE_NAME_13=974;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FGtk%2FUpdateNotificationWindow.vala;0;4 +FILE_NAME_14=822;None;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fdebian%2Fchangelog;0;4 +FILE_NAME_15=341;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fdebian%2Fcontrol;0;4 +FILE_NAME_16=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FAppLock.vala;0;4 +FILE_NAME_17=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FArchiveFile.vala;0;4 +FILE_NAME_18=5916;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FAsyncTask.vala;0;4 +FILE_NAME_19=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FBash.vala;0;4 +FILE_NAME_20=50;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FCronTab.vala;0;4 +FILE_NAME_21=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FDeleteFileTask.vala;0;4 +FILE_NAME_22=2450;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FDevice.vala;0;4 +FILE_NAME_23=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FFileItem.vala;0;4 +FILE_NAME_24=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FLinuxDistro.vala;0;4 +FILE_NAME_25=886;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FOSDNotify.vala;0;4 +FILE_NAME_26=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FProcStats.vala;0;4 +FILE_NAME_27=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FRsyncTask.vala;0;4 +FILE_NAME_28=16488;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.FileSystem.vala;0;4 +FILE_NAME_29=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.Json.vala;0;4 +FILE_NAME_30=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.Logging.vala;0;4 +FILE_NAME_31=3581;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.Misc.vala;0;4 +FILE_NAME_32=4830;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.Process.vala;0;4 +FILE_NAME_33=2710;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTeeJee.System.vala;0;4 +FILE_NAME_34=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Fukuu%2Fsrc%2FUtility%2FTimeoutCounter.vala;0;4 [VTE] last_dir=/home/teejee diff -Nru ukuu-16.11.1~47~ubuntu16.10.1/ukuu.pot ukuu-16.12~57~ubuntu16.10.1/ukuu.pot --- ukuu-16.11.1~47~ubuntu16.10.1/ukuu.pot 2016-11-27 05:46:27.000000000 +0000 +++ ukuu-16.12~57~ubuntu16.10.1/ukuu.pot 2016-12-07 16:47:10.000000000 +0000 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: ukuu 2.2\n" "Report-Msgid-Bugs-To: teejeetech@gmail.com\n" -"POT-Creation-Date: 2016-11-16 00:05+0530\n" +"POT-Creation-Date: 2016-12-07 22:02+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,78 +17,105 @@ "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: Gtk/MainWindow.vala:473 +#: Gtk/MainWindow.vala:472 msgid "About" msgstr "" -#: Console/AppConsole.vala:98 +#: Console/AppConsole.vala:99 msgid "Admin access is required for running this application." msgstr "" -#: Gtk/AboutWindow.vala:324 +#: Utility/AppLock.vala:50 +msgid "Another instance of this application is running" +msgstr "" + +#: Utility/Gtk/AboutWindow.vala:348 #, c-format msgid "Artists" msgstr "" -#: Gtk/AboutWindow.vala:316 +#: Utility/Gtk/AboutWindow.vala:324 #, c-format msgid "Authors" msgstr "" -#: Common/LinuxKernel.vala:1060 +#: Common/LinuxKernel.vala:1016 msgid "Available Kernels" msgstr "" -#: Gtk/AboutWindow.vala:285 +#: Utility/Gtk/AboutWindow.vala:295 msgid "Back" msgstr "" -#: Gtk/ProgressWindow.vala:139 Gtk/UpdateNotificationWindow.vala:177 -#: Gtk/TerminalWindow.vala:167 +#: Utility/GtkHelper.vala:122 Gtk/ProgressWindow.vala:138 +#: Gtk/UpdateNotificationWindow.vala:176 Gtk/TerminalWindow.vala:166 msgid "Cancel" msgstr "" -#: Gtk/MainWindow.vala:429 +#: Gtk/MainWindow.vala:428 msgid "Changes" msgstr "" -#: Gtk/SettingsDialog.vala:122 +#: Gtk/SettingsDialog.vala:121 msgid "Check every" msgstr "" -#: Console/AppConsole.vala:84 +#: Console/AppConsole.vala:85 msgid "Check for kernel updates" msgstr "" -#: Gtk/AboutWindow.vala:295 Gtk/TerminalWindow.vala:177 +#: Utility/Gtk/AboutWindow.vala:305 Gtk/TerminalWindow.vala:176 msgid "Close" msgstr "" -#: Common/Main.vala:105 +#: Common/Main.vala:104 msgid "Commands listed below are not available on this system" msgstr "" -#: Console/AppConsole.vala:200 Gtk/MainWindow.vala:97 +#: Utility/Gtk/AboutWindow.vala:332 +#, c-format +msgid "Contributions" +msgstr "" + +#: Utility/Device.vala:1101 +#, c-format +msgid "Could not find file" +msgstr "" + +#: Console/AppConsole.vala:201 Gtk/MainWindow.vala:96 msgid "Could not find requested version" msgstr "" -#: Gtk/AboutWindow.vala:272 Gtk/AboutWindow.vala:289 +#: Utility/Gtk/AboutWindow.vala:282 Utility/Gtk/AboutWindow.vala:299 msgid "Credits" msgstr "" -#: Common/CronTab.vala:65 +#: Utility/CronTab.vala:87 msgid "Cron job added" msgstr "" -#: Common/CronTab.vala:115 +#: Utility/CronTab.vala:168 msgid "Cron job removed" msgstr "" -#: Gtk/SettingsDialog.vala:155 +#: Gtk/SettingsDialog.vala:154 msgid "Day(s)" msgstr "" -#: Gtk/DonationWindow.vala:55 +#: Utility/Device.vala:1727 Utility/Device.vala:1737 +#, c-format +msgid "Device" +msgstr "" + +#: Utility/Device.vala:1183 +msgid "Device is unlocked" +msgstr "" + +#: Utility/Device.vala:1078 Utility/Device.vala:1140 +msgid "Device name is empty!" +msgstr "" + +#: Utility/Gtk/DonationWindow.vala:54 msgid "" "Did you find this software useful?\n" "\n" @@ -105,11 +132,11 @@ "(teejeetech@gmail.com)" msgstr "" -#: Common/Utility.vala:429 +#: Utility/TeeJee.FileSystem.vala:449 msgid "Dir not found" msgstr "" -#: Gtk/SettingsDialog.vala:162 +#: Gtk/SettingsDialog.vala:161 msgid "Display" msgstr "" @@ -117,106 +144,131 @@ msgid "Distribution" msgstr "" -#: Gtk/AboutWindow.vala:348 +#: Utility/Gtk/AboutWindow.vala:364 #, c-format msgid "Documenters" msgstr "" -#: Gtk/MainWindow.vala:461 Gtk/DonationWindow.vala:36 +#: Utility/Gtk/DonationWindow.vala:36 Gtk/MainWindow.vala:460 msgid "Donate" msgstr "" -#: Gtk/DonationWindow.vala:75 +#: Utility/Gtk/DonationWindow.vala:74 msgid "Donate with Google Wallet" msgstr "" -#: Gtk/DonationWindow.vala:68 +#: Utility/Gtk/DonationWindow.vala:67 msgid "Donate with PayPal" msgstr "" -#: Gtk/AboutWindow.vala:356 +#: Utility/Gtk/AboutWindow.vala:372 #, c-format msgid "Donations" msgstr "" -#: Console/AppConsole.vala:89 +#: Console/AppConsole.vala:90 msgid "Download packages for specified kernel" msgstr "" -#: Common/LinuxKernel.vala:1098 +#: Common/LinuxKernel.vala:1054 #, c-format msgid "Downloading" msgstr "" -#: Common/Utility.vala:100 +#: Utility/TeeJee.Logging.vala:89 msgid "E" msgstr "" -#: Common/LinuxKernel.vala:1122 +#: Common/LinuxKernel.vala:1080 #, c-format msgid "ERROR" msgstr "" -#: Gtk/GtkHelper.vala:18 +#: Utility/Device.vala:1247 +msgid "Encrypted Device" +msgstr "" + +#: Utility/Device.vala:1248 +#, c-format +msgid "Enter passphrase to unlock '%s'" +msgstr "" + +#: Utility/GtkHelper.vala:860 +msgid "Enter path or browse for directory" +msgstr "" + +#: Utility/GtkHelper.vala:18 msgid "Error" msgstr "" -#: Common/CronTab.vala:61 +#: Utility/CronTab.vala:83 msgid "Failed to add cron job" msgstr "" -#: Common/Utility.vala:257 +#: Utility/TeeJee.FileSystem.vala:191 msgid "Failed to copy file" msgstr "" -#: Common/Utility.vala:336 +#: Utility/TeeJee.FileSystem.vala:310 msgid "Failed to create dir" msgstr "" -#: Common/Utility.vala:196 +#: Utility/TeeJee.FileSystem.vala:100 msgid "Failed to delete file" msgstr "" -#: Common/Utility.vala:276 +#: Utility/CronTab.vala:208 +msgid "Failed to export crontab file" +msgstr "" + +#: Utility/Device.vala:541 +msgid "Failed to get partition list" +msgstr "" + +#: Utility/CronTab.vala:191 +msgid "Failed to install crontab file" +msgstr "" + +#: Utility/TeeJee.FileSystem.vala:210 msgid "Failed to move file" msgstr "" -#: Common/CronTab.vala:18 +#: Utility/CronTab.vala:31 msgid "Failed to read cron tab" msgstr "" -#: Common/Utility.vala:214 +#: Utility/TeeJee.FileSystem.vala:148 msgid "Failed to read file" msgstr "" -#: Common/CronTab.vala:111 +#: Utility/CronTab.vala:164 msgid "Failed to remove cron job" msgstr "" -#: Common/Utility.vala:241 -msgid "Failed to write file" +#: Utility/Device.vala:1174 Utility/Device.vala:1228 Utility/Device.vala:1253 +#: Utility/Device.vala:1274 Utility/Device.vala:1294 +msgid "Failed to unlock device" msgstr "" -#: Common/LinuxKernel.vala:955 -#, c-format -msgid "Fetching changelog for" +#: Utility/Device.vala:1528 +msgid "Failed to unmount" msgstr "" -#: Common/LinuxKernel.vala:913 -#, c-format -msgid "Fetching index for" +#: Utility/TeeJee.FileSystem.vala:175 +msgid "Failed to write file" msgstr "" -#: Common/LinuxKernel.vala:349 +#: Common/LinuxKernel.vala:376 msgid "Fetching index from kernel.ubuntu.com..." msgstr "" -#: Common/Utility.vala:575 Common/Utility.vala:624 +#: Utility/TeeJee.FileSystem.vala:602 Utility/TeeJee.FileSystem.vala:651 msgid "File is missing" msgstr "" -#: Common/DownloadManager.vala:347 Common/Utility.vala:271 -#: Common/Utility.vala:458 Common/LinuxKernel.vala:969 +#: Common/LinuxKernel.vala:924 Utility/RsyncTask.vala:226 +#: Utility/CronTab.vala:176 Utility/TeeJee.FileSystem.vala:205 +#: Utility/TeeJee.FileSystem.vala:478 msgid "File not found" msgstr "" @@ -225,243 +277,354 @@ msgid "File not found: %s" msgstr "" -#: Gtk/SettingsDialog.vala:181 +#: Utility/Device.vala:1745 +#, c-format +msgid "Filesystem" +msgstr "" + +#: Gtk/SettingsDialog.vala:180 msgid "Hide kernels older than 4.0" msgstr "" -#: Gtk/SettingsDialog.vala:170 +#: Gtk/SettingsDialog.vala:169 msgid "Hide unstable and RC releases" msgstr "" -#: Gtk/SettingsDialog.vala:153 +#: Gtk/SettingsDialog.vala:152 msgid "Hour(s)" msgstr "" -#: Gtk/UpdateNotificationWindow.vala:178 +#: Gtk/UpdateNotificationWindow.vala:177 msgid "Ignore this update" msgstr "" -#: Common/LinuxKernel.vala:250 +#: Common/LinuxKernel.vala:252 msgid "Index is fresh" msgstr "" -#: Common/LinuxKernel.vala:247 +#: Common/LinuxKernel.vala:249 msgid "Index is stale" msgstr "" -#: Gtk/MainWindow.vala:382 Gtk/UpdateNotificationWindow.vala:145 +#: Gtk/MainWindow.vala:381 Gtk/UpdateNotificationWindow.vala:144 msgid "Install" msgstr "" -#: Console/AppConsole.vala:87 +#: Console/AppConsole.vala:88 msgid "Install specified mainline kernel" msgstr "" -#: Gtk/UpdateNotificationWindow.vala:146 +#: Gtk/UpdateNotificationWindow.vala:145 msgid "Install this kernel" msgstr "" -#: Common/LinuxKernel.vala:1167 +#: Common/LinuxKernel.vala:1125 msgid "Installation completed with errors" msgstr "" -#: Common/LinuxKernel.vala:1164 +#: Common/LinuxKernel.vala:1122 msgid "Installation completed. A reboot is required to use the new kernel." msgstr "" -#: Common/LinuxKernel.vala:1077 Gtk/MainWindow.vala:229 +#: Common/LinuxKernel.vala:1033 Gtk/MainWindow.vala:228 msgid "Installed" msgstr "" -#: Console/AppConsole.vala:340 Gtk/MainWindow.vala:517 +#: Console/AppConsole.vala:341 Gtk/MainWindow.vala:516 msgid "Internet connection is not active" msgstr "" -#: Gtk/MainWindow.vala:141 +#: Gtk/MainWindow.vala:140 msgid "Kernel" msgstr "" -#: Gtk/MainWindow.vala:501 +#: Gtk/MainWindow.vala:500 msgid "Kernel upgrade utility for Ubuntu-based distributions" msgstr "" -#: Console/AppConsole.vala:86 +#: Utility/Device.vala:1746 +#, c-format +msgid "Label" +msgstr "" + +#: Console/AppConsole.vala:87 msgid "List all available mainline kernels" msgstr "" -#: Gtk/GtkHelper.vala:177 +#: Utility/GtkHelper.vala:262 msgid "Missing Icon" msgstr "" -#: Console/AppConsole.vala:334 +#: Utility/Device.vala:1729 +#, c-format +msgid "Model" +msgstr "" + +#: Utility/Device.vala:1378 +#, c-format +msgid "Mounted" +msgstr "" + +#: Console/AppConsole.vala:335 msgid "No updates found" msgstr "" -#: Gtk/SettingsDialog.vala:67 +#: Gtk/SettingsDialog.vala:66 msgid "Notification" msgstr "" -#: Gtk/SettingsDialog.vala:74 +#: Gtk/SettingsDialog.vala:73 msgid "Notify if a major release is available" msgstr "" -#: Gtk/SettingsDialog.vala:85 +#: Gtk/SettingsDialog.vala:84 msgid "Notify if a point release is available" msgstr "" -#: Console/AppConsole.vala:85 +#: Console/AppConsole.vala:86 msgid "Notify if kernel update is available" msgstr "" -#: Common/LinuxKernel.vala:1113 Gtk/DonationWindow.vala:96 +#: Common/LinuxKernel.vala:1071 Utility/Gtk/DonationWindow.vala:95 +#: Utility/GtkHelper.vala:121 #, c-format msgid "OK" msgstr "" -#: Gtk/UpdateNotificationWindow.vala:162 +#: Gtk/UpdateNotificationWindow.vala:161 msgid "Open" msgstr "" -#: Gtk/UpdateNotificationWindow.vala:163 +#: Gtk/UpdateNotificationWindow.vala:162 msgid "Open Ukuu" msgstr "" -#: Console/AppConsole.vala:82 Gtk/AppGtk.vala:179 +#: Console/AppConsole.vala:83 Gtk/AppGtk.vala:178 msgid "Options" msgstr "" -#: Common/Main.vala:106 +#: Utility/Device.vala:1741 +#, c-format +msgid "Parent Device" +msgstr "" + +#: Common/Main.vala:105 msgid "Please install required packages and try again" msgstr "" -#: Gtk/AppGtk.vala:181 +#: Gtk/AppGtk.vala:180 msgid "Print debug information" msgstr "" -#: Gtk/MainWindow.vala:521 +#: Gtk/MainWindow.vala:520 msgid "Refreshing..." msgstr "" -#: Gtk/MainWindow.vala:393 +#: Gtk/MainWindow.vala:392 msgid "Remove" msgstr "" -#: Console/AppConsole.vala:91 +#: Console/AppConsole.vala:92 msgid "Remove files from application cache" msgstr "" -#: Console/AppConsole.vala:88 +#: Console/AppConsole.vala:89 msgid "Remove specified mainline kernel" msgstr "" -#: Gtk/AppGtk.vala:105 +#: Utility/Device.vala:1731 +#, c-format +msgid "Revision" +msgstr "" + +#: Gtk/AppGtk.vala:104 msgid "Root Access Required" msgstr "" -#: Gtk/AppGtk.vala:103 +#: Gtk/AppGtk.vala:102 msgid "Root access is required for running this application." msgstr "" -#: Console/AppConsole.vala:204 +#: Console/AppConsole.vala:205 msgid "Run 'ukuu --list' and use the version string listed in first column" msgstr "" -#: Console/AppConsole.vala:99 Gtk/AppGtk.vala:104 +#: Console/AppConsole.vala:100 Gtk/AppGtk.vala:103 msgid "Run the application as root or using gksu/sudo." msgstr "" -#: Common/LinuxKernel.vala:1077 Gtk/MainWindow.vala:229 +#: Common/LinuxKernel.vala:1033 Gtk/MainWindow.vala:228 msgid "Running" msgstr "" -#: Gtk/DonationWindow.vala:82 +#: Utility/GtkHelper.vala:870 +msgid "Select Path" +msgstr "" + +#: Utility/Gtk/DonationWindow.vala:81 msgid "Send Email" msgstr "" -#: Gtk/SettingsDialog.vala:57 Gtk/MainWindow.vala:440 +#: Utility/Device.vala:1730 +#, c-format +msgid "Serial" +msgstr "" + +#: Gtk/SettingsDialog.vala:56 Gtk/MainWindow.vala:439 msgid "Settings" msgstr "" -#: Gtk/AppGtk.vala:182 +#: Gtk/AppGtk.vala:181 msgid "Show all options" msgstr "" -#: Gtk/SettingsDialog.vala:96 +#: Gtk/SettingsDialog.vala:95 msgid "Show notification bubble on desktop" msgstr "" -#: Gtk/SettingsDialog.vala:107 +#: Gtk/SettingsDialog.vala:106 msgid "Show notification dialog" msgstr "" -#: Gtk/MainWindow.vala:217 +#: Utility/Device.vala:1733 Utility/Device.vala:1748 +#, c-format +msgid "Size" +msgstr "" + +#: Gtk/MainWindow.vala:216 msgid "Status" msgstr "" -#: Common/Utility.vala:1233 +#: Utility/TeeJee.Process.vala:511 msgid "Stopped" msgstr "" -#: Console/AppConsole.vala:80 Gtk/AppGtk.vala:177 +#: Console/AppConsole.vala:81 Gtk/AppGtk.vala:176 msgid "Syntax" msgstr "" +#: Utility/Device.vala:1754 +#, c-format +msgid "System" +msgstr "" + #: Common/LinuxKernel.vala:101 msgid "System architecture" msgstr "" -#: Gtk/AboutWindow.vala:340 +#: Utility/Gtk/AboutWindow.vala:340 #, c-format -msgid "Third Party Tools & Software" +msgid "Third Party Tools" +msgstr "" + +#: Utility/Device.vala:1173 +msgid "This device is not encrypted" msgstr "" -#: Common/LinuxKernel.vala:1136 Gtk/MainWindow.vala:631 +#: Common/LinuxKernel.vala:1094 Gtk/MainWindow.vala:630 msgid "This kernel is already installed." msgstr "" -#: Common/LinuxKernel.vala:1181 +#: Common/LinuxKernel.vala:1139 msgid "" "This kernel is currently running and cannot be removed.\n" " Install another kernel before removing this one." msgstr "" -#: Gtk/AboutWindow.vala:332 +#: Utility/Gtk/AboutWindow.vala:356 #, c-format msgid "Translators" msgstr "" -#: Common/LinuxKernel.vala:1221 +#: Utility/Device.vala:1744 +#, c-format +msgid "Type" +msgstr "" + +#: Utility/Device.vala:1743 +#, c-format +msgid "UUID" +msgstr "" + +#: Common/LinuxKernel.vala:1179 msgid "Un-install completed" msgstr "" -#: Common/LinuxKernel.vala:1224 +#: Common/LinuxKernel.vala:1182 msgid "Un-install completed with errors" msgstr "" -#: Console/AppConsole.vala:239 Gtk/AppGtk.vala:165 +#: Console/AppConsole.vala:240 Gtk/AppGtk.vala:164 msgid "Unknown option" msgstr "" -#: Console/AppConsole.vala:90 +#: Utility/Device.vala:1184 Utility/Device.vala:1300 +#, c-format +msgid "Unlocked device is mapped to '%s'" +msgstr "" + +#: Utility/Device.vala:1299 +msgid "Unlocked successfully" +msgstr "" + +#: Utility/Device.vala:1517 +msgid "Unmounting from" +msgstr "" + +#: Console/AppConsole.vala:91 msgid "Use specified user's cache directory" msgstr "" -#: Console/AppConsole.vala:140 Gtk/AppGtk.vala:113 Gtk/AppGtk.vala:131 +#: Utility/Device.vala:1751 +#, c-format +msgid "Used" +msgstr "" + +#: Utility/Device.vala:1254 +msgid "User cancelled the password prompt" +msgstr "" + +#: Console/AppConsole.vala:141 Gtk/AppGtk.vala:112 msgid "Using cache directory" msgstr "" -#: Gtk/MainWindow.vala:190 +#: Utility/Device.vala:1728 +#, c-format +msgid "Vendor" +msgstr "" + +#: Gtk/MainWindow.vala:189 msgid "Version" msgstr "" -#: Gtk/DonationWindow.vala:89 +#: Utility/Gtk/DonationWindow.vala:88 msgid "Visit Website" msgstr "" -#: Common/Utility.vala:100 +#: Utility/TeeJee.Logging.vala:89 msgid "W" msgstr "" -#: Gtk/SettingsDialog.vala:157 +#: Gtk/SettingsDialog.vala:156 msgid "Week(s)" msgstr "" + +#: Utility/Device.vala:1227 Utility/Device.vala:1273 +msgid "Wrong password" +msgstr "" + +#: Utility/AppLock.vala:55 +msgid "[Warning] Deleted invalid lock" +msgstr "" + +#: Utility/CronTab.vala:212 +msgid "crontab file exported" +msgstr "" + +#: Utility/CronTab.vala:195 +msgid "crontab file installed" +msgstr "" + +#: Utility/Device.vala:1378 +msgid "device" +msgstr ""