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