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