1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19
20 /*
21 * preRestore -> dialog put up to determine the restore type
22 *
23 * Kern Sibbald, February MMVII
24 *
25 */
26
27 #include "bat.h"
28 #include "restore.h"
29
30 /* Constructor to have jobid list default in */
prerestorePage(QString & data,unsigned int datatype)31 prerestorePage::prerestorePage(QString &data, unsigned int datatype) : Pages()
32 {
33 m_dataIn = data;
34 m_dataInType = datatype;
35 buildPage();
36 }
37
38 /* Basic Constructor */
prerestorePage()39 prerestorePage::prerestorePage()
40 {
41 m_dataIn = "";
42 m_dataInType = R_NONE;
43 buildPage();
44 }
45
46 /*
47 * This is really the constructor
48 */
buildPage()49 void prerestorePage::buildPage()
50 {
51 m_name = tr("Restore");
52 setupUi(this);
53 pgInitialize();
54 m_conn = m_console->notifyOff();
55 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
56 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
57
58 jobCombo->addItems(m_console->job_list);
59 filesetCombo->addItems(m_console->fileset_list);
60 clientCombo->addItems(m_console->client_list);
61 poolCombo->addItem(tr("Any"));
62 poolCombo->addItems(m_console->pool_list);
63 storageCombo->addItems(m_console->storage_list);
64 /* current or before . . Start out with current checked */
65 recentCheckBox->setCheckState(Qt::Checked);
66 beforeDateTime->setDisplayFormat(mainWin->m_dtformat);
67 beforeDateTime->setDateTime(QDateTime::currentDateTime());
68 beforeDateTime->setEnabled(false);
69 selectFilesRadio->setChecked(true);
70 if (m_dataInType == R_NONE) {
71 selectJobRadio->setChecked(true);
72 selectJobIdsRadio->setChecked(false);
73 jobIdEdit->setText(tr("Comma separated list of JobIds"));
74 jobIdEdit->setEnabled(false);
75 } else if (m_dataInType == R_JOBIDLIST) {
76 selectJobIdsRadio->setChecked(true);
77 selectJobRadio->setChecked(false);
78 jobIdEdit->setText(m_dataIn);
79 jobRadioClicked(false);
80 QStringList fieldlist;
81 if (jobdefsFromJob(fieldlist, m_dataIn) == 1) {
82 filesetCombo->setCurrentIndex(filesetCombo->findText(fieldlist[2], Qt::MatchExactly));
83 clientCombo->setCurrentIndex(clientCombo->findText(fieldlist[1], Qt::MatchExactly));
84 jobCombo->setCurrentIndex(jobCombo->findText(fieldlist[0], Qt::MatchExactly));
85 }
86 } else if (m_dataInType == R_JOBDATETIME) {
87 selectJobRadio->setChecked(true);
88 selectJobIdsRadio->setChecked(false);
89 jobIdEdit->setText(tr("Comma separated list of JobIds"));
90 jobIdEdit->setEnabled(false);
91 recentCheckBox->setCheckState(Qt::Unchecked);
92 jobRadioClicked(true);
93 QStringList fieldlist;
94 if (jobdefsFromJob(fieldlist, m_dataIn) == 1) {
95 filesetCombo->setCurrentIndex(filesetCombo->findText(fieldlist[2], Qt::MatchExactly));
96 clientCombo->setCurrentIndex(clientCombo->findText(fieldlist[1], Qt::MatchExactly));
97 jobCombo->setCurrentIndex(jobCombo->findText(fieldlist[0], Qt::MatchExactly));
98 beforeDateTime->setDateTime(QDateTime::fromString(fieldlist[3], mainWin->m_dtformat));
99 }
100 }
101 job_name_change(0);
102 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(job_name_change(int)));
103 connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
104 connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
105 connect(recentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(recentChanged(int)));
106 connect(selectJobRadio, SIGNAL(clicked(bool)), this, SLOT(jobRadioClicked(bool)));
107 connect(selectJobIdsRadio, SIGNAL(clicked(bool)), this, SLOT(jobidsRadioClicked(bool)));
108 connect(jobIdEdit, SIGNAL(editingFinished()), this, SLOT(jobIdEditFinished()));
109
110 dockPage();
111 setCurrent();
112 this->show();
113 if (mainWin->m_miscDebug) Pmsg0(000, "Leave preRestore\n");
114 }
115
116
117 /*
118 * Check to make sure all is ok then start either the select window or the restore
119 * run window
120 */
okButtonPushed()121 void prerestorePage::okButtonPushed()
122 {
123 if (!selectJobRadio->isChecked()) {
124 if (!checkJobIdList()) {
125 return;
126 }
127 }
128 QString cmd;
129
130 this->hide();
131
132
133 cmd = QString("restore");
134 cmd += " fileset=\"" + filesetCombo->currentText() + "\"";
135 cmd += " client=\"" + clientCombo->currentText() + "\"";
136 if (selectJobRadio->isChecked()) {
137 if (poolCombo->currentText() != tr("Any") ){
138 cmd += " pool=\"" + poolCombo->currentText() + "\"";
139 }
140 cmd += " storage=\"" + storageCombo->currentText() + "\"";
141 if (recentCheckBox->checkState() == Qt::Checked) {
142 cmd += " current";
143 } else {
144 QDateTime stamp = beforeDateTime->dateTime();
145 QString before = stamp.toString(mainWin->m_dtformat);
146 cmd += " before=\"" + before + "\"";
147 }
148 } else {
149 cmd += " jobid=\"" + jobIdEdit->text() + "\"";
150 }
151 if (selectFilesRadio->isChecked()) {
152 if (!selectJobIdsRadio->isChecked())
153 cmd += " select";
154 } else {
155 cmd += " all done";
156 }
157
158 if (mainWin->m_commandDebug) {
159 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
160 }
161 /*
162 * Send off command that looks something like:
163 *
164 * restore fileset="Full Set" client="timmy-fd"
165 * storage="File" current select
166 */
167 m_console->write_dir(m_conn, cmd.toUtf8().data());
168
169 /* Note, do not turn notifier back on here ... */
170 if (selectFilesRadio->isChecked()) {
171 setConsoleCurrent();
172 closeStackPage();
173 /* wait will be exited in the restore page constructor */
174 mainWin->waitEnter();
175 } else {
176 closeStackPage();
177 mainWin->resetFocus();
178 }
179 m_console->notify(m_conn, true);
180 if (mainWin->m_miscDebug) Pmsg0(000, "preRestore OK pressed\n");
181 }
182
183
184 /*
185 * Destroy the instace of the class
186 */
cancelButtonPushed()187 void prerestorePage::cancelButtonPushed()
188 {
189 mainWin->set_status(tr("Canceled"));
190 this->hide();
191 m_console->notify(m_conn, true);
192 closeStackPage();
193 }
194
195
196 /*
197 * Handle updating the other widget with job defaults when the job combo is changed.
198 */
job_name_change(int index)199 void prerestorePage::job_name_change(int index)
200 {
201 job_defaults job_defs;
202
203 (void)index;
204 job_defs.job_name = jobCombo->currentText();
205 if (m_console->get_job_defaults(m_conn, job_defs)) {
206 filesetCombo->setCurrentIndex(filesetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
207 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
208 poolCombo->setCurrentIndex(poolCombo->findText(tr("Any"), Qt::MatchExactly));
209 storageCombo->setCurrentIndex(storageCombo->findText(job_defs.store_name, Qt::MatchExactly));
210 }
211 }
212
213 /*
214 * Handle the change of enabled of input widgets when the recent checkbox state
215 * is changed.
216 */
recentChanged(int state)217 void prerestorePage::recentChanged(int state)
218 {
219 if ((state == Qt::Unchecked) && (selectJobRadio->isChecked())) {
220 beforeDateTime->setEnabled(true);
221 } else {
222 beforeDateTime->setEnabled(false);
223 }
224 }
225
226
227 /*
228 * For when jobs list is to be used, return a list which is the needed items from
229 * the job record
230 */
jobdefsFromJob(QStringList & fieldlist,QString & jobId)231 int prerestorePage::jobdefsFromJob(QStringList &fieldlist, QString &jobId)
232 {
233 QString job, client, fileset;
234 QString query("");
235 query = "SELECT DISTINCT Job.Name AS JobName, Client.Name AS Client,"
236 " FileSet.FileSet AS FileSet, Job.EndTime AS JobEnd,"
237 " Job.Type AS JobType"
238 " From Job, Client, FileSet"
239 " WHERE Job.FileSetId=FileSet.FileSetId AND Job.ClientId=Client.ClientId"
240 " AND JobId=\'" + jobId + "\'";
241 if (mainWin->m_sqlDebug) { Pmsg1(000, "query = %s\n", query.toUtf8().data()); }
242 QStringList results;
243 if (m_console->sql_cmd(m_conn, query, results)) {
244 QString field;
245
246 /* Iterate through the lines of results, there should only be one. */
247 foreach (QString resultline, results) {
248 fieldlist = resultline.split("\t");
249 } /* foreach resultline */
250 } /* if results from query */
251
252 /* ***FIXME*** This should not ever be getting more than one */
253 return results.count() >= 1;
254 }
255
256 /*
257 * Function to handle when the jobidlist line edit input loses focus or is entered
258 */
jobIdEditFinished()259 void prerestorePage::jobIdEditFinished()
260 {
261 checkJobIdList();
262 }
263
checkJobIdList()264 bool prerestorePage::checkJobIdList()
265 {
266 /* Need to check and make sure the text is a comma separated list of integers */
267 QString line = jobIdEdit->text();
268 if (line.contains(" ")) {
269 QMessageBox::warning(this, "Bat",
270 tr("There can be no spaces in the text for the joblist.\n"
271 "Press OK to continue?"), QMessageBox::Ok );
272 return false;
273 }
274 QStringList joblist = line.split(",", QString::SkipEmptyParts);
275 bool allintokay = true, alljobok = true, allisjob = true;
276 QString jobName(""), clientName("");
277 foreach (QString job, joblist) {
278 bool intok;
279 job.toInt(&intok, 10);
280 if (intok) {
281 /* are the integers representing a list of jobs all with the same job
282 * and client */
283 QStringList fields;
284 if (jobdefsFromJob(fields, job) == 1) {
285 if (jobName == "")
286 jobName = fields[0];
287 else if (jobName != fields[0])
288 alljobok = false;
289 if (clientName == "")
290 clientName = fields[1];
291 else if (clientName != fields[1])
292 alljobok = false;
293 } else {
294 allisjob = false;
295 }
296 } else {
297 allintokay = false;
298 }
299 }
300 if (!allintokay){
301 QMessageBox::warning(this, "Bat",
302 tr("The string is not a comma separated list of integers.\n"
303 "Press OK to continue?"), QMessageBox::Ok );
304 return false;
305 }
306 if (!allisjob){
307 QMessageBox::warning(this, tr("Bat"),
308 tr("At least one of the jobs is not a valid job of type \"Backup\".\n"
309 "Press OK to continue?"), QMessageBox::Ok );
310 return false;
311 }
312 if (!alljobok){
313 QMessageBox::warning(this, "Bat",
314 tr("All jobs in the list must be of the same jobName and same client.\n"
315 "Press OK to continue?"), QMessageBox::Ok );
316 return false;
317 }
318 return true;
319 }
320
321 /*
322 * Handle the change of enabled of input widgets when the job radio buttons
323 * are changed.
324 */
jobRadioClicked(bool checked)325 void prerestorePage::jobRadioClicked(bool checked)
326 {
327 if (checked) {
328 jobCombo->setEnabled(true);
329 filesetCombo->setEnabled(true);
330 clientCombo->setEnabled(true);
331 poolCombo->setEnabled(true);
332 storageCombo->setEnabled(true);
333 recentCheckBox->setEnabled(true);
334 if (!recentCheckBox->isChecked()) {
335 beforeDateTime->setEnabled(true);
336 }
337 jobIdEdit->setEnabled(false);
338 selectJobRadio->setChecked(true);
339 selectJobIdsRadio->setChecked(false);
340 } else {
341 jobCombo->setEnabled(false);
342 filesetCombo->setEnabled(false);
343 clientCombo->setEnabled(false);
344 poolCombo->setEnabled(false);
345 storageCombo->setEnabled(false);
346 recentCheckBox->setEnabled(false);
347 beforeDateTime->setEnabled(false);
348 jobIdEdit->setEnabled(true);
349 selectJobRadio->setChecked(false);
350 selectJobIdsRadio->setChecked(true);
351 }
352 if (mainWin->m_miscDebug) {
353 Pmsg2(000, "jobRadio=%d jobidsRadio=%d\n", selectJobRadio->isChecked(),
354 selectJobIdsRadio->isChecked());
355 }
356 }
357
jobidsRadioClicked(bool checked)358 void prerestorePage::jobidsRadioClicked(bool checked)
359 {
360 if (checked) {
361 jobCombo->setEnabled(false);
362 filesetCombo->setEnabled(false);
363 clientCombo->setEnabled(false);
364 poolCombo->setEnabled(false);
365 storageCombo->setEnabled(false);
366 recentCheckBox->setEnabled(false);
367 beforeDateTime->setEnabled(false);
368 jobIdEdit->setEnabled(true);
369 selectJobRadio->setChecked(false);
370 selectJobIdsRadio->setChecked(true);
371 } else {
372 jobCombo->setEnabled(true);
373 filesetCombo->setEnabled(true);
374 clientCombo->setEnabled(true);
375 poolCombo->setEnabled(true);
376 storageCombo->setEnabled(true);
377 recentCheckBox->setEnabled(true);
378 if (!recentCheckBox->isChecked()) {
379 beforeDateTime->setEnabled(true);
380 }
381 jobIdEdit->setEnabled(false);
382 selectJobRadio->setChecked(true);
383 selectJobIdsRadio->setChecked(false);
384 }
385 if (mainWin->m_miscDebug) {
386 Pmsg2(000, "jobRadio=%d jobidsRadio=%d\n", selectJobRadio->isChecked(),
387 selectJobIdsRadio->isChecked());
388 }
389 }
390