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