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