]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/tray-monitor/conf.cpp
Big backport from Enterprise
[bacula/bacula] / bacula / src / qt-console / tray-monitor / conf.cpp
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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 #include "conf.h"
21 #include "tray-monitor.h"
22 #include <QFileDialog>
23
24 extern char *configfile;        // defined in tray-monitor.cpp
25 extern RES_TABLE resources[];
26 extern int32_t r_first;
27 extern int32_t r_last;
28 extern int32_t res_all_size;
29 extern URES res_all;
30
31 bool Conf::parse_config()
32 {
33    bool ret;
34    config = New(CONFIG());
35    config->encode_password(false);
36    config->init(configfile, NULL, M_ERROR, (void *)&res_all, res_all_size,
37                 r_first, r_last, resources, &rhead);
38    ret = config->parse_config();
39    return ret;
40 }
41
42 /* Check for \ at the end */
43 static char *is_str_valid(POOLMEM **buf, const char *p)
44 {
45    char *p1;
46    if (!p || !*p) {
47       return NULL;
48    }
49    p1 = *buf = check_pool_memory_size(*buf, (strlen(p) + 1));
50    for (; *p ; p++) {
51       if (*p == '\\') {
52          *p1++ = '/';
53
54       } else if (*p == '"') {
55          return NULL;
56
57       } else {
58          *p1++ = *p;
59       }
60    }
61    *p1 = 0;
62    return *buf;
63 }
64
65 /* The .toUtf8().data() function can be called only one time at a time */
66 void Conf::accept()
67 {
68    POOLMEM *buf = get_pool_memory(PM_FNAME);
69    POOL_MEM tmp, tmp2, name;
70    QString str;
71    const char *restype=NULL, *p=NULL, *pname;
72    struct stat sp;
73    FILE *fp=NULL;
74    int   n;
75    bool  commit=false;
76    bool  doclose=true;
77    bool  ok;
78
79    Mmsg(tmp, "%s.temp", configfile);
80    fp = fopen(tmp.c_str(), "w");
81    if (!fp) {
82       berrno be;
83       display_error("Unable to open %s to write the new configuration file. ERR=%s\n", tmp.c_str(), be.bstrerror());
84       goto bail_out;
85    }
86    str = UIConf.editName->text();
87    p = is_str_valid(&buf, str.toUtf8().data());
88    if (!p) {
89       display_error(_("The Name of the Monitor should be set"));
90       doclose = false;
91       goto bail_out;
92    }
93
94    fprintf(fp, "Monitor {\n Name=\"%s\"\n", p);
95
96    n = UIConf.spinRefresh->value();
97    fprintf(fp, " Refresh Interval = %d\n", n);
98
99    if (UIConf.cbDspAdvanced->isChecked()) {
100       fprintf(fp, " Display Advanced Options = yes\n");
101    }
102
103    str = UIConf.editCommandDir->text();
104    p = is_str_valid(&buf, str.toUtf8().data());
105    if (p) {   // TODO: Check for \ at the end of the string
106       fprintf(fp, " Command Directory = \"%s\"\n", p);
107    }
108
109    fprintf(fp, "}\n");
110
111    for (int i = 1; i < UIConf.tabWidget->count() ; i++) {
112       ConfTab *t = (ConfTab *) UIConf.tabWidget->widget(i);
113       if (t->isEnabled() == false) {
114          continue;              // This one was deleted
115       }
116       for(int i = 0; resources[i].name ; i++) {
117          if (resources[i].rcode == t->res->type) {
118             restype = resources[i].name;
119             break;
120          }
121       }
122       if (!restype) {
123          goto bail_out;
124       }
125
126       str = t->ui.editName->text();
127       pname = is_str_valid(&buf, str.toUtf8().data());
128       if (!pname) {
129          display_error(_("The name of the Resource should be set"));
130          doclose = false;
131          goto bail_out;
132       }
133       pm_strcpy(name, pname);
134
135       str = t->ui.editAddress->text();
136       p = is_str_valid(&buf, str.toUtf8().data());
137       if (!p) {
138          display_error(_("The address of the Resource should be set for resource %s"), name.c_str());
139          doclose = false;
140          goto bail_out;
141       }
142       fprintf(fp, "%s {\n Name = \"%s\"\n Address = \"%s\"\n", restype, name.c_str(), p);
143
144       str = t->ui.editPassword->text();
145       p = is_str_valid(&buf, str.toUtf8().data());
146       if (!p) {
147          display_error(_("The Password of should be set for resource %s"), name.c_str());
148          doclose = false;
149          goto bail_out;
150       }
151       fprintf(fp, " Password = \"%s\"\n", p);
152
153       str = t->ui.editDescription->text();
154       p = is_str_valid(&buf, str.toUtf8().data());
155       if (p) {
156          fprintf(fp, " Description = \"%s\"\n", p);
157       }
158       n = t->ui.editPort->text().toInt(&ok, 10);
159       if (ok && n > 0 && n < 65636) {
160          fprintf(fp, " Port = %d\n", n);
161       }
162       n = t->ui.editTimeout->text().toInt(&ok, 10);
163       if (ok && n > 0) {
164          fprintf(fp, " Connect Timeout = %d\n", n);
165       }
166
167       str = t->ui.editCaCertificateFile->text();
168       p = is_str_valid(&buf, str.toUtf8().data());
169       if (p) {
170          if (stat(p, &sp) != 0 || !S_ISREG(sp.st_mode)) {
171             display_error(_("The TLS CA Certificate File should be a PEM file for resource %s"), name.c_str());
172             doclose = false;
173             goto bail_out;
174          }
175          fprintf(fp, " TLSCaCertificateFile = \"%s\"\n", p);
176       }
177
178       str = t->ui.editCaCertificateDir->text();
179       p = is_str_valid(&buf, str.toUtf8().data());
180       if (p) {
181          if (stat(p, &sp) != 0 || !S_ISDIR(sp.st_mode)) {
182             display_error(_("The TLS CA Certificate Directory should be a directory for resource %s"), name.c_str());
183             doclose = false;
184             goto bail_out;
185          }
186          fprintf(fp, " TLSCaCertificateDir = \"%s\"\n", p);
187       }
188
189       str = t->ui.editCertificate->text();
190       p = is_str_valid(&buf, str.toUtf8().data());
191       if (p) {
192          if (stat(p, &sp) != 0 || !S_ISREG(sp.st_mode)) {
193             display_error(_("The TLS Certificate File should be a file for resource %s"), name.c_str());
194             doclose = false;
195             goto bail_out;
196          }
197          fprintf(fp, " TLSCertificate = \"%s\"\n", p);
198       }
199
200       str = t->ui.editKey->text();
201       p = is_str_valid(&buf, str.toUtf8().data());
202       if (p) {
203          if (stat(p, &sp) != 0 || !S_ISREG(sp.st_mode)) {
204             display_error(_("The TLS Key File should be a file for resource %s"), name.c_str());
205             doclose = false;
206             goto bail_out;
207          }
208          fprintf(fp, " TLSKey = \"%s\"\n", p);
209       }
210       if (t->ui.cbTLSEnabled->isChecked()) {
211          fprintf(fp, " TLS Enable = yes\n");
212       }
213       if (strcmp(restype, "client") == 0 && t->ui.cbRemote->isChecked()) {
214          fprintf(fp, " Remote = yes\n");
215       }
216       if (strcmp(restype, "director") == 0 && t->ui.cbUseSetIp->isChecked()) {
217          fprintf(fp, " UseSetIp = yes\n");
218       }
219       if (t->ui.cbMonitor->isChecked()) {
220          fprintf(fp, " Monitor = yes\n");
221       }
222       fprintf(fp, "}\n");
223    }
224    commit = true;
225    // Save the configuration file
226 bail_out:
227    if (fp) {
228       fclose(fp);
229    }
230    if (commit) {
231       // TODO: We probably need to load the configuration file to see if it works
232       unlink(configfile);
233       if (rename(tmp.c_str(), configfile) == 0) {
234          reload();
235
236       } else {
237          berrno be;
238          display_error("Unable to write to the configuration file %s ERR=%s\n", configfile, be.bstrerror());
239       }
240    }
241    if (doclose) {
242       close();
243       deleteLater();
244    }
245 }
246
247 Conf::~Conf()
248 {
249    if (config) {
250       delete config;
251    }
252 }
253
254 Conf::Conf(): QDialog()
255 {
256    RESMON  *res;
257    MONITOR *mon;
258
259    rhead = NULL;
260    items = 0;
261    UIConf.setupUi(this);
262    if (parse_config()) {
263       for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_CLIENT, (RES*)res));) {
264          addResource(res, res->hdr.name);
265       }
266       for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_DIRECTOR, (RES*)res));) {
267          addResource(res, res->hdr.name);
268       }
269       for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_STORAGE, (RES*)res));) {
270          addResource(res, res->hdr.name);
271       }
272       mon = (MONITOR *)GetNextRes(rhead, R_MONITOR, NULL);
273       UIConf.editName->setText(QString(mon->hdr.name));
274       UIConf.spinRefresh->setValue(mon->RefreshInterval);
275       UIConf.editCommandDir->setText(QString(NPRTB(mon->command_dir)));
276
277       if (mon->display_advanced_options) {
278          UIConf.cbDspAdvanced->setChecked(true);
279       }
280    }
281    setAttribute(Qt::WA_DeleteOnClose, true);
282    show();
283 }
284
285 void Conf::addResource(RESMON *res, const char *title)
286 {
287    char ed1[50];
288    ConfTab *w = new ConfTab(res);
289    w->ui.editName->setText(QString(res->hdr.name));
290    if (res->password) {
291       w->ui.editPassword->setText(QString(res->password));
292    }
293    if (res->type != R_CLIENT) {
294       w->ui.cbRemote->hide();
295       w->ui.labelRemote->hide();
296
297    } else if (res->use_remote) {
298       w->ui.cbRemote->setChecked(true);
299    }
300
301    if (res->type != R_DIRECTOR) {
302       w->ui.cbUseSetIp->hide();
303       w->ui.labelSetIp->hide();
304
305    } else if (res->use_setip) {
306       w->ui.cbUseSetIp->setChecked(true);
307    }
308
309    if (res->use_monitor) {
310       w->ui.cbMonitor->setChecked(true);
311    }
312    w->ui.editAddress->setText(QString(res->address));
313    w->ui.editPort->setText(QString(edit_uint64(res->port, ed1)));
314    w->ui.editTimeout->setText(QString(edit_uint64(res->connect_timeout, ed1)));
315    if (!res->tls_enable) {
316       if (w->ui.cbTLSEnabled->isChecked()) {
317          emit w->ui.cbTLSEnabled->click();
318       }
319    }
320    if (res->tls_ca_certfile) {
321       w->ui.editCaCertificateFile->setText(QString(res->tls_ca_certfile));
322    }
323    if (res->tls_ca_certdir) {
324       w->ui.editCaCertificateDir->setText(QString(res->tls_ca_certdir));
325    }
326    if (res->tls_certfile) {
327       w->ui.editCertificate->setText(QString(res->tls_certfile));
328    }
329    if (res->tls_keyfile) {
330       w->ui.editKey->setText(QString(res->tls_keyfile));
331    }
332    
333    UIConf.tabWidget->addTab(w, QString(title));
334    items++;
335 }
336
337 void Conf::addRes(int type, const char *title)
338 {
339    RESMON *res = (RESMON *) malloc(sizeof(RESMON));
340    init_resource(config, type, res);
341    res->type = type;            // Not sure it's set by init_resource
342    res->new_resource = true;    // We want to free this resource with the ConfTab
343    addResource(res, title);
344 }
345
346 void Conf::addDir()
347 {
348    addRes(R_DIRECTOR, "New Director");
349 }
350
351 void Conf::addStore()
352 {
353    addRes(R_STORAGE, "New Storage");
354 }
355
356 void Conf::addClient()
357 {
358    addRes(R_CLIENT, "New Client");
359 }
360
361 void Conf::togglePassword()
362 {
363    if (passtype == QLineEdit::Normal) {
364       passtype = QLineEdit::PasswordEchoOnEdit;
365    } else {
366       passtype = QLineEdit::Normal;
367    }
368    for (int i = 1; i < UIConf.tabWidget->count() ; i++) {
369       ConfTab *tab = (ConfTab *) UIConf.tabWidget->widget(i);
370       tab->ui.editPassword->setEchoMode(passtype);
371    }
372 }
373
374 void Conf::selectCommandDir()
375 {
376    QString directory = QFileDialog::getExistingDirectory(this,
377                                                          tr("Select Command Directory"),
378                                                          QDir::currentPath());
379    UIConf.editCommandDir->setText(directory);
380 }
381
382 void ConfTab::selectCaCertificateFile()
383 {
384    QString directory = QFileDialog::getOpenFileName(this,
385                                                     tr("Select CA Certificate File PEM file"),
386                                                     QDir::currentPath());
387    ui.editCaCertificateFile->setText(directory);
388 }
389
390 void ConfTab::selectCaCertificateDir()
391 {
392    QString directory = QFileDialog::getExistingDirectory(this,
393                                                          tr("Select CA Certificate Directory"),
394                                                          QDir::currentPath());
395    ui.editCaCertificateDir->setText(directory);
396 }
397
398 void ConfTab::selectCertificate()
399 {
400    QString file = QFileDialog::getOpenFileName(this,
401                                                tr("Select TLS Certificate File"),
402                                                QDir::currentPath());
403    ui.editCertificate->setText(file);
404 }
405
406 void ConfTab::selectKey()
407 {
408    QString file = QFileDialog::getOpenFileName(this,
409                                                tr("Select TLS Certificate File"),
410                                                QDir::currentPath());
411    ui.editKey->setText(file);
412 }