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