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> -----| " +
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> -----| " +
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