1 /* ---------------------------------- global.cpp ---------------------------------------------------------------------------
2 file containing all variables & functions used globaly
3 
4 ===============================================================================================================================
5 ===============================================================================================================================
6     This file is part of "luckyBackup" project
7     Copyright, Loukas Avgeriou
8     luckyBackup is distributed under the terms of the GNU General Public License
9     luckyBackup is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation, either version 3 of the License, or
12     (at your option) any later version.
13 
14     luckyBackup is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with luckyBackup.  If not, see <http://www.gnu.org/licenses/>.
21 
22 project version    : Please see "main.cpp" for project version
23 
24 developer          : luckyb
25 last modified      : 2 Nov 2018
26 ===============================================================================================================================
27 ===============================================================================================================================
28 */
29 
30 #include "global.h"
31 
32 #include <iostream>
33 using namespace std;
34 
35 #include <QProcess>
36 #include <QDataStream>
37 #include <QTemporaryFile>
38 #include <QTextStream>
39 #include <QVariant>
40 
41 #include "operationClass.h"
42 
43 // global Variables declarations ~~~~~~~~~~~~~~~~~
44 
45 namespace Global {
46 
47 QString myHome = QDir::homePath();
48 QString currentUser;
49 QString const appName = "luckyBackup";
50 double const appVersion = 0.50;
51 QString appVersionString = "0.5.0";
52 double const validProfileVersion = 0.21;
53 double const validScheduleVersion = 0.34;
54 double const validSettingsVersion = 0.3;
55 QString luckyBackupDir = myHome + "/."+appName+"/";
56 QString luckyBackupDefaultDir = myHome + "/."+appName+"/";
57 QString settingsFile = luckyBackupDir + "settings.ini";
58 QString profileDir = luckyBackupDir + "profiles/";
59 QString defaultProfile = profileDir + "default.profile";
60 QString standardDefaultProfile = profileDir + "default.profile";
61 QString logDir = luckyBackupDir + "logs/";
62 QString logfilename = logDir + "logfile.log";
63 QString cronlogString = "LastCronLog.log";
64 QString emailLogString = "-email.log";
65 QString emailLastLogString = "-email-LastLog.log";
66 QString snapDefaultDir = ".luckybackup-snaphots/";
67 QString snapChangesDir = luckyBackupDir + "snaps/";
68 QString snapEmptyDir = snapChangesDir + "EMPTY/";
69 QString snapchangesfilename = snapChangesDir + "changes.log";
70 QString snapChangesString = "[changed_data]%i[LB]%n";
71 QString scheduleDir = luckyBackupDir + "schedule/";
72 QString schedulefilename = scheduleDir + "schedule.dat";
73 QString cronfilename = scheduleDir + "luckyCron.txt";
74 QString relativeTransDir = "translations/";
75 QString systemTransDir = "/usr/local/share/luckybackup/translations/";
76 QDir transDir;
77 QTranslator appTranslator;
78 QTranslator translator_qt;
79 QString locale = QLocale::system().name();
80 QString relativeLicense = "license/gpl.html";
81 QString systemLicense = "/usr/local/share/doc/luckybackup/license/gpl.html";
82 QString suseLicense = "/usr/local/share/doc/packages/luckybackup/license/gpl.html";
83 QString debianLicense = "/usr/local/share/common-licenses/GPL-3";
84 QString relativeManual = "manual/index.html";
85 QString systemManual = "/usr/local/share/doc/luckybackup/manual/index.html";
86 QString suseManual = "/usr/local/share/doc/packages/luckybackup/manual/index.html";
87 
88 QString countStr;
89 QString message="";
90 QString messageCLI="";
91 int errorsFound;
92 int filesTransfered;
93 unsigned long long int bytesTransfered;
94 
95 // Useful variables for operations ---------------------------------------------------------------------------------------------------
96 int const maxOperations = 100;
97 int TotalOperations=0;
98 int currentOperation=-1;
99 int removeCharLimit;
100 bool modifyOK=false;
101 bool modifyConnected=false;
102 bool DryRun=false;
103 bool ask=false;
104 bool newTaskThisIs = true;
105 bool NothingToDo=false;
106 bool NothingIncluded=false;
107 bool crontabUpdated=false;
108 QString currentProfile="";
109 QString profileName="";
110 QString profileDescription="";
111 QFile profile("");
112 QFile logfile("");
113 QFile snapfile("");
114 QString CheckedData;
115 QString CheckedDataCLI;
116 operation *Operation[maxOperations];
117 
118 bool console;
119 bool NoQuestions;
120 bool SkipCritical;
121 bool silentMode;
122 bool runImmediately;
123 bool validation;
124 bool KDErunning = false;
125 bool GNOMErunning = false;
126 bool writeToLog;
127 
128 QString emailCommand;
129 QString emailArguments;
130 bool    emailNever;
131 bool    emailError;
132 bool    emailSchedule;
133 bool    emailTLS;
134 QString emailFrom;
135 QString emailTo;
136 QString emailSubject;
137 QString emailSMTP;
138 QString emailBody;
139 QString emailDefaultSubject =   appName + " report";
140 QString emailDefaultBody    =   "Profile:      %p"
141                                 "\nDate:         %d"
142                                 "\nTime:         %i"
143                                 "\nErrors found: %e";
144 QString emailDefaultCommand    =   "sendemail";
145 QString emailDefaultArguments  =   "-f %f -t %t -u %s -m %b -a %l -s %v";
146 QString emailDefaultWinCommand ="C:\\Program Files (x86)\\luckyBackup\\blat\\blat.exe";
147 QString emailDefaultWinArguments ="-f %f -to %t -s %s -server %v -attach %l -body %b";
148 
149 QString rsyncDefaultCommand = "rsync";
150 QString sshDefaultCommand = "ssh";
151 
152 // WINDOWS related variables. Also search variables above for "WINDOWS use"
153 //QString rsyncDefaultWinCommand = "C:\\Program Files (x86)\\luckyBackup\\cygwin\\rsync.exe";
154 //QString sshDefaultWinCommand = "C:\\Program Files (x86)\\luckyBackup\\cygwin\\ssh.exe";
155 QString rsyncDefaultWinCommand = "";
156 QString sshDefaultWinCommand = "";
157 QString appPath = "";
158 //"QCoreApplication::applicationDirPath: Please instantiate the QApplication object first" WARNING message
159 //QString rsyncDefaultWinCommand = appPath+"/rsync.exe";
160 //QString sshDefaultWinCommand = appPath+"/ssh.exe";
161 QString mapdrive="w";
162 QString vshadowDir=             "";
163 QString vshadowDefaultDir=      "";
164 QString dosdevCommand=          "";
165 QString dosdevDefaultCommand=   "";
166 QString cygpathCommand=         "";
167 QString cygpathDefaultCommand=  "";
168 bool isTempDirPath=false;
169 QString tempDirPath=QDir::tempPath();
170 QString tempDefaultDirPath=QDir::tempPath();
171 //void setAppDir(QString s);
172 /* disable vss until
173   * int doVss=0;
174   * int vssPos=0;
175   * int vssErrPos=0;
176   * QTimer *vssTimer;
177   * int vssSleepTime=50;
178   * int vssReadSize=400;
179   * QFile *pipeVssFile;
180   * QFile *pipeVssErrFile;*/
181 //QString createWinMkdirCommand(QString tempPath,bool vss,QStringList rsyncArgs,bool logGui);
182 // END of Windows related variables
183 
184 QString rsyncCommandPath;
185 QString sshCommandPath;
186 
187 QString XnixSLASH = "/";
188 
189 #ifdef Q_OS_OS2
190 bool OS2running = true;
191 QString SLASH = "\\";
192 #else
193 bool OS2running = false;
194 QString SLASH = "/";
195 #endif
196 
197 #ifdef Q_OS_WIN32
198 bool WINrunning = true;
199 #else
200 bool WINrunning = false;
201 #endif
202 
203 #if defined Q_OS_OS2 || defined Q_OS_WIN32
204 bool notXnixRunning=true;
205 #else
206 bool notXnixRunning=false;
207 #endif
208 
209 // end of global Variables declarations ~~~~~~~~~~~~~~~~~
210 
211 // argumentsTest===================================================================================================================
212 // tests the arguments given when LB executed at command-line
argumentsTest(int ArgsNo,char ** arg)213 bool argumentsTest(int ArgsNo, char **arg)
214 {
215     console = false;
216     NoQuestions = false;
217     SkipCritical = false;
218     DryRun = false;
219     silentMode = false;
220     runImmediately = false;
221 
222     if (ArgsNo == 1)		// if just luckybackup is given without argumets just run the gui
223         return true;
224 
225     int NoOfArgs = ArgsNo-1;	//the number of arguments given minus the command luckybackup
226     string stdArgs[7] = { "-c",	"--no-questions",	"--skip-critical",	"--dry-run",	"--silent"};
227     bool argCheck = false;	// if a specific argument is ok this becomes true
228 
229     int count = 1;
230     while (count < NoOfArgs)
231     {
232         if (arg[count] == stdArgs[0])
233             { console = true; argCheck = true; }
234         if (arg[count] == stdArgs[1])
235             { NoQuestions = true; console = true; argCheck = true; }
236         if (arg[count] == stdArgs[2])
237             { SkipCritical = true; argCheck = true; }
238         if (arg[count] == stdArgs[3])
239             { DryRun = true; argCheck = true; }
240         if (arg[count] == stdArgs[4])
241             { silentMode = true; argCheck = true; }
242         if ((arg[count] == stdArgs[5]) || (arg[count] == stdArgs[6]))
243         {
244             // what was I thinking ???
245         }
246         if (!argCheck)			// if the argument is unknown
247             { help(); return false;	}
248         argCheck = false;
249         count++;
250     }
251 
252     const char *profileNameChar = arg[NoOfArgs];	//const char* used cause argument in terminal is in utf-8 and this helps to convert it to QString
253     QString profileNameArg = arg[NoOfArgs];
254     if ( (profileNameArg == "--help") || (profileNameArg == "-h") )
255         { help(); return false;}
256     if ( (profileNameArg == "--version") || (profileNameArg == "-v") )
257     {
258         cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
259         cout << "     You are using luckyBackup version: " << appVersionString.toStdString() <<"\n";
260         cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
261         return false;
262     }
263 
264     //currentProfile = profileNameArg;	// currentProfile holds the full path+filename of the current profile
265     currentProfile = QString::fromUtf8(profileNameChar);	// currentProfile holds the full path+filename of the current profile
266 
267     if ( notXnixRunning )
268     {
269         profileDir.replace("/",SLASH);
270         profileNameArg.replace("/",SLASH);
271         currentProfile.replace("/",SLASH);
272     }
273     if (!profileNameArg.endsWith(".profile",Qt::CaseSensitive))
274         currentProfile.append(".profile");
275     if ( (!profileNameArg.startsWith(SLASH)) && (!notXnixRunning) )
276         currentProfile.prepend(profileDir);
277     if ( (notXnixRunning) && (!profileNameArg.contains(":"+SLASH)) )
278         currentProfile.prepend(profileDir);
279 
280     //current profile QFile
281     profile.setFileName(currentProfile);
282 
283     //current profile's name (QString) - this just holds the profile name. No path & no extension
284     profileName = currentProfile;
285     profileName = profileName.right(profileName.size() - profileName.lastIndexOf(SLASH) - 1);
286     profileName.chop(8);
287 
288     runImmediately = true;
289     return true;	// all arguments ok
290 }
291 
292 // declareRsyncCommand===================================================================================================================
293 // declares the rsync and ssh commands (full path for windows)
declareRsyncCommand()294 void declareRsyncCommand()
295 {
296 
297     // WINDOWS related variables
298     appPath = QCoreApplication::applicationDirPath();
299     rsyncDefaultWinCommand = appPath+"/rsync.exe";
300     sshDefaultWinCommand   = appPath+"/ssh.exe";
301     vshadowDir             = appPath;
302     vshadowDefaultDir      = appPath;
303     dosdevCommand          = appPath+"/dosdev.exe";
304     dosdevDefaultCommand   = appPath+"/dosdev.exe";
305     cygpathCommand         = appPath+"/cygpath.exe";
306     cygpathDefaultCommand  = appPath+"/cygpath.exe";
307     // END of Windows related variables
308 
309     if (notXnixRunning)
310     {
311         if (WINrunning)
312         {
313             rsyncCommandPath    = rsyncDefaultWinCommand;                                     // This is the default rsync path that windows use
314             sshCommandPath      = sshDefaultWinCommand;                                       // This is the default ssh path that windows use
315         }
316 
317         if (OS2running)
318         {
319             rsyncCommandPath    = rsyncDefaultCommand;                                     // This is the default rsync path that OS2 use
320             sshCommandPath      = sshDefaultCommand;                                       // This is the default ssh path that OS2 use
321         }
322     }
323     else        // normal *nix
324     {
325         rsyncCommandPath    = rsyncDefaultCommand;                                     // This is the default rsync command that *nix use
326         sshCommandPath      = sshDefaultCommand;                                       // This is the default ssh command that *nix use
327 
328     }
329 }
330 
331 // loadCurrentProfile===================================================================================================================
332 // loads an existing profile - non-gui call
loadCurrentProfile()333 bool loadCurrentProfile()
334 {
335     QString currentProfileUTF8 = QString(currentProfile.toUtf8());
336 
337     cout << "\n============================================================================================\n";
338     cout << "		Loading profile " << currentProfileUTF8.toStdString() << "\n";
339     cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
340 
341     QString source, dest;
342 
343     //read the file and fill all arrays
344     int loadOK = loadProfile(currentProfileUTF8);	// try to load the currentProfile
345     if (loadOK == 1)		// if it cannot open
346     {
347         cout << "	** Unable to open profile : " << currentProfileUTF8.toStdString() << " **\n";
348         cout << "	" << profile.errorString().toStdString();
349         cout << "\n\n";
350         return false;					//do nothing more
351     }
352 
353     if (loadOK == 2)			// if it is not a valid profile
354     {
355         cout << "	** The profile you are trying to open is not a valid luckyBackup v."
356         << countStr.setNum(appVersion).toStdString() << " profile **\n\n";
357         return false;	//do nothing more
358     }
359 
360     // if all went ok (profile loaded) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
361 
362     //append the profile description (CLI)
363     //if (profileDescription != "")
364     //	cout << "\n\n Profile description: \n" << (QString(profileDescription.toUtf8())).toStdString() <<"\n\n";
365 
366     currentOperation = 0;
367     while (currentOperation < TotalOperations)
368     {
369         source = Operation[currentOperation]->GetSource();
370         dest = Operation[currentOperation]->GetDestination();
371 
372         if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteSource()) )
373         {
374             if (Operation[currentOperation] -> GetRemoteModule())
375                 source.prepend(":");
376             source.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
377             if (Operation[currentOperation] -> GetRemoteUser()!="")
378                 source.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
379         }
380 
381         if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteDestination()) )
382         {
383             if (Operation[currentOperation] -> GetRemoteModule())
384                 dest.prepend(":");
385             dest.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
386             if (Operation[currentOperation] -> GetRemoteUser()!="")
387                 dest.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
388         }
389         cout << "\n* task name		: " << QString((Operation[currentOperation]->GetName()).toUtf8()).toStdString();
390         cout << "\n* source			: " << QString(source.toUtf8()).toStdString();
391         cout << "\n* destination			: " << QString(dest.toUtf8()).toStdString();
392 
393         if (Operation[currentOperation]->GetIncluded())
394             cout << "\n* This task is included\n";
395         else
396             cout << "\n* This task is NOT included\n";
397 
398         currentOperation++;
399     }
400     cout << "\n\n			** Profile loaded successfully ... **\n\n";
401     return true;
402 }
403 
404 // check_list===================================================================================================================
405 // checks the loaded operations list for errors (eg nothing is included)
406 // calls global function checkTaskList()
check_list()407 bool check_list()
408 {
409     cout << "\n============================================================================================\n";
410     cout << "				Task list check \n";
411     cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
412 
413 
414 
415     cout << "\n* Checking if the task list is empty...					done";
416     cout << "\n* Checking if 2 connected tasks have been selected for execution...	done";
417     cout << "\n* Checking if no task is included...					done";
418     cout << "\n* Checking if 2 or more identical destination directories are declared\n  & 'Backup dir contents' is checked...					done\n";
419 
420     checkTaskList();
421 
422     if (ask)
423     {
424         cout << messageCLI.toStdString();;
425         return false;
426     }
427     else
428     {
429         cout << "\n\n			** Task list looks ok... **\n";
430         return true;
431     }
432     return true;
433 }
434 
435 // check_dirs===================================================================================================================
436 // checks all declared directories for errors by calling checkBackupDirs or checkSyncDirs
437 //This is called from the console
check_dirs()438 bool check_dirs()
439 {
440     cout << "\n============================================================================================\n";
441     cout << "				Directories check\n";
442     cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
443 
444     checkDeclaredDirs(false);
445 
446     if (ask == false)	//if all the dirs are ok prepend  this lines to the dialog message
447     {
448         CheckedDataCLI.prepend("\n		(Have in mind that checks are not performed for remote data)\n\n"
449         "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
450         CheckedDataCLI.prepend("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
451         "		All data declared appears to be ok - You are ready to go !!"
452         "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
453     }
454     else			//else prepend the following
455     {
456         CheckedDataCLI.prepend("			Errors have been found\n"
457         "		Please have a good look at the following messages\n\n"
458         "	WARNING means that the task is NOT going to be performed\n"
459         "	CRITICAL means that the task is going to be performed normally\n\n"
460         "	If a directory is empty or does not exist,\n"
461         "	there is a possibility that you 've forgotten to mount a partition/drive\n	or have just mistyped a path !!\n"
462         "\n	BEWARE if a destination is empty or non-existent\n"
463         "	and it is not the first time you perform the specific task(s)\n\n"
464         "	Also have in mind that checks are not performed for remote data\n"
465         "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
466 
467         CheckedDataCLI.prepend("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
468         "		Source & destination data check results"
469         "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
470     }
471 
472     cout << CheckedDataCLI.toStdString();
473     //cout << CheckedDataCLI.toUtf8().constData();
474 
475     cout <<"\n\n";
476     if (NothingToDo) //if there is nothing to Do anyway then just display a message
477     {
478         cout << "\n\n		** ..nothing to do !! **\n\n";
479         return false;
480     }
481     return true;
482 }
483 
484 // help===================================================================================================================
485 // displays command line usage instructions
help()486 void help()
487 {
488     cout << "\n============================================================================================\n";
489     cout << "\n * usage :       luckybackup [options] [filename]";
490     cout << "\n -------------------------------------------------------------------------------------------\n";
491     cout << " [options] can be  :\n\n";
492     cout << " --help            : displays this help message\n";
493     cout << " --version         : displays the current version of the application\n\n";
494 
495     cout << " --skip-critical   : does not execute tasks that appear with a 'CRITICAL' warning message.\n";
496     cout << " --dry-run         : executes luckybackup in dry-run (simulation) mode\n";
497     cout << " --silent          : executes luckybackup in silent mode (just tray notification icon shown)\n";
498     cout << "\n";
499     cout << " -c                : console mode. Use this, if there is no graphical envrironment available\n";
500     cout << " --no-questions: skips confirmation questions asked to user. Implies -c (console mode).\n\n";
501 
502     cout << " [filename] is the already created profile that is going to be executed\n";
503     cout << " -------------------------------------------------------------------------------------------\n";
504     cout << " * examples:\n";
505     cout << " Execute luckybackup gui :\n";
506     cout << " $ luckybackup\n\n";
507 
508     cout << " Execute luckybackup in silent mode for profile '~/.luckyBackup/profiles/BackupHome.profile' :\n";
509     cout << " $ luckybackup --silent ~/.luckyBackup/profiles/BackupHome.profile\n\n";
510 
511     cout << " Execute luckybackup in console mode for profile '~/.luckyBackup/profiles/BackupHome.profile' :\n";
512     cout << " $ luckybackup -c BackupHome.profile\n\n";
513 
514     cout << " Execute luckybackup in console mode for profile '~/.luckyBackup/profiles/BackupHome.profile' :\n";
515     cout << " Do not ask any questions and skip all tasks that apear CRITICAL after the checks\n";
516     cout << " $ luckybackup --skip-critical --no-questions ~/.luckyBackup/profiles/BackupHome.profile";
517     cout << "\n -------------------------------------------------------------------------------------------\n";
518     cout << " see also luckybackup man page:\n";
519     cout << " $ man luckybackup";
520     cout << "\n============================================================================================\n\n";
521 }
522 // loadProfile =====================================================================================================================================
523 // loads an existing profile
loadProfile(QString profileToLoad)524 int loadProfile(QString profileToLoad)
525 {
526     profile.setFileName(profileToLoad);
527 
528     if (!profile.open(QIODevice::ReadOnly))		//if the profile cannot be opened
529     {
530         profile.close();
531         return 1;
532     }
533 
534     QTextStream in(&profile);
535 
536     QString ProfileLine="";				//temp variable to import the profile line by line
537     ProfileLine = in.readLine();
538 
539     // First check if the profile is a text or data stream
540     // if data, call loadProfileQV
541     if (ProfileLine !="***************************** WARNING *****************************")
542     {
543         profile.close();
544         return loadProfileQV(profileToLoad);
545     }
546 
547     QString tempAppName = "asxeto";
548     profileDescription = "";
549     double tempAppVersion=0;
550     bool IntOk;
551 
552     // Init email variables in case profile does not contain them
553     if(WINrunning)
554     {
555         emailCommand = emailDefaultWinCommand;
556         emailArguments = emailDefaultWinArguments;
557     }
558     else
559     {
560         emailCommand = emailDefaultCommand;
561         emailArguments = emailDefaultArguments;
562     }
563     emailBody = emailDefaultBody;
564     emailSubject = emailDefaultSubject;
565     emailNever = true;
566     emailError = false;
567     emailSchedule = false;
568     emailTLS = false;
569     emailFrom = "";
570     emailTo = "";
571     emailSMTP = "";
572 
573     // Read all lines until the first task line or end of file if invalid
574     while ( !(ProfileLine.startsWith("[Task]")) && (!in.atEnd()) )
575     {
576         ProfileLine = in.readLine();
577 
578         //input the application name & version--------------------------
579         if (ProfileLine.startsWith("appName="))             tempAppName = ProfileLine.remove("appName=");
580         if (ProfileLine.startsWith("appVersion="))          tempAppVersion = (ProfileLine.remove("appVersion=")).toDouble(&IntOk);
581 
582         //input the size of the tasks list
583         if (ProfileLine.startsWith("TotalTasks="))          TotalOperations = (ProfileLine.remove("TotalTasks=")).toInt(&IntOk,10);
584 
585         //input the profile description
586         if (ProfileLine.startsWith("ProfileDescription="))  profileDescription.append("\n" + ProfileLine.remove("ProfileDescription="));
587 
588         //input email stuff
589         if (ProfileLine.startsWith("[email]"))              emailBody = "";// the profile contains email info, so init this var to start appending
590         if (ProfileLine.startsWith("emailCommand="))        emailCommand = ProfileLine.remove("emailCommand=");
591         if (ProfileLine.startsWith("emailArguments="))      emailArguments = ProfileLine.remove("emailArguments=");
592         if (ProfileLine.startsWith("emailSubject="))        emailSubject = ProfileLine.remove("emailSubject=");
593         if (ProfileLine.startsWith("emailNever="))          emailNever = (ProfileLine.remove("emailNever=")).toInt(&IntOk,10);
594         if (ProfileLine.startsWith("emailError="))          emailError = (ProfileLine.remove("emailError=")).toInt(&IntOk,10);
595         if (ProfileLine.startsWith("emailSchedule="))       emailSchedule = (ProfileLine.remove("emailSchedule=")).toInt(&IntOk,10);
596         if (ProfileLine.startsWith("emailTLS="))            emailTLS = (ProfileLine.remove("emailTLS=")).toInt(&IntOk,10);
597         if (ProfileLine.startsWith("emailFrom="))           emailFrom = ProfileLine.remove("emailFrom=");
598         if (ProfileLine.startsWith("emailTo="))             emailTo = ProfileLine.remove("emailTo=");
599         if (ProfileLine.startsWith("emailSMTP="))           emailSMTP = ProfileLine.remove("emailSMTP=");
600         if (ProfileLine.startsWith("emailBody="))           emailBody.append("\n" + ProfileLine.remove("emailBody="));
601 
602     }
603     profileDescription.remove(0,1); //remove the first "\n" from the profileDescription as well as the email body
604     if (emailBody.startsWith("\n"))
605         emailBody.remove(0,1);
606 
607     if ( (tempAppName != appName) || (tempAppVersion < validProfileVersion) )//check if the file is a valid luckybackup profile
608     {
609         profile.close();
610         return 2;		//profile is not valid
611     }
612 
613     // import task details one bye one
614     currentOperation = 0;
615     while (currentOperation < TotalOperations)
616     {
617         operation *tempOp = new operation;
618         bool doNotReadNextLine = false;
619 
620         ProfileLine = in.readLine();	// inport the next line
621         while ( (!ProfileLine.startsWith("[Task_end]")) && (!in.atEnd()) )
622         {
623             doNotReadNextLine = false;
624             if (ProfileLine.startsWith("Name="))					tempOp	-> SetName(ProfileLine.remove("Name="));
625             if (ProfileLine.startsWith("TaskDescription="))			tempOp	-> SetDescription(tempOp->GetDescription() + "\n" + ProfileLine.remove("TaskDescription="));
626             if (ProfileLine.startsWith("Args="))					tempOp	-> AppendArg(ProfileLine.remove("Args="));
627 
628             if (ProfileLine.startsWith("ConnectRestore="))			tempOp	-> SetConnectRestore(ProfileLine.remove("ConnectRestore="));
629 
630             if (ProfileLine.startsWith("LastExecutionTime="))		tempOp	-> SetLastExecutionTime(QDateTime::fromString(ProfileLine.remove("LastExecutionTime="),
631 "yyyyMMddhhmmss"));
632             if (ProfileLine.startsWith("LastExecutionErrors="))		tempOp	-> SetLastExecutionErrors((ProfileLine.remove("LastExecutionErrors=")).toInt(&IntOk,10));
633             if (ProfileLine.startsWith("KeepSnapshots="))			tempOp	-> SetKeepSnapshots((ProfileLine.remove("KeepSnapshots=")).toInt(&IntOk,10)); //see also "update the max.." few lines below
634             if (ProfileLine.startsWith("SnapshotsListItem="))		tempOp	-> AddSnapshotsListItem(ProfileLine.remove("SnapshotsListItem="));
635 
636             if (ProfileLine.startsWith("TypeDirContents="))			tempOp	-> SetTypeDirContents(ProfileLine.remove("TypeDirContents=").toInt(&IntOk,10));
637             if (ProfileLine.startsWith("TypeDirName="))             tempOp	-> SetTypeDirName(ProfileLine.remove("TypeDirName=").toInt(&IntOk,10));
638             if (ProfileLine.startsWith("TypeSync="))				tempOp	-> SetTypeSync(ProfileLine.remove("TypeSync=").toInt(&IntOk,10));
639 
640             if (ProfileLine.startsWith("Source="))                  tempOp	-> SetSource(ProfileLine.remove("Source="));
641             if (ProfileLine.startsWith("Destination="))				tempOp	-> SetDestination(ProfileLine.remove("Destination="));
642 
643             if (ProfileLine.startsWith("ExcludeTemp="))             tempOp	-> SetExcludeTemp(ProfileLine.remove("ExcludeTemp=").toInt(&IntOk,10));
644             if (ProfileLine.startsWith("ExcludeFromFile="))			tempOp	-> SetExcludeFromFile(ProfileLine.remove("ExcludeFromFile=").toInt(&IntOk,10));
645             if (ProfileLine.startsWith("ExcludeFile="))				tempOp	-> SetExcludeFile(ProfileLine.remove("ExcludeFile="));
646             if (ProfileLine.startsWith("ExcludeCache="))			tempOp	-> SetExcludeCache(ProfileLine.remove("ExcludeCache=").toInt(&IntOk,10));
647             if (ProfileLine.startsWith("ExcludeBackup="))			tempOp	-> SetExcludeBackup(ProfileLine.remove("ExcludeBackup=").toInt(&IntOk,10));
648             if (ProfileLine.startsWith("ExcludeMount="))			tempOp	-> SetExcludeMount(ProfileLine.remove("ExcludeMount=").toInt(&IntOk,10));
649             if (ProfileLine.startsWith("ExcludeLostFound="))		tempOp	-> SetExcludeLostFound(ProfileLine.remove("ExcludeLostFound=").toInt(&IntOk,10));
650             if (ProfileLine.startsWith("ExcludeSystem="))			tempOp	-> SetExcludeSystem(ProfileLine.remove("ExcludeSystem=").toInt(&IntOk,10));
651             if (ProfileLine.startsWith("ExcludeTrash="))			tempOp	-> SetExcludeTrash(ProfileLine.remove("ExcludeTrash=").toInt(&IntOk,10));
652             if (ProfileLine.startsWith("ExcludeGVFS="))             tempOp  -> SetExcludeGVFS(ProfileLine.remove("ExcludeGVFS=").toInt(&IntOk,10));
653             if (ProfileLine.startsWith("ExcludeListItem="))			tempOp	-> AddExcludeListItem(ProfileLine.remove("ExcludeListItem="));
654             tempOp	-> SetExclude();
655 
656             if (ProfileLine.startsWith("IncludeListItem="))			tempOp	-> AddIncludeListItem(ProfileLine.remove("IncludeListItem="));
657             if (ProfileLine.startsWith("IncludeModeNormal="))		tempOp	-> SetIncludeModeNormal(ProfileLine.remove("IncludeModeNormal=").toInt(&IntOk,10));
658             if (ProfileLine.startsWith("IncludeFromFile="))			tempOp	-> SetIncludeFromFile(ProfileLine.remove("IncludeFromFile=").toInt(&IntOk,10));
659             if (ProfileLine.startsWith("IncludeFile="))				tempOp	-> SetIncludeFile(ProfileLine.remove("IncludeFile="));
660             tempOp	-> SetInclude();
661 
662             if (ProfileLine.startsWith("Remote="))				    tempOp	-> SetRemote(ProfileLine.remove("Remote=").toInt(&IntOk,10));
663             if (ProfileLine.startsWith("RemoteModule="))			tempOp	-> SetRemoteModule(ProfileLine.remove("RemoteModule=").toInt(&IntOk,10));
664             if (ProfileLine.startsWith("RemoteDestination="))		tempOp	-> SetRemoteDestination(ProfileLine.remove("RemoteDestination=").toInt(&IntOk,10));
665             if (ProfileLine.startsWith("RemoteSource="))			tempOp	-> SetRemoteSource(ProfileLine.remove("RemoteSource=").toInt(&IntOk,10));
666             if (ProfileLine.startsWith("RemoteSSH="))			    tempOp	-> SetRemoteSSH(ProfileLine.remove("RemoteSSH=").toInt(&IntOk,10));
667             if (ProfileLine.startsWith("RemoteHost="))			    tempOp	-> SetRemoteHost(ProfileLine.remove("RemoteHost="));
668             if (ProfileLine.startsWith("RemoteUser="))			    tempOp	-> SetRemoteUser(ProfileLine.remove("RemoteUser="));
669             if (ProfileLine.startsWith("RemotePassword="))		    tempOp	-> SetRemotePassword(ProfileLine.remove("RemotePassword="));
670             if (ProfileLine.startsWith("RemoteSSHPassword="))		tempOp	-> SetRemoteSSHPassword(ProfileLine.remove("RemoteSSHPassword="));
671             if (ProfileLine.startsWith("RemoteSSHPasswordStr="))    tempOp  -> SetRemoteSSHPasswordStr(ProfileLine.remove("RemoteSSHPasswordStr="));
672             if (ProfileLine.startsWith("RemoteSSHOptions="))        tempOp  -> SetRemoteSSHOptions(ProfileLine.remove("RemoteSSHOptions="));
673             if (ProfileLine.startsWith("RemoteSSHPort="))			tempOp	-> SetRemoteSSHPort((ProfileLine.remove("RemoteSSHPort=")).toInt(&IntOk,10));
674 
675             if (ProfileLine.startsWith("OptionsUpdate="))			tempOp	-> SetOptionsUpdate(ProfileLine.remove("OptionsUpdate=").toInt(&IntOk,10));
676             if (ProfileLine.startsWith("OptionsDelete="))			tempOp	-> SetOptionsDelete(ProfileLine.remove("OptionsDelete=").toInt(&IntOk,10));
677             if (ProfileLine.startsWith("OptionsRecurse="))			tempOp	-> SetOptionsRecurse(ProfileLine.remove("OptionsRecurse=").toInt(&IntOk,10));
678             if (ProfileLine.startsWith("OptionsOwnership="))		tempOp	-> SetOptionsOwnership(ProfileLine.remove("OptionsOwnership=").toInt(&IntOk,10));
679             if (ProfileLine.startsWith("OptionsSymlinks="))		    tempOp	-> SetOptionsSymlinks(ProfileLine.remove("OptionsSymlinks=").toInt(&IntOk,10));
680             if (ProfileLine.startsWith("OptionsPermissions=")) 		tempOp	-> SetOptionsPermissions(ProfileLine.remove("OptionsPermissions=").toInt(&IntOk,10));
681             if (ProfileLine.startsWith("OptionsDevices="))			tempOp	-> SetOptionsDevices(ProfileLine.remove("OptionsDevices=").toInt(&IntOk,10));
682             if (ProfileLine.startsWith("OptionsCVS="))			    tempOp	-> SetOptionsCVS(ProfileLine.remove("OptionsCVS=").toInt(&IntOk,10));
683             if (ProfileLine.startsWith("OptionsHardLinks="))		tempOp	-> SetOptionsHardLinks(ProfileLine.remove("OptionsHardLinks=").toInt(&IntOk,10));
684             if (ProfileLine.startsWith("OptionsFATntfs="))			tempOp	-> SetOptionsFATntfs(ProfileLine.remove("OptionsFATntfs=").toInt(&IntOk,10));
685             if (ProfileLine.startsWith("OptionsSuper="))            tempOp  -> SetOptionsSuper(ProfileLine.remove("OptionsSuper=").toInt(&IntOk,10));
686             if (ProfileLine.startsWith("OptionsNumericIDs="))       tempOp  -> SetOptionsNumericIDs(ProfileLine.remove("OptionsNumericIDs=").toInt(&IntOk,10));
687             if (ProfileLine.startsWith("OptionsListItem="))			tempOp	-> AddOptionsListItem(ProfileLine.remove("OptionsListItem="));
688 
689             if (ProfileLine.startsWith("OptionsRestorent="))        tempOp  -> SetOptionsRestorent(ProfileLine.remove("OptionsRestorent=").toInt(&IntOk,10));
690             if (ProfileLine.startsWith("OptionsVss="))              tempOp  -> SetOptionsVss(ProfileLine.remove("OptionsVss=").toInt(&IntOk,10));
691 
692             if (ProfileLine.startsWith("TempPath="))                tempOp  -> SetTempPath(ProfileLine.remove("TempPath="));
693             if (ProfileLine.startsWith("LuckyBackupDir="))          tempOp  -> SetLuckyBackupDir(ProfileLine.remove("LuckyBackupDir="));
694             if (ProfileLine.startsWith("VshadowDir="))              tempOp  -> SetVshadowDir(ProfileLine.remove("VshadowDir="));
695             if (ProfileLine.startsWith("RsyncCommand="))            tempOp  -> SetRsyncCommand(ProfileLine.remove("RsyncCommand="));
696             if (ProfileLine.startsWith("SshCommand="))              tempOp  -> SetSshCommand(ProfileLine.remove("SshCommand="));
697             if (ProfileLine.startsWith("DosdevCommand="))           tempOp  -> SetDosdevCommand(ProfileLine.remove("DosdevCommand="));
698             if (ProfileLine.startsWith("CygpathCommand="))          tempOp  -> SetCygpathCommand(ProfileLine.remove("CygpathCommand="));
699 
700             if (ProfileLine.startsWith("ExecuteBeforeListItem="))
701             {
702                 tempOp	-> AddExecuteBeforeListItem(ProfileLine.remove("ExecuteBeforeListItem="));
703                 ProfileLine = in.readLine();    // inport the next line to check if it states the checked state !!
704                 if (ProfileLine.startsWith("ExecuteBeforeListItemState="))
705                     tempOp  -> AddExecuteBeforeListItemState(ProfileLine.remove("ExecuteBeforeListItemState=").toInt(&IntOk,10));
706                 else    // if there wasn't such a line -> older version of profile
707                 {
708                     tempOp  -> AddExecuteBeforeListItemState(true);
709                     doNotReadNextLine = true;
710                 }
711             }
712 
713             if (ProfileLine.startsWith("ExecuteAfterListItem="))
714             {
715                 tempOp	-> AddExecuteAfterListItem(ProfileLine.remove("ExecuteAfterListItem="));
716                 ProfileLine = in.readLine();    // inport the next line to check if it states the checked state !!
717                 if (ProfileLine.startsWith("ExecuteAfterListItemState="))
718                     tempOp  -> AddExecuteAfterListItemState(ProfileLine.remove("ExecuteAfterListItemState=").toInt(&IntOk,10));
719                 else    // if there wasn't such a line -> older version of profile
720                 {
721                     tempOp  -> AddExecuteAfterListItemState(true);
722                     doNotReadNextLine = true;
723                 }
724             }
725 
726             if (ProfileLine.startsWith("ByPassWarning="))           tempOp	-> SetByPassWARNING(ProfileLine.remove("ByPassWarning=").toInt(&IntOk,10));
727             if (ProfileLine.startsWith("CloneWarning="))            tempOp	-> SetCloneWARNING(ProfileLine.remove("CloneWarning=").toInt(&IntOk,10));
728             if (ProfileLine.startsWith("RepeatOnFail="))            tempOp  -> SetRepeatOnFail((ProfileLine.remove("RepeatOnFail=")).toInt(&IntOk,10));
729             //import include checkbox state
730             if (ProfileLine.startsWith("IncludeState="))            tempOp	-> SetIncluded((ProfileLine.remove("IncludeState=")).toInt(&IntOk,10));
731 
732             if (!doNotReadNextLine)
733                 ProfileLine = in.readLine();	// import the next line if it's not already imported
734             if (ProfileLine.startsWith("[Task_end]"))	// all properties have been loaded
735             {
736                 // first fix some icompatibilities with older versions that did not save the following properties:
737                 // 1. update the max "keep snapshots" number if it is < 1 (or not defined !!) or if the task is a sync task
738                 if ((tempOp -> GetTypeSync()) || (tempOp -> GetKeepSnapshots() < 1) )
739                     tempOp -> SetKeepSnapshots(1);
740                 // 2. Add a snapshot if last executiontime exists but snapshot list is empty
741                 QString LastTime = ( tempOp -> GetLastExecutionTime() ).toString("yyyyMMddhhmmss");
742                 if ( !(LastTime == "") && (tempOp -> SnapshotsListIsEmpty()) )
743                     tempOp -> AddSnapshotsListItem (LastTime);
744                 //3. Remove the first "\n" from the task description
745                 tempOp	-> SetDescription(tempOp->GetDescription().remove(0,1));
746                 Operation[currentOperation] = tempOp;	// update the currentOperation
747             }
748         }
749         currentOperation++;
750     }
751 
752     profile.close();
753 
754     // If the email fields are set from a version < 0.48
755     if (tempAppVersion < 0.48)
756     {
757         emailArguments = emailCommand;
758         emailCommand = emailCommand.left(emailCommand.indexOf(" "));
759         emailArguments.remove(emailCommand + " ");
760 
761         saveProfile(profileToLoad);     //save the profile with all new info
762     }
763 
764     return 0;
765 }
766 
767 
768 // loadProfileQV - qvariant =============================================================================================================================
769 // loads an existing profile using qvariant then saves this profile as simple text
770 // This is kept for compatibility purposes for older versions that use the qvariant and not simple text
loadProfileQV(QString profileToLoad)771 int loadProfileQV(QString profileToLoad)
772 {
773     int count;
774     profile.setFileName(profileToLoad);
775 
776     if (!profile.open(QIODevice::ReadOnly))		//if the profile cannot be opened
777     {
778         profile.close();
779         return 1;
780     }
781 
782     QDataStream in(&profile);
783     in.setVersion(QDataStream::Qt_4_3);
784 
785     QVariant v;					//we will import everything as QVariant using this temp variable
786     QString vString;				//temp variable to import "labels" of real data
787     QString tempAppName = "asxeto";
788     profileDescription = "";
789     double tempAppVersion=0;
790     in>>v;
791     if (v.toString()=="appName")
792         in >> v;
793     tempAppName = v.toString();	//input the application name & version--------------------------
794     in>>v;
795     if (v.toString()=="appVersion")
796         in >> v;
797     tempAppVersion = v.toDouble();
798 
799     if ( (tempAppName != appName) || (tempAppVersion < validProfileVersion) )//check if the file is a valid luckybackup profile
800     {
801         profile.close();
802         return 2;		//profile is not valid
803     }
804 
805     in>>v;
806     if (v.toString()=="TotalOperations")
807         in >> v;
808     TotalOperations = v.toInt();	//input the size of the operations list
809 
810     currentOperation = 0;	vString="";
811     while (currentOperation < TotalOperations)
812     {
813         operation *tempOp = new operation;
814 
815         in>>v;	vString = v.toString();	in >> v;	//input a label in vString and real data in v
816         while (vString != "operation end")
817         {
818             if (vString == "ProfileDescription")	profileDescription = v.toString();//input the profile description
819 
820             //cout << "\ntask: " <<currentOperation << "\nvString: " << vString.toStdString() << "\n";
821             if (vString == "Name")			tempOp	-> SetName(v.toString());
822             if (vString == "TaskDescription")	tempOp	-> SetDescription(v.toString());
823             if (vString == "Args")			tempOp	-> SetArgs(v.toStringList());
824 
825             if (vString == "ConnectRestore")	tempOp	-> SetConnectRestore(v.toString());
826 
827             if (vString == "LastExecutionTime")	tempOp	-> SetLastExecutionTime(v.toDateTime());
828             if (vString == "LastExecutionErrors")	tempOp	-> SetLastExecutionErrors(v.toInt());
829             if (vString == "KeepSnapshots")		tempOp	-> SetKeepSnapshots(v.toInt()); //see also "update the max.." few lines below
830             if (vString == "SnapshotsListSize")
831             {
832                 int snapshotsListSize = v.toInt();
833                 count = 0;
834                 while ( count < snapshotsListSize)
835                 {
836                     in >> v;		// load the string SnapshotsListItem1,2....XX
837                     in >> v; 		tempOp	-> AddSnapshotsListItem(v.toString());
838                     count++;
839                 }
840             }
841 
842             if (vString == "TypeDirContents")	tempOp	-> SetTypeDirContents(v.toBool());
843             if (vString == "TypeDirName")		tempOp	-> SetTypeDirName(v.toBool());
844             if (vString == "TypeSync")		tempOp	-> SetTypeSync(v.toBool());
845 
846             if (vString == "Source")		tempOp	-> SetSource(v.toString());
847             if (vString == "Destination")		tempOp	-> SetDestination(v.toString());
848 
849             if (vString == "ExcludeTemp")		tempOp	-> SetExcludeTemp(v.toBool());
850             if (vString == "ExcludeFromFile")	tempOp	-> SetExcludeFromFile(v.toBool());
851             if (vString == "ExcludeFile")		tempOp	-> SetExcludeFile(v.toString());
852             if (vString == "ExcludeCache")		tempOp	-> SetExcludeCache(v.toBool());
853             if (vString == "ExcludeBackup")		tempOp	-> SetExcludeBackup(v.toBool());
854             if (vString == "ExcludeMount")		tempOp	-> SetExcludeMount(v.toBool());
855             if (vString == "ExcludeLostFound")	tempOp	-> SetExcludeLostFound(v.toBool());
856             if (vString == "ExcludeSystem")		tempOp	-> SetExcludeSystem(v.toBool());
857             if (vString == "ExcludeTrash")		tempOp	-> SetExcludeTrash(v.toBool());
858             if (vString == "ExcludeListSize")
859             {
860                 int excludeListSize = v.toInt();
861                 count = 0;
862                 while ( count < excludeListSize)
863                 {
864                     in >> v; 		tempOp	-> AddExcludeListItem(v.toString());
865                     count++;
866                 }
867             }
868             tempOp	-> SetExclude();
869 
870             if (vString == "IncludeListSize")
871             {
872                 int IncludeListSize = v.toInt();
873                 count = 0;
874                 while ( count < IncludeListSize)
875                 {
876                     in >> v; 		tempOp	-> AddIncludeListItem(v.toString());
877                     count++;
878                 }
879             }
880             if (vString == "IncludeModeNormal")	tempOp	-> SetIncludeModeNormal(v.toBool());
881             if (vString == "IncludeFromFile")	tempOp	-> SetIncludeFromFile(v.toBool());
882             if (vString == "IncludeFile")		tempOp	-> SetIncludeFile(v.toString());
883             tempOp	-> SetInclude();
884 
885             if (vString == "Remote")			tempOp	-> SetRemote(v.toBool());
886             if (vString == "RemoteModule")		tempOp	-> SetRemoteModule(v.toBool());
887             if (vString == "RemoteDestination")	tempOp	-> SetRemoteDestination(v.toBool());
888             if (vString == "RemoteSource")		tempOp	-> SetRemoteSource(v.toBool());
889             if (vString == "RemoteSSH")			tempOp	-> SetRemoteSSH(v.toBool());
890             if (vString == "RemoteHost")		tempOp	-> SetRemoteHost(v.toString());
891             if (vString == "RemoteUser")		tempOp	-> SetRemoteUser(v.toString());
892             if (vString == "RemotePassword")	tempOp	-> SetRemotePassword(v.toString());
893             if (vString == "RemoteSSHPassword")	tempOp	-> SetRemoteSSHPassword(v.toString());
894             if (vString == "RemoteSSHPasswordStr")  tempOp  -> SetRemoteSSHPasswordStr(v.toString());
895             if (vString == "RemoteSSHOptions")  tempOp  -> SetRemoteSSHOptions(v.toString());
896             if (vString == "RemoteSSHPort")		tempOp	-> SetRemoteSSHPort(v.toInt());
897 
898             if (vString == "OptionsUpdate")		tempOp  -> SetOptionsUpdate(v.toBool());
899             if (vString == "OptionsDelete")		tempOp  -> SetOptionsDelete(v.toBool());
900             if (vString == "OptionsRecurse")	tempOp  -> SetOptionsRecurse(v.toBool());
901             if (vString == "OptionsOwnership")	tempOp  -> SetOptionsOwnership(v.toBool());
902             if (vString == "OptionsSymlinks")	tempOp  -> SetOptionsSymlinks(v.toBool());
903             if (vString == "OptionsPermissions") tempOp -> SetOptionsPermissions(v.toBool());
904             if (vString == "OptionsDevices")	tempOp  -> SetOptionsDevices(v.toBool());
905             if (vString == "OptionsCVS")		tempOp  -> SetOptionsCVS(v.toBool());
906             if (vString == "OptionsHardLinks")	tempOp  -> SetOptionsHardLinks(v.toBool());
907             if (vString == "OptionsFATntfs")	tempOp  -> SetOptionsFATntfs(v.toBool());
908             if (vString == "OptionsRestorent")  tempOp  -> SetOptionsRestorent(v.toBool());
909             if (vString == "OptionsVss")        tempOp  -> SetOptionsVss(v.toBool());
910 
911             if (vString == "OptionsListSize")
912             {
913                 int OptionsListSize = v.toInt();
914                 count = 0;
915                 while ( count < OptionsListSize)
916                 {
917                     in >> v;			tempOp	-> AddOptionsListItem(v.toString());
918                     count++;
919                 }
920             }
921             if (vString == "ExecuteBeforeListSize")
922             {
923                 int ExecuteBeforeListSize = v.toInt();
924                 count = 0;
925                 while ( count < ExecuteBeforeListSize)
926                 {
927                     in >> v;			tempOp	-> AddExecuteBeforeListItem(v.toString());
928                     count++;
929                 }
930             }
931             if (vString == "ExecuteAfterListSize")
932             {
933                 int ExecuteAfterListSize = v.toInt();
934                 count = 0;
935                 while ( count < ExecuteAfterListSize)
936                 {
937                     in >> v;			tempOp	-> AddExecuteAfterListItem(v.toString());
938                     count++;
939                 }
940             }
941             if (vString == "ByPassWarning")		tempOp	-> SetByPassWARNING(v.toBool());
942             if (vString == "CloneWarning")		tempOp	-> SetCloneWARNING(v.toBool());
943             //import include checkbox state
944             if (vString == "IncludeState")		tempOp	-> SetIncluded(v.toBool());
945             in>>v;	vString = v.toString();
946             if (vString!="operation end")
947                 in >> v;
948             else			// all properties have been loaded
949             {
950                 // first fix some icompatibilities with older versions that did not save the following properties:
951                 // 1. update the max "keep snapshots" number if it is < 1 (or not defined !!) or if the task is a sync task
952                 if ((tempOp -> GetTypeSync()) || (tempOp -> GetKeepSnapshots() < 1) )
953                     tempOp -> SetKeepSnapshots(1);
954                 // 2. Add a snapshot if last executiontime exists but snapshot list is empty
955                 QString LastTime = ( tempOp -> GetLastExecutionTime() ).toString("yyyyMMddhhmmss");
956                 if ( !(LastTime == "") && (tempOp -> SnapshotsListIsEmpty()) )
957                     tempOp -> AddSnapshotsListItem (LastTime);
958 
959                 Operation[currentOperation] = tempOp;	// update the currentOperation
960             }
961         }
962         currentOperation++;
963     }
964     profile.close();
965 
966     //backup the original qvariant profile before replacing it with a plain text one
967     //create directory ~/.luckyBackup including folders "logs", "profiles", "schedule", snaps if they do not exist for the current user
968     QDir profilebackupdir(profileDir + "backups/");
969     if (!profilebackupdir.exists())
970         profilebackupdir.mkpath(profileDir + "backups/");
971     profile.copy(profileDir + "backups/" + profileName + ".profile" );
972 
973     saveProfile(profileToLoad);		//save the profile to text format
974     return 0;
975 }
976 
977 // saveProfile =====================================================================================================================================
978 // saves an existing profile
saveProfile(QString profileToSave)979 bool saveProfile(QString profileToSave)
980 {
981     int count;
982 
983     profile.setFileName(profileToSave);
984 
985     if (!profile.open(QIODevice::WriteOnly))	// if the profile cannot be saved (or fails to create)
986     {
987         profile.close();
988         return false;
989     }
990 
991     //write arrays to profile file
992     QTextStream out(&profile);
993 
994     out << "***************************** WARNING *****************************\n";
995     out << "Do NOT edit this file directly, unless you REALLY know what you are doing !!\n\n\n";
996 
997     out << "[profile_global]\n";
998     out << "appName="                       << appName << "\n";             //output the application name
999     out << "appVersion="                    << appVersion << "\n";          //output the application version
1000     out << "TotalTasks="                    << TotalOperations << "\n";     //output the size of the opeartions list
1001 
1002     if (profileDescription!="")
1003     {
1004         QStringList DescriptionLines = profileDescription.split("\n");
1005         for (count=0; count<DescriptionLines.size();++count)
1006             out << "ProfileDescription=" 		<< DescriptionLines.at(count) << "\n";  //output the profile description
1007     }
1008 
1009     out << "\n[email]\n";
1010 
1011     out << "emailCommand="  << emailCommand     << "\n"; //output the full email command with arguments
1012     out << "emailArguments="<< emailArguments   << "\n"; //output the full email arguments
1013     out << "emailSubject="  << emailSubject     << "\n"; //output the email subject
1014     out << "emailNever="    << emailNever       << "\n"; //output the email never condition
1015     out << "emailError="    << emailError       << "\n"; //output the email error condition
1016     out << "emailSchedule=" << emailSchedule    << "\n"; //output the email schedule condition
1017     out << "emailTLS="      << emailTLS         << "\n"; //output the TLS option condition
1018     out << "emailFrom="     << emailFrom        << "\n"; //output the email from
1019     out << "emailTo="       << emailTo          << "\n"; //output the email To
1020     out << "emailSMTP="     << emailSMTP        << "\n"; //output the email smtp server
1021     if (emailBody!="")
1022     {
1023         QStringList emailBodyLines = emailBody.split("\n");
1024         for (count=0; count<emailBodyLines.size();++count)
1025             out << "emailBody="        << emailBodyLines.at(count) << "\n";  //output the email body line by line
1026     }
1027 
1028     out << "\n";
1029     currentOperation = 0;
1030 
1031     while ( currentOperation < TotalOperations )
1032     {
1033         out << "[Task] - "                  << currentOperation << "\n";
1034         out << "Name="                      << Operation[currentOperation] -> GetName() << "\n";
1035 
1036         out << "TypeDirContents="           << Operation[currentOperation] -> GetTypeDirContents() << "\n";
1037         out << "TypeDirName="               << Operation[currentOperation] -> GetTypeDirName() << "\n";
1038         out << "TypeSync="                  << Operation[currentOperation] -> GetTypeSync() << "\n";
1039 
1040         out << "Source="                    << Operation[currentOperation] -> GetSource() << "\n";
1041         out << "Destination="               << Operation[currentOperation] -> GetDestination() << "\n";
1042 
1043         out << "LastExecutionTime="         << Operation[currentOperation] -> GetLastExecutionTime().toString("yyyyMMddhhmmss") << "\n";
1044         out << "LastExecutionErrors="       << Operation[currentOperation] -> GetLastExecutionErrors() << "\n";
1045 
1046         if (Operation[currentOperation] -> GetDescription() != "")
1047         {
1048             QStringList DescriptionLines = Operation[currentOperation] -> GetDescription().split("\n");
1049             for (count=0; count<DescriptionLines.size();++count)
1050                 out << "TaskDescription="   << DescriptionLines.at(count) << "\n";	//output the task description
1051         }
1052 
1053         QStringList TaskArgs = Operation[currentOperation] -> GetArgs();
1054         for (count = 0; count < TaskArgs.size(); ++count)
1055             out << "Args=" << TaskArgs.at(count) << "\n";
1056 
1057         out << "ConnectRestore="            << Operation[currentOperation] -> GetConnectRestore() << "\n";
1058 
1059         out << "KeepSnapshots="             << Operation[currentOperation] -> GetKeepSnapshots() << "\n";
1060         count = 0;
1061         while ( count < (Operation[currentOperation] -> GetSnapshotsListSize()) )
1062         {
1063             out << "SnapshotsListItem="     << Operation[currentOperation] -> GetSnapshotsListItem(count) << "\n";
1064             count++;
1065         }
1066 
1067         out << "Exclude="                   << Operation[currentOperation] -> GetExclude() << "\n";
1068         out << "ExcludeFromFile="           << Operation[currentOperation] -> GetExcludeFromFile() << "\n";
1069         out << "ExcludeFile="               << Operation[currentOperation] -> GetExcludeFile() << "\n";
1070         out << "ExcludeTemp="               << Operation[currentOperation] -> GetExcludeTemp() << "\n";
1071         out << "ExcludeCache="              << Operation[currentOperation] -> GetExcludeCache() << "\n";
1072         out << "ExcludeBackup="             << Operation[currentOperation] -> GetExcludeBackup() << "\n";
1073         out << "ExcludeMount="              << Operation[currentOperation] -> GetExcludeMount() << "\n";
1074         out << "ExcludeLostFound="          << Operation[currentOperation] -> GetExcludeLostFound() << "\n";
1075         out << "ExcludeSystem="             << Operation[currentOperation] -> GetExcludeSystem() << "\n";
1076         out << "ExcludeTrash="              << Operation[currentOperation] -> GetExcludeTrash() << "\n";
1077         out << "ExcludeGVFS="               << Operation[currentOperation] -> GetExcludeGVFS() << "\n";
1078         count = 0;
1079         while ( count < (Operation[currentOperation] -> GetExcludeListSize()) )
1080         {
1081             out << "ExcludeListItem="       << Operation[currentOperation] -> GetExcludeListItem(count) << "\n";
1082             count++;
1083         }
1084 
1085         out << "Include="                   << Operation[currentOperation] -> GetInclude() << "\n";
1086         out << "IncludeFromFile="           << Operation[currentOperation] -> GetIncludeFromFile() << "\n";
1087         out << "IncludeModeNormal="         << Operation[currentOperation] -> GetIncludeModeNormal() << "\n";
1088         out << "IncludeFile="               << Operation[currentOperation] -> GetIncludeFile() << "\n";
1089         count = 0;
1090         while ( count < (Operation[currentOperation] -> GetIncludeListSize()) )
1091         {
1092             out << "IncludeListItem="       << Operation[currentOperation] -> GetIncludeListItem(count) << "\n";
1093             count++;
1094         }
1095 
1096         out << "Remote="                    << Operation[currentOperation] -> GetRemote() << "\n";
1097         out << "RemoteModule="              << Operation[currentOperation] -> GetRemoteModule() << "\n";
1098         out << "RemoteDestination="         << Operation[currentOperation] -> GetRemoteDestination() << "\n";
1099         out << "RemoteSource="              << Operation[currentOperation] -> GetRemoteSource() << "\n";
1100         out << "RemoteSSH="                 << Operation[currentOperation] -> GetRemoteSSH() << "\n";
1101         out << "RemoteHost="                << Operation[currentOperation] -> GetRemoteHost() << "\n";
1102         out << "RemoteUser="                << Operation[currentOperation] -> GetRemoteUser() << "\n";
1103         out << "RemotePassword="            << Operation[currentOperation] -> GetRemotePassword() << "\n";
1104         out << "RemoteSSHPassword="         << Operation[currentOperation] -> GetRemoteSSHPassword() << "\n";
1105         out << "RemoteSSHPasswordStr="      << Operation[currentOperation] -> GetRemoteSSHPasswordStr() << "\n";
1106         out << "RemoteSSHOptions="          << Operation[currentOperation] -> GetRemoteSSHOptions() << "\n";
1107         out << "RemoteSSHPort="             << Operation[currentOperation] -> GetRemoteSSHPort() << "\n";
1108 
1109         out << "OptionsUpdate="             << Operation[currentOperation] -> GetOptionsUpdate() << "\n";
1110         out << "OptionsDelete="             << Operation[currentOperation] -> GetOptionsDelete() << "\n";
1111         out << "OptionsRecurse="            << Operation[currentOperation] -> GetOptionsRecurse() << "\n";
1112         out << "OptionsOwnership="          << Operation[currentOperation] -> GetOptionsOwnership() << "\n";
1113         out << "OptionsSymlinks="           << Operation[currentOperation] -> GetOptionsSymlinks() << "\n";
1114         out << "OptionsPermissions="        << Operation[currentOperation] -> GetOptionsPermissions() << "\n";
1115         out << "OptionsDevices="            << Operation[currentOperation] -> GetOptionsDevices() << "\n";
1116         out << "OptionsCVS="                << Operation[currentOperation] -> GetOptionsCVS() << "\n";
1117         out << "OptionsHardLinks="          << Operation[currentOperation] -> GetOptionsHardLinks() << "\n";
1118         out << "OptionsFATntfs="            << Operation[currentOperation] -> GetOptionsFATntfs() << "\n";
1119         out << "OptionsSuper="              << Operation[currentOperation] -> GetOptionsSuper() << "\n";
1120         out << "OptionsNumericIDs="         << Operation[currentOperation] -> GetOptionsNumericIDs() << "\n";
1121 
1122         out << "OptionsRestorent="          << Operation[currentOperation] -> GetOptionsRestorent() << "\n";
1123         out << "OptionsVss="                << Operation[currentOperation] -> GetOptionsVss() << "\n";
1124 
1125         out << "LuckyBackupDir="            << Operation[currentOperation] -> GetLuckyBackupDir() << "\n";
1126         out << "VshadowDir="                << Operation[currentOperation] -> GetVshadowDir() << "\n";
1127         out << "RsyncCommand="              << Operation[currentOperation] -> GetRsyncCommand() << "\n";
1128         out << "SshCommand="                << Operation[currentOperation] -> GetSshCommand() << "\n";
1129         out << "DosdevCommand="             << Operation[currentOperation] -> GetDosdevCommand() << "\n";
1130         out << "CygpathCommand="            << Operation[currentOperation] -> GetCygpathCommand() << "\n";
1131         out << "TempPath="                  << Operation[currentOperation] -> GetTempPath() << "\n";
1132 
1133         count = 0;
1134         while ( count < (Operation[currentOperation] -> GetOptionsListSize()) )
1135         {
1136             out << "OptionsListItem="       << Operation[currentOperation] -> GetOptionsListItem(count) << "\n";
1137             count++;
1138         }
1139         count = 0;
1140         while ( count < (Operation[currentOperation] -> GetExecuteBeforeListSize()) )
1141         {
1142             out << "ExecuteBeforeListItem=" << Operation[currentOperation] -> GetExecuteBeforeListItem(count) << "\n";
1143             out << "ExecuteBeforeListItemState=" << Operation[currentOperation] -> GetExecuteBeforeListItemState(count) << "\n";
1144             count++;
1145         }
1146         count = 0;
1147         while ( count < (Operation[currentOperation] -> GetExecuteAfterListSize()) )
1148         {
1149             out << "ExecuteAfterListItem="  << Operation[currentOperation] -> GetExecuteAfterListItem(count) << "\n";
1150             out << "ExecuteAfterListItemState=" << Operation[currentOperation] -> GetExecuteAfterListItemState(count) << "\n";
1151             count++;
1152         }
1153         out << "ByPassWarning="             << Operation[currentOperation] -> GetByPassWARNING() << "\n";
1154         out << "CloneWarning="              << Operation[currentOperation] -> GetCloneWARNING() << "\n";
1155         out << "RepeatOnFail="              << Operation[currentOperation] -> GetRepeatOnFail() << "\n";
1156         //export include state
1157         out << "IncludeState="              << Operation[currentOperation] -> GetIncluded() << "\n";
1158 
1159         out << "[Task_end] - "              << currentOperation <<  "\n\n";
1160         currentOperation++;
1161     }
1162     out << "\n[profile end]" << "\n";
1163 
1164     profile.close();
1165     return true;
1166 }
1167 
1168 
1169 // exportFullProfile ====================================================================================================================================
1170 //function to export the .profile file + logs + snaps to a location
exportFullProfile(QString ExportPath,QString exportType)1171 bool exportFullProfile(QString ExportPath, QString exportType)
1172 {
1173     //we will export everything by using an rsync command
1174     QProcess *exportProcess;    exportProcess  = new QProcess;      QStringList exportArgs;
1175     exportArgs  << "-t" << "-r" << "--delete-after" << "--delete-excluded";      // standard rsync args
1176 
1177     if (exportType == "ExportOnlyTask")           // Only include the .profile file and logs and snaps for a specific task
1178         exportArgs << "--include=" + profileName + ".profile" << "--include=/*/" + profileName + "-" + Operation[currentOperation] -> GetName() +"-*";
1179     else                                    // Include the .profile file and all logs & snaps related to that
1180         exportArgs << "--include=/*/" + profileName +"*";
1181 
1182     exportArgs << "--include=*/" << "--exclude=*" << "--prune-empty-dirs";  // "only include" rsync args
1183 
1184     //also add all remote arguments exactly as used at normal backup
1185     if (exportType == "ExportOnlyTask")
1186     {
1187         if ((Operation[currentOperation] -> GetRemoteDestination()) && (Operation[currentOperation] -> GetRemote()))
1188         {
1189             exportArgs << "--protect-args";
1190             //if ( Operation[currentOperation] -> GetRemotePassword() != "")
1191             if ( (Operation[currentOperation]-> GetRemoteModule()) && (Operation[currentOperation] -> GetRemotePassword() != "") )
1192                 exportArgs.append("--password-file=" + ( Operation[currentOperation] -> GetRemotePassword()) );
1193             if ( Operation[currentOperation] -> GetRemoteSSH())
1194             {
1195                 QString sshOptions=(Operation[currentOperation] -> GetRemoteSSHOptions()).replace("\"","\\\"")+" -o \"StrictHostKeyChecking no\"  -o \"PasswordAuthentication no\" ";
1196                 if (WINrunning)
1197                 {
1198                     if ( Operation[currentOperation] -> GetRemoteSSHPassword() != "")
1199                         if ( Operation[currentOperation] -> GetRemoteSSHPort() != 0)
1200                             exportArgs.append("-e \""+Operation[currentOperation] -> GetSshCommand()+"\" "+sshOptions+" -i \"" +  Operation[currentOperation] -> GetRemoteSSHPassword() +"\" -p " +
1201                                         countStr.setNum( Operation[currentOperation] -> GetRemoteSSHPort()) );
1202                         else
1203                             exportArgs.append("-e \""+Operation[currentOperation] -> GetSshCommand()+"\" "+sshOptions+" -i \"" +  Operation[currentOperation] -> GetRemoteSSHPassword()+"\"");
1204                     else
1205                         if ( Operation[currentOperation] -> GetRemoteSSHPort() != 0)
1206                             exportArgs.append("-e \""+Operation[currentOperation] -> GetSshCommand()+"\" "+sshOptions+" -p " + countStr.setNum( Operation[currentOperation] -> GetRemoteSSHPort()) );
1207                         else
1208                             exportArgs.append("-e \""+Operation[currentOperation] -> GetSshCommand()+"\" "+sshOptions+"");
1209                 }
1210                 else
1211                 {
1212                     if ( Operation[currentOperation] -> GetRemoteSSHPassword() != "")
1213                         if ( Operation[currentOperation] -> GetRemoteSSHPort() != 0)
1214                             exportArgs.append("-e "+sshCommandPath+" -i " +  Operation[currentOperation] -> GetRemoteSSHPassword() +" -p " +
1215                                         countStr.setNum( Operation[currentOperation] -> GetRemoteSSHPort()) );
1216                         else
1217                             exportArgs.append("-e "+sshCommandPath+" -i " +  Operation[currentOperation] -> GetRemoteSSHPassword());
1218                     else
1219                         if ( Operation[currentOperation] -> GetRemoteSSHPort() != 0)
1220                             exportArgs.append("-e "+sshCommandPath+" -p " + countStr.setNum( Operation[currentOperation] -> GetRemoteSSHPort()) );
1221                         else
1222                             exportArgs.append("-e "+sshCommandPath);
1223                 }
1224             }
1225         }
1226     }
1227 
1228     exportArgs.append(luckyBackupDir);      // The source is ~/.luckyBackup/
1229 
1230     //cycnet debemos comprobar que es windows y el destino es remoto
1231     if (WINrunning && (Operation[currentOperation] -> GetRemoteDestination()) && (Operation[currentOperation] -> GetRemote()))
1232         ExportPath.replace(SLASH,XnixSLASH);
1233 
1234     exportArgs.append(ExportPath);          // The destination is given by the user
1235 
1236     //cycnet code. Windows use
1237     if (WINrunning)
1238     {
1239         //bool createWinRsyncCommand(tempDirPath,QFile command1,QFile command2,bool vss,QString rsyncArgs,QString source,QString dest);
1240         QString command2=createWinRsyncCommand(Operation[currentOperation] -> GetTempPath(),false,exportArgs,false);
1241         if (command2=="")
1242             cout << "\nfailed to create bat file in rmProccess";
1243         else
1244             exportProcess -> start (command2);
1245     }
1246     else
1247       exportProcess -> start (rsyncCommandPath,exportArgs);
1248 
1249     exportProcess -> waitForFinished();
1250 
1251     if (!(exportProcess -> exitCode() == 0))
1252         return false;
1253 
1254     return true;
1255 }
1256 
1257 // importFullProfile ====================================================================================================================================
1258 //function to import the .profile file + logs + snaps from a location to ~/.luckyBackup with the profilename given
importFullProfile(QString ImportPath,QString newProfileName)1259 int importFullProfile(QString ImportPath,QString newProfileName)
1260 {
1261     int returnThis = 0;
1262     QString PathProfileName = ImportPath;
1263     PathProfileName = PathProfileName.right(PathProfileName.size() - PathProfileName.lastIndexOf(SLASH) - 1);
1264     if (PathProfileName.endsWith(".profile"))
1265         PathProfileName.chop(8);
1266 
1267     // copy everything from the importFullProfile to ~/.luckyBackupDir
1268     QDir dirToCopy;     QStringList dirToCopyContents;  QFile fileToCopy;   QList<QString>::iterator count;
1269 
1270     // import all .profile files from ImportPath/profiles
1271     dirToCopy.setPath(ImportPath + SLASH + "profiles");
1272     dirToCopyContents = dirToCopy.entryList(QStringList("*.profile"),QDir::Files, QDir::NoSort);
1273 
1274     if (dirToCopyContents.size() == 0)
1275         return 1;
1276     for (count = dirToCopyContents.begin(); count != dirToCopyContents.end(); ++count)
1277     {
1278         QString oldFileNamePart = *count;
1279         oldFileNamePart = oldFileNamePart.right(oldFileNamePart.size() - oldFileNamePart.lastIndexOf(SLASH) - 1);
1280         oldFileNamePart.chop(8);
1281         oldFileNamePart.remove(0,PathProfileName.size());
1282 
1283         fileToCopy.setFileName(ImportPath + SLASH + "profiles" +SLASH +*count);
1284         if ((!fileToCopy.copy(profileDir + newProfileName + oldFileNamePart + ".profile")) && (returnThis < 1))
1285             return 1;
1286     }
1287 
1288     // import all .log files from ImportPath/logs
1289     dirToCopy.setPath(ImportPath + SLASH + "logs");
1290     dirToCopyContents = dirToCopy.entryList(QStringList("*.log"),QDir::Files, QDir::NoSort);
1291 
1292     for (count = dirToCopyContents.begin(); count != dirToCopyContents.end(); ++count)
1293     {
1294         QString oldFileNamePart = *count;
1295         oldFileNamePart = oldFileNamePart.right(oldFileNamePart.size() - oldFileNamePart.lastIndexOf(SLASH) - 1);
1296         oldFileNamePart.chop(4);
1297         oldFileNamePart.remove(0,PathProfileName.size());
1298 
1299         // TESTING
1300         //QMessageBox::information(0, "LB","source= " +ImportPath + SLASH + "logs" +SLASH + *count + "<br><br>dest: " + logDir + newProfileName + oldFileNamePart + ".log<br><br>oldFileNamePar= "+oldFileNamePart);
1301 
1302         fileToCopy.setFileName(ImportPath + SLASH + "logs" +SLASH +*count);
1303         if ((!fileToCopy.copy(logDir + newProfileName + oldFileNamePart + ".log")) && (returnThis < 10))
1304             returnThis=returnThis+10;
1305     }
1306 
1307     // import all changes.log files from ImportPath/snaps
1308     dirToCopy.setPath(ImportPath + SLASH + "snaps");
1309     dirToCopyContents = dirToCopy.entryList(QStringList("*.changes.log"),QDir::Files, QDir::NoSort);
1310 
1311     for (count = dirToCopyContents.begin(); count != dirToCopyContents.end(); ++count)
1312     {
1313         QString oldFileNamePart = *count;
1314         oldFileNamePart = oldFileNamePart.right(oldFileNamePart.size() - oldFileNamePart.lastIndexOf(SLASH) - 1);
1315         oldFileNamePart.chop(12);
1316         oldFileNamePart.remove(0,PathProfileName.size());
1317 
1318         fileToCopy.setFileName(ImportPath + SLASH + "snaps" +SLASH +*count);
1319         if ((!fileToCopy.copy(snapChangesDir + newProfileName + oldFileNamePart + ".changes.log")) && (returnThis < 20))
1320             returnThis=returnThis+20;
1321     }
1322 
1323     return returnThis;
1324 }
1325 
1326 // checkTaskList =====================================================================================================================================
1327 // Checks if the Task list is ok to proceed
checkTaskList()1328 bool checkTaskList()
1329 {
1330     int count;
1331     QString tempConnect="";
1332     message="";
1333     messageCLI="";
1334     ask = false;
1335     NothingIncluded=true;
1336 
1337     if (TotalOperations==0)						//check if the operations list is empty ------------------------------
1338     {
1339         message.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br><b>" +
1340                 QObject::tr("The task list is empty")+" !!</b><br>..."+
1341             QObject::tr("nothing to start"));
1342         messageCLI.append("\nThe task list is empty !!\n"
1343             "nothing to start !!\n\n");
1344         ask = true;
1345         return false;
1346     }
1347 
1348     //first check if 2 connected operations have been selected for execution--------------------------------------------------------------
1349     //set NothingInluded to false if 1 or more operation is included
1350     bool askTemp = false;	QString dirNames="";	QString dirNamesCLI="";	currentOperation=0;
1351     while  (currentOperation < TotalOperations)
1352     {
1353         if (Operation[currentOperation] -> GetIncluded())	//if the operations is "included"
1354         {
1355             NothingIncluded = false;
1356 
1357             tempConnect = Operation[currentOperation] -> GetConnectRestore();
1358             if (tempConnect != "")							//if it is connected to another operation
1359             {
1360                 count = currentOperation+1;
1361                 while (count < TotalOperations)
1362                 {
1363                     if  ( (Operation[count]->GetName() == tempConnect)	//if 2 connected operations are both included
1364                     && (Operation[count] -> GetIncluded()) )
1365                     {
1366                         dirNames.append("* " + Operation[currentOperation]->GetName() + "<br>* " + tempConnect + "<br>");
1367                         dirNamesCLI.append(Operation[currentOperation]->GetName() + "\n" + tempConnect + "\n\n");
1368                         askTemp = true; ask=true;
1369                         break;
1370                     }
1371                     count++;
1372                 }
1373             }
1374         }
1375         currentOperation++;
1376     }
1377     if (askTemp)
1378     {
1379         message.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>" +
1380                 QObject::tr("You have included both of the following connected tasks:")+"<b><br>" + dirNames +
1381                 "</b>" + QObject::tr("this is not allowed for obvious reasons")+" !!<br>"+
1382                 QObject::tr("Please <b>uncheck appropriate include boxes</b> before proceeding")+"... <br>");
1383         messageCLI.append("\nYou have included both of the following connected tasks:\n" + QString(dirNamesCLI.toUtf8()) +
1384                 "this is not allowed for obvious reasons !!\n"
1385                 "Please uncheck appropriate include boxes before proceeding...\n\n");
1386     }
1387 
1388     if ( (NothingIncluded) && (TotalOperations!=0) )		//if no checkboxes are selected show this message ---------------------
1389     {
1390         message.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br><b>"+
1391             QObject::tr("You have not included any tasks")+" !!</b><br>"
1392             "..." + QObject::tr("nothing to start"));
1393         messageCLI.append("\nYou have not included any tasks !!\n\n"
1394             "nothing to start !!\n\n");
1395         ask = true;
1396         return false;
1397     }
1398 
1399     //check if 2 or more identical destination directories are decleared & "Backup dir contents" is checked -------------------------------
1400     currentOperation=0;	askTemp = false;	dirNames="";	dirNamesCLI="";
1401     QString dest1="", dest2="";
1402     //the following loop compares an included operation (currentoperation) with all the other included
1403     //to check if they share the same destination
1404     while  (currentOperation < TotalOperations)
1405     {
1406         dest1 = Operation[currentOperation] -> GetDestination();
1407         if (dest1.endsWith(SLASH)) dest1.chop(1);
1408         if (WINrunning && dest1.endsWith(XnixSLASH)) dest1.chop(1);
1409 
1410         if (Operation[currentOperation] -> GetIncluded())
1411         {
1412             count = 0;
1413             while (count < TotalOperations)
1414             {
1415                 if (count == currentOperation) count++;
1416                 else
1417                 {
1418                     dest2 = Operation[count] -> GetDestination();
1419                     if (dest2.endsWith(SLASH)) dest2.chop(1);
1420                     if (WINrunning && dest2.endsWith(XnixSLASH))  dest2.chop(1);
1421 
1422                 //if this operation's destination is identical to another one's which is included and is of type 'Backup dir contents'
1423                     if ( (Operation[count] -> GetIncluded())
1424                     && ( dest1 == dest2 )
1425                     && ( ((Operation[count] -> GetTypeDirContents()) && (!Operation[count] -> GetInclude())) ||
1426                     ((Operation[currentOperation] -> GetTypeDirContents()) && (!Operation[currentOperation] -> GetInclude()))) )
1427                     {
1428                         dirNames.append("* " + Operation[currentOperation]->GetName() + "<br>");
1429                         dirNamesCLI.append(Operation[currentOperation]->GetName() + "\n");
1430                         askTemp = true; ask=true;
1431                         break;
1432                     }
1433                     count++;
1434                 }
1435             }
1436         }
1437         currentOperation++;
1438     }
1439     if (askTemp)
1440     {
1441         message.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>" +
1442                 QObject::tr("The following included tasks <b>share the same destination directory</b> (all together or at groups) and at least one of them will backup the contents of a directory")+" :<br><b>"
1443                 + dirNames +
1444                 "</b>" + QObject::tr("this will lead to one task canceling the other")+" !!<br>"+
1445                 QObject::tr("Please uncheck appropriate include boxes or change all task types to other than '<b>Backup dir contents</b>' "
1446                 " or use 'Backup dir contents' together with the '<b>Only include</b>' option, before proceeding")+"...");
1447 
1448         messageCLI.append("\nThe following included tasks share the same destination directory (all together or at groups) and at least one of them will backup the contents of a directory :\n"
1449                 + QString(dirNamesCLI.toUtf8()) +
1450                 "\nthis will lead to one task canceling the other !!\n"
1451                 "Please uncheck appropriate include boxes or change all task types to other than 'Backup dir contents'\n "
1452                 "or use 'Backup dir contents' together with the 'Only include' option, before proceeding...\n\n");
1453     }
1454 
1455     return true;
1456 }
1457 
1458 // checkDeclaredDirs =================================================================================================================================
1459 //Check if the declared data are ok by calling checkBackupDirs or checkSyncDirs
1460 //If guiExec is true this is called from the gui, otherwise from console
checkDeclaredDirs(bool guiExec)1461 bool checkDeclaredDirs(bool guiExec)
1462 {
1463     ask=false;
1464     NothingToDo = true;
1465 
1466     QString source, dest;
1467 
1468     currentOperation = 0;
1469     CheckedData = "";
1470     CheckedDataCLI = "";
1471     while (currentOperation < TotalOperations)
1472     {
1473         Operation[currentOperation] -> SetOK(false);
1474         Operation[currentOperation] -> SetWARNING(false);
1475         Operation[currentOperation] -> SetCRITICAL(false);
1476         Operation[currentOperation] -> SetSourcePerms(false);
1477         Operation[currentOperation] -> SetDestPerms(false);
1478         Operation[currentOperation] -> SetDestMounted(false);
1479         Operation[currentOperation] -> SetSourceMounted(false);
1480 
1481         if (Operation[currentOperation] -> GetIncluded())	//if the operations is "included"
1482         {
1483             //first set  variables source & dest as well as itsPerform which will finaly decide if the task will be preformed
1484             source = Operation[currentOperation] -> GetSource();
1485             dest = Operation[currentOperation] -> GetDestination();
1486 
1487             if (!guiExec)	//this is used for compatibility issues with console
1488             {
1489                 source=QString(source.toUtf8());
1490                 dest=QString(dest.toUtf8());
1491             }
1492 
1493             Operation[currentOperation] -> SetIncluded(true);
1494             Operation[currentOperation] -> SetPerform(true);	//this will change at the next commands
1495 
1496             if ( (Operation[currentOperation] -> GetTypeDirContents()) || (Operation[currentOperation] -> GetTypeDirName()) )
1497                 checkBackupDirs(source,dest);			//if the operation is of type "backup dir ...'
1498             if (Operation[currentOperation] -> GetTypeSync())	//if the operation is of type "sync dirs'
1499                 checkSyncDirs(source,dest);
1500         }
1501         else
1502         {
1503             Operation[currentOperation] -> SetIncluded(false);
1504             Operation[currentOperation] -> SetPerform(false);
1505         }
1506         currentOperation++;
1507     }
1508     return true;
1509 }
1510 
1511 //===================================================================================================================================================
1512 //Check if the directories to be synced are empty or don't exist
checkSyncDirs(QString source,QString dest)1513 void checkSyncDirs(QString source, QString dest)
1514 {
1515     Operation[currentOperation] -> SetOK(false);
1516     Operation[currentOperation] -> SetWARNING(false);
1517     Operation[currentOperation] -> SetCRITICAL(false);
1518     Operation[currentOperation] -> SetSourcePerms(false);
1519     Operation[currentOperation] -> SetDestPerms(false);
1520     Operation[currentOperation] -> SetDestMounted(false);
1521     Operation[currentOperation] -> SetSourceMounted(false);
1522 
1523     bool remoteSource = false;
1524     bool remoteDest = false;
1525 
1526     if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteSource()) )
1527     {
1528         if (Operation[currentOperation] -> GetRemoteModule())
1529             source.prepend(":");
1530         source.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
1531         if (Operation[currentOperation] -> GetRemoteUser()!="")
1532             source.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
1533         remoteSource = true;
1534     }
1535 
1536     if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteDestination()) )
1537     {
1538         if (Operation[currentOperation] -> GetRemoteModule())
1539             dest.prepend(":");
1540         dest.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
1541         if (Operation[currentOperation] -> GetRemoteUser()!="")
1542             dest.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
1543         remoteDest = true;
1544     }
1545 
1546     QFileInfo dirAFile(source);
1547     QFileInfo dirBFile(dest);
1548     QString currentOpNameCLI = QString((Operation[currentOperation] -> GetName())).toUtf8();
1549 
1550     //QString taskDescriptionCLI = QString((Operation[currentOperation] -> GetDescription())).toUtf8();
1551     QString taskDescription = Operation[currentOperation] -> GetDescription();
1552     taskDescription.replace("\n","<br>");
1553 
1554     //If user does not have sufficient permissions for the dirA or dirB, skip it
1555     if ( (dirAFile.exists()) && ((!dirAFile.isReadable()) || (!dirAFile.isExecutable())) && (!remoteSource) )
1556     {
1557         setTextMessages(source,dest,remoteSource,remoteDest, "warning","sync","source-perms");
1558 
1559         if (!Operation[currentOperation] -> GetByPassWARNING())
1560             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1561         else
1562             NothingToDo = false;
1563         Operation[currentOperation] -> SetSourcePerms(true);
1564         ask=true;	//ask the user if he/she wants to continue
1565         return;
1566     }
1567 
1568     if ( (dirBFile.exists()) && ((!dirBFile.isReadable()) || (!dirBFile.isExecutable())) && (!remoteDest) )
1569     {
1570         setTextMessages(source,dest,remoteSource,remoteDest,"warning","sync","dest-perms");
1571 
1572         ask=true;	//ask the user if he/she wants to continue
1573         if (!Operation[currentOperation] -> GetByPassWARNING())
1574             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1575         else
1576             NothingToDo = false;
1577         Operation[currentOperation] -> SetDestPerms(true);
1578         return;
1579     }
1580 
1581     QDir dirA (source);
1582     QDir dirB (dest);
1583 
1584     // WARNING The following 2 commands cause a "std::bad_alloc" crash when cloudfuse is used
1585     QStringList dirAList = dirA.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
1586     QStringList dirBList = dirB.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
1587     bool dirAIsEmpty, dirBIsEmpty;
1588     if (dirAList.size() == 0)
1589         dirAIsEmpty = true;
1590     else
1591         dirAIsEmpty = false;
1592     if (dirBList.size() == 0)
1593         dirBIsEmpty = true;
1594     else
1595         dirBIsEmpty = false;
1596 
1597     // Check if sync dirs A & B are under /media or /mnt and belong to a mountpoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1598     Operation[currentOperation] -> SetDestMounted(checkMountPoint(dest));
1599     Operation[currentOperation] -> SetSourceMounted(checkMountPoint(source));
1600 
1601     //Do directories exist and are not emty ??(skip remote)								->	[ Ok ]
1602     if ( ( ((dirA.exists())  && !(dirAIsEmpty)) || (remoteSource) )
1603     && (((dirB.exists()) && !(dirBIsEmpty)) ||(remoteDest) ) )
1604     {
1605         setTextMessages(source,dest,remoteSource,remoteDest,"okay","sync","okay");
1606 
1607         NothingToDo = false;
1608         Operation[currentOperation] -> SetOK(true);
1609     }
1610 
1611     //is one or both sync dirs non-existent ??									    ->	[ WARNING ]
1612     else if ( !(dirA.exists()) || !(dirB.exists()) )
1613     {
1614         setTextMessages(source,dest,remoteSource,remoteDest,"warning","sync","sync-not-exist");
1615 
1616         if (!Operation[currentOperation] -> GetByPassWARNING())
1617             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1618         else
1619             NothingToDo = false;
1620         Operation[currentOperation] -> SetWARNING(true);
1621         ask=true;
1622     }
1623 
1624     //Is one or both of the directories empty ??
1625     else
1626     {
1627         // if it is NOT mounted under /media or /mnt                                            ->  [ WARNING ]
1628         if ( (!Operation[currentOperation] -> GetDestMounted()) || (!Operation[currentOperation] -> GetSourceMounted()) )
1629         {
1630             setTextMessages(source,dest,remoteSource,remoteDest,"warning","sync","sync-not-mounted");
1631 
1632             if (!Operation[currentOperation] -> GetByPassWARNING())
1633                 Operation[currentOperation] -> SetPerform(false);   //don't perform this operation if the "bypass WARNING" OPTION is disabled
1634             else
1635                 NothingToDo = false;
1636             Operation[currentOperation] -> SetWARNING(true);
1637 
1638         }
1639         else                //                                                      ->  [ CRITICAL ]
1640         {
1641             setTextMessages(source,dest,remoteSource,remoteDest,"critical","sync","sync-empty");
1642 
1643             Operation[currentOperation] -> SetCRITICAL(true);
1644             if (SkipCritical)						// if a --skip-critical is given as argument
1645                 Operation[currentOperation] -> SetPerform(false);	//don't perform this operation
1646             else
1647                 NothingToDo = false;
1648         }
1649         ask=true;   //ask the user if he/she wants to continue
1650     }
1651 
1652 }
1653 
1654 //===================================================================================================================================================
1655 //Check if the source and destination backup directories are empty or don't exist
checkBackupDirs(QString source,QString dest)1656 void checkBackupDirs(QString source, QString dest)
1657 {
1658     Operation[currentOperation] -> SetOK(false);
1659     Operation[currentOperation] -> SetWARNING(false);
1660     Operation[currentOperation] -> SetCRITICAL(false);
1661     Operation[currentOperation] -> SetSourcePerms(false);
1662     Operation[currentOperation] -> SetDestPerms(false);
1663     Operation[currentOperation] -> SetDestMounted(false);
1664     Operation[currentOperation] -> SetSourceMounted(false);
1665 
1666     bool remoteSource = false;
1667     bool remoteDest = false;
1668 
1669     //first check if a remote source or dest is used so that to skip checks
1670     if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteSource()) )
1671     {
1672         if (Operation[currentOperation] -> GetRemoteModule())
1673             source.prepend(":");
1674         source.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
1675         if (Operation[currentOperation] -> GetRemoteUser()!="")
1676             source.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
1677         remoteSource = true;
1678     }
1679     if ( (Operation[currentOperation] -> GetRemote()) && (Operation[currentOperation] -> GetRemoteDestination()) )
1680     {
1681         if (Operation[currentOperation] -> GetRemoteModule())
1682             dest.prepend(":");
1683         dest.prepend((Operation[currentOperation] -> GetRemoteHost())+":");
1684         if (Operation[currentOperation] -> GetRemoteUser()!="")
1685             dest.prepend((Operation[currentOperation] -> GetRemoteUser())+"@");
1686         remoteDest = true;
1687     }
1688 
1689     //If user does not have sufficient permissions for the source or dest, skip it
1690     QFileInfo destFile(dest);
1691     QFileInfo sourceFile(source);
1692 
1693     if ( (sourceFile.exists()) && ((!sourceFile.isReadable()) || (!sourceFile.isExecutable())) && (!remoteSource) )
1694     {
1695         setTextMessages(source,dest,remoteSource,remoteDest,"warning","backup","source-perms");
1696 
1697         if (!Operation[currentOperation] -> GetByPassWARNING())
1698             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1699         else
1700             NothingToDo = false;
1701 
1702         ask=true;	//ask the user if he/she wants to continue
1703         Operation[currentOperation] -> SetSourcePerms(true);
1704         return;
1705     }
1706 
1707     if ( (destFile.exists()) && ((!destFile.isReadable()) || (!destFile.isExecutable())) && (!remoteDest) )
1708     {
1709         setTextMessages(source,dest,remoteSource,remoteDest,"warning","backup","dest-perms");
1710 
1711         if (!Operation[currentOperation] -> GetByPassWARNING())
1712             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1713         else
1714             NothingToDo = false;
1715         ask=true;	//ask the user if he/she wants to continue
1716         Operation[currentOperation] -> SetDestPerms(true);
1717         return;
1718     }
1719 
1720     QDir sourceDir (source);
1721     QDir destDir (dest);
1722 
1723     // WARNING The following 2 commands cause a "std::bad_alloc" crash when cloudfuse is used
1724     QStringList sourceList = sourceDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
1725     QStringList destList = destDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
1726 
1727     bool SourceIsEmpty, DestIsEmpty;
1728     if (sourceList.size() == 0)
1729         SourceIsEmpty = true;
1730     else
1731         SourceIsEmpty = false;
1732     if (destList.size() == 0)
1733         DestIsEmpty = true;
1734     else
1735         DestIsEmpty = false;
1736 
1737     // Check if source & dest are under /media or /mnt and belong to a mountpoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1738     Operation[currentOperation] -> SetDestMounted(checkMountPoint(dest));
1739     Operation[currentOperation] -> SetSourceMounted(checkMountPoint(source));
1740 
1741     //Does the source directory exist and it is not empty OR we're using remote source??
1742     if  ( ((sourceDir.exists())  && !(SourceIsEmpty)) || (remoteSource) )
1743     {
1744         //Does the destination directory exist and it is not empty ?? 								->	[ Ok ]
1745         if ( ((destDir.exists())  && !(DestIsEmpty)) || (remoteDest) )
1746         {
1747             setTextMessages(source,dest,remoteSource,remoteDest,"okay","backup","okay");
1748 
1749             Operation[currentOperation] -> SetOK(true);
1750             NothingToDo = false;
1751         }
1752         else //The destination directory does not exist or it is empty
1753         {
1754             // A partition is NOT mounted under /media or /mnt                                     ->  [WARNING ]
1755             if (!Operation[currentOperation] -> GetDestMounted())
1756             {
1757                 setTextMessages(source,dest,remoteSource,remoteDest,"warning","backup","dest-not-mounted");
1758                 if (!Operation[currentOperation] -> GetByPassWARNING())
1759                     Operation[currentOperation] -> SetPerform(false);   //don't perform this operation if the "bypass WARNING" OPTION is disabled
1760                 else
1761                     NothingToDo = false;
1762                 Operation[currentOperation] -> SetWARNING(true);
1763                 ask=true;   //ask the user if he/she wants to continue
1764             }
1765             else    // partition is mounted                                                     ->  [ CRITICAL ]
1766             {
1767                 setTextMessages(source,dest,remoteSource,remoteDest,"critical","backup","dest-not-exist");
1768 
1769                 ask=true;	//ask the user if he/she wants to continue
1770 
1771                 Operation[currentOperation] -> SetCRITICAL(true);
1772 
1773                 if (SkipCritical)						// if a --skip-critical is given as argument
1774                     Operation[currentOperation] -> SetPerform(false);	//don't perform this operation
1775                 else
1776                     NothingToDo = false;
1777             }
1778         }
1779     }
1780     else //The source directory does not exist or it is empty								->	[WARNING ]
1781     {
1782         setTextMessages(source,dest,remoteSource,remoteDest,"warning","backup","source-not-exist");
1783 
1784         if (!Operation[currentOperation] -> GetByPassWARNING())
1785             Operation[currentOperation] -> SetPerform(false);	//don't perform this operation if the "bypass WARNING" OPTION is disabled
1786         else
1787             NothingToDo = false;
1788         Operation[currentOperation] -> SetWARNING(true);
1789         ask=true;	//ask the user if he/she wants to continue
1790     }
1791 
1792 }
1793 
1794 // /AppendArguments =======================================================================================================
1795 //function to append "arguments" object at a given operation according to the fields of the modify window
AppendArguments(operation * operationToAppend)1796 QStringList AppendArguments(operation *operationToAppend)
1797 {
1798     QStringList arguments; int count;
1799     int operationToAppendCurrentSnaps = operationToAppend -> GetSnapshotsListSize();	// this is the current number of snapshots
1800     int operationToAppendMaxSnaps = operationToAppend -> GetKeepSnapshots();		// this is the max number of snapshots to keep
1801 
1802     arguments << "-h" << "--progress" << "--stats";	//These are the standard arguments used by rsync
1803 
1804     //add rsync arguments	--------------------------------------------------------------------------------------------------
1805     if (operationToAppend -> GetOptionsRecurse())           arguments.append("-r");
1806     if (operationToAppend -> GetOptionsFATntfs())
1807     {
1808         arguments.append("-t");
1809         arguments.append("--modify-window=1");
1810     }
1811     else
1812     {
1813         if (operationToAppend -> GetOptionsOwnership())     arguments.append("-tgo");
1814         if ((!WINrunning) && (operationToAppend -> GetOptionsPermissions()))
1815                                                             arguments.append("-p");
1816         if ((WINrunning) && (operationToAppend -> GetOptionsPermissions()))       // Windows ONLY: Do not use -p but --backup-nt-streams and --source-filter-tmp=
1817         {
1818             arguments.append("--source-filter-tmp="+operationToAppend->GetTempPath());
1819             arguments.append("--backup-nt-streams");
1820         }
1821     }
1822     if (WINrunning)
1823     {
1824         /* disable vss until...
1825         if (operationToAppend -> GetOptionsVss())           arguments.append("--vss");                  // this option is only visbile at windows */
1826         if (operationToAppend -> GetOptionsRestorent())     arguments.append("--restore-nt-streams");   // this option is only visbile at windows
1827     }
1828     if (operationToAppend -> GetOptionsSymlinks())          arguments.append("-l");
1829     if (operationToAppend -> GetOptionsDevices())           arguments.append("-D");
1830     if (operationToAppend -> GetOptionsCVS())               arguments.append("-C");
1831     if (operationToAppend -> GetOptionsHardLinks())         arguments.append("-H");
1832     if (operationToAppend -> GetOptionsSuper())             arguments.append("--super");
1833     if (operationToAppend -> GetOptionsNumericIDs())        arguments.append("--numeric-ids");
1834     if (operationToAppend -> GetOptionsUpdate())            arguments.append("--update");
1835     if (operationToAppend -> GetOptionsDelete())            arguments.append("--delete-after");
1836     count =0;
1837     while ( count < (operationToAppend -> GetOptionsListSize()) )
1838     {
1839         arguments.append(operationToAppend -> GetOptionsListItem(count));
1840         count++;
1841     }
1842 
1843     bool disableExclude=false;
1844     //add included items------------------------------------------------------------------------------
1845     if (operationToAppend -> GetInclude())
1846     {
1847         // from file
1848         if ( (operationToAppend -> GetIncludeFromFile()) && !(operationToAppend -> GetIncludeFile()=="") )
1849             arguments.append("--include-from=" + (operationToAppend -> GetIncludeFile()) );
1850         // from "only include" tab
1851         count =0;
1852         while ( count < (operationToAppend -> GetIncludeListSize()) )
1853         {
1854             arguments.append("--include=" + (operationToAppend -> GetIncludeListItem(count)) );
1855             count++;
1856         }
1857         // if "Only Include" mode is used add the following
1858         if (!operationToAppend -> GetIncludeModeNormal())
1859         {
1860             arguments.append("--include=*/");
1861             arguments.append("--exclude=*");
1862             arguments.append("--prune-empty-dirs");
1863             disableExclude=true;
1864         }
1865     }
1866 
1867     //add excluded items (unless "only include" is used and the include list is not empty)--------------------------------------------------------------
1868     if ( (operationToAppend -> GetExclude()) && (!disableExclude) )
1869     {
1870         if (operationToAppend -> GetOptionsDelete())	arguments.append("--delete-excluded");
1871         if ( (operationToAppend -> GetExcludeFromFile()) && !(operationToAppend -> GetExcludeFile()=="") )
1872             arguments.append("--exclude-from=" + (operationToAppend -> GetExcludeFile()) );
1873         if (operationToAppend -> GetExcludeTemp())	arguments.append("--exclude=**/*tmp*/");
1874         if (operationToAppend -> GetExcludeCache()){	arguments.append("--exclude=**/*cache*/");
1875                                 arguments.append("--exclude=**/*Cache*/");}
1876         if (operationToAppend -> GetExcludeBackup())	arguments.append("--exclude=**~");
1877         if (operationToAppend -> GetExcludeMount()){	arguments.append("--exclude=/mnt/*/**");
1878                                 arguments.append("--exclude=/media/*/**");}
1879         if (operationToAppend -> GetExcludeLostFound())	arguments.append("--exclude=**/lost+found*/");
1880         if (operationToAppend -> GetExcludeSystem()){	arguments.append("--exclude=/var/run/**");
1881                                 arguments.append("--exclude=/run/**");
1882                                 arguments.append("--exclude=/proc/**");
1883                                 arguments.append("--exclude=/dev/**");
1884                                 arguments.append("--exclude=/sys/**");}
1885         if (operationToAppend -> GetExcludeTrash()){	arguments.append("--exclude=**/*Trash*/");
1886                                 arguments.append("--exclude=**/*trash*/");}
1887         if (operationToAppend -> GetExcludeGVFS()) {    arguments.append("--exclude=**/.gvfs/");}
1888 
1889         //also read the custom exclude list
1890         count =0;
1891         while ( count < (operationToAppend -> GetExcludeListSize()) )
1892         {
1893             arguments.append("--exclude=" + (operationToAppend -> GetExcludeListItem(count)) );
1894             count++;
1895         }
1896     }
1897 
1898     //set temp strings sourceString & destString accordingly if groupbox "remote" is checked--------------------------------------------
1899     //also add -e ssh if "ssh" is checked & --password-file=FILE
1900     // WARNING: if you change something here, also change it in executenow.cpp when removing older snapshopt data
1901     QString sourceString, destString, remoteHost = "";	//temp strings
1902     if (operationToAppend -> GetRemote())
1903     {
1904         //append --protect-args because trouble is caused with spaces
1905         arguments.append("--protect-args");
1906 
1907         if (operationToAppend -> GetRemoteUser() != "")	//append remote user@ if applicable to temp string
1908             remoteHost.append(operationToAppend -> GetRemoteUser() + "@");
1909 
1910         if (operationToAppend -> GetRemoteModule())	//append remote host: (or :: if it's a module) to temp string
1911         {
1912             remoteHost.append(operationToAppend -> GetRemoteHost() + "::");
1913             //add --password-file=FILE if password file lineEdit is not empty
1914             if (operationToAppend -> GetRemotePassword() != "")
1915                 arguments.append("--password-file=" + (operationToAppend -> GetRemotePassword()) );
1916         }
1917         else
1918             remoteHost.append(operationToAppend -> GetRemoteHost() + ":");
1919 
1920         if (operationToAppend -> GetRemoteDestination())	//set temp source & destination strings
1921         {
1922             remoteHost.append(operationToAppend -> GetDestination());
1923             destString = remoteHost;
1924 
1925             sourceString 	= operationToAppend -> GetSource();
1926             if (WINrunning)   // Bruce patch condition for winpaths~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1927             {
1928                 // Commented after Juan's patch
1929                 //destString = fixWinPathForRsync(destString, true);         //fix destination (which is remote)
1930                 //sourceString =  fixWinPathForRsync(sourceString, false);    //fix source (which is local)
1931             }
1932         }
1933         else
1934         {
1935             remoteHost.append(operationToAppend -> GetSource());
1936             sourceString = remoteHost;
1937 
1938             destString 	= operationToAppend -> GetDestination();
1939             if (WINrunning)   // Bruce patch condition for winpaths~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1940             {
1941                 // Commented after Juan's patch
1942                 //sourceString =  fixWinPathForRsync(sourceString, true);     //fix source (which is remote)
1943                 //destString = fixWinPathForRsync(destString, false);        //fix destination (which is local)
1944             }
1945         }
1946 
1947         //add argument for ssh if the checkbox is checked & ssh keyfile
1948         if (operationToAppend -> GetRemoteSSH())
1949         {
1950             QString sshOptions=(Operation[currentOperation] -> GetRemoteSSHOptions()).replace("\"","\\\"")+" -o \"StrictHostKeyChecking no\"  -o \"PasswordAuthentication no\" ";
1951             if (WINrunning)
1952             {
1953                 if (operationToAppend -> GetRemoteSSHPassword() != "")
1954                     if ( operationToAppend -> GetRemoteSSHPort() != 0 )
1955                         arguments.append("-e \""+operationToAppend -> GetSshCommand()+"\" "+sshOptions+" -i \"" +  operationToAppend -> GetRemoteSSHPassword() + "\" -p " + countStr.setNum( operationToAppend -> GetRemoteSSHPort()) );
1956                     else
1957                         arguments.append("-e \""+operationToAppend -> GetSshCommand()+"\" "+sshOptions+" -i \"" +  operationToAppend -> GetRemoteSSHPassword() + "\"");
1958                 else
1959                     if ( operationToAppend -> GetRemoteSSHPort() != 0 )
1960                         arguments.append("-e \""+operationToAppend -> GetSshCommand()+"\" "+sshOptions+" -p " + countStr.setNum( operationToAppend -> GetRemoteSSHPort()) );
1961                     else
1962                         arguments.append("-e \""+operationToAppend -> GetSshCommand()+"\" "+sshOptions+"");
1963             }
1964             else
1965             {
1966                 if (operationToAppend -> GetRemoteSSHPassword() != "")
1967                 {
1968                     //arguments.append("-e \"ssh -i " + uiM.lineEdit_sshPassword -> text() + "\"");
1969 
1970                     // NOTE:  character ' is not used in linux due to QT comptibility issues. It works just fine without it. It is added at the "validate" dialog though for real CLI command pasting purposes!!  NOTE
1971 
1972                     if (operationToAppend -> GetRemoteSSHPort() != 0)
1973                         arguments.append("-e "+sshCommandPath+" -i " + operationToAppend -> GetRemoteSSHPassword() + " -p " + countStr.setNum(operationToAppend -> GetRemoteSSHPort()) );
1974                     else
1975                         arguments.append("-e "+sshCommandPath+" -i " + operationToAppend -> GetRemoteSSHPassword());
1976                 }
1977                 else
1978                 {
1979                     if (operationToAppend -> GetRemoteSSHPort() != 0)
1980                         arguments.append("-e "+sshCommandPath+" -p " + countStr.setNum(operationToAppend -> GetRemoteSSHPort()) );
1981                     else
1982                         arguments.append("-e "+sshCommandPath);
1983                 }
1984             }
1985         }
1986     }
1987     else		//Operate locally----------------------------------------------------------------------------------------
1988     {
1989         sourceString    = operationToAppend -> GetSource();
1990         destString      = operationToAppend -> GetDestination();
1991 
1992         // Bruce patch condition for winpaths~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1993         // convert path to cygwin paths, change any \ to / :)
1994         if (WINrunning)
1995         {
1996             // Commented after Juan's patch
1997             //sourceString =  fixWinPathForRsync(sourceString, false);    //fix local source
1998             //destString =    fixWinPathForRsync(destString, false);      //fix local destination
1999         }
2000         // Bruce patch end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
2001     }
2002     //add snapshot arguments - do not perform this if the function is called when "validate" button pressed
2003     //perform this if more than 1 snapshot is already made
2004     if  ( (operationToAppendCurrentSnaps > 1) && (!validation) )
2005     {
2006         //fix source and dest for snapshots directory
2007         QString snapSource=sourceString;	QString snapDest=destString;	//temp variables
2008 
2009         //if ( (snapDest.contains(":")) && (!notXnixRunning))// this is normal for a remote directory (not for OS/2 or win: eg c:\)
2010         if ( ((snapDest.contains(":")) && (!notXnixRunning)) || (snapDest.contains(":") && WINrunning && operationToAppend -> GetRemote()) )// this is normal for a remote directory
2011         {
2012                 snapDest = snapDest.right(snapDest.size()-snapDest.lastIndexOf(":")-1);	//this is the remote dest dir without the remote pc
2013                 snapDest = "";
2014         }
2015 
2016         if (!snapSource.endsWith(SLASH))   // this means task is of type "backup dir by name"
2017         {
2018             QString sourceLast = snapSource;
2019             sourceLast = calculateLastPath(sourceLast); // This is the lowest dir of the source
2020 
2021             if (WINrunning && operationToAppend -> GetRemote())
2022                 sourceLast.append(XnixSLASH);
2023             else
2024                 sourceLast.append(SLASH);
2025 
2026             snapDest.append(sourceLast);
2027         }
2028 
2029         QString prevSnapDateTime = operationToAppend -> GetSnapshotsListItem(operationToAppendCurrentSnaps-2);
2030 
2031         QString prevSnapDir = snapDest + snapDefaultDir + prevSnapDateTime + SLASH; // This is where the deleted files (== previous snapshot) will go
2032         if (WINrunning)     // windows
2033             prevSnapDir.replace(SLASH,XnixSLASH);
2034         else if (notXnixRunning)    //OS2
2035             prevSnapDir.replace("/",SLASH);
2036 
2037         // add arguments to backup files to be be deleted inside the snapshot direcotry
2038         arguments.append("--backup");
2039         arguments.append("--backup-dir=" + prevSnapDir);
2040     }
2041 
2042     // protect the snapshots directories from being deleted. Do nothing for older snapshots dirs
2043     // This is outside the condition because the snapDefaultDir also contains the backup of the profile + logs + snaps
2044     if (!validation)
2045     {
2046         if (WINrunning)
2047             arguments.append("--filter=protect " + snapDefaultDir.replace(SLASH,XnixSLASH));
2048         else        // linux & OS2
2049             arguments.append("--filter=protect " + snapDefaultDir);
2050     }
2051 
2052     // keep snapshot changes files only for backup task types, not sync
2053     if ( (!validation) && (operationToAppendMaxSnaps > 1) )
2054     {
2055         //Define a file to log new files transfered so that to exclude these when restoring previous snapshots
2056         arguments.append("--log-file=" + snapchangesfilename);
2057         arguments.append("--log-file-format=" + snapChangesString);
2058     }
2059 
2060     //set source & destination according to sourceString & destString ---------------------------------------------------------
2061     arguments.append(sourceString);
2062     arguments.append(destString);
2063 
2064     return arguments;
2065 }
2066 
2067 // calculateLastPath =====================================================================================================================================
2068 // Calculates the last part of a path eg path=user@host:destination/path/here/ -> returns "here"
calculateLastPath(QString origPath)2069 QString calculateLastPath(QString origPath)
2070 {
2071     QString returnPATH = origPath;
2072 
2073     if ( returnPATH.contains(":") )   // this is a remote directory eg user@host:directory/path
2074         returnPATH = returnPATH.right(returnPATH.size()-returnPATH.lastIndexOf(":")-1); //this is the remote returnPATH dir without the remote pc ([user@]host:)
2075 
2076     if (returnPATH.endsWith(SLASH))
2077         returnPATH.chop(1);
2078 
2079     if (returnPATH.contains(SLASH)) // this is normal for a directory unless it is remote
2080         returnPATH = returnPATH.right(returnPATH.size()-returnPATH.lastIndexOf(SLASH)-1);   //this is the lowest dir of returnPATH
2081 
2082     return returnPATH;
2083 }
2084 // fixWinPathForRsync =====================================================================================================================================
2085 // Fixes a windows path for rsync use
fixWinPathForRsync(QString fixTHIS,bool remotePATH)2086 QString fixWinPathForRsync(QString fixTHIS, bool remotePATH)
2087 {
2088     QString returnPATH = fixTHIS;
2089     QChar drive = fixTHIS[0];
2090     drive = drive.toLower();        // This is the windows drive letter eg C ..as in C:\ :P
2091 
2092     if (remotePATH)
2093     {
2094         returnPATH = returnPATH.replace("\\","/");
2095         if (returnPATH.endsWith("//"))
2096             returnPATH.chop(1);
2097     }
2098     else
2099     {
2100         if (fixTHIS.startsWith("\\\\"))    // this is probably a remote share
2101             returnPATH = returnPATH.replace("\\","/");
2102         else
2103             returnPATH = returnPATH.replace(0,3,"/cygdrive/"+QString(drive)+"/").replace("\\","/");
2104     }
2105 
2106     return returnPATH;
2107 }
2108 
2109 // logFileUpdate =====================================================================================================================================
2110 // Updates the current logfile with some string
logFileUpdate(QString appendTYPE,QString appendTHIS,int currentPrePost)2111 QString logFileUpdate(QString appendTYPE, QString appendTHIS, int currentPrePost)
2112 {
2113     QTextStream out(&logfile);
2114     QString dirA = Operation[currentOperation] -> GetSource();
2115     QString dirB = Operation[currentOperation] -> GetDestination();
2116 
2117     if (appendTYPE == "pre-starting")
2118         appendTHIS = "\n<font color=magenta>" +
2119             QObject::tr("pre-task execution of command","Full phrase: pre-task execution of command: <COMMAND> starting")+
2120             "	: <b>" + Operation[currentOperation] -> GetExecuteBeforeListItem(currentPrePost) +
2121             "</b>, "+ QObject::tr("starting","Full phrase: pre-task execution of command: <COMMAND> starting")+"</font>\n";
2122 
2123     if (appendTYPE == "repeat-on-fail")
2124         appendTHIS = "\n<font color=cyan>&nbsp;&nbsp;&nbsp;&nbsp;-----| " +
2125             QObject::tr("Command re-run due to failure","This means that a specific command is run for once more because it failed the first time")+
2126                     " |-----</font>\n";
2127 
2128     if (appendTYPE == "post-starting")
2129         appendTHIS = "\n<font color=magenta>" +
2130             QObject::tr("post-task execution of command","Full phrase: post-task execution of command: <COMMAND> starting")+
2131             "	: <b>" + Operation[currentOperation] -> GetExecuteAfterListItem(currentPrePost) +
2132             "</b>, "+QObject::tr("starting","Full phrase: post-task execution of command: <COMMAND> starting")+"</font>\n";
2133 
2134     if (appendTYPE == "rsync-starting-backup")
2135         appendTHIS = "\n=====================================<br><font color=magenta>" +
2136                 QObject::tr("execution of task","Full phrase: execution of task: <TASKNAME> starting")+
2137                 "	: <b>" + Operation[currentOperation] -> GetName() +
2138                 "</b>, "+QObject::tr("starting","Full phrase: execution of task: <TASKNAME> starting")+"</font><br>"+
2139                 QObject::tr("Source","Full phrase: source: <SOURCE_NAME")+"	: <b><font color=blue>" + dirA +
2140                 "</font></b><br>"+QObject::tr("Destination","Full phrase: Destination: <DEST_NAME")+
2141                 "	: <b><font color=blue>" + dirB + "</font></b>\n";
2142 
2143     if (appendTYPE == "rsync-starting-syncAB")
2144         appendTHIS = "\n=====================================<br><font color=magenta>" +
2145                 QObject::tr("execution of 1st part of task","Full phrase: execution of 1st part of task: <TASKNAME> starting")+
2146                 "	: <b>" + Operation[currentOperation] -> GetName() +
2147                 "</b>, "+QObject::tr("starting","Full phrase: execution of 1st part of task: <TASKNAME> starting")+"</font><br>"+
2148                 QObject::tr("Syncing","Full phrase: Syncing <DIR-A> to <DIR-B>")+"	: <b><font color=blue>" + dirA +
2149                 "</font></b><br>"+QObject::tr("to","Full phrase: Syncing <DIR-A> to <DIR-B>")+
2150                 "	: <b><font color=blue>" + dirB + "</font></b>\n";
2151 
2152     if (appendTYPE == "rsync-starting-syncBA")
2153         appendTHIS = "\n=====================================<br><font color=magenta>" +
2154                 QObject::tr("execution of 2nd part of task","Full phrase: execution of 2nd part of task: <TASKNAME> starting")+
2155                 "	: <b>" + Operation[currentOperation] -> GetName() +
2156                 "</b>, "+QObject::tr("starting","Full phrase: execution of 2nd part of task: <TASKNAME> starting")+"</font><br>"+
2157                 QObject::tr("Syncing","Full phrase: Syncing <DIR-B> to <DIR-A>")+"	: <b><font color=blue>" + dirB +
2158                 "</font></b><br>"+QObject::tr("to","Full phrase: Syncing <DIR-B> to <DIR-A>")+"	: <b><font color=blue>" + dirA + "</font></b>\n";
2159 
2160     if (appendTYPE == "pre-finished")
2161         appendTHIS = "\n<font color=magenta>" +
2162             QObject::tr("pre-task execution of command","Full phrase: pre-task execution of COMMAND: <COMMANDNAME> finished")+
2163             "	: <b>" + Operation[currentOperation] -> GetExecuteBeforeListItem(currentPrePost) +
2164             "</b>, "+QObject::tr("finished","Full phrase: pre-task execution of COMMAND: <COMMANDNAME> finished")+"</font>\n";
2165 
2166     if (appendTYPE == "post-finished")
2167         appendTHIS = "\n<font color=magenta>" +
2168             QObject::tr("post-task execution of command","Full phrase: post-task execution of COMMAND: <COMMANDNAME> finished")+
2169             "	: <b>" + Operation[currentOperation] -> GetExecuteAfterListItem(currentPrePost) +
2170             "</b>, "+QObject::tr("finished","Full phrase: post-task execution of COMMAND: <COMMANDNAME> finished")+"</font><br>";
2171 
2172     if (appendTYPE == "rsync-finished-sync1")
2173         appendTHIS = "\n<font color=magenta>" +
2174                 QObject::tr("execution of 1st part of task","Full phrase: execution of 1st part of task: <TASKNAME> finished")+
2175                 "	: <b>" + Operation[currentOperation] -> GetName() +
2176                 "</b>, "+QObject::tr("finished","Full phrase: execution of 1st part of task: <TASKNAME> finished") +
2177                 "</font><br>=====================================<br>";
2178 
2179     if (appendTYPE == "rsync-finished")
2180         appendTHIS = "\n<font color=magenta>" +
2181                 QObject::tr("execution of task","Full phrase: execution of task: <TASKNAME> finished")+
2182                 "	: <b>" + Operation[currentOperation] -> GetName() +
2183                 "</b>, "+QObject::tr("finished","Full phrase: execution of task: <TASKNAME> finished") +
2184                 "</font>\n=====================================<br>";
2185 
2186     if (appendTYPE == "pre-task-exited-with-error")
2187         appendTHIS = "\n<font color=magenta>" +
2188                 QObject::tr("execution of task","Full phrase: execution of task: <TASKNAME> finished because of pre/post task command execution error")+
2189                 "	: <b>" + Operation[currentOperation] -> GetName() +
2190                 "</b>, "+QObject::tr("finished because of pre/post task command execution error",
2191                             "Full phrase: execution of task: <TASKNAME> finished because of pre/post task command execution error") +
2192                 "</font>\n=====================================<br>";
2193 
2194     if (appendTYPE == "process-reported-error")
2195         appendTHIS = "<a name=\"error" + countStr.setNum(errorsFound) + "\"></a><font color=red>" + QObject::tr("The process reported an error") + ": \"" +
2196                         appendTHIS + "\"</font>\n";
2197 
2198     if (appendTYPE == "rsync-standard")
2199         appendTHIS = appendTHIS + "\n";
2200 
2201     if (appendTYPE == "rsync-error")
2202         appendTHIS = "<a name=\"error" + countStr.setNum(errorsFound) + "\"></a><font color=red>" + appendTHIS + "</font>\n";
2203 
2204     if (appendTYPE == "backup-profile")
2205         appendTHIS = "\n<font color=cyan>&nbsp;&nbsp;&nbsp;&nbsp;-----| " +
2206             QObject::tr("Backing-up profile, logfiles and snapshot data") + appendTHIS + " |-----</font><br>";
2207 
2208     if (writeToLog)
2209     {
2210         if (console)	//this is used for console compatibility with utf-8
2211             appendTHIS = QString(appendTHIS.toUtf8());
2212         out << appendTHIS;
2213     }
2214 
2215     return appendTHIS;
2216 }
2217 
2218 // checkMountPoint =====================================================================================================================================
2219 // Checks if the given path belongs to a mountpoint structure under /media or /mnt
2220 // Will also return true for every path that does not start with /media or /mnt
checkMountPoint(QString dirPath)2221 bool checkMountPoint(QString dirPath)
2222 {
2223     bool returnTHISplease = true;
2224 
2225     if ( (dirPath.startsWith ("/media", Qt::CaseSensitive )) || (dirPath.startsWith ("/mnt", Qt::CaseSensitive )) )
2226     {
2227         if (!dirPath.endsWith(SLASH))
2228             dirPath.append(SLASH);
2229         int ROOTcounts = dirPath.count(SLASH) - 2;
2230 
2231         QString mountpoint = dirPath;
2232 
2233         int count = 0;
2234         while (count < ROOTcounts)  // scan all directory depth one by one except /media or /mnt
2235         {
2236             QProcess *mountProcess;                         mountProcess = new QProcess;
2237             QStringList mArgs;                              mArgs << mountpoint;
2238             mountProcess -> start ("mountpoint",mArgs);     mountProcess -> waitForFinished();
2239 
2240             // The following means that the given path belongs to a directory structure under /media or /mnt that is a mountpoint
2241             if (mountProcess -> exitCode() == 0)
2242             {
2243                 returnTHISplease = true;
2244                 count = ROOTcounts;         // Exit this loop and return true if mount point found
2245             }
2246             else
2247                 returnTHISplease = false;
2248 
2249             mountpoint = mountpoint.left(mountpoint.lastIndexOf(SLASH,mountpoint.size()-2)+1);    // Cut the right part of the path
2250 
2251             count++;
2252         }
2253     }
2254 
2255     return returnTHISplease;
2256 }
2257 
2258 // sendEmailNow =====================================================================================================================================
2259 // Send an email after a profile run. bool is true if called for testing purposes
sendEmailNow(bool testEmail)2260 QString sendEmailNow (bool testEmail)
2261 {
2262     QString returnString = "";      // This is the string that will be finally returned
2263 
2264     // Form command to execute (first argument of emailCommand ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2265     //QString emailCommandExec = emailCommand.left(emailCommand.indexOf(" "));
2266     QString emailCommandExec = emailCommand;
2267     //if (WINrunning)
2268     //    emailCommandExec = luckyBackupDir+SLASH+emailCommandExec;
2269 
2270     // Calculate arguments and command used from variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2271     //QString emailArgs = emailCommand;   emailArgs.remove(emailCommandExec);
2272     QStringList emailArgsExec = emailArguments.split(" ",QString::SkipEmptyParts);
2273 
2274     // Body & Subject might contain other args inside them. So,replace first ~~~~~~~~~~~
2275     emailArgsExec.replaceInStrings("%s",emailSubject);          // %s subject
2276     emailArgsExec.replaceInStrings("%b",emailBody);             // %b body
2277 
2278     // %l or %c logfile filename - Only do this is there exists a %l or %c arguments because many file actions are involved
2279     bool stopEmail = false;
2280     if ( (emailArgsExec.contains("%l")) || (emailArgsExec.contains("%c")) )
2281     {
2282         QString argLog = logDir + profileName + emailLogString;
2283         QFile sendlogfile(argLog);
2284 
2285         if (!sendlogfile.open(QIODevice::WriteOnly))    // if the log file to send cannot be opened for writing
2286             stopEmail = true;
2287         else
2288         {
2289             QTextStream out(&sendlogfile);
2290 
2291             if (testEmail)                                      // if this is a test email
2292                 out << "This logfile is used for TESTING purposes only !!";
2293             else                    // if this is a real email - merge all task logs to a single file
2294             {
2295                 currentOperation = 0;
2296                 while (currentOperation < TotalOperations)  // scan all tasks one by one
2297                 {
2298                     if ( (Operation[currentOperation] -> GetPerform()) || (Operation[currentOperation] -> GetByPassWARNING()) ) // if the task did run
2299                     {
2300                         out     << "\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~ " << Operation[currentOperation] -> GetName().toUtf8()
2301                                 << " - START ~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
2302 
2303                         logfilename = logDir + QString(profileName.toUtf8()) + "-" +
2304                                     QString((Operation[currentOperation] -> GetName()).toUtf8()) + "-" +
2305                                     Operation[currentOperation] -> GetSnapshotsListItem(Operation[currentOperation]->GetSnapshotsListSize()-1)
2306                                     + ".log";
2307                         logfile.setFileName(logfilename);   // this is the last logfile
2308                         if (logfile.exists())
2309                         {
2310                             if (logfile.open(QIODevice::ReadOnly))     //if the profile cannot be opened
2311                             {
2312                                 QTextStream in(&logfile);
2313                                 out << in.readAll();
2314                                 logfile.close();
2315                             }
2316                             else
2317                                 out << "\n" << QObject::tr("Could not open the logfile") << "\n";
2318                         }
2319                         else
2320                             out << "\n" << QObject::tr("The logfile does not exist") << "\n";
2321                         out << "\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "+ Operation[currentOperation] -> GetName().toUtf8() + " - END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
2322                     }
2323                     currentOperation++;
2324                 }
2325 
2326             }
2327             sendlogfile.close();
2328         }
2329 
2330         if (emailArgsExec.contains("%c") && !WINrunning)  // if the argument %c is included, also compress the file. This is valid for non windows systems
2331         {
2332             // Execute the tar command
2333             QString compressCommand="tar", compressExtension=".tar.gz";
2334             QStringList compressArgs;
2335             compressArgs << "-C" << logDir << "-cvzf" << argLog + compressExtension << profileName + emailLogString;
2336             //compressArgs << "-cvzf" << argLog + compressExtension << argLog + emailLogString; // this adds the full path of the logfile inside the tar.gz
2337             QProcess *compressProcess;                         compressProcess = new QProcess;
2338             compressProcess -> setProcessChannelMode(QProcess::MergedChannels);
2339 
2340             if (WINrunning)
2341             {
2342                 compressProcess -> setWorkingDirectory(luckyBackupDir);
2343                 QDir::setCurrent(luckyBackupDir);
2344             }
2345 
2346             compressProcess -> start (compressCommand,compressArgs);
2347             compressProcess -> waitForFinished(10000);
2348             emailArgsExec.replaceInStrings("%c",argLog+compressExtension);
2349         }
2350 
2351         if (WINrunning)
2352             emailArgsExec.replaceInStrings("%l",argLog.replace(XnixSLASH,SLASH));
2353         else
2354             emailArgsExec.replaceInStrings("%l",argLog);
2355     }
2356 
2357     // %d  Current Date
2358     QString argDate = QDate::currentDate().toString(Qt::DefaultLocaleLongDate);
2359     emailArgsExec.replaceInStrings("%d",argDate);
2360 
2361     // %i  Current Time
2362     QString argTime = QTime::currentTime().toString("hh:mm:ss");
2363     emailArgsExec.replaceInStrings("%i",argTime);
2364 
2365     // %p  Profile Name
2366     emailArgsExec.replaceInStrings("%p",profileName);
2367 
2368     // %e  No. of errors
2369     QString argErrors = countStr.setNum(errorsFound);
2370     emailArgsExec.replaceInStrings("%e",argErrors);
2371 
2372     // %f From address
2373     emailArgsExec.replaceInStrings("%f",emailFrom);
2374 
2375     // %t To address
2376     emailArgsExec.replaceInStrings("%t",emailTo);
2377 
2378     // %v smtp server
2379     emailArgsExec.replaceInStrings("%v",emailSMTP);
2380     // End of arguments calculations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2381 
2382     // Execute the email command
2383     QProcess *emailProcess;                         emailProcess = new QProcess;
2384     emailProcess -> setProcessChannelMode(QProcess::MergedChannels);
2385     if(WINrunning)
2386     {
2387         QDir::setCurrent(luckyBackupDir);
2388         emailProcess -> setWorkingDirectory(luckyBackupDir);
2389     }
2390     emailProcess -> start (emailCommandExec,emailArgsExec);
2391     emailProcess -> waitForFinished(10000);
2392 
2393     // Build the return string ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2394     QString errorOccured = emailProcess -> errorString();
2395     if (errorOccured == "Unknown error")
2396         errorOccured = "";
2397     if (errorOccured == "No such file or directory")
2398         returnString.append(QObject::tr("The specified command is probably not installed") + "\n");
2399     if (stopEmail)
2400         returnString.append(QObject::tr("The logfile could not be created") + "\n");
2401 
2402     returnString.append(  "\n"+QObject::tr("command:   ") + emailCommandExec+
2403                             //"\n"+QObject::tr("arguments: ") + emailArgsExec.join(" ") +
2404                             //"\n"+QObject::tr("arguments: ") + emailArgs +
2405                             "\n"+QObject::tr("exit code: ") + countStr.setNum(emailProcess -> exitCode()) +
2406                             "\n"+QObject::tr("output:    ") + errorOccured + "\n" + emailProcess -> readAll() );
2407 
2408     if (!testEmail)     //  email last log
2409     {
2410         QFile emailLog(logDir + profileName + emailLastLogString);
2411         if (emailLog.open(QIODevice::WriteOnly))    // Create the test log file to send
2412         {
2413             QTextStream out(&emailLog);
2414             out << returnString;
2415         }
2416         emailLog.close();
2417     }
2418 
2419     return returnString;
2420 
2421 }
2422 
2423 // setTextMessages =======================================================================================================
2424 // function to set text feedback for the user
2425 // This will be displayed at the gui info window or at CLI
setTextMessages(QString source,QString dest,bool remoteSource,bool remoteDest,QString status,QString type,QString reason)2426 void setTextMessages (QString source,QString dest,bool remoteSource,bool remoteDest,QString status, QString type, QString reason)
2427 {
2428     // useful variables
2429     QString currentOpNameCLI = QString((Operation[currentOperation] -> GetName())).toUtf8();
2430     int lastErrors = Operation[currentOperation] -> GetLastExecutionErrors();
2431     QString lastTimeReadable = (Operation[currentOperation] -> GetLastExecutionTime()).toString(Qt::DefaultLocaleLongDate);
2432     QString lastTime = (Operation[currentOperation] -> GetLastExecutionTime()).toString();
2433     //QString taskDescriptionCLI = QString((Operation[currentOperation] -> GetDescription())).toUtf8();
2434     QString taskDescription = Operation[currentOperation] -> GetDescription();
2435     taskDescription.replace("\n","<br>");
2436 
2437     if (status == "okay")
2438         CheckedDataCLI.append("[Ok]         ->  ");
2439     if (status == "warning")
2440         CheckedDataCLI.append("[WARNING]    ->  ");
2441     if (status == "critical")
2442         CheckedDataCLI.append("[CRITICAL]   ->  ");
2443     CheckedDataCLI.append(currentOpNameCLI);
2444 
2445     // Last execution time & errors
2446     CheckedData.append(QObject::tr("Last execution time") + ": <b>");
2447     CheckedDataCLI.append("\nLast execution time    : ");
2448     if (lastTime == "")
2449     {
2450         CheckedData.append(QObject::tr("not available") + "</b><br>");
2451         CheckedDataCLI.append("not available");
2452     }
2453     else
2454     {
2455         CheckedData.append(lastTimeReadable +"</b>");
2456         CheckedDataCLI.append(lastTimeReadable);
2457         if (lastErrors > -1)    // if there is error information available
2458         {
2459             if (lastErrors == 0)
2460             {
2461                 CheckedData.append(" (" + QObject::tr("no errors") + ")");
2462                 CheckedDataCLI.append(" (no errors)");
2463             }
2464             else
2465             {
2466                 CheckedData.append(" (" + QObject::tr("errors found") + ")");
2467                 CheckedDataCLI.append(" (errors found)");
2468             }
2469         }
2470         CheckedData.append("<br>");
2471     }
2472 
2473     // task status          ->          [ok] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2474     if (status == "okay")
2475     {
2476         CheckedData.append(QObject::tr("status") + ": <font color=green><b>" + QObject::tr("OK") + "</font></b><br>");
2477         if (type == "sync")
2478         {
2479             CheckedData.append(QObject::tr("Sync directory")+" A: <b>");
2480             CheckedDataCLI.append("\nSync directory A       : ");
2481         }
2482         if (type == "backup")
2483         {
2484             CheckedData.append(QObject::tr("Source directory")+": <b>");
2485             CheckedDataCLI.append("\nSource directory       : ");
2486         }
2487 
2488         CheckedData.append(source+"</b>");
2489         CheckedDataCLI.append(source);
2490 
2491         if (remoteSource)
2492         {
2493             CheckedData.append("<br><font color=magenta>("+QObject::tr("Using remote, check is skipped")+"...)</font>");
2494             CheckedDataCLI.append(" (Using remote, check is skipped...)");
2495         }
2496         if (type == "sync")
2497         {
2498             CheckedData.append("<br>" + QObject::tr("Sync directory")+" B: <b>");
2499             CheckedDataCLI.append("\nSync directory B       : ");
2500         }
2501         if (type == "backup")
2502         {
2503             CheckedData.append("<br>" + QObject::tr("Destination directory")+": <b>");
2504             CheckedDataCLI.append("\nDestination directory  : ");
2505         }
2506 
2507         CheckedData.append(dest+"</b>");
2508         CheckedDataCLI.append(dest);
2509 
2510         if (remoteDest)
2511         {
2512             CheckedData.append("<br><font color=magenta>("+QObject::tr("Using remote, check is skipped")+"...)</font>");
2513             CheckedDataCLI.append(" (Using remote, check is skipped...)");
2514         }
2515         else       // display destination disk free space
2516         if (!WINrunning)
2517         {
2518             QProcess *diskSpace;
2519             diskSpace  = new QProcess(0);
2520             QStringList diskSpaceArgs;
2521             diskSpaceArgs << "-h" << dest;
2522             diskSpace -> start ("df",diskSpaceArgs);
2523             diskSpace -> waitForFinished();
2524             QString diskSpaceString = diskSpace->readAllStandardOutput();
2525             if (diskSpaceString.contains("Avail"))
2526             {
2527                 QStringList diskLines = diskSpaceString.split( "\n", QString::SkipEmptyParts );
2528                 QStringList diskFields = diskLines[1].split(" ", QString::SkipEmptyParts );
2529                 CheckedData.append(" (" + diskFields[3] +" " + QObject::tr("free", "as in free disk space")  + ")");
2530             }
2531         }
2532     }
2533 
2534     // task status          ->          [WARNING] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2535     if (status == "warning")
2536     {
2537         CheckedData.append(QObject::tr("status") + ": <font color=red><b>"+QObject::tr("WARNING")+"</font></b><br>");
2538         if (reason == "source-perms")
2539         {
2540             if (type == "sync")
2541             {
2542                 CheckedData.append(QObject::tr("I do not have the permission to read/enter sync directory A")+":<b><br>");
2543                 CheckedDataCLI.append("\nI do not have the permission to read/enter sync directory A :\n");
2544             }
2545             if (type == "backup")
2546             {
2547                 CheckedData.append(QObject::tr("I do not have the permission to read/enter the source directory")+":<b><br>");
2548                 CheckedDataCLI.append("\nI do not have the permission to read/enter the source directory :\n");
2549             }
2550             CheckedData.append(source + "</b><br>");
2551             CheckedDataCLI.append(source);
2552         }
2553 
2554         if (reason == "dest-perms")
2555         {
2556             if (type == "sync")
2557             {
2558                 CheckedData.append(QObject::tr("I do not have the permission to read/enter sync directory B")+":<b><br>");
2559                 CheckedDataCLI.append("\nI do not have the permission to read/enter sync directory B :\n");
2560             }
2561             if (type == "backup")
2562             {
2563                 CheckedData.append(QObject::tr("I do not have the permission to read/enter the destination directory")+":<b><br>");
2564                 CheckedDataCLI.append("\nI do not have the permission to read/enter the destination directory :\n");
2565             }
2566             CheckedData.append(dest + "</b><br>");
2567             CheckedDataCLI.append(dest);
2568         }
2569 
2570         if ((reason == "sync-not-exist") || (reason == "sync-not-mounted"))
2571         {
2572             CheckedData.append(QObject::tr("Directory")+" <b>");
2573             CheckedData.append(source);
2574             CheckedData.append("</b><br>"+QObject::tr("and/or")+" <b>");
2575             CheckedData.append(dest);
2576             if (reason == "sync-not-exist")
2577                 CheckedData.append("</b><br><font color=red><b>"+QObject::tr("does not exist")+"</b></font>.<br>");
2578             if (reason == "sync-not-mounted")
2579                 CheckedData.append("</b><br><font color=red><b>"+QObject::tr("is not mounted")+"</b></font>.<br>");
2580 
2581             CheckedDataCLI.append("\nDirectory ");
2582             CheckedDataCLI.append(source);
2583             CheckedDataCLI.append("\nand/or ");
2584             CheckedDataCLI.append(dest);
2585             if (reason == "sync-not-exist")
2586                 CheckedDataCLI.append("\ndoes not exist.\n");
2587             if (reason == "sync-not-mounted")
2588                 CheckedDataCLI.append("\nis not mounted.\n");
2589         }
2590         if (reason == "source-not-exist")
2591         {
2592             CheckedData.append(QObject::tr("Source directory")+": <b>");
2593             CheckedData.append(source);
2594             CheckedData.append("<br><font color=red> "+QObject::tr("is empty or does not exist")+"</font>.</b><br>");
2595 
2596             CheckedDataCLI.append("\nSource directory   : ");
2597             CheckedDataCLI.append(source);
2598             CheckedDataCLI.append(" is empty or does not exist.\n"
2599                     "Destination directory  : ");
2600             CheckedDataCLI.append(dest);
2601             if (remoteDest)
2602                 CheckedDataCLI.append(" (Using remote, check is skipped...)");
2603         }
2604 
2605         if (reason == "dest-not-mounted")
2606         {
2607             CheckedData.append(QObject::tr("Destination directory")+": <b>");
2608             CheckedData.append(dest);
2609             CheckedData.append("<br><font color=red> "+QObject::tr("is not mounted")+"</font>.</b><br>");
2610 
2611             CheckedDataCLI.append("\nSource directory   : ");
2612             CheckedDataCLI.append(source);
2613             if (remoteSource)
2614                 CheckedDataCLI.append(" (Using remote, check is skipped...)");
2615             CheckedDataCLI.append("\nDestination directory  : ");
2616             CheckedDataCLI.append(dest);
2617             CheckedDataCLI.append(" is not mounted.\n");
2618         }
2619 
2620 
2621         if (Operation[currentOperation] -> GetByPassWARNING())
2622         {
2623             CheckedData.append(QObject::tr("I will <font color=red><b>NOT SKIP</b></font> this task because you have enabled the \"by-pass WARNING\" option"));
2624             CheckedDataCLI.append("\nThis task will NOT be skipped because you have enabled the \"by-pass WARNING\" option\n");
2625         }
2626         else
2627         {
2628             CheckedData.append(QObject::tr("This task will be <font color=red><b>skipped</b></font>"));
2629             CheckedDataCLI.append("\nThis task will be SKIPPED\n");
2630         }
2631     }
2632 
2633     // task status          ->          [CRITICAL] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2634     if (status == "critical")
2635     {
2636         CheckedData.append(QObject::tr("status") + ": <font color=orange><b>"+QObject::tr("CRITICAL")+"</font></b><br>");
2637         if (type == "sync")
2638         {
2639             CheckedData.append(QObject::tr("Directory")+" <b>");
2640             CheckedData.append(source);
2641             CheckedData.append("</b><br>"+QObject::tr("and/or")+" <b>");
2642             CheckedData.append(dest);
2643             CheckedData.append("</b><br><font color=orange><b>"+QObject::tr("is empty")+"</b></font>.<br>"+
2644             QObject::tr("I will <font color=orange><b>not skip</b></font> this task. Synchronizing is going to be performed anyway"));
2645 
2646             CheckedDataCLI.append("\nDirectory ");
2647             CheckedDataCLI.append(source);
2648             CheckedDataCLI.append("\nand/or ");
2649             CheckedDataCLI.append(dest);
2650             CheckedDataCLI.append("\nis empty.\n"
2651             "I will NOT skip this task (unless '--skip-critical' is given as argument).\n"
2652             "Synchronizing is going to be performed anyway !!\n");
2653         }
2654         if (type == "backup")
2655         {
2656             CheckedDataCLI.append("\nSource directory   : ");
2657             CheckedDataCLI.append(source);
2658             if (remoteSource)
2659                 CheckedDataCLI.append(" (Using remote, check is skipped...)");
2660             CheckedDataCLI.append("\nDestination directory  : ");
2661             CheckedDataCLI.append(dest);
2662             CheckedDataCLI.append(" is empty or does not exist.\n"
2663             "This task will NOT be skipped (unless '--skip-critical' is given as argument)\n"
2664             "The Destination Directory will be created if it doesn't exist and filled with new backup data.\n");
2665 
2666             CheckedData.append(QObject::tr("Destination directory")+": <b>");
2667             CheckedData.append(dest);
2668             CheckedData.append("<br><font color=orange> "+QObject::tr("is empty or does not exist")+"</font>.</b><br>"+
2669             QObject::tr("This task will <font color=orange><b>not be skipped")+"</b></font> <br>"+
2670             QObject::tr("The Destination Directory will be created if it doesn't exist and filled with new backup data")+".");
2671         }
2672     }
2673 
2674     CheckedDataCLI.append("\n_____________________________________________________________________________________________\n");
2675 
2676     // Task description
2677     if (taskDescription != "")
2678         CheckedData.append("<br><br><b>"+QObject::tr("Task description") + ":</b><br>" + taskDescription);
2679 }
2680 
2681 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2682 // Various windows stuff from this point to the end of the file...
getMapdrive()2683 QString getMapdrive(){
2684     QString mapdrive="w";
2685     QStringList units;
2686     units << "w"<<"v"<<"u"<<"t"<<"s"<<"r"<<"q"<<"p"<<"z"<<"y"<<"x"<<"o"<<"n"<<"m"<<"l"<<"k"<<"j"<<"i";
2687     for (int i = 0; i < units.size(); ++i){
2688         mapdrive=units.at(i);
2689         if (! QDir(units.at(i)+":"+SLASH).exists())
2690           break;
2691       }
2692     return mapdrive;
2693 }
2694 /*luckyb commended this function out
2695 //Create execute command in windows ==================================================
2696 //Modify source and dest with cygpath and analyze vss
2697 QString createWinMkdirCommand(QString tempPath,bool vss,QStringList rsyncArgs,bool logGui=true){
2698       rsyncArgs << "";
2699 
2700       //return createWinRsyncCommand(tempPath,vss,rsyncArgs,logGui);
2701       QString logstring="";
2702       //QFile command1(tempPath+"\\l1qt_temp"+QString::number(qrand() % (999998) + 1) +".bat");
2703       QFile command2(tempPath+"l2qt_temp"+QString::number(qrand() % (999998) + 1) +".bat");
2704       //QTemporaryFile setvar(tempPath+"\\qt_tempXXXXXX.bat");
2705       QString dest=rsyncArgs.takeLast();
2706       QString source=rsyncArgs.takeLast();
2707       bool srcremote=false;
2708       bool dstremote=false;
2709       rsyncArgs.replaceInStrings("\"","\\\"");
2710       QString args="\""+rsyncArgs.join("\" \"")+"\"";
2711       args.replace("\"--vss\"","");
2712       if (source.contains('@')||source.startsWith("\\\\")){
2713           args.replace("\"--backup-nt-streams\"","");
2714           vss=false;
2715           srcremote=true;
2716           //source=source.replace("\\","/");
2717         }
2718       if (dest.contains('@')||dest.startsWith("\\\\")){
2719           args.replace("\"--restore-nt-streams\"","");
2720           args.append(" \"--chmod=u=rwX\" ");
2721           dstremote=true;
2722           //dest=dest.replace("\\","/");
2723         }
2724       //source=fixWinPathForRsync(source,srcremote);
2725       //dest=fixWinPathForRsync(dest,dstremote);
2726       mapdrive=getMapdrive();
2727       QTextStream outCommand2(&command2);
2728       outCommand2 << "\n@ECHO OFF";
2729       outCommand2 << "\nSET tdebug=y";
2730       outCommand2 << "\nSET tdeleteshadows=y";
2731       outCommand2 << "\nSET el=0";
2732           if (!srcremote) outCommand2 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \""+source+"\"> "+tempPath+"\\_cygpath.tmp";
2733           else outCommand2 << "\nECHO "+source+"> "+tempPath+"\\_cygpath.tmp";
2734           outCommand2 << "\nSET /p source=< "+tempPath+"\\_cygpath.tmp";
2735           if (!dstremote) outCommand2 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \""+dest+"/\"> "+tempPath+"\\_cygpath.tmp";
2736           else outCommand2 << "\nECHO "+dest+"> "+tempPath+"\\_cygpath.tmp";
2737           outCommand2 << "\nSET /p dest=< "+tempPath+"\\_cygpath.tmp";
2738           outCommand2 << "\n \""+Operation[currentOperation] -> GetRsyncCommand()+"\" "+args+" \"%source%\" \"%dest%\" ";
2739           outCommand2 << "\n  SET el=%ERRORLEVEL%";
2740           outCommand2 << "\ndel "+tempPath+"/_cygpath.tmp 2>nul";
2741 
2742       outCommand2 << "\n:ennd";
2743       outCommand2 << "\nIF %el% neq 0 exit /b %el%";
2744       //outCommand2 << "\ndel \""+command1.fileName().replace("/","\\")+"\"";
2745       //outCommand2 << "\nstart \"rsync.bat\" /min cmd /C del \"%0\" >nul 2>&1";
2746       outCommand2 << "\nECHO BACKUP OK";
2747       QString ret=command2.fileName();
2748       command2.close();
2749 
2750 
2751 }*/
2752 
createWinRsyncCommand(QString tempPath,bool vss,QStringList rsyncArgs,bool logGui)2753 QString createWinRsyncCommand(QString tempPath,bool vss,QStringList rsyncArgs,bool logGui){
2754 //  QFile settingsfile(settingsFile);
2755 //  if (!settingsfile.open(QIODevice::WriteOnly))   // if the settings file cannot be saved (or fails to create)
2756 //  {
2757 //      settingsfile.close();
2758 //      return false;
2759 //  }
2760 
2761     //luckyb line to avoid compile WARNING
2762     vss = logGui;
2763     if (vss)
2764         vss=true;
2765     // end of luckyb lines
2766 
2767 //  showOnlyErrors = ui.checkBox_onlyShowErrors -> isChecked();
2768     QString logstring="";
2769     QFile command1(tempPath+SLASH+"l1qt_temp"+QString::number(qrand() % (999998) + 1) +".bat");
2770     QFile command2(tempPath+SLASH+"l2qt_temp"+QString::number(qrand() % (999998) + 1) +".bat");
2771     QTemporaryFile setvar(tempPath+SLASH+"qt_tempXXXXXX.bat");
2772     QString dest=rsyncArgs.takeLast();
2773     QString source=rsyncArgs.takeLast();
2774     //bool srcremote=false; // luckyb commend to avoid compile WARNING
2775     //bool dstremote=false;
2776     rsyncArgs.replaceInStrings("\"","\\\"");//double escape chars to include in bat
2777     QString args="\""+rsyncArgs.join("\" \"")+"\"";
2778 /* disable vss until...
2779     args.replace("\"--vss\"",""); */
2780     if (source.contains('@')||source.startsWith(SLASH+SLASH)){
2781         args.replace("\"--backup-nt-streams\"","");
2782         vss=false;
2783         //srcremote=true;   // luckyb lines to avoid compile WARNING
2784         if (source.startsWith("\\\\"))
2785             source="\\\\"+source;
2786         //source=source.replace("\\","/");
2787       }
2788     if (dest.contains('@')||dest.startsWith(SLASH+SLASH)){
2789         args.replace("\"--restore-nt-streams\"","");
2790         args.append(" \"--chmod=u=rwX\" ");
2791         // dstremote=true;  // luckyb lines to avoid compile WARNING
2792         //dest=dest.replace("\\","/");
2793         if (dest.startsWith("\\\\"))
2794             dest="\\\\"+dest;
2795       }
2796     //source=fixWinPathForRsync(source,srcremote);
2797     //dest=fixWinPathForRsync(dest,dstremote);
2798     mapdrive=getMapdrive();
2799     /* disable vss until...
2800     if (vss)
2801     {
2802         doVss=1;
2803         logstring=" >> \""+pipeVssFile->fileName()+"\" 2>> \""+pipeVssErrFile->fileName()+"\"";
2804 
2805 
2806         if (!setvar.open()) // if the settings file cannot be saved (or fails to create)
2807         {
2808             setvar.close();
2809             return "";
2810         }
2811         setvar.close();
2812 
2813         //QTemporaryFile logfile;
2814         //if (!logfile.open())    // if the settings file cannot be saved (or fails to create)
2815         //{
2816         //   logfile.close();
2817         //    return "";
2818         //}
2819         logfile.close();
2820 
2821         //write arrays to file
2822         if (!command1.open(QIODevice::WriteOnly | QIODevice::Text)) // if the settings file cannot be saved (or fails to create)
2823         {
2824             command1.close();
2825             return "";
2826         }
2827 
2828         QTextStream outCommand1(&command1);
2829         outCommand1 << "\n@ECHO OFF";
2830         outCommand1 << "\nECHO DOING RSYNC >> \""+pipeVssFile->fileName()+"\" ";
2831         //outCommand1 << "\nECHO \"\" > \""+pipeVssErrFile->fileName()+"\"";
2832         outCommand1 << "\nSETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION ";
2833 
2834         outCommand1 << "\nCALL "+setvar.fileName();
2835 
2836         outCommand1 << "\n\""+Operation[currentOperation] -> GetDosdevCommand()+"\" "+mapdrive+": %SHADOW_DEVICE_1%  >> \""+pipeVssFile->fileName()+"\" 2>> \""+pipeVssErrFile->fileName()+"\"";
2837         outCommand1 << "\n SET SOURCE="+source;
2838         if (vss) outCommand1 << "\n SET SOURCE="+mapdrive+"%SOURCE:~1%";
2839         if (!source.contains('@')) outCommand1 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \"%SOURCE%\"> "+tempPath+SLASH+"_cygpath.tmp";
2840         else outCommand1 << "\nECHO "+source+"> "+tempPath+SLASH+"_cygpath.tmp";
2841         outCommand1 << "\nSET /p source=< "+tempPath+SLASH+"_cygpath.tmp";
2842         if (!dest.contains('@')) outCommand1 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \""+dest+"/\"> "+tempPath+SLASH+"_cygpath.tmp";
2843         else outCommand1 << "\nECHO "+dest+"> "+tempPath+SLASH+"_cygpath.tmp";
2844         outCommand1 << "\nSET /p dest=< "+tempPath+SLASH+"_cygpath.tmp";
2845         outCommand1 << "\nSET HOME="+luckyBackupDir;
2846         outCommand1 << "\nSET CYGWIN=nodosfilewarning";
2847         outCommand1 << "\n\""+Operation[currentOperation] -> GetRsyncCommand()+"\" "+args+" \"!source!\" \"!dest!\"  >> \""+pipeVssFile->fileName()+"\" 2>> \""+pipeVssErrFile->fileName()+"\"";
2848         outCommand1 << "\nSET ACTERR=!ERRORLEVEL! ";
2849 
2850         outCommand1 << "\nECHO Backing up completed: !ACTERR!. !DATE! !TIME!  >> \""+pipeVssFile->fileName()+"\"";
2851 
2852         outCommand1 << "\nECHO delete shadow device drive mapping >> \""+pipeVssFile->fileName()+"\" 2>> \""+pipeVssErrFile->fileName()+"\"";
2853         outCommand1 << "\n\""+Operation[currentOperation] -> GetDosdevCommand()+"\" -r -d "+mapdrive+": 2>NUL ";
2854         //outCommand1 << "\nrem del "+setvar.fileName()+" ";
2855         //outCommand1 << "\nrem del %0 ";
2856         outCommand1 << "\nIF %ACTERR% GTR 0 ( ";
2857         outCommand1 << "\nECHO ERROR on backup.  %DATE% %TIME% >> \""+pipeVssErrFile->fileName()+"\"";
2858         outCommand1 << "\nexit 1 ";
2859         outCommand1 << "\n) ";
2860         command1.close();
2861     }*/
2862 
2863 
2864     if (!command2.open(QIODevice::WriteOnly | QIODevice::Text)) // if the settings file cannot be saved (or fails to create)
2865     {
2866         command2.close();
2867         return "";
2868     }
2869     QTextStream outCommand2(&command2);
2870     outCommand2 << "\n@ECHO OFF";
2871     outCommand2 << "\nSET tdebug=y";
2872     outCommand2 << "\nSET tdeleteshadows=y";
2873     outCommand2 << "\nSET el=0";
2874     //remove vss and
2875     /* disable vss until...
2876     if (vss)
2877     {
2878         outCommand2 << "\nFOR /F \"tokens=2* delims=[]\" %%A IN ('VER') DO FOR /F \"tokens=2,3 delims=. \" %%B IN (\"%%A\") DO SET WINVER=%%B.%%C";
2879         outCommand2 << "\nSET WINBIT=x86&&IF \"%PROCESSOR_ARCHITECTURE%\" == \"AMD64\" (SET WINBIT=x64) ELSE IF \"%PROCESSOR_ARCHITEW6432%\" == \"AMD64\" SET WINBIT=x64";
2880         outCommand2 << "\nIF %WINVER% LSS 5.1 (";
2881         outCommand2 << "\n        ECHO Sorry, %this% cannot run under this version of Windows %WINVER%-%WINBIT%  " + logstring;
2882         outCommand2 << "\n        SET el=12";
2883         outCommand2 << "\n        GOTO :ennd";
2884         outCommand2 << "\n)";
2885         outCommand2 << "\nSET VSHADOWVER=%WINVER%";
2886         outCommand2 << "\nIF %WINVER%==5.1 SET VSHADOWVER=xp&&SET WINBIT=x86";
2887         outCommand2 << "\nIF %WINVER%==5.2 SET VSHADOWVER=2003&&SET WINBIT=x86";
2888         outCommand2 << "\nIF %WINVER%==6.0 SET VSHADOWVER=2008";
2889         outCommand2 << "\nIF %WINVER%==6.1 SET VSHADOWVER=2008-r2";
2890         outCommand2 << "\nCD "+tempPath+"";
2891         outCommand2 << "\n      IF NOT \"%tdeleteshadows%\"==\"y\" (";
2892         outCommand2 << "\n              IF \"%tdebug%\"==\"y\" ECHO Skipping deletion of any existing shadow copies  " + logstring;
2893         outCommand2 << "\n      ) ELSE (";
2894         outCommand2 << "\n              IF \"%tdebug%\"==\"y\" ECHO About to delete any existing shadow copies  " + logstring;
2895         outCommand2 << "\n              ECHO y|\""+Operation[currentOperation] -> GetVshadowDir()+SLASH+"vshadow-%VSHADOWVER%-%WINBIT%.exe\" -da>nul";
2896         outCommand2 << "\n              IF ERRORLEVEL 1 (";
2897         outCommand2 << "\n                      IF \"%tdebug%\"==\"y\" ECHO Error occurred: testing for administrator permissions  " + logstring;
2898         outCommand2 << "\n                      IF EXIST \"%windir%\\system32\\test\" RMDIR \"%windir%\\system32\\__test\" 2>nul";
2899         outCommand2 << "\n                      VERIFY>NUL";
2900         outCommand2 << "\n                      MKDIR \"%windir%\\system32\\test\" 2>nul";
2901         outCommand2 << "\n                      IF ERRORLEVEL 1 (";
2902         outCommand2 << "\n                              REM not running as administrator, this is cause of failure" + logstring;
2903         outCommand2 << "\n                              IF \"%tdebug%\"==\"y\" ECHO No administrator permissions   " + logstring;
2904         outCommand2 << "\n                              SET /A el=11";
2905         outCommand2 << "\n                      ) ELSE (";
2906         outCommand2 << "\n                              ECHO running as administrator, there is a problem with vshadow" + logstring;
2907         outCommand2 << "\n                              RMDIR \"%windir%\\system32\\__test";
2908         outCommand2 << "\n                              SET /A el=7";
2909         outCommand2 << "\n                      )";
2910         outCommand2 << "\n                      GOTO :endd";
2911         outCommand2 << "\n              )";
2912         outCommand2 << "\n              IF \"%tdebug%\"==\"y\" ECHO Deleted any existing shadow copies   " + logstring;
2913         outCommand2 << "\n      )";
2914         outCommand2 << "\n       \""+Operation[currentOperation] -> GetVshadowDir()+SLASH+"vshadow-%VSHADOWVER%-%WINBIT%.exe\" -script=\""+setvar.fileName()+"\" -exec=\""+command1.fileName()+"\" "+source.left(1)+": ";
2915         outCommand2 << "\n      SET el=%ERRORLEVEL%";
2916         outCommand2 << "\n      del "+tempPath+"/_cygpath.tmp 2>nul";
2917         //outCommand2 << "\ncall \""+setvar.fileName()+"\"";
2918         //outCommand2 << "\n  \""+dosdevCommand+"\" "+mapdrive+": %SHADOW_DEVICE_1%  ";
2919         //outCommand2 << "\n       \""+vshadowDir+SLASH+"vshadow-%VSHADOWVER%-%WINBIT%.exe\" -ds=%SHADOW_ID_1%";
2920         if (!logGui){
2921           outCommand2 << "\nTYPE \""+pipeVssFile->fileName()+"\" ";
2922           outCommand2 << "\nTYPE \""+pipeVssErrFile->fileName()+"\" 1>&2";
2923           }
2924     }
2925 
2926     else {*/
2927         if (!source.contains('@')) outCommand2 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \""+source+"\"> "+tempPath+SLASH+"_cygpath.tmp";
2928         else outCommand2 << "\nECHO "+source+"> "+tempPath+SLASH+"_cygpath.tmp";
2929         outCommand2 << "\nSET /p source=< "+tempPath+SLASH+"_cygpath.tmp";
2930         if (!dest.contains('@')) outCommand2 << "\n\""+Operation[currentOperation] -> GetCygpathCommand()+"\" \""+dest+"/\"> "+tempPath+SLASH+"_cygpath.tmp";
2931         else outCommand2 << "\nECHO "+dest+"> "+tempPath+SLASH+"_cygpath.tmp";
2932         outCommand2 << "\nSET /p dest=< "+tempPath+SLASH+"_cygpath.tmp";
2933         outCommand2 << "\nSET HOME="+luckyBackupDir;
2934         outCommand2 << "\nSET CYGWIN=nodosfilewarning";
2935         outCommand2 << "\n \""+Operation[currentOperation] -> GetRsyncCommand()+"\" "+args+" \"%source%\" \"%dest%\" ";
2936         outCommand2 << "\n  SET el=%ERRORLEVEL%";
2937         outCommand2 << "\ndel "+tempPath+"/_cygpath.tmp 2>nul";
2938     /* disable vss until...
2939     } */
2940     outCommand2 << "\n:ennd";
2941     outCommand2 << "\nIF %el% neq 0 exit /b %el%";
2942     //outCommand2 << "\ndel \""+command1.fileName().replace("/",SLASH+"")+"\"";
2943     //outCommand2 << "\nstart \"rsync.bat\" /min cmd /C del \"%0\" >nul 2>&1";
2944     outCommand2 << "\nECHO BACKUP OK";
2945     QString ret=command2.fileName();
2946     command2.close();
2947     return ret;
2948 }
setAppDir(QString s)2949 void setAppDir(QString s){
2950   luckyBackupDir = s;
2951   settingsFile = luckyBackupDir + "settings.ini";     // settings file
2952   profileDir = luckyBackupDir + "profiles/";          // profiles directory
2953   defaultProfile = profileDir + "default.profile";    // default profile
2954   standardDefaultProfile = profileDir + "default.profile"; // standard default profile
2955   logDir = luckyBackupDir + "logs/";                  // logs directory
2956   logfilename = logDir + "logfile.log";               // logfile filename - this will change according to the profile an task executed
2957   snapChangesDir = luckyBackupDir + "snaps/";         // Snapshots changes files are stored here. It lies inside ~
2958   snapEmptyDir = snapChangesDir + "EMPTY/";           // empty directory used to delete older snapshots
2959   snapchangesfilename = snapChangesDir + "changes.log"; // Snapshot changes filename. This will change according to the snapshot
2960   snapChangesString = "[changed_data]%i[LB]%n";       // The log lines format of the "changes" file that stores changes made for every snapshot
2961   scheduleDir = luckyBackupDir + "schedule/";         // schedule directory
2962   schedulefilename = scheduleDir + "schedule.dat";    // cron data filename
2963   cronfilename = scheduleDir + "luckyCron.txt";       // cron filename
2964 }
2965 }
2966 // end of global.cpp ---------------------------------------------------------------------------
2967 
2968