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