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