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