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