]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
Properly save RecyclePoolId
[bacula/bacula] / bacula / src / qt-console / console / console.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Version $Id$
30  *
31  *  Console Class
32  *
33  *   Kern Sibbald, January MMVII
34  *
35  */ 
36
37 //#include <QAbstractEventDispatcher>
38 #include "bat.h"
39 #include "console.h"
40 #include "restore.h"
41 #include "select.h"
42 #include "run/run.h"
43
44 static int tls_pem_callback(char *buf, int size, const void *userdata);
45
46
47 Console::Console(QStackedWidget *parent)
48 {
49    QFont font;
50    m_parent = parent;
51    m_closeable = false;
52    m_console = this;
53
54    setupUi(this);
55    m_sock = NULL;
56    m_at_prompt = false;
57    m_at_main_prompt = false;
58    m_textEdit = textEdit;   /* our console screen */
59    m_cursor = new QTextCursor(m_textEdit->document());
60    mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
61
62    m_timer = NULL;
63    m_contextActions.append(actionStatusDir);
64    m_contextActions.append(actionConsoleHelp);
65    m_contextActions.append(actionRequestMessages);
66    m_contextActions.append(actionConsoleReload);
67    connect(actionStatusDir, SIGNAL(triggered()), this, SLOT(status_dir()));
68    connect(actionConsoleHelp, SIGNAL(triggered()), this, SLOT(consoleHelp()));
69    connect(actionConsoleReload, SIGNAL(triggered()), this, SLOT(consoleReload()));
70    connect(actionRequestMessages, SIGNAL(triggered()), this, SLOT(messages()));
71 }
72
73 Console::~Console()
74 {
75 }
76
77 void Console::startTimer()
78 {
79    m_timer = new QTimer(this);
80    QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
81    m_timer->start(mainWin->m_checkMessagesInterval*1000);
82 }
83
84 void Console::stopTimer()
85 {
86    if (m_timer) {
87       QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
88       m_timer->stop();
89       delete m_timer;
90       m_timer = NULL;
91    }
92 }
93       
94 void Console::poll_messages()
95 {
96    m_messages_pending = true;
97    if ((m_at_main_prompt) && (mainWin->m_checkMessages)){
98       write(".messages");
99       displayToPrompt();
100    }
101 }
102
103 /* Terminate any open socket */
104 void Console::terminate()
105 {
106    if (m_sock) {
107       stopTimer();
108       m_sock->close();
109       m_sock = NULL;
110    }
111 }
112
113 /*
114  * Connect to Director. 
115  */
116 void Console::connect_dir()
117 {
118    JCR *jcr = new JCR;
119    utime_t heart_beat;
120    char buf[1024];
121    CONRES *cons;
122       
123    buf[0] = 0;
124
125    m_textEdit = textEdit;   /* our console screen */
126
127    if (!m_dir) {          
128       mainWin->set_status("No Director found.");
129       goto bail_out;
130    }
131    if (m_sock) {
132       mainWin->set_status("Already connected.");
133       goto bail_out;
134    }
135
136    memset(jcr, 0, sizeof(JCR));
137
138    mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
139    display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
140
141    /* Give GUI a chance */
142    app->processEvents();
143    
144    LockRes();
145    /* If cons==NULL, default console will be used */
146    cons = (CONRES *)GetNextRes(R_CONSOLE, NULL);
147    UnlockRes();
148
149    /* Initialize Console TLS context once */
150    if (cons && !cons->tls_ctx && (cons->tls_enable || cons->tls_require)) {
151       /* Generate passphrase prompt */
152       bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", 
153                 cons->name());
154
155       /* Initialize TLS context:
156        * Args: CA certfile, CA certdir, Certfile, Keyfile,
157        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer   
158        */
159       cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
160          cons->tls_ca_certdir, cons->tls_certfile,
161          cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
162
163       if (!cons->tls_ctx) {
164          display_textf(_("Failed to initialize TLS context for Console \"%s\".\n"),
165             m_dir->name());
166          goto bail_out;
167       }
168    }
169
170    /* Initialize Director TLS context once */
171    if (!m_dir->tls_ctx && (m_dir->tls_enable || m_dir->tls_require)) {
172       /* Generate passphrase prompt */
173       bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", 
174                 m_dir->name());
175
176       /* Initialize TLS context:
177        * Args: CA certfile, CA certdir, Certfile, Keyfile,
178        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
179       m_dir->tls_ctx = new_tls_context(m_dir->tls_ca_certfile,
180                           m_dir->tls_ca_certdir, m_dir->tls_certfile,
181                           m_dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
182
183       if (!m_dir->tls_ctx) {
184          display_textf(_("Failed to initialize TLS context for Director \"%s\".\n"),
185             m_dir->name());
186          mainWin->set_status("Connection failed");
187          goto bail_out;
188       }
189    }
190
191    if (m_dir->heartbeat_interval) {
192       heart_beat = m_dir->heartbeat_interval;
193    } else if (cons) {
194       heart_beat = cons->heartbeat_interval;
195    } else {
196       heart_beat = 0;
197    }        
198
199    m_sock = bnet_connect(NULL, 5, 15, heart_beat,
200                           _("Director daemon"), m_dir->address,
201                           NULL, m_dir->DIRport, 0);
202    if (m_sock == NULL) {
203       mainWin->set_status("Connection failed");
204       goto bail_out;
205    } else {
206       /* Update page selector to green to indicate that Console is connected */
207       mainWin->actionConnect->setIcon(QIcon(":images/connected.png"));
208       QBrush greenBrush(Qt::green);
209       QTreeWidgetItem *item = mainWin->getFromHash(this);
210       item->setForeground(0, greenBrush);
211    }
212
213    jcr->dir_bsock = m_sock;
214
215    if (!authenticate_director(jcr, m_dir, cons, buf, sizeof(buf))) {
216       display_text(buf);
217       goto bail_out;
218    }
219
220    if (buf[0]) {
221       display_text(buf);
222    }
223
224    /* Give GUI a chance */
225    app->processEvents();
226
227    mainWin->set_status(_("Initializing ..."));
228
229    /* Set up input notifier */
230    m_notifier = new QSocketNotifier(m_sock->m_fd, QSocketNotifier::Read, 0);
231    QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
232
233    write(".api 1");
234    displayToPrompt();
235
236    beginNewCommand();
237    job_list.clear();
238    client_list.clear();
239    fileset_list.clear();
240    fileset_list.clear();
241    messages_list.clear();
242    pool_list.clear();
243    storage_list.clear();
244    type_list.clear();
245    level_list.clear();
246    dir_cmd(".jobs", job_list);
247    dir_cmd(".clients", client_list);
248    dir_cmd(".filesets", fileset_list);  
249    dir_cmd(".msgs", messages_list);
250    dir_cmd(".pools", pool_list);
251    dir_cmd(".storage", storage_list);
252    dir_cmd(".types", type_list);
253    dir_cmd(".levels", level_list);
254
255    mainWin->set_status(_("Connected"));
256    startTimer();                      /* start message timer */
257
258 bail_out:
259    delete jcr;
260    return;
261 }
262
263 bool Console::dir_cmd(QString &cmd, QStringList &results)
264 {
265    return dir_cmd(cmd.toUtf8().data(), results);
266 }
267
268 /*
269  * Send a command to the Director, and return the
270  *  results in a QStringList.  
271  */
272 bool Console::dir_cmd(const char *cmd, QStringList &results)
273 {
274    int stat;
275
276    notify(false);
277    write(cmd);
278    while ((stat = read()) > 0) {
279       if (mainWin->m_displayAll) display_text(msg());
280       strip_trailing_junk(msg());
281       results << msg();
282    }
283    notify(true);
284    discardToPrompt();
285    return true;              /* ***FIXME*** return any command error */
286 }
287
288 bool Console::sql_cmd(QString &query, QStringList &results)
289 {
290    return sql_cmd(query.toUtf8().data(), results);
291 }
292
293 /*
294  * Send an sql query to the Director, and return the
295  *  results in a QStringList.  
296  */
297 bool Console::sql_cmd(const char *query, QStringList &results)
298 {
299    int stat;
300    POOL_MEM cmd(PM_MESSAGE);
301
302    if (!is_connectedGui()) {
303       return false;
304    }
305
306    notify(false);
307    
308    pm_strcpy(cmd, ".sql query=\"");
309    pm_strcat(cmd, query);
310    pm_strcat(cmd, "\"");
311    write(cmd.c_str());
312    while ((stat = read()) > 0) {
313       if (mainWin->m_displayAll) display_text(msg());
314       strip_trailing_junk(msg());
315       results << msg();
316    }
317    notify(true);
318    discardToPrompt();
319    return true;              /* ***FIXME*** return any command error */
320 }
321
322
323 /*  
324  * Send a job name to the director, and read all the resulting
325  *  defaults. 
326  */
327 bool Console::get_job_defaults(struct job_defaults &job_defs)
328 {
329    QString scmd;
330    int stat;
331    char *def;
332
333    notify(false);
334    beginNewCommand();
335    scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
336    write(scmd);
337    while ((stat = read()) > 0) {
338       if (mainWin->m_displayAll) display_text(msg());
339       def = strchr(msg(), '=');
340       if (!def) {
341          continue;
342       }
343       /* Pointer to default value */
344       *def++ = 0;
345       strip_trailing_junk(def);
346
347       if (strcmp(msg(), "job") == 0) {
348          if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
349             goto bail_out;
350          }
351          continue;
352       }
353       if (strcmp(msg(), "pool") == 0) {
354          job_defs.pool_name = def;
355          continue;
356       }
357       if (strcmp(msg(), "messages") == 0) {
358          job_defs.messages_name = def;
359          continue;
360       }
361       if (strcmp(msg(), "client") == 0) {
362          job_defs.client_name = def;
363          continue;
364       }
365       if (strcmp(msg(), "storage") == 0) {
366          job_defs.store_name = def;
367          continue;
368       }
369       if (strcmp(msg(), "where") == 0) {
370          job_defs.where = def;
371          continue;
372       }
373       if (strcmp(msg(), "level") == 0) {
374          job_defs.level = def;
375          continue;
376       }
377       if (strcmp(msg(), "type") == 0) {
378          job_defs.type = def;
379          continue;
380       }
381       if (strcmp(msg(), "fileset") == 0) {
382          job_defs.fileset_name = def;
383          continue;
384       }
385       if (strcmp(msg(), "catalog") == 0) {
386          job_defs.catalog_name = def;
387          continue;
388       }
389       if (strcmp(msg(), "enabled") == 0) {
390          job_defs.enabled = *def == '1' ? true : false;
391          continue;
392       }
393    }
394
395    notify(true);
396    return true;
397
398 bail_out:
399    notify(true);
400    return false;
401 }
402
403
404 /*
405  * Save user settings associated with this console
406  */
407 void Console::writeSettings()
408 {
409    QFont font = get_font();
410
411    QSettings settings(m_dir->name(), "bat");
412    settings.beginGroup("Console");
413    settings.setValue("consoleFont", font.family());
414    settings.setValue("consolePointSize", font.pointSize());
415    settings.setValue("consoleFixedPitch", font.fixedPitch());
416    settings.endGroup();
417 }
418
419 /*
420  * Read and restore user settings associated with this console
421  */
422 void Console::readSettings()
423
424    QFont font = get_font();
425
426    QSettings settings(m_dir->name(), "bat");
427    settings.beginGroup("Console");
428    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
429    font.setPointSize(settings.value("consolePointSize", 10).toInt());
430    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
431    settings.endGroup();
432    m_textEdit->setFont(font);
433 }
434
435 /*
436  * Set the console textEdit font
437  */
438 void Console::set_font()
439 {
440    bool ok;
441    QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
442    if (ok) {
443       m_textEdit->setFont(font);
444    }
445 }
446
447 /*
448  * Get the console text edit font
449  */
450 const QFont Console::get_font()
451 {
452    return m_textEdit->font();
453 }
454
455 /*
456  * Slot for responding to status dir button on button bar
457  */
458 void Console::status_dir()
459 {
460    QString cmd("status dir");
461    consoleCommand(cmd);
462 }
463
464 /*
465  * Slot for responding to messages button on button bar
466  */
467 void Console::messages()
468 {
469    QString cmd(".messages");
470    consoleCommand(cmd);
471 }
472
473 /*
474  * Put text into the console window
475  */
476 void Console::display_textf(const char *fmt, ...)
477 {
478    va_list arg_ptr;
479    char buf[1000];
480    int len;
481    va_start(arg_ptr, fmt);
482    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
483    va_end(arg_ptr);
484    display_text(buf);
485 }
486
487 void Console::display_text(const QString buf)
488 {
489    m_cursor->insertText(buf);
490    update_cursor();
491 }
492
493
494 void Console::display_text(const char *buf)
495 {
496    m_cursor->insertText(buf);
497    update_cursor();
498 }
499
500 void Console::display_html(const QString buf)
501 {
502    m_cursor->insertHtml(buf);
503    update_cursor();
504 }
505
506 /* Position cursor to end of screen */
507 void Console::update_cursor()
508 {
509    QApplication::restoreOverrideCursor();
510    m_textEdit->moveCursor(QTextCursor::End);
511    m_textEdit->ensureCursorVisible();
512 }
513
514 /* 
515  * This should be moved into a bSocket class 
516  */
517 char *Console::msg()
518 {
519    if (m_sock) {
520       return m_sock->msg;
521    }
522    return NULL;
523 }
524
525 /* Send a command to the Director */
526 void Console::write_dir(const char *msg)
527 {
528    if (m_sock) {
529       mainWin->set_status(_("Processing command ..."));
530       QApplication::setOverrideCursor(Qt::WaitCursor);
531       write(msg);
532    } else {
533       mainWin->set_status(" Director not connected. Click on connect button.");
534       mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
535       QBrush redBrush(Qt::red);
536       QTreeWidgetItem *item = mainWin->getFromHash(this);
537       item->setForeground(0, redBrush);
538       m_at_prompt = false;
539       m_at_main_prompt = false;
540    }
541 }
542
543 int Console::write(const QString msg)
544 {
545    return write(msg.toUtf8().data());
546 }
547
548 int Console::write(const char *msg)
549 {
550    if (!m_sock) {
551       return -1;
552    }
553    m_sock->msglen = pm_strcpy(m_sock->msg, msg);
554    m_at_prompt = false;
555    m_at_main_prompt = false;
556    if (mainWin->m_commDebug) Pmsg1(000, "send: %s\n", msg);
557    return m_sock->send();
558
559 }
560
561 /*
562  * Get to main command prompt -- i.e. abort any subcommand
563  */
564 void Console::beginNewCommand()
565 {
566    for (int i=0; i < 3; i++) {
567       write(".");
568       while (read() > 0) {
569          if (mainWin->m_displayAll) display_text(msg());
570       }
571       if (m_at_main_prompt) {
572          break;
573       }
574    }
575    display_text("\n");
576 }
577
578 void Console::displayToPrompt()
579
580    int stat = 0;
581    if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
582    while (!m_at_prompt) {
583       if ((stat=read()) > 0) {
584          display_text(msg());
585       }
586    }
587    if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
588 }
589
590 void Console::discardToPrompt()
591
592    int stat = 0;
593    if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
594    while (!m_at_prompt) {
595       if ((stat=read()) > 0) {
596          if (mainWin->m_displayAll) display_text(msg());
597       }
598    }
599    if (mainWin->m_commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
600 }
601
602
603 /* 
604  * Blocking read from director
605  */
606 int Console::read()
607 {
608    int stat = 0;
609    while (m_sock) {
610       for (;;) {
611          stat = bnet_wait_data_intr(m_sock, 1);
612          if (stat > 0) {
613             break;
614          } 
615          app->processEvents();
616          if (m_api_set && m_messages_pending) {
617             write_dir(".messages");
618             m_messages_pending = false;
619          }
620       }
621       m_sock->msg[0] = 0;
622       stat = m_sock->recv();
623       if (stat >= 0) {
624          if (mainWin->m_commDebug) Pmsg1(000, "got: %s\n", m_sock->msg);
625          if (m_at_prompt) {
626             display_text("\n");
627             m_at_prompt = false;
628             m_at_main_prompt = false;
629          }
630       }
631       switch (m_sock->msglen) {
632       case BNET_MSGS_PENDING:
633          if (mainWin->m_commDebug) Pmsg0(000, "MSGS PENDING\n");
634          write_dir(".messages");
635          displayToPrompt();
636          m_messages_pending = false;
637          continue;
638       case BNET_CMD_OK:
639          if (mainWin->m_commDebug) Pmsg0(000, "CMD OK\n");
640          m_at_prompt = false;
641          m_at_main_prompt = false;
642          mainWin->set_status(_("Command completed ..."));
643          continue;
644       case BNET_CMD_BEGIN:
645          if (mainWin->m_commDebug) Pmsg0(000, "CMD BEGIN\n");
646          m_at_prompt = false;
647          m_at_main_prompt = false;
648          mainWin->set_status(_("Processing command ..."));
649          continue;
650       case BNET_MAIN_PROMPT:
651          if (mainWin->m_commDebug) Pmsg0(000, "MAIN PROMPT\n");
652          m_at_prompt = true;
653          m_at_main_prompt = true;
654          mainWin->set_status(_("At main prompt waiting for input ..."));
655          QApplication::restoreOverrideCursor();
656          break;
657       case BNET_PROMPT:
658          if (mainWin->m_commDebug) Pmsg0(000, "PROMPT\n");
659          m_at_prompt = true;
660          m_at_main_prompt = false;
661          mainWin->set_status(_("At prompt waiting for input ..."));
662          QApplication::restoreOverrideCursor();
663          break;
664       case BNET_CMD_FAILED:
665          if (mainWin->m_commDebug) Pmsg0(000, "CMD FAILED\n");
666          mainWin->set_status(_("Command failed."));
667          QApplication::restoreOverrideCursor();
668          break;
669       /* We should not get this one */
670       case BNET_EOD:
671          if (mainWin->m_commDebug) Pmsg0(000, "EOD\n");
672          mainWin->set_status_ready();
673          QApplication::restoreOverrideCursor();
674          if (!m_api_set) {
675             break;
676          }
677          continue;
678       case BNET_START_SELECT:
679          if (mainWin->m_commDebug) Pmsg0(000, "START SELECT\n");
680          new selectDialog(this);    
681          break;
682       case BNET_RUN_CMD:
683          if (mainWin->m_commDebug) Pmsg0(000, "RUN CMD\n");
684          new runCmdPage();
685          break;
686       case BNET_ERROR_MSG:
687          if (mainWin->m_commDebug) Pmsg0(000, "ERROR MSG\n");
688          m_sock->recv();              /* get the message */
689          display_text(msg());
690          QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
691          break;
692       case BNET_WARNING_MSG:
693          if (mainWin->m_commDebug) Pmsg0(000, "WARNING MSG\n");
694          m_sock->recv();              /* get the message */
695          display_text(msg());
696          QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
697          break;
698       case BNET_INFO_MSG:
699          if (mainWin->m_commDebug) Pmsg0(000, "INFO MSG\n");
700          m_sock->recv();              /* get the message */
701          display_text(msg());
702          mainWin->set_status(msg());
703          break;
704       }
705       if (is_bnet_stop(m_sock)) {         /* error or term request */
706          if (mainWin->m_commDebug) Pmsg0(000, "BNET STOP\n");
707          stopTimer();
708          m_sock->close();
709          m_sock = NULL;
710          mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
711          QBrush redBrush(Qt::red);
712          QTreeWidgetItem *item = mainWin->getFromHash(this);
713          item->setForeground(0, redBrush);
714          m_notifier->setEnabled(false);
715          delete m_notifier;
716          m_notifier = NULL;
717          mainWin->set_status(_("Director disconnected."));
718          QApplication::restoreOverrideCursor();
719          stat = BNET_HARDEOF;
720       }
721       break;
722    } 
723    return stat;
724 }
725
726 /* Called by signal when the Director has output for us */
727 void Console::read_dir(int /* fd */)
728 {
729    if (mainWin->m_commDebug) Pmsg0(000, "read_dir\n");
730    while (read() >= 0) {
731       display_text(msg());
732    }
733 }
734
735 /*
736  * When the notifier is enabled, read_dir() will automatically be
737  * called by the Qt event loop when ever there is any output 
738  * from the Directory, and read_dir() will then display it on
739  * the console.
740  *
741  * When we are in a bat dialog, we want to control *all* output
742  * from the Directory, so we set notify to off.
743  *    m_console->notifiy(false);
744  */
745 void Console::notify(bool enable) 
746
747    m_notifier->setEnabled(enable);   
748 }
749
750 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
751 {
752    m_directorTreeItem = item;
753 }
754
755 void Console::setDirRes(DIRRES *dir) 
756
757    m_dir = dir;
758 }
759
760 /*
761  * To have the ability to get the name of the director resource.
762  */
763 void Console::getDirResName(QString &name_returned)
764 {
765    name_returned = m_dir->name();
766 }
767
768 bool Console::is_connectedGui()
769 {
770    if (is_connected()) {
771       return true;
772    } else {
773       QString message("Director ");
774       message += " is currently disconnected\n  Please reconnect!!";
775       QMessageBox::warning(this, "Bat",
776          tr(message.toUtf8().data()), QMessageBox::Ok );
777       return false;
778    }
779 }
780
781 /*
782  * A temporary function to prevent connecting to the director if the director
783  * is busy with a restore.
784  */
785 bool Console::preventInUseConnect()
786 {
787    if (!is_connected()) {
788       QString message("Director ");
789       message += m_dir->name();
790       message += " is currently disconnected\n  Please reconnect!!";
791       QMessageBox::warning(this, "Bat",
792          tr(message.toUtf8().data()), QMessageBox::Ok );
793       return false;
794    } else if (!m_at_main_prompt){
795       QString message("Director ");
796       message += m_dir->name();
797       message += " is currently busy\n  Please complete restore or other "
798                  " operation !!  This is a limitation that will be resolved before a beta"
799                  " release.  This is currently an alpha release.";
800       QMessageBox::warning(this, "Bat",
801          tr(message.toUtf8().data()), QMessageBox::Ok );
802       return false;
803    } else if (!m_at_prompt){
804       QString message("Director ");
805       message += m_dir->name();
806       message += " is currently not at a prompt\n  Please try again!!";
807       QMessageBox::warning(this, "Bat",
808          tr(message.toUtf8().data()), QMessageBox::Ok );
809       return false;
810    } else {
811       return true;
812    }
813 }
814
815 /*
816  * Call-back for reading a passphrase for an encrypted PEM file
817  * This function uses getpass(), 
818  *  which uses a static buffer and is NOT thread-safe.
819  */
820 static int tls_pem_callback(char *buf, int size, const void *userdata)
821 {
822    (void)size;
823    (void)userdata;
824 #ifdef HAVE_TLS
825    const char *prompt = (const char *)userdata;
826 # if defined(HAVE_WIN32)
827    sendit(prompt);
828    if (win32_cgets(buf, size) == NULL) {
829       buf[0] = 0;
830       return 0;
831    } else {
832       return strlen(buf);
833    }
834 # else
835    char *passwd;
836
837    passwd = getpass(prompt);
838    bstrncpy(buf, passwd, size);
839    return strlen(buf);
840 # endif
841 #else
842    buf[0] = 0;
843    return 0;
844 #endif
845 }
846
847 /* Slot for responding to page selectors status help command */
848 void Console::consoleHelp()
849 {
850    QString cmd("help");
851    consoleCommand(cmd);
852 }
853
854 /* Slot for responding to page selectors reload bacula-dir.conf */
855 void Console::consoleReload()
856 {
857    QString cmd("reload");
858    consoleCommand(cmd);
859 }
860
861 /* Function to get a list of volumes */
862 void Console::getVolumeList(QStringList &volumeList)
863 {
864    QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
865    if (mainWin->m_sqlDebug) {
866       Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
867    }
868    QStringList results;
869    if (sql_cmd(query, results)) {
870       QString field;
871       QStringList fieldlist;
872       /* Iterate through the lines of results. */
873       foreach (QString resultline, results) {
874          fieldlist = resultline.split("\t");
875          volumeList.append(fieldlist[0]);
876       } /* foreach resultline */
877    } /* if results from query */
878 }
879
880 /* Function to get a list of volumes */
881 void Console::getStatusList(QStringList &statusLongList)
882 {
883    QString statusQuery("SELECT JobStatusLong FROM Status");
884    if (mainWin->m_sqlDebug) {
885       Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
886    }
887    QStringList statusResults;
888    if (sql_cmd(statusQuery, statusResults)) {
889       QString field;
890       QStringList fieldlist;
891       /* Iterate through the lines of results. */
892       foreach (QString resultline, statusResults) {
893          fieldlist = resultline.split("\t");
894          statusLongList.append(fieldlist[0]);
895       } /* foreach resultline */
896    } /* if results from statusquery */
897 }