4
* Copyright 2012 Tony George <teejeetech@gmail.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27
using TeeJee.FileSystem;
29
using TeeJee.ProcessManagement;
30
using TeeJee.GtkHelper;
31
using TeeJee.Multimedia;
36
extern void exit(int exit_code);
39
namespace TeeJee.Logging{
41
/* Functions for logging messages to console and log files */
45
public DataOutputStream dos_log;
46
public string err_log;
47
public bool LOG_ENABLE = true;
48
public bool LOG_TIMESTAMP = true;
49
public bool LOG_COLORS = true;
50
public bool LOG_DEBUG = false;
51
public bool LOG_COMMANDS = false;
53
public void log_msg (string message, bool highlight = false){
55
if (!LOG_ENABLE) { return; }
59
if (highlight && LOG_COLORS){
60
msg += "\033[1;38;5;34m";
64
msg += "[" + timestamp() + "] ";
69
if (highlight && LOG_COLORS){
80
dos_log.put_string ("[%s] %s\n".printf(timestamp(), message));
84
stdout.printf (e.message);
88
public void log_error (string message, bool highlight = false, bool is_warning = false){
89
if (!LOG_ENABLE) { return; }
93
if (highlight && LOG_COLORS){
94
msg += "\033[1;38;5;160m";
98
msg += "[" + timestamp() + "] ";
101
string prefix = (is_warning) ? _("W") : _("E");
103
msg += prefix + ": " + message;
105
if (highlight && LOG_COLORS){
115
string str = "[%s] %s: %s\n".printf(timestamp(), prefix, message);
117
if (dos_log != null){
118
dos_log.put_string (str);
121
if (err_log != null){
122
err_log += "%s\n".printf(message);
126
stdout.printf (e.message);
130
public void log_debug (string message){
131
if (!LOG_ENABLE) { return; }
138
if (dos_log != null){
139
dos_log.put_string ("[%s] %s\n".printf(timestamp(), message));
143
stdout.printf (e.message);
147
public void log_draw_line(){
148
log_msg(string.nfill(70,'='));
151
public void show_err_log(Gtk.Window parent, bool disable_log = true){
152
if ((err_log != null) && (err_log.length > 0)){
153
gtk_messagebox(_("Error"), err_log, parent, true);
161
public void clear_err_log(){
165
public void disable_err_log(){
170
namespace TeeJee.FileSystem{
172
/* Convenience functions for handling files and directories */
174
using TeeJee.Logging;
175
using TeeJee.FileSystem;
176
using TeeJee.ProcessManagement;
179
// path helpers ----------------------------
181
public string file_parent(string file_path){
182
return File.new_for_path(file_path).get_parent().get_path();
185
public string file_basename(string file_path){
186
return File.new_for_path(file_path).get_basename();
189
public string path_combine(string path1, string path2){
190
return GLib.Path.build_path("/", path1, path2);
193
// file helpers -----------------------------
195
public bool file_or_dir_exists(string item_path){
197
/* check if item exists on disk*/
199
var item = File.parse_name(item_path);
200
return item.query_exists();
203
public bool file_exists (string file_path){
204
/* Check if file exists */
205
return ( FileUtils.test(file_path, GLib.FileTest.EXISTS) && FileUtils.test(file_path, GLib.FileTest.IS_REGULAR));
208
public bool file_delete(string file_path){
210
/* Check and delete file */
213
var file = File.new_for_path (file_path);
214
if (file.query_exists ()) {
219
log_error (e.message);
220
log_error(_("Failed to delete file") + ": %s".printf(file_path));
225
public string? file_read (string file_path){
227
/* Reads text from file */
233
GLib.FileUtils.get_contents (file_path, out txt, out size);
237
log_error (e.message);
238
log_error(_("Failed to read file") + ": %s".printf(file_path));
244
public bool file_write (string file_path, string contents){
246
/* Write text to file */
250
dir_create(file_parent(file_path));
252
var file = File.new_for_path (file_path);
253
if (file.query_exists ()) {
257
var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION);
258
var data_stream = new DataOutputStream (file_stream);
259
data_stream.put_string (contents);
264
log_error (e.message);
265
log_error(_("Failed to write file") + ": %s".printf(file_path));
270
public bool file_copy (string src_file, string dest_file){
272
var file_src = File.new_for_path (src_file);
273
if (file_src.query_exists()) {
274
var file_dest = File.new_for_path (dest_file);
275
file_src.copy(file_dest,FileCopyFlags.OVERWRITE,null,null);
280
log_error (e.message);
281
log_error(_("Failed to copy file") + ": '%s', '%s'".printf(src_file, dest_file));
287
public void file_move (string src_file, string dest_file){
289
var file_src = File.new_for_path (src_file);
290
if (file_src.query_exists()) {
291
var file_dest = File.new_for_path (dest_file);
292
file_src.move(file_dest,FileCopyFlags.OVERWRITE,null,null);
295
log_error (_("File not found") + ": %s".printf(src_file));
296
log_error("file_move()");
300
log_error (e.message);
301
log_error(_("Failed to move file") + ": '%s', '%s'".printf(src_file, dest_file));
305
public DateTime file_modified_date(string file_path){
308
File file = File.parse_name (file_path);
309
if (file.query_exists()) {
310
info = file.query_info("%s".printf(FileAttribute.TIME_MODIFIED), 0);
311
return (new DateTime.from_timeval_utc(info.get_modification_time())).to_local();
315
log_error (e.message);
318
return (new DateTime.from_unix_utc(0)); //1970
321
// directory helpers ----------------------
323
public int64 file_get_size(string file_path){
325
File file = File.parse_name (file_path);
326
if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){
327
if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR)
328
&& !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){
329
return file.query_info("standard::size",0).get_size();
334
log_error (e.message);
340
// dep: find wc TODO: rewrite
341
public long dir_count(string path){
343
/* Return total count of files and directories */
350
cmd = "find '%s' | wc -l".printf(escape_single_quote(path));
351
ret_val = exec_script_sync(cmd, out std_out, out std_err);
352
return long.parse(std_out);
355
public bool dir_exists (string dir_path){
356
/* Check if directory exists */
357
return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR));
360
public bool dir_create (string dir_path){
362
/* Creates a directory along with parents */
365
var dir = File.parse_name (dir_path);
366
if (dir.query_exists () == false) {
367
dir.make_directory_with_parents (null);
372
log_error (e.message);
373
log_error(_("Failed to create dir") + ": %s".printf(dir_path));
378
public bool dir_tar (string src_dir, string tar_file, bool recursion){
379
if (dir_exists(src_dir)) {
381
if (file_exists(tar_file)){
382
file_delete(tar_file);
385
var src_parent = file_parent(src_dir);
386
var src_name = file_basename(src_dir);
388
string cmd = "tar cvf '%s' --overwrite --%srecursion -C '%s' '%s'\n".printf(tar_file, (recursion ? "" : "no-"), src_parent, src_name);
392
string stdout, stderr;
393
int status = exec_script_sync(cmd, out stdout, out stderr);
402
log_error(_("Dir not found") + ": %s".printf(src_dir));
408
public bool dir_untar (string tar_file, string dst_dir){
409
if (file_exists(tar_file)) {
411
if (!dir_exists(dst_dir)){
415
string cmd = "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf(tar_file, dst_dir);
419
string stdout, stderr;
420
int status = exec_script_sync(cmd, out stdout, out stderr);
429
log_error(_("File not found") + ": %s".printf(tar_file));
435
// archiving and encryption ----------------
437
public bool file_tar_encrypt (string src_file, string dst_file, string password){
438
if (file_exists(src_file)) {
439
if (file_exists(dst_file)){
440
file_delete(dst_file);
443
var src_dir = file_parent(src_file);
444
var src_name = file_basename(src_file);
446
var dst_dir = file_parent(dst_file);
447
var dst_name = file_basename(dst_file);
448
var tar_name = dst_name[0 : dst_name.index_of(".gpg")];
449
var tar_file = "%s/%s".printf(dst_dir, tar_name);
451
string cmd = "tar cvf '%s' --overwrite -C '%s' '%s'\n".printf(tar_file, src_dir, src_name);
452
cmd += "gpg --passphrase '%s' -o '%s' --symmetric '%s'\n".printf(password, dst_file, tar_file);
453
cmd += "rm -f '%s'\n".printf(tar_file);
457
string stdout, stderr;
458
int status = exec_script_sync(cmd, out stdout, out stderr);
470
public string file_decrypt_untar_read (string src_file, string password){
472
if (file_exists(src_file)) {
474
//var src_name = file_basename(src_file);
475
//var tar_name = src_name[0 : src_name.index_of(".gpg")];
476
//var tar_file = "%s/%s".printf(TEMP_DIR, tar_name);
477
//var temp_file = "%s/%s".printf(TEMP_DIR, random_string());
480
cmd += "gpg --quiet --no-verbose --passphrase '%s' -o- --decrypt '%s'".printf(password, src_file);
481
cmd += " | tar xf - --to-stdout 2>/dev/null\n";
486
string std_out, std_err;
487
int status = exec_script_sync(cmd, out std_out, out std_err);
497
log_error(_("File is missing") + ": %s".printf(src_file));
503
public bool decrypt_and_untar (string src_file, string dst_file, string password){
504
if (file_exists(src_file)) {
505
if (file_exists(dst_file)){
506
file_delete(dst_file);
509
var src_dir = file_parent(src_file);
510
var src_name = file_basename(src_file);
511
var tar_name = src_name[0 : src_name.index_of(".gpg")];
512
var tar_file = "%s/%s".printf(src_dir, tar_name);
515
cmd += "rm -f '%s'\n".printf(tar_file); // gpg cannot overwrite - remove tar file if it exists
516
cmd += "gpg --passphrase '%s' -o '%s' --decrypt '%s'\n".printf(password, tar_file, src_file);
517
cmd += "status=$?; if [ $status -ne 0 ]; then exit $status; fi\n";
518
cmd += "tar xvf '%s' --overwrite --same-permissions -C '%s'\n".printf(tar_file, file_parent(dst_file));
519
cmd += "rm -f '%s'\n".printf(tar_file);
523
string stdout, stderr;
524
int status = exec_script_sync(cmd, out stdout, out stderr);
534
log_error(_("File is missing") + ": %s".printf(src_file));
540
// misc --------------------
542
public long get_file_count(string path){
544
/* Return total count of files and directories */
551
cmd = "find \"%s\" | wc -l".printf(path);
552
ret_val = exec_script_sync(cmd, out std_out, out std_err);
553
return long.parse(std_out);
556
public long get_file_size(string path){
558
/* Returns size of files and directories in KB*/
563
cmd = "du -s \"%s\"".printf(path);
564
output = execute_command_sync_get_output(cmd);
565
return long.parse(output.split("\t")[0]);
568
public int64 get_file_size_bytes(string file_path){
570
File file = File.parse_name (file_path);
571
if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){
572
if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR)
573
&& !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){
574
return file.query_info("standard::size",0).get_size();
579
log_error (e.message);
585
public uint64 dir_size(string path){
586
/* Returns size of directories */
591
cmd = "du -s \"%s\"".printf(path);
592
output = execute_command_sync_get_output(cmd);
593
return uint64.parse(output.split("\t")[0].strip()) * 1024;
596
public string get_file_size_formatted2(string path){
598
/* Returns size of files and directories in KB*/
603
cmd = "du -s -h \"%s\"".printf(path);
604
output = execute_command_sync_get_output(cmd);
605
return output.split("\t")[0].strip();
608
public string format_file_size (uint64 size, bool binary_units = false){
609
int64 KB = binary_units ? 1024 : 1000;
610
int64 MB = binary_units ? 1024 * KB : 1000 * KB;
611
int64 GB = binary_units ? 1024 * MB : 1000 * MB;
614
return "%'0.1f %sB".printf(size/(1.0*GB), (binary_units)?"Gi":"G");
617
return "%'0.1f %sB".printf(size/(1.0*MB), (binary_units)?"Mi":"M");
620
return "%'0.0f %sB".printf(size/(1.0*KB), (binary_units)?"Ki":"K");
623
return "%'0lld B".printf(size);
627
public int chmod (string file, string permission){
629
/* Change file permissions */
631
return exec_sync ("chmod " + permission + " \"%s\"".printf(file));
634
public string resolve_relative_path (string filePath){
636
/* Resolve the full path of given file using 'realpath' command */
638
string filePath2 = filePath;
639
if (filePath2.has_prefix ("~")){
640
filePath2 = Environment.get_home_dir () + "/" + filePath2[2:filePath2.length];
645
Process.spawn_command_line_sync("realpath \"%s\"".printf(filePath2), out output);
646
output = output.strip ();
647
if (FileUtils.test(output, GLib.FileTest.EXISTS)){
652
log_error (e.message);
658
public int rsync (string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){
660
/* Sync files with rsync */
662
string cmd = "rsync --recursive --perms --chmod=a=rwx";
663
cmd += updateExisting ? "" : " --ignore-existing";
664
cmd += deleteExtra ? " --delete" : "";
665
cmd += " \"%s\"".printf(sourceDirectory + "//");
666
cmd += " \"%s\"".printf(destDirectory);
667
return exec_sync (cmd);
670
public string escape_single_quote(string file_path){
671
return file_path.replace("'","'\\''");
675
namespace TeeJee.JSON{
677
using TeeJee.Logging;
679
/* Convenience functions for reading and writing JSON files */
681
public string json_get_string(Json.Object jobj, string member, string def_value){
682
if (jobj.has_member(member)){
683
return jobj.get_string_member(member);
686
log_error ("Member not found in JSON object: " + member, false, true);
691
public bool json_get_bool(Json.Object jobj, string member, bool def_value){
692
if (jobj.has_member(member)){
693
return bool.parse(jobj.get_string_member(member));
696
log_error ("Member not found in JSON object: " + member, false, true);
701
public int json_get_int(Json.Object jobj, string member, int def_value){
702
if (jobj.has_member(member)){
703
return int.parse(jobj.get_string_member(member));
706
log_error ("Member not found in JSON object: " + member, false, true);
713
namespace TeeJee.ProcessManagement{
714
using TeeJee.Logging;
715
using TeeJee.FileSystem;
718
public string TEMP_DIR;
720
/* Convenience functions for executing commands and managing processes */
722
public static void init_tmp(){
723
string std_out, std_err;
725
TEMP_DIR = Environment.get_tmp_dir() + "/" + AppShortName + "/" + random_string();
726
dir_create(TEMP_DIR);
728
exec_script_sync("echo 'ok'",out std_out,out std_err, true);
729
if ((std_out == null)||(std_out.strip() != "ok")){
730
TEMP_DIR = Environment.get_home_dir() + "/.temp/" + AppShortName + "/" + random_string();
731
exec_sync("rm -rf '%s'".printf(TEMP_DIR));
732
dir_create(TEMP_DIR);
735
//log_debug("TEMP_DIR=" + TEMP_DIR);
738
public int exec_sync (string cmd, out string? std_out = null, out string? std_err = null){
740
/* Executes single command synchronously.
741
* Pipes and multiple commands are not supported.
742
* std_out, std_err can be null. Output will be written to terminal if null. */
746
Process.spawn_command_line_sync(cmd, out std_out, out std_err, out status);
750
log_error (e.message);
755
public int exec_script_sync (string script, out string? std_out = null, out string? std_err = null, bool supress_errors = false){
757
/* Executes commands synchronously.
758
* Pipes and multiple commands are fully supported.
759
* Commands are written to a temporary bash script and executed.
760
* std_out, std_err can be null. Output will be written to terminal if null.
763
string path = save_bash_script_temp(script, supress_errors);
767
string[] argv = new string[1];
770
string[] env = Environ.get();
775
TEMP_DIR, //working dir
778
SpawnFlags.SEARCH_PATH,
788
if (!supress_errors){
789
log_error (e.message);
795
public int exec_script_async (string script){
797
/* Executes commands synchronously.
798
* Pipes and multiple commands are fully supported.
799
* Commands are written to a temporary bash script and executed.
800
* Return value indicates if script was started successfully.
805
string scriptfile = save_bash_script_temp (script);
807
string[] argv = new string[1];
808
argv[0] = scriptfile;
810
string[] env = Environ.get();
813
Process.spawn_async_with_pipes(
814
TEMP_DIR, //working dir
817
SpawnFlags.SEARCH_PATH,
824
log_error (e.message);
830
//TODO: Deprecated, Remove this
831
public string execute_command_sync_get_output (string cmd){
833
/* Executes single command synchronously and returns std_out
834
* Pipes and multiple commands are not supported */
839
Process.spawn_command_line_sync(cmd, out std_out, null, out exitCode);
843
log_error (e.message);
848
//TODO: Deprecated, Remove this
849
public bool execute_command_script_async (string cmd){
851
/* Creates a temporary bash script with given commands and executes it asynchronously
852
* Return value indicates if script was started successfully */
856
string scriptfile = save_bash_script_temp (cmd);
858
string[] argv = new string[1];
859
argv[0] = scriptfile;
861
string[] env = Environ.get();
864
Process.spawn_async_with_pipes(
865
TEMP_DIR, //working dir
868
SpawnFlags.SEARCH_PATH,
875
log_error (e.message);
880
public string? save_bash_script_temp (string commands, bool force_locale = true, bool supress_errors = false){
882
/* Creates a temporary bash script with given commands
883
* Returns the script file path */
885
var script = new StringBuilder();
886
script.append ("#!/bin/bash\n");
887
script.append ("\n");
889
script.append ("LANG=C\n");
891
script.append ("\n");
892
script.append ("%s\n".printf(commands));
893
script.append ("\n\nexitCode=$?\n");
894
script.append ("echo ${exitCode} > ${exitCode}\n");
895
script.append ("echo ${exitCode} > status\n");
897
string script_path = get_temp_file_path() + ".sh";
901
var file = File.new_for_path (script_path);
902
if (file.query_exists ()) { file.delete (); }
903
var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION);
904
var data_stream = new DataOutputStream (file_stream);
905
data_stream.put_string (script.str);
908
// set execute permission
909
chmod (script_path, "u+x");
914
if (!supress_errors){
915
log_error (e.message);
922
public string get_temp_file_path(){
924
/* Generates temporary file path */
926
return TEMP_DIR + "/" + timestamp2() + (new Rand()).next_int().to_string();
929
public string get_cmd_path (string cmd){
931
/* Returns the full path to a command */
935
string stdout, stderr;
936
Process.spawn_command_line_sync("which " + cmd, out stdout, out stderr, out exitCode);
940
log_error (e.message);
945
public int get_pid_by_name (string name){
947
/* Get the process ID for a process with given name */
951
Process.spawn_command_line_sync("pidof \"%s\"".printf(name), out output);
953
string[] arr = output.split ("\n");
955
return int.parse (arr[0]);
960
log_error (e.message);
966
public int get_pid_by_command(string cmdline){
968
FileEnumerator enumerator;
970
File file = File.parse_name ("/proc");
972
enumerator = file.enumerate_children ("standard::name", 0);
973
while ((info = enumerator.next_file()) != null) {
975
string io_stat_file_path = "/proc/%s/cmdline".printf(info.get_name());
976
var io_stat_file = File.new_for_path(io_stat_file_path);
977
if (file.query_exists()){
978
var dis = new DataInputStream (io_stat_file.read());
983
while((line = dis.read_until ("\0", out length)) != null){
987
if ((text != null) && text.contains(cmdline)){
988
return int.parse(info.get_name());
993
//log_error (e.message);
998
log_error (e.message);
1004
public void get_proc_io_stats(int pid, out int64 read_bytes, out int64 write_bytes){
1005
string io_stat_file_path = "/proc/%d/io".printf(pid);
1006
var file = File.new_for_path(io_stat_file_path);
1012
if (file.query_exists()){
1013
var dis = new DataInputStream (file.read());
1015
while ((line = dis.read_line (null)) != null) {
1016
if(line.has_prefix("rchar:")){
1017
read_bytes = int64.parse(line.replace("rchar:","").strip());
1019
else if(line.has_prefix("wchar:")){
1020
write_bytes = int64.parse(line.replace("wchar:","").strip());
1026
log_error (e.message);
1030
public bool process_is_running(long pid){
1032
/* Checks if given process is running */
1040
cmd = "ps --pid %ld".printf(pid);
1041
Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val);
1044
log_error (e.message);
1048
return (ret_val == 0);
1051
public int[] get_process_children (Pid parentPid){
1053
/* Returns the list of child processes spawned by given process */
1058
Process.spawn_command_line_sync("ps --ppid %d".printf(parentPid), out output);
1061
log_error (e.message);
1065
int[] procList = {};
1068
foreach (string line in output.split ("\n")){
1069
arr = line.strip().split (" ");
1070
if (arr.length < 1) { continue; }
1073
pid = int.parse (arr[0]);
1082
public void process_quit(Pid process_pid, bool killChildren = true){
1084
/* Kills specified process and its children (optional) */
1086
int[] child_pids = get_process_children (process_pid);
1087
Posix.kill (process_pid, Posix.SIGTERM);
1091
foreach (long pid in child_pids){
1092
childPid = (Pid) pid;
1093
Posix.kill (childPid, Posix.SIGTERM);
1098
public void process_kill(Pid process_pid, bool killChildren = true){
1100
/* Kills specified process and its children (optional) */
1102
int[] child_pids = get_process_children (process_pid);
1103
Posix.kill (process_pid, Posix.SIGKILL);
1107
foreach (long pid in child_pids){
1108
childPid = (Pid) pid;
1109
Posix.kill (childPid, Posix.SIGKILL);
1114
public int process_pause (Pid procID){
1116
/* Pause/Freeze a process */
1118
return exec_sync ("kill -STOP %d".printf(procID));
1121
public int process_resume (Pid procID){
1123
/* Resume/Un-freeze a process*/
1125
return exec_sync ("kill -CONT %d".printf(procID));
1128
public void command_kill(string cmd_name, string cmd_to_match, bool exact_match){
1130
/* Kills a specific command */
1132
string txt = execute_command_sync_get_output ("ps w -C '%s'".printf(cmd_name));
1133
//use 'ps ew -C conky' for all users
1136
foreach(string line in txt.split("\n")){
1137
if ((exact_match && line.has_suffix(" " + cmd_to_match))
1138
|| (!exact_match && (line.index_of(cmd_to_match) != -1))){
1139
pid = line.strip().split(" ")[0];
1140
Posix.kill ((Pid) int.parse(pid), 15);
1141
log_debug(_("Stopped") + ": [PID=" + pid + "] ");
1146
public bool process_is_running_by_name(string proc_name){
1148
/* Checks if given process is running */
1156
cmd = "pgrep -f '%s'".printf(proc_name);
1157
Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val);
1160
log_error (e.message);
1164
return (ret_val == 0);
1167
public void process_set_priority (Pid procID, int prio){
1169
/* Set process priority */
1171
if (Posix.getpriority (Posix.PRIO_PROCESS, procID) != prio)
1172
Posix.setpriority (Posix.PRIO_PROCESS, procID, prio);
1175
public int process_get_priority (Pid procID){
1177
/* Get process priority */
1179
return Posix.getpriority (Posix.PRIO_PROCESS, procID);
1182
public void process_set_priority_normal (Pid procID){
1184
/* Set normal priority for process */
1186
process_set_priority (procID, 0);
1189
public void process_set_priority_low (Pid procID){
1191
/* Set low priority for process */
1193
process_set_priority (procID, 5);
1197
public bool user_is_admin (){
1199
/* Check if current application is running with admin priviledges */
1203
string[] argv = { "sleep", "10" };
1205
Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId);
1207
// try changing the priority
1208
Posix.setpriority (Posix.PRIO_PROCESS, procId, -5);
1210
// check if priority was changed successfully
1211
if (Posix.getpriority (Posix.PRIO_PROCESS, procId) == -5)
1217
log_error (e.message);
1222
public int get_user_id(){
1224
// returns actual user id of current user (even for applications executed with sudo and pkexec)
1228
string pkexec_uid = GLib.Environment.get_variable("PKEXEC_UID");
1230
if (pkexec_uid != null){
1231
return int.parse(pkexec_uid);
1234
string sudo_user = GLib.Environment.get_variable("SUDO_USER");
1236
if (sudo_user != null){
1237
return get_user_id_from_username(sudo_user);
1240
return get_user_id_effective(); // normal user
1243
public string get_username(){
1245
// returns actual username of current user (even for applications executed with sudo and pkexec)
1247
return get_username_from_uid(get_user_id());
1250
public int get_user_id_effective(){
1252
// returns effective user id (0 for applications executed with sudo and pkexec)
1255
string cmd = "id -u";
1256
string std_out, std_err;
1257
exec_sync(cmd, out std_out, out std_err);
1258
if ((std_out != null) && (std_out.length > 0)){
1259
uid = int.parse(std_out);
1265
public int get_user_id_from_username(string username){
1269
foreach(var line in file_read("/etc/passwd").split("\n")){
1270
var arr = line.split(":");
1271
if (arr.length < 3) { continue; }
1272
if (arr[0] == username){
1273
user_id = int.parse(arr[2]);
1281
public string get_username_from_uid(int user_id){
1283
string username = "";
1285
foreach(var line in file_read("/etc/passwd").split("\n")){
1286
var arr = line.split(":");
1287
if (arr.length < 3) { continue; }
1288
if (int.parse(arr[2]) == user_id){
1297
public string get_user_home(string username = get_username()){
1299
string userhome = "";
1301
foreach(var line in file_read("/etc/passwd").split("\n")){
1302
var arr = line.split(":");
1303
if (arr.length < 6) { continue; }
1304
if (arr[0] == username){
1313
public string get_app_path (){
1315
/* Get path of current process */
1318
return GLib.FileUtils.read_link ("/proc/self/exe");
1321
log_error (e.message);
1326
public string get_app_dir (){
1328
/* Get parent directory of current process */
1331
return (File.new_for_path (GLib.FileUtils.read_link ("/proc/self/exe"))).get_parent ().get_path ();
1334
log_error (e.message);
1341
namespace TeeJee.GtkHelper{
1345
public void gtk_do_events (){
1347
/* Do pending events */
1349
while(Gtk.events_pending ())
1350
Gtk.main_iteration ();
1353
public void gtk_set_busy (bool busy, Gtk.Window win) {
1355
/* Show or hide busy cursor on window */
1357
Gdk.Cursor? cursor = null;
1360
cursor = new Gdk.Cursor(Gdk.CursorType.WATCH);
1363
cursor = new Gdk.Cursor(Gdk.CursorType.ARROW);
1366
var window = win.get_window ();
1368
if (window != null) {
1369
window.set_cursor (cursor);
1375
public void gtk_messagebox(string title, string message, Gtk.Window? parent_win, bool is_error = false){
1377
/* Shows a simple message box */
1379
var type = Gtk.MessageType.INFO;
1381
type = Gtk.MessageType.ERROR;
1384
type = Gtk.MessageType.INFO;
1387
/*var dlg = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, type, Gtk.ButtonsType.OK, message);
1389
dlg.set_default_size (200, -1);
1390
if (parent_win != null){
1391
dlg.set_transient_for(parent_win);
1392
dlg.set_modal(true);
1397
var dlg = new CustomMessageDialog(title,message,type,parent_win, Gtk.ButtonsType.OK);
1402
public bool gtk_combobox_set_value (ComboBox combo, int index, string val){
1404
/* Conveniance function to set combobox value */
1408
TreeModel model = (TreeModel) combo.model;
1410
bool iterExists = model.get_iter_first (out iter);
1412
model.get(iter, 1, out comboVal);
1413
if (comboVal == val){
1414
combo.set_active_iter(iter);
1417
iterExists = model.iter_next (ref iter);
1423
public string gtk_combobox_get_value (ComboBox combo, int index, string default_value){
1425
/* Conveniance function to get combobox value */
1427
if ((combo.model == null) || (combo.active < 0)) { return default_value; }
1431
combo.get_active_iter (out iter);
1432
TreeModel model = (TreeModel) combo.model;
1433
model.get(iter, index, out val);
1438
public int gtk_combobox_get_value_enum (ComboBox combo, int index, int default_value){
1440
/* Conveniance function to get combobox value */
1442
if ((combo.model == null) || (combo.active < 0)) { return default_value; }
1446
combo.get_active_iter (out iter);
1447
TreeModel model = (TreeModel) combo.model;
1448
model.get(iter, index, out val);
1453
public class CellRendererProgress2 : Gtk.CellRendererProgress{
1454
public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) {
1458
int diff = (int) ((cell_area.height - height)/2);
1460
// Apply the new height into the bar, and center vertically:
1461
Gdk.Rectangle new_area = Gdk.Rectangle() ;
1462
new_area.x = cell_area.x;
1463
new_area.y = cell_area.y + diff;
1464
new_area.width = width - 5;
1465
new_area.height = height;
1467
base.render(cr, widget, background_area, new_area, flags);
1471
public Gdk.Pixbuf? get_app_icon(int icon_size, string format = ".png"){
1472
var img_icon = get_shared_icon(AppShortName, AppShortName + format,icon_size,"pixmaps");
1473
if (img_icon != null){
1474
return img_icon.pixbuf;
1481
public Gtk.Image? get_shared_icon(string icon_name, string fallback_icon_file_name, int icon_size, string icon_directory = AppShortName + "/images"){
1482
Gdk.Pixbuf pix_icon = null;
1483
Gtk.Image img_icon = null;
1486
Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default();
1487
pix_icon = icon_theme.load_icon (icon_name, icon_size, 0);
1489
//log_error (e.message);
1492
string fallback_icon_file_path = "/usr/share/%s/%s".printf(icon_directory, fallback_icon_file_name);
1494
if (pix_icon == null){
1496
pix_icon = new Gdk.Pixbuf.from_file_at_size (fallback_icon_file_path, icon_size, icon_size);
1498
log_error (e.message);
1502
if (pix_icon == null){
1503
log_error (_("Missing Icon") + ": '%s', '%s'".printf(icon_name, fallback_icon_file_path));
1506
img_icon = new Gtk.Image.from_pixbuf(pix_icon);
1512
public int gtk_treeview_model_count(TreeModel model){
1515
if (model.get_iter_first(out iter)){
1517
while(model.iter_next(ref iter)){
1525
namespace TeeJee.Multimedia{
1527
using TeeJee.Logging;
1529
/* Functions for working with audio/video files */
1531
public long get_file_duration(string filePath){
1533
/* Returns the duration of an audio/video file using MediaInfo */
1535
string output = "0";
1538
Process.spawn_command_line_sync("mediainfo \"--Inform=General;%Duration%\" \"" + filePath + "\"", out output);
1541
log_error (e.message);
1544
return long.parse(output);
1547
public string get_file_crop_params (string filePath){
1549
/* Returns cropping parameters for a video file using avconv */
1555
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);
1558
log_error (e.message);
1561
int w=0,h=0,x=10000,y=10000;
1566
foreach (string line in error.split ("\n")){
1567
if (line == null) { continue; }
1568
if (line.index_of ("crop=") == -1) { continue; }
1570
foreach (string part in line.split (" ")){
1571
if (part == null || part.length == 0) { continue; }
1573
arr = part.split (":");
1574
if (arr.length != 2) { continue; }
1576
key = arr[0].strip ();
1577
val = arr[1].strip ();
1581
num = int.parse (arr[1]);
1582
if (num < x) { x = num; }
1585
num = int.parse (arr[1]);
1586
if (num < y) { y = num; }
1589
num = int.parse (arr[1]);
1590
if (num > w) { w = num; }
1593
num = int.parse (arr[1]);
1594
if (num > h) { h = num; }
1600
if (x == 10000 || y == 10000)
1601
return "%i:%i:%i:%i".printf(0,0,0,0);
1603
return "%i:%i:%i:%i".printf(w,h,x,y);
1606
public string get_mediainfo (string filePath){
1608
/* Returns the multimedia properties of an audio/video file using MediaInfo */
1613
Process.spawn_command_line_sync("mediainfo \"%s\"".printf(filePath), out output);
1616
log_error (e.message);
1626
namespace TeeJee.System{
1628
using TeeJee.ProcessManagement;
1629
using TeeJee.Logging;
1631
public double get_system_uptime_seconds(){
1633
/* Returns the system up-time in seconds */
1641
cmd = "cat /proc/uptime";
1642
Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val);
1643
string uptime = std_out.split(" ")[0];
1644
double secs = double.parse(uptime);
1648
log_error (e.message);
1653
public string get_desktop_name(){
1655
/* Return the names of the current Desktop environment */
1659
pid = get_pid_by_name("cinnamon");
1664
pid = get_pid_by_name("xfdesktop");
1669
pid = get_pid_by_name("lxsession");
1674
pid = get_pid_by_name("gnome-shell");
1679
pid = get_pid_by_name("wingpanel");
1681
return "Elementary";
1684
pid = get_pid_by_name("unity-panel-service");
1689
pid = get_pid_by_name("plasma-desktop");
1697
public Gee.ArrayList<string> list_dir_names(string path){
1698
var list = new Gee.ArrayList<string>();
1702
File f_home = File.new_for_path (path);
1703
FileEnumerator enumerator = f_home.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0);
1705
while ((file = enumerator.next_file ()) != null) {
1706
string name = file.get_name();
1707
//string item = path + "/" + name;
1712
log_error (e.message);
1716
CompareDataFunc<string> entry_compare = (a, b) => {
1719
list.sort((owned) entry_compare);
1724
public bool check_internet_connectivity(){
1725
bool connected = false;
1726
connected = check_internet_connectivity_test1();
1733
connected = check_internet_connectivity_test2();
1739
public bool check_internet_connectivity_test1(){
1744
string cmd = "ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3`\n";
1746
exit_code = exec_script_sync(cmd, out std_out, out std_err, false);
1748
return (exit_code == 0);
1751
public bool check_internet_connectivity_test2(){
1756
string cmd = "ping -q -w 1 -c 1 google.com\n";
1758
exit_code = exec_script_sync(cmd, out std_out, out std_err, false);
1760
return (exit_code == 0);
1764
public bool shutdown (){
1766
/* Shutdown the system immediately */
1769
string[] argv = { "shutdown", "-h", "now" };
1771
Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId);
1775
log_error (e.message);
1780
public bool xdg_open (string file, string user = ""){
1781
string path = get_cmd_path ("xdg-open");
1782
if ((path != null) && (path != "")){
1783
string cmd = "xdg-open '%s'".printf(escape_single_quote(file));
1784
if (user.length > 0){
1785
cmd = "pkexec --user %s env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY ".printf(user) + cmd;
1787
int status = exec_script_async(cmd);
1788
return (status == 0);
1793
public bool exo_open_folder (string dir_path, bool xdg_open_try_first = true){
1795
/* Tries to open the given directory in a file manager */
1798
xdg-open is a desktop-independent tool for configuring the default applications of a user.
1799
Inside a desktop environment (e.g. GNOME, KDE, Xfce), xdg-open simply passes the arguments
1800
to that desktop environment's file-opener application (gvfs-open, kde-open, exo-open, respectively).
1801
We will first try using xdg-open and then check for specific file managers if it fails.
1806
if (xdg_open_try_first){
1807
//try using xdg-open
1808
path = get_cmd_path ("xdg-open");
1809
if ((path != null)&&(path != "")){
1810
return execute_command_script_async ("xdg-open \"" + dir_path + "\"");
1814
path = get_cmd_path ("nemo");
1815
if ((path != null)&&(path != "")){
1816
return execute_command_script_async ("nemo \"" + dir_path + "\"");
1819
path = get_cmd_path ("nautilus");
1820
if ((path != null)&&(path != "")){
1821
return execute_command_script_async ("nautilus \"" + dir_path + "\"");
1824
path = get_cmd_path ("thunar");
1825
if ((path != null)&&(path != "")){
1826
return execute_command_script_async ("thunar \"" + dir_path + "\"");
1829
path = get_cmd_path ("pantheon-files");
1830
if ((path != null)&&(path != "")){
1831
return execute_command_script_async ("pantheon-files \"" + dir_path + "\"");
1834
path = get_cmd_path ("marlin");
1835
if ((path != null)&&(path != "")){
1836
return execute_command_script_async ("marlin \"" + dir_path + "\"");
1839
if (xdg_open_try_first == false){
1840
//try using xdg-open
1841
path = get_cmd_path ("xdg-open");
1842
if ((path != null)&&(path != "")){
1843
return execute_command_script_async ("xdg-open \"" + dir_path + "\"");
1850
public bool exo_open_textfile (string txt){
1852
/* Tries to open the given text file in a text editor */
1856
path = get_cmd_path ("exo-open");
1857
if ((path != null)&&(path != "")){
1858
return execute_command_script_async ("exo-open \"" + txt + "\"");
1861
path = get_cmd_path ("gedit");
1862
if ((path != null)&&(path != "")){
1863
return execute_command_script_async ("gedit --new-document \"" + txt + "\"");
1869
public bool exo_open_url (string url){
1871
/* Tries to open the given text file in a text editor */
1875
path = get_cmd_path ("exo-open");
1876
if ((path != null)&&(path != "")){
1877
return execute_command_script_async ("exo-open \"" + url + "\"");
1880
path = get_cmd_path ("firefox");
1881
if ((path != null)&&(path != "")){
1882
return execute_command_script_async ("firefox \"" + url + "\"");
1885
path = get_cmd_path ("chromium-browser");
1886
if ((path != null)&&(path != "")){
1887
return execute_command_script_async ("chromium-browser \"" + url + "\"");
1893
public GLib.Timer timer_start(){
1894
var timer = new GLib.Timer();
1899
public ulong timer_elapsed(GLib.Timer timer){
1902
seconds = timer.elapsed (out microseconds);
1903
return microseconds;
1906
public void sleep(int milliseconds){
1907
Thread.usleep ((ulong) milliseconds * 1000);
1910
public string timer_elapsed_string(GLib.Timer timer, bool stop = true){
1913
seconds = timer.elapsed (out microseconds);
1917
return "%.0f ms".printf((seconds * 1000 ) + microseconds/1000);
1920
public void timer_elapsed_print(GLib.Timer timer, bool stop = true){
1923
seconds = timer.elapsed (out microseconds);
1927
log_msg("%s %lu\n".printf(seconds.to_string(), microseconds));
1930
public string[] array_concat(string[] a, string[] b){
1932
foreach(string str in a){ c += str; }
1933
foreach(string str in b){ c += str; }
1937
private DateTime dt_last_notification = null;
1938
private const int NOTIFICATION_INTERVAL = 3;
1940
public int notify_send (string title, string message, int durationMillis, string urgency, string dialog_type = "info"){
1942
/* Displays notification bubble on the desktop */
1946
switch (dialog_type){
1953
dialog_type = "info";
1957
long seconds = 9999;
1958
if (dt_last_notification != null){
1959
DateTime dt_end = new DateTime.now_local();
1960
TimeSpan elapsed = dt_end.difference(dt_last_notification);
1961
seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND);
1964
if (seconds > NOTIFICATION_INTERVAL){
1965
string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\"".printf(durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message);
1966
retVal = exec_sync (s);
1967
dt_last_notification = new DateTime.now_local();
1973
public bool set_directory_ownership(string dir_name, string login_name){
1975
string cmd = "chown %s:%s -R '%s'".printf(login_name, login_name, dir_name);
1977
Process.spawn_command_line_sync(cmd, null, null, out exit_code);
1979
if (exit_code == 0){
1980
log_debug(_("Set owner: %s, dir: %s").printf(login_name, dir_name));
1984
log_error(_("Failed to set ownership") + ": %s, '%s'".printf(login_name, dir_name));
1989
log_error (e.message);
1994
public string random_string(int length = 8, string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"){
1997
for(int i=0;i<length;i++){
1998
int random_index = Random.int_range(0,charset.length);
1999
string ch = charset.get_char(charset.index_of_nth_char(random_index)).to_string();
2006
public class ProcStats{
2007
public double user = 0;
2008
public double nice = 0;
2009
public double system = 0;
2010
public double idle = 0;
2011
public double iowait = 0;
2013
public double user_delta = 0;
2014
public double nice_delta = 0;
2015
public double system_delta = 0;
2016
public double idle_delta = 0;
2017
public double iowait_delta = 0;
2019
public double usage_percent = 0;
2021
public static ProcStats stat_prev = null;
2023
public ProcStats(string line){
2024
string[] arr = line.split(" ");
2026
if (arr[col++] == "cpu"){
2027
if (arr[col].length == 0){ col++; };
2029
user = double.parse(arr[col++]);
2030
nice = double.parse(arr[col++]);
2031
system = double.parse(arr[col++]);
2032
idle = double.parse(arr[col++]);
2033
iowait = double.parse(arr[col++]);
2035
if (ProcStats.stat_prev != null){
2036
user_delta = user - ProcStats.stat_prev.user;
2037
nice_delta = nice - ProcStats.stat_prev.nice;
2038
system_delta = system - ProcStats.stat_prev.system;
2039
idle_delta = idle - ProcStats.stat_prev.idle;
2040
iowait_delta = iowait - ProcStats.stat_prev.iowait;
2042
usage_percent = (user_delta + nice_delta + system_delta) * 100 / (user_delta + nice_delta + system_delta + idle_delta);
2049
ProcStats.stat_prev = this;
2053
//returns 0 when it is called first time
2054
public static double get_cpu_usage(){
2055
string txt = file_read("/proc/stat");
2056
foreach(string line in txt.split("\n")){
2057
string[] arr = line.split(" ");
2058
if (arr[0] == "cpu"){
2059
ProcStats stat = new ProcStats(line);
2060
return stat.usage_percent;
2067
public class SystemGroup : GLib.Object {
2068
public string name = "";
2069
public string password = "";
2070
public int gid = -1;
2071
public string user_names = "";
2073
public string shadow_line = "";
2074
public string password_hash = "";
2075
public string admin_list = "";
2076
public string member_list = "";
2078
public bool is_selected = false;
2079
public Gee.ArrayList<string> users;
2081
public static Gee.HashMap<string,SystemGroup> all_groups;
2083
public SystemGroup(string name){
2085
this.users = new Gee.ArrayList<string>();
2088
public static void query_groups(){
2089
all_groups = read_groups_from_file("/etc/group","/etc/gshadow", "");
2092
public bool is_installed{
2094
return SystemGroup.all_groups.has_key(name);
2098
public static Gee.HashMap<string,SystemGroup> read_groups_from_file(string group_file, string gshadow_file, string password){
2099
var list = new Gee.HashMap<string,SystemGroup>();
2101
// read 'group' file -------------------------------
2105
if (group_file.has_suffix(".tar.gpg")){
2106
txt = file_decrypt_untar_read(group_file, password);
2109
txt = file_read(group_file);
2112
if (txt.length == 0){
2116
foreach(string line in txt.split("\n")){
2117
if ((line == null) || (line.length == 0)){
2121
var group = parse_line_group(line);
2123
list[group.name] = group;
2127
// read 'gshadow' file -------------------------------
2131
if (gshadow_file.has_suffix(".tar.gpg")){
2132
txt = file_decrypt_untar_read(gshadow_file, password);
2135
txt = file_read(gshadow_file);
2138
if (txt.length == 0){
2142
foreach(string line in txt.split("\n")){
2143
if ((line == null) || (line.length == 0)){
2147
parse_line_gshadow(line, list);
2153
private static SystemGroup? parse_line_group(string line){
2154
if ((line == null) || (line.length == 0)){
2158
SystemGroup group = null;
2160
//cdrom:x:24:teejee,user2
2161
string[] fields = line.split(":");
2163
if (fields.length == 4){
2164
group = new SystemGroup(fields[0].strip());
2165
group.password = fields[1].strip();
2166
group.gid = int.parse(fields[2].strip());
2167
group.user_names = fields[3].strip();
2168
foreach(string user_name in group.user_names.split(",")){
2169
group.users.add(user_name);
2173
log_error("'group' file contains a record with non-standard fields" + ": %d".printf(fields.length));
2180
private static SystemGroup? parse_line_gshadow(string line, Gee.HashMap<string,SystemGroup> list){
2181
if ((line == null) || (line.length == 0)){
2185
SystemGroup group = null;
2187
//adm:*::syslog,teejee
2188
//<groupname>:<encrypted-password>:<admins>:<members>
2189
string[] fields = line.split(":");
2191
if (fields.length == 4){
2192
string group_name = fields[0].strip();
2193
if (list.has_key(group_name)){
2194
group = list[group_name];
2195
group.shadow_line = line;
2196
group.password_hash = fields[1].strip();
2197
group.admin_list = fields[2].strip();
2198
group.member_list = fields[3].strip();
2202
log_error("group in file 'gshadow' does not exist in file 'group'" + ": %s".printf(group_name));
2207
log_error("'gshadow' file contains a record with non-standard fields" + ": %d".printf(fields.length));
2212
public static int add_group(string group_name, bool system_account = false){
2213
string std_out, std_err;
2214
string cmd = "groupadd%s %s".printf((system_account)? " --system" : "", group_name);
2215
int status = exec_sync(cmd, out std_out, out std_err);
2226
return add_group(name,is_system);
2229
public static int add_user_to_group(string user_name, string group_name){
2230
string std_out, std_err;
2231
string cmd = "adduser %s %s".printf(user_name, group_name);
2233
int status = exec_sync(cmd, out std_out, out std_err);
2243
public int add_to_group(string user_name){
2244
return add_user_to_group(user_name, name);
2247
public bool is_system{
2249
return (gid < 1000);
2253
public bool update_group_file(){
2254
string file_path = "/etc/group";
2255
string txt = file_read(file_path);
2258
foreach(string line in txt.split("\n")){
2259
if (line.strip().length == 0) {
2263
string[] parts = line.split(":");
2265
if (parts.length != 4){
2266
log_error("'group' file contains a record with non-standard fields" + ": %d".printf(parts.length));
2270
if (parts[0].strip() == name){
2271
txt_new += get_group_line() + "\n";
2274
txt_new += line + "\n";
2278
file_write(file_path, txt_new);
2280
log_msg("Updated group settings in /etc/group" + ": %s".printf(name));
2285
public string get_group_line(){
2287
txt += "%s".printf(name);
2288
txt += ":%s".printf(password);
2289
txt += ":%d".printf(gid);
2290
txt += ":%s".printf(user_names);
2294
public bool update_gshadow_file(){
2295
string file_path = "/etc/gshadow";
2296
string txt = file_read(file_path);
2299
foreach(string line in txt.split("\n")){
2300
if (line.strip().length == 0) {
2304
string[] parts = line.split(":");
2306
if (parts.length != 4){
2307
log_error("'gshadow' file contains a record with non-standard fields" + ": %d".printf(parts.length));
2311
if (parts[0].strip() == name){
2312
txt_new += get_gshadow_line() + "\n";
2315
txt_new += line + "\n";
2319
file_write(file_path, txt_new);
2321
log_msg("Updated group settings in /etc/gshadow" + ": %s".printf(name));
2326
public string get_gshadow_line(){
2328
txt += "%s".printf(name);
2329
txt += ":%s".printf(password_hash);
2330
txt += ":%s".printf(admin_list);
2331
txt += ":%s".printf(member_list);
2337
namespace TeeJee.Misc {
2339
/* Various utility functions */
2342
using TeeJee.Logging;
2343
using TeeJee.FileSystem;
2344
using TeeJee.ProcessManagement;
2346
public class DistInfo : GLib.Object{
2348
/* Class for storing information about linux distribution */
2350
public string dist_id = "";
2351
public string description = "";
2352
public string release = "";
2353
public string codename = "";
2362
public string full_name(){
2369
val += (release.length > 0) ? " " + release : "";
2370
val += (codename.length > 0) ? " (" + codename + ")" : "";
2375
public static DistInfo get_dist_info(string root_path){
2377
/* Returns information about the Linux distribution
2378
* installed at the given root path */
2380
DistInfo info = new DistInfo();
2382
string dist_file = root_path + "/etc/lsb-release";
2383
var f = File.new_for_path(dist_file);
2384
if (f.query_exists()){
2388
DISTRIB_RELEASE=13.04
2389
DISTRIB_CODENAME=raring
2390
DISTRIB_DESCRIPTION="Ubuntu 13.04"
2393
foreach(string line in file_read(dist_file).split("\n")){
2395
if (line.split("=").length != 2){ continue; }
2397
string key = line.split("=")[0].strip();
2398
string val = line.split("=")[1].strip();
2400
if (val.has_prefix("\"")){
2401
val = val[1:val.length];
2404
if (val.has_suffix("\"")){
2405
val = val[0:val.length-1];
2412
case "DISTRIB_RELEASE":
2415
case "DISTRIB_CODENAME":
2416
info.codename = val;
2418
case "DISTRIB_DESCRIPTION":
2419
info.description = val;
2426
dist_file = root_path + "/etc/os-release";
2427
f = File.new_for_path(dist_file);
2428
if (f.query_exists()){
2432
VERSION="13.04, Raring Ringtail"
2435
PRETTY_NAME="Ubuntu 13.04"
2437
HOME_URL="http://www.ubuntu.com/"
2438
SUPPORT_URL="http://help.ubuntu.com/"
2439
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
2442
foreach(string line in file_read(dist_file).split("\n")){
2444
if (line.split("=").length != 2){ continue; }
2446
string key = line.split("=")[0].strip();
2447
string val = line.split("=")[1].strip();
2456
//case "DISTRIB_CODENAME":
2457
//info.codename = val;
2460
info.description = val;
2472
public static Gdk.RGBA hex_to_rgba (string hex_color){
2474
/* Converts the color in hex to RGBA */
2476
string hex = hex_color.strip().down();
2477
if (hex.has_prefix("#") == false){
2481
Gdk.RGBA color = Gdk.RGBA();
2482
if(color.parse(hex) == false){
2483
color.parse("#000000");
2490
public static string rgba_to_hex (Gdk.RGBA color, bool alpha = false, bool prefix_hash = true){
2492
/* Converts the color in RGBA to hex */
2497
hex = "%02x%02x%02x%02x".printf((uint)(Math.round(color.red*255)),
2498
(uint)(Math.round(color.green*255)),
2499
(uint)(Math.round(color.blue*255)),
2500
(uint)(Math.round(color.alpha*255)))
2504
hex = "%02x%02x%02x".printf((uint)(Math.round(color.red*255)),
2505
(uint)(Math.round(color.green*255)),
2506
(uint)(Math.round(color.blue*255)))
2517
public string timestamp2 (){
2519
/* Returns a numeric timestamp string */
2521
return "%ld".printf((long) time_t ());
2524
public string timestamp (){
2526
/* Returns a formatted timestamp string */
2528
Time t = Time.local (time_t ());
2529
return t.format ("%H:%M:%S");
2532
public string timestamp3 (){
2534
/* Returns a formatted timestamp string */
2536
Time t = Time.local (time_t ());
2537
return t.format ("%Y-%d-%m_%H-%M-%S");
2540
public string format_duration (long millis){
2542
/* Converts time in milliseconds to format '00:00:00.0' */
2544
double time = millis / 1000.0; // time in seconds
2546
double hr = Math.floor(time / (60.0 * 60));
2547
time = time - (hr * 60 * 60);
2548
double min = Math.floor(time / 60.0);
2549
time = time - (min * 60);
2550
double sec = Math.floor(time);
2552
return "%02.0lf:%02.0lf:%02.0lf".printf (hr, min, sec);
2555
public double parse_time (string time){
2557
/* Converts time in format '00:00:00.0' to milliseconds */
2559
string[] arr = time.split (":");
2561
if (arr.length >= 3){
2562
millis += double.parse(arr[0]) * 60 * 60;
2563
millis += double.parse(arr[1]) * 60;
2564
millis += double.parse(arr[2]);
2569
public string string_replace(string str, string search, string replacement, int count = -1){
2570
string[] arr = str.split(search);
2571
string new_txt = "";
2574
foreach(string part in arr){
2584
new_txt += replacement;
2595
public string escape_html(string html){
2597
.replace("&","&")
2598
.replace("\"",""")
2599
//.replace(" "," ") //pango markup throws an error with
2600
.replace("<","<")
2601
.replace(">",">")
2605
public string unescape_html(string html){
2607
.replace("&","&")
2608
.replace(""","\"")
2609
//.replace(" "," ") //pango markup throws an error with
2610
.replace("<","<")
2611
.replace(">",">")
2615
public DateTime datetime_from_string (string date_time_string){
2617
/* Converts date time string to DateTime
2622
* 'yyyy-MM-dd HH:mm'
2623
* 'yyyy-MM-dd HH:mm:ss'
2626
string[] arr = date_time_string.replace(":"," ").replace("-"," ").strip().split(" ");
2628
int year = (arr.length >= 3) ? int.parse(arr[0]) : 0;
2629
int month = (arr.length >= 3) ? int.parse(arr[1]) : 0;
2630
int day = (arr.length >= 3) ? int.parse(arr[2]) : 0;
2631
int hour = (arr.length >= 4) ? int.parse(arr[3]) : 0;
2632
int min = (arr.length >= 5) ? int.parse(arr[4]) : 0;
2633
int sec = (arr.length >= 6) ? int.parse(arr[5]) : 0;
2635
return new DateTime.utc(year,month,day,hour,min,sec);