]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
Update
[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       stopTimer();
100       m_sock->close();
101       m_sock = NULL;
102    }
103 }
104
105 /*
106  * Connect to Director. 
107  */
108 void Console::connect_dir()
109 {
110    JCR jcr;
111    utime_t heart_beat;
112    char buf[1024];
113
114    m_textEdit = textEdit;   /* our console screen */
115
116    if (!m_dir) {          
117       mainWin->set_status("No Director found.");
118       return;
119    }
120    if (m_sock) {
121       mainWin->set_status("Already connected.");
122       return;
123    }
124
125    memset(&jcr, 0, sizeof(jcr));
126
127    mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
128    display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
129
130    /* Give GUI a chance */
131    app->processEvents();
132    
133    LockRes();
134    /* If cons==NULL, default console will be used */
135    CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, NULL);
136    UnlockRes();
137
138    /* Initialize Console TLS context once */
139    if (cons && !cons->tls_ctx && (cons->tls_enable || cons->tls_require)) {
140       /* Generate passphrase prompt */
141       bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", 
142                 cons->name());
143
144       /* Initialize TLS context:
145        * Args: CA certfile, CA certdir, Certfile, Keyfile,
146        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer   
147        */
148       cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
149          cons->tls_ca_certdir, cons->tls_certfile,
150          cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
151
152       if (!cons->tls_ctx) {
153          display_textf(_("Failed to initialize TLS context for Console \"%s\".\n"),
154             m_dir->name());
155          return;
156       }
157    }
158
159    /* Initialize Director TLS context once */
160    if (!m_dir->tls_ctx && (m_dir->tls_enable || m_dir->tls_require)) {
161       /* Generate passphrase prompt */
162       bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", 
163                 m_dir->name());
164
165       /* Initialize TLS context:
166        * Args: CA certfile, CA certdir, Certfile, Keyfile,
167        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
168       m_dir->tls_ctx = new_tls_context(m_dir->tls_ca_certfile,
169                           m_dir->tls_ca_certdir, m_dir->tls_certfile,
170                           m_dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
171
172       if (!m_dir->tls_ctx) {
173          display_textf(_("Failed to initialize TLS context for Director \"%s\".\n"),
174             m_dir->name());
175          mainWin->set_status("Connection failed");
176          return;
177       }
178    }
179
180    if (m_dir->heartbeat_interval) {
181       heart_beat = m_dir->heartbeat_interval;
182    } else if (cons) {
183       heart_beat = cons->heartbeat_interval;
184    } else {
185       heart_beat = 0;
186    }        
187
188    m_sock = bnet_connect(NULL, 5, 15, heart_beat,
189                           _("Director daemon"), m_dir->address,
190                           NULL, m_dir->DIRport, 0);
191    if (m_sock == NULL) {
192       mainWin->set_status("Connection failed");
193       return;
194    } else {
195       /* Update page selector to green to indicate that Console is connected */
196       mainWin->actionConnect->setIcon(QIcon(":images/connected.png"));
197       QBrush greenBrush(Qt::green);
198       QTreeWidgetItem *item = mainWin->getFromHash(this);
199       item->setForeground(0, greenBrush);
200    }
201
202    jcr.dir_bsock = m_sock;
203
204    if (!authenticate_director(&jcr, m_dir, cons, buf, sizeof(buf))) {
205       display_text(buf);
206       return;
207    }
208    if (buf[0]) {
209       display_text(buf);
210    }
211
212    /* Give GUI a chance */
213    app->processEvents();
214
215    mainWin->set_status(_("Initializing ..."));
216
217    /* Set up input notifier */
218    m_notifier = new QSocketNotifier(m_sock->m_fd, QSocketNotifier::Read, 0);
219    QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
220
221    write(".api 1");
222    displayToPrompt();
223
224    beginNewCommand();
225    dir_cmd(".jobs", job_list);
226    dir_cmd(".clients", client_list);
227    dir_cmd(".filesets", fileset_list);  
228    dir_cmd(".msgs", messages_list);
229    dir_cmd(".pools", pool_list);
230    dir_cmd(".storage", storage_list);
231    dir_cmd(".types", type_list);
232    dir_cmd(".levels", level_list);
233
234    mainWin->set_status(_("Connected"));
235    startTimer();                      /* start message timer */
236    return;
237 }
238
239 bool Console::dir_cmd(QString &cmd, QStringList &results)
240 {
241    return dir_cmd(cmd.toUtf8().data(), results);
242 }
243
244 /*
245  * Send a command to the Director, and return the
246  *  results in a QStringList.  
247  */
248 bool Console::dir_cmd(const char *cmd, QStringList &results)
249 {
250    int stat;
251
252    notify(false);
253    write(cmd);
254    while ((stat = read()) > 0) {
255       if (mainWin->m_displayAll) display_text(msg());
256       strip_trailing_junk(msg());
257       results << msg();
258    }
259    notify(true);
260    discardToPrompt();
261    return true;              /* ***FIXME*** return any command error */
262 }
263
264 bool Console::sql_cmd(QString &query, QStringList &results)
265 {
266    return sql_cmd(query.toUtf8().data(), results);
267 }
268
269 /*
270  * Send an sql query to the Director, and return the
271  *  results in a QStringList.  
272  */
273 bool Console::sql_cmd(const char *query, QStringList &results)
274 {
275    if (!is_connectedGui())
276       return false;
277    int stat;
278    POOL_MEM cmd(PM_MESSAGE);
279
280    notify(false);
281    
282    pm_strcpy(cmd, ".sql query=\"");
283    pm_strcat(cmd, query);
284    pm_strcat(cmd, "\"");
285    write(cmd.c_str());
286    while ((stat = read()) > 0) {
287       if (mainWin->m_displayAll) display_text(msg());
288       strip_trailing_junk(msg());
289       results << msg();
290    }
291    notify(true);
292    discardToPrompt();
293    return true;              /* ***FIXME*** return any command error */
294 }
295
296
297 /*  
298  * Send a job name to the director, and read all the resulting
299  *  defaults. 
300  */
301 bool Console::get_job_defaults(struct job_defaults &job_defs)
302 {
303    QString scmd;
304    int stat;
305    char *def;
306
307    notify(false);
308    beginNewCommand();
309    scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
310    write(scmd);
311    while ((stat = read()) > 0) {
312       if (mainWin->m_displayAll) display_text(msg());
313       def = strchr(msg(), '=');
314       if (!def) {
315          continue;
316       }
317       /* Pointer to default value */
318       *def++ = 0;
319       strip_trailing_junk(def);
320
321       if (strcmp(msg(), "job") == 0) {
322          if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
323             goto bail_out;
324          }
325          continue;
326       }
327       if (strcmp(msg(), "pool") == 0) {
328          job_defs.pool_name = def;
329          continue;
330       }
331       if (strcmp(msg(), "messages") == 0) {
332          job_defs.messages_name = def;
333          continue;
334       }
335       if (strcmp(msg(), "client") == 0) {
336          job_defs.client_name = def;
337          continue;
338       }
339       if (strcmp(msg(), "storage") == 0) {
340          job_defs.store_name = def;
341          continue;
342       }
343       if (strcmp(msg(), "where") == 0) {
344          job_defs.where = def;
345          continue;
346       }
347       if (strcmp(msg(), "level") == 0) {
348          job_defs.level = def;
349          continue;
350       }
351       if (strcmp(msg(), "type") == 0) {
352          job_defs.type = def;
353          continue;
354       }
355       if (strcmp(msg(), "fileset") == 0) {
356          job_defs.fileset_name = def;
357          continue;
358       }
359       if (strcmp(msg(), "catalog") == 0) {
360          job_defs.catalog_name = def;
361          continue;
362       }
363       if (strcmp(msg(), "enabled") == 0) {
364          job_defs.enabled = *def == '1' ? true : false;
365          continue;
366       }
367    }
368
369 #ifdef xxx
370    bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
371       "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
372       job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(), 
373       job_defs.client_name.toUtf8().data(), 
374       job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(), 
375       job_defs.store_name.toUtf8().data(),
376       job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(), 
377       job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
378       job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
379 #endif
380
381    notify(true);
382    return true;
383
384 bail_out:
385    notify(true);
386    return false;
387 }
388
389
390 /*
391  * Save user settings associated with this console
392  */
393 void Console::writeSettings()
394 {
395    QFont font = get_font();
396
397    QSettings settings(m_dir->name(), "bat");
398    settings.beginGroup("Console");
399    settings.setValue("consoleFont", font.family());
400    settings.setValue("consolePointSize", font.pointSize());
401    settings.setValue("consoleFixedPitch", font.fixedPitch());
402    settings.endGroup();
403 }
404
405 /*
406  * Read and restore user settings associated with this console
407  */
408 void Console::readSettings()
409
410    QFont font = get_font();
411
412    QSettings settings(m_dir->name(), "bat");
413    settings.beginGroup("Console");
414    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
415    font.setPointSize(settings.value("consolePointSize", 10).toInt());
416    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
417    settings.endGroup();
418    m_textEdit->setFont(font);
419 }
420
421 /*
422  * Set the console textEdit font
423  */
424 void Console::set_font()
425 {
426    bool ok;
427    QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
428    if (ok) {
429       m_textEdit->setFont(font);
430    }
431 }
432
433 /*
434  * Get the console text edit font
435  */
436 const QFont Console::get_font()
437 {
438    return m_textEdit->font();
439 }
440
441 /*
442  * Slot for responding to status dir button on button bar
443  */
444 void Console::status_dir()
445 {
446    QString cmd("status dir");
447    consoleCommand(cmd);
448 }
449
450 /*
451  * Slot for responding to messages button on button bar
452  */
453 void Console::messages()
454 {
455    QString cmd(".messages");
456    consoleCommand(cmd);
457 }
458
459 /*
460  * Put text into the console window
461  */
462 void Console::display_textf(const char *fmt, ...)
463 {
464    va_list arg_ptr;
465    char buf[1000];
466    int len;
467    va_start(arg_ptr, fmt);
468    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
469    va_end(arg_ptr);
470    display_text(buf);
471 }
472
473 void Console::display_text(const QString buf)
474 {
475    m_cursor->insertText(buf);
476    update_cursor();
477 }
478
479
480 void Console::display_text(const char *buf)
481 {
482    m_cursor->insertText(buf);
483    update_cursor();
484 }
485
486 void Console::display_html(const QString buf)
487 {
488    m_cursor->insertHtml(buf);
489    update_cursor();
490 }
491
492 /* Position cursor to end of screen */
493 void Console::update_cursor()
494 {
495    QApplication::restoreOverrideCursor();
496    m_textEdit->moveCursor(QTextCursor::End);
497    m_textEdit->ensureCursorVisible();
498 }
499
500 /* 
501  * This should be moved into a bSocket class 
502  */
503 char *Console::msg()
504 {
505    if (m_sock) {
506       return m_sock->msg;
507    }
508    return NULL;
509 }
510
511 /* Send a command to the Director */
512 void Console::write_dir(const char *msg)
513 {
514    if (m_sock) {
515       mainWin->set_status(_("Processing command ..."));
516       QApplication::setOverrideCursor(Qt::WaitCursor);
517       write(msg);
518    } else {
519       mainWin->set_status(" Director not connected. Click on connect button.");
520       mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
521       QBrush redBrush(Qt::red);
522       QTreeWidgetItem *item = mainWin->getFromHash(this);
523       item->setForeground(0, redBrush);
524       m_at_prompt = false;
525       m_at_main_prompt = false;
526    }
527 }
528
529 int Console::write(const QString msg)
530 {
531    return write(msg.toUtf8().data());
532 }
533
534 int Console::write(const char *msg)
535 {
536    if (!m_sock) {
537       return -1;
538    }
539    m_sock->msglen = pm_strcpy(m_sock->msg, msg);
540    m_at_prompt = false;
541    m_at_main_prompt = false;
542    if (mainWin->m_commDebug) Pmsg1(000, "send: %s\n", msg);
543    return m_sock->send();
544
545 }
546
547 /*
548  * Get to main command prompt -- i.e. abort any subcommand
549  */
550 void Console::beginNewCommand()
551 {
552    for (int i=0; i < 3; i++) {
553       write(".\n");
554       while (read() > 0) {
555          if (mainWin->m_displayAll) display_text(msg());
556       }
557       if (m_at_main_prompt) {
558          break;
559       }
560    }
561    display_text("\n");
562 }
563
564 void Console::displayToPrompt()
565
566    int stat = 0;
567    if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
568    while (!m_at_prompt) {
569       if ((stat=read()) > 0) {
570          display_text(msg());
571       }
572    }
573    if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
574 }
575
576 void Console::discardToPrompt()
577
578    int stat = 0;
579    if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
580    while (!m_at_prompt) {
581       if ((stat=read()) > 0) {
582          if (mainWin->m_displayAll) display_text(msg());
583       }
584    }
585    if (mainWin->m_commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
586 }
587
588
589 /* 
590  * Blocking read from director
591  */
592 int Console::read()
593 {
594    int stat = 0;
595    while (m_sock) {
596       for (;;) {
597          stat = bnet_wait_data_intr(m_sock, 1);
598          if (stat > 0) {
599             break;
600          } 
601          app->processEvents();
602          if (m_api_set && m_messages_pending) {
603             write_dir(".messages");
604             m_messages_pending = false;
605          }
606       }
607       stat = m_sock->recv();
608       if (stat >= 0) {
609          if (m_at_prompt) {
610             display_text("\n");
611             m_at_prompt = false;
612             m_at_main_prompt = false;
613          }
614          if (mainWin->m_commDebug) Pmsg1(000, "got: %s", m_sock->msg);
615       }
616       switch (m_sock->msglen) {
617       case BNET_MSGS_PENDING:
618          if (mainWin->m_commDebug) Pmsg0(000, "MSGS PENDING\n");
619          write_dir(".messages");
620          displayToPrompt();
621          m_messages_pending = false;
622          continue;
623       case BNET_CMD_OK:
624          if (mainWin->m_commDebug) Pmsg0(000, "CMD OK\n");
625          m_at_prompt = false;
626          m_at_main_prompt = false;
627          continue;
628       case BNET_CMD_BEGIN:
629          if (mainWin->m_commDebug) Pmsg0(000, "CMD BEGIN\n");
630          m_at_prompt = false;
631          m_at_main_prompt = false;
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 curerntly disconnected\n  Please reconnect!!";
758       QMessageBox::warning(this, tr("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 curerntly disconnected\n  Please reconnect!!";
774       QMessageBox::warning(this, tr("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 curerntly 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, tr("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 curerntly not at a prompt\n  Please try again!!";
790       QMessageBox::warning(this, tr("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 }