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