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