1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2016 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  *   Dirk Bartley, March 2007
21  */
22 
23 #include "bat.h"
24 #include <QAbstractEventDispatcher>
25 #include <QTableWidgetItem>
26 #include <QMessageBox>
27 #include "mediaedit.h"
28 
29 /*
30  * A constructor
31  */
MediaEdit(QTreeWidgetItem * parentWidget,QString & mediaId)32 MediaEdit::MediaEdit(QTreeWidgetItem *parentWidget, QString &mediaId)
33   : Pages()
34 {
35    setupUi(this);
36    pgInitialize(tr("Media Edit"), parentWidget);
37    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
38    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/cartridge-edit.png")));
39    dockPage();
40    setCurrent();
41 
42    connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
43    connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
44    connectSpins();
45    connect(retentionSpin, SIGNAL(valueChanged(int)), this, SLOT(retentionChanged()));
46    connect(useDurationSpin, SIGNAL(valueChanged(int)), this, SLOT(useDurationChanged()));
47    connect(retentionRadio, SIGNAL(pressed()), this, SLOT(retentionRadioPressed()));
48    connect(useDurationRadio, SIGNAL(pressed()), this, SLOT(useDurationRadioPressed()));
49 
50    m_pool = "";
51    m_recyclePool = "";
52    m_status = "";
53    m_slot = 0;
54 
55    /* The media's pool */
56    poolCombo->addItems(m_console->pool_list);
57 
58    /* The media's Status */
59    QStringList statusList = (QStringList() << "Full" << "Used" << "Append"
60        << "Error" << "Purged" << "Recycle" << "Read-Only" << "Cleaning");
61    statusCombo->addItems(statusList);
62 
63    /* Set up the query for the default values */
64    QStringList FieldList = (QStringList()
65       << "Media.VolumeName" << "Pool.Name" << "Media.VolStatus" << "Media.Slot"
66       << "Media.VolRetention" << "Media.VolUseDuration" << "Media.MaxVolJobs"
67       << "Media.MaxVolFiles" << "Media.MaxVolBytes" << "Media.Recycle" << "Media.Enabled"
68       << "Pol.Name");
69    QStringList AsList = (QStringList()
70       << "VolumeName" << "PoolName" << "Status" << "Slot"
71       << "Retention" << "UseDuration" << "MaxJobs"
72       << "MaxFiles" << "MaxBytes" << "Recycle" << "Enabled"
73       << "RecyclePool");
74    int i = 0;
75    QString query("SELECT ");
76    foreach (QString field, FieldList) {
77       if (i != 0) {
78          query += ", ";
79       }
80       query += field + " AS " + AsList[i];
81       i += 1;
82    }
83 
84    QString where = " WHERE Media.VolumeName = '" + mediaId + "' ";
85    if (mediaId.contains(QRegExp("^[0-9]+$"))) {
86       where = " WHERE Media.MediaId=" + mediaId;
87    }
88    query += " FROM Media"
89             " JOIN Pool ON (Media.PoolId=Pool.PoolId)"
90             " LEFT OUTER JOIN Pool AS Pol ON (Media.RecyclePoolId=Pol.PoolId)"
91             + where;
92 
93    if (mainWin->m_sqlDebug) {
94       Pmsg1(000, "MediaList query cmd : %s\n",query.toUtf8().data());
95    }
96    QStringList results;
97    if (m_console->sql_cmd(query, results)) {
98       QString field;
99       QStringList fieldlist;
100 
101       /* Iterate through the lines of results, there should only be one. */
102       foreach (QString resultline, results) {
103          fieldlist = resultline.split("\t");
104          i = 0;
105 
106          /* Iterate through fields in the record */
107          foreach (field, fieldlist) {
108             field = field.trimmed();  /* strip leading & trailing spaces */
109             bool ok;
110             if (i == 0) {
111                m_mediaName = field;
112                volumeLabel->setText(QString("Volume : %1").arg(m_mediaName));
113             } else if (i == 1) {
114                m_pool = field;
115             } else if (i == 2) {
116                m_status = field;
117             } else if (i == 3) {
118                m_slot = field.toInt(&ok, 10);
119                if (!ok){ m_slot = 0; }
120             } else if (i == 4) {
121                m_retention = field.toInt(&ok, 10);
122                if (!ok){ m_retention = 0; }
123             } else if (i == 5) {
124                m_useDuration = field.toInt(&ok, 10);
125                if (!ok){ m_useDuration = 0; }
126             } else if (i == 6) {
127                m_maxVolJobs = field.toInt(&ok, 10);
128                if (!ok){ m_maxVolJobs = 0; }
129             } else if (i == 7) {
130                m_maxVolFiles = field.toInt(&ok, 10);
131                if (!ok){ m_maxVolFiles = 0; }
132             } else if (i == 8) {
133                m_maxVolBytes = field.toInt(&ok, 10);
134                if (!ok){ m_maxVolBytes = 0; }
135             } else if (i == 9) {
136                if (field == "1") m_recycle = true;
137                else m_recycle = false;
138             } else if (i == 10) {
139                if (field == "1") m_enabled = true;
140                else m_enabled = false;
141             } else if (i == 11) {
142                m_recyclePool = field;
143             }
144             i++;
145          } /* foreach field */
146       } /* foreach resultline */
147    } /* if results from query */
148 
149    if (m_mediaName != "") {
150       int index;
151       /* default value for pool */
152       index = poolCombo->findText(m_pool, Qt::MatchExactly);
153       if (index != -1) {
154          poolCombo->setCurrentIndex(index);
155       }
156 
157       /* default value for status */
158       index = statusCombo->findText(m_status, Qt::MatchExactly);
159       if (index != -1) {
160          statusCombo->setCurrentIndex(index);
161       }
162       slotSpin->setValue(m_slot);
163       retentionSpin->setValue(m_retention);
164       useDurationSpin->setValue(m_useDuration);
165       setSpins(retentionSpin->value());
166       retentionRadio->setChecked(true);
167       maxJobsSpin->setValue(m_maxVolJobs);
168       maxFilesSpin->setValue(m_maxVolFiles);
169       maxBytesSpin->setValue(m_maxVolBytes);
170       if (m_recycle) recycleCheck->setCheckState(Qt::Checked);
171       else recycleCheck->setCheckState(Qt::Unchecked);
172       if (m_enabled) enabledCheck->setCheckState(Qt::Checked);
173       else enabledCheck->setCheckState(Qt::Unchecked);
174       /* default for recycle pool */
175       recyclePoolCombo->addItems(m_console->pool_list);
176       recyclePoolCombo->insertItem(0, "*None*");
177       index = recyclePoolCombo->findText(m_recyclePool, Qt::MatchExactly);
178       if (index == -1) {
179          index = 0;
180       }
181       recyclePoolCombo->setCurrentIndex(index);
182    } else {
183       QMessageBox::warning(this, tr("No Volume name"), tr("No Volume name given"),
184                            QMessageBox::Ok, QMessageBox::Ok);
185       return;
186    }
187 }
188 
189 /*
190  * Function to handle updating the record then closing the page
191  */
okButtonPushed()192 void MediaEdit::okButtonPushed()
193 {
194    QString scmd;
195    this->hide();
196    bool docmd = false;
197    scmd = QString("update volume=\"%1\"")
198                   .arg(m_mediaName);
199    if (m_pool != poolCombo->currentText()) {
200       scmd += " pool=\"" + poolCombo->currentText() + "\"";
201       docmd = true;
202    }
203    if (m_status != statusCombo->currentText()) {
204       scmd += " volstatus=\"" + statusCombo->currentText() + "\"";
205       docmd = true;
206    }
207    if (m_slot != slotSpin->value()) {
208       scmd += " slot=" + QString().setNum(slotSpin->value());
209       docmd = true;
210    }
211    if (m_retention != retentionSpin->value()) {
212       scmd += " VolRetention=" + QString().setNum(retentionSpin->value());
213       docmd = true;
214    }
215    if (m_useDuration != useDurationSpin->value()) {
216       scmd += " VolUse=" + QString().setNum(useDurationSpin->value());
217       docmd = true;
218    }
219    if (m_maxVolJobs != maxJobsSpin->value()) {
220       scmd += " MaxVolJobs=" + QString().setNum(maxJobsSpin->value());
221       docmd = true;
222    }
223    if (m_maxVolFiles != maxFilesSpin->value()) {
224       scmd += " MaxVolFiles=" + QString().setNum(maxFilesSpin->value());
225       docmd = true;
226    }
227    if (m_maxVolBytes != maxBytesSpin->value()) {
228       scmd += " MaxVolBytes=" + QString().setNum(maxBytesSpin->value());
229       docmd = true;
230    }
231    if ((m_recycle) && (recycleCheck->checkState() == Qt::Unchecked)) {
232       scmd += " Recycle=no";
233       docmd = true;
234    }
235    if ((!m_recycle) && (recycleCheck->checkState() == Qt::Checked)) {
236       scmd += " Recycle=yes";
237       docmd = true;
238    }
239    if ((m_enabled) && (enabledCheck->checkState() == Qt::Unchecked)) {
240       scmd += " enabled=no";
241       docmd = true;
242    }
243    if ((!m_enabled) && (enabledCheck->checkState() == Qt::Checked)) {
244       scmd += " enabled=yes";
245       docmd = true;
246    }
247    if (m_recyclePool != recyclePoolCombo->currentText()) {
248       scmd += " recyclepool=\"";
249       if (recyclePoolCombo->currentText() != "*None*") {
250          scmd += recyclePoolCombo->currentText();
251       }
252       scmd += "\"";
253       docmd = true;
254    }
255    if (docmd) {
256       if (mainWin->m_commandDebug) {
257          Pmsg1(000, "sending command : %s\n",scmd.toUtf8().data());
258       }
259       consoleCommand(scmd);
260    }
261    closeStackPage();
262 }
263 
264 /* close if cancel */
cancelButtonPushed()265 void MediaEdit::cancelButtonPushed()
266 {
267    closeStackPage();
268 }
269 
270 /*
271  * Slot for user changed retention
272  */
retentionChanged()273 void MediaEdit::retentionChanged()
274 {
275    retentionRadio->setChecked(true);
276    setSpins(retentionSpin->value());
277 }
278 
279 /*
280  * Slot for user changed the use duration
281  */
useDurationChanged()282 void MediaEdit::useDurationChanged()
283 {
284    useDurationRadio->setChecked(true);
285    setSpins(useDurationSpin->value());
286 }
287 
288 /*
289  * Set the 5 duration spins from a known duration value
290  */
setSpins(int value)291 void MediaEdit::setSpins(int value)
292 {
293    int years, months, days, hours, minutes, seconds, left;
294 
295    years = abs(value / 31536000);
296    left = value - years * 31536000;
297    months = abs(left / 2592000);
298    left = left - months * 2592000;
299    days = abs(left / 86400);
300    left = left - days * 86400;
301    hours = abs(left / 3600);
302    left = left - hours * 3600;
303    minutes = abs(left / 60);
304    seconds = left - minutes * 60;
305    disconnectSpins();
306    yearsSpin->setValue(years);
307    monthsSpin->setValue(months);
308    daysSpin->setValue(days);
309    hoursSpin->setValue(hours);
310    minutesSpin->setValue(minutes);
311    secondsSpin->setValue(seconds);
312    connectSpins();
313 }
314 
315 /*
316  * This slot is called any time any one of the 5 duration spins a changed.
317  */
durationChanged()318 void MediaEdit::durationChanged()
319 {
320    disconnectSpins();
321    if (secondsSpin->value() == -1) {
322       secondsSpin->setValue(59);
323       minutesSpin->setValue(minutesSpin->value()-1);
324    }
325    if (minutesSpin->value() == -1) {
326       minutesSpin->setValue(59);
327       hoursSpin->setValue(hoursSpin->value()-1);
328    }
329    if (hoursSpin->value() == -1) {
330       hoursSpin->setValue(23);
331       daysSpin->setValue(daysSpin->value()-1);
332    }
333    if (daysSpin->value() == -1) {
334       daysSpin->setValue(29);
335       monthsSpin->setValue(monthsSpin->value()-1);
336    }
337    if (monthsSpin->value() == -1) {
338       monthsSpin->setValue(11);
339       yearsSpin->setValue(yearsSpin->value()-1);
340    }
341    if (yearsSpin->value() == -1) {
342       yearsSpin->setValue(0);
343    }
344 
345    if (secondsSpin->value() == 60) {
346       secondsSpin->setValue(0);
347       minutesSpin->setValue(minutesSpin->value()+1);
348    }
349    if (minutesSpin->value() == 60) {
350       minutesSpin->setValue(0);
351       hoursSpin->setValue(hoursSpin->value()+1);
352    }
353    if (hoursSpin->value() == 24) {
354       hoursSpin->setValue(0);
355       daysSpin->setValue(daysSpin->value()+1);
356    }
357    if (daysSpin->value() == 30) {
358       daysSpin->setValue(0);
359       monthsSpin->setValue(monthsSpin->value()+1);
360    }
361    if (monthsSpin->value() == 12) {
362       monthsSpin->setValue(0);
363       yearsSpin->setValue(yearsSpin->value()+1);
364    }
365    connectSpins();
366    if (retentionRadio->isChecked()) {
367       int retention;
368       retention = secondsSpin->value() + minutesSpin->value() * 60 +
369          hoursSpin->value() * 3600 + daysSpin->value() * 86400 +
370          monthsSpin->value() * 2592000 +
371          yearsSpin->value() * 31536000;
372       disconnect(retentionSpin, SIGNAL(valueChanged(int)), this, SLOT(retentionChanged()));
373       retentionSpin->setValue(retention);
374       connect(retentionSpin, SIGNAL(valueChanged(int)), this, SLOT(retentionChanged()));
375    }
376    if (useDurationRadio->isChecked()) {
377       int useDuration;
378       useDuration = secondsSpin->value() + minutesSpin->value() * 60 +
379          hoursSpin->value() * 3600 + daysSpin->value() * 86400 +
380          monthsSpin->value() * 2592000 +
381          yearsSpin->value() * 31536000;
382       disconnect(useDurationSpin, SIGNAL(valueChanged(int)), this, SLOT(useDurationChanged()));
383       useDurationSpin->setValue(useDuration);
384       connect(useDurationSpin, SIGNAL(valueChanged(int)), this, SLOT(useDurationChanged()));
385    }
386 }
387 
388 /* Connect the spins */
connectSpins()389 void MediaEdit::connectSpins()
390 {
391    connect(secondsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
392    connect(minutesSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
393    connect(hoursSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
394    connect(daysSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
395    connect(monthsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
396    connect(yearsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
397 }
398 
399 /* disconnect spins so that we can set the value of other spin from changed duration spin */
disconnectSpins()400 void MediaEdit::disconnectSpins()
401 {
402    disconnect(secondsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
403    disconnect(minutesSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
404    disconnect(hoursSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
405    disconnect(daysSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
406    disconnect(monthsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
407    disconnect(yearsSpin, SIGNAL(valueChanged(int)), this, SLOT(durationChanged()));
408 }
409 
410 /* slot for setting spins when retention radio checked */
retentionRadioPressed()411 void MediaEdit::retentionRadioPressed()
412 {
413    setSpins(retentionSpin->value());
414 }
415 
416 /* slot for setting spins when duration radio checked */
useDurationRadioPressed()417 void MediaEdit::useDurationRadioPressed()
418 {
419    setSpins(useDurationSpin->value());
420 }
421