]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
Remove a message I intended to remove last commit..
[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       if (mainWin->m_displayAll) {
327          display_text(msg());
328          display_text("\n");
329       }
330       strip_trailing_junk(msg());
331       results << msg();
332    }
333    notify(true);
334    discardToPrompt();
335    return true;              /* ***FIXME*** return any command error */
336 }
337
338
339 /*  
340  * Send a job name to the director, and read all the resulting
341  *  defaults. 
342  */
343 bool Console::get_job_defaults(struct job_defaults &job_defs)
344 {
345    QString scmd;
346    int stat;
347    char *def;
348
349    notify(false);
350    beginNewCommand();
351    scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
352    write(scmd);
353    while ((stat = read()) > 0) {
354       if (mainWin->m_displayAll) display_text(msg());
355       def = strchr(msg(), '=');
356       if (!def) {
357          continue;
358       }
359       /* Pointer to default value */
360       *def++ = 0;
361       strip_trailing_junk(def);
362
363       if (strcmp(msg(), "job") == 0) {
364          if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
365             goto bail_out;
366          }
367          continue;
368       }
369       if (strcmp(msg(), "pool") == 0) {
370          job_defs.pool_name = def;
371          continue;
372       }
373       if (strcmp(msg(), "messages") == 0) {
374          job_defs.messages_name = def;
375          continue;
376       }
377       if (strcmp(msg(), "client") == 0) {
378          job_defs.client_name = def;
379          continue;
380       }
381       if (strcmp(msg(), "storage") == 0) {
382          job_defs.store_name = def;
383          continue;
384       }
385       if (strcmp(msg(), "where") == 0) {
386          job_defs.where = def;
387          continue;
388       }
389       if (strcmp(msg(), "level") == 0) {
390          job_defs.level = def;
391          continue;
392       }
393       if (strcmp(msg(), "type") == 0) {
394          job_defs.type = def;
395          continue;
396       }
397       if (strcmp(msg(), "fileset") == 0) {
398          job_defs.fileset_name = def;
399          continue;
400       }
401       if (strcmp(msg(), "catalog") == 0) {
402          job_defs.catalog_name = def;
403          continue;
404       }
405       if (strcmp(msg(), "enabled") == 0) {
406          job_defs.enabled = *def == '1' ? true : false;
407          continue;
408       }
409    }
410
411    notify(true);
412    return true;
413
414 bail_out:
415    notify(true);
416    return false;
417 }
418
419
420 /*
421  * Save user settings associated with this console
422  */
423 void Console::writeSettings()
424 {
425    QFont font = get_font();
426
427    QSettings settings(m_dir->name(), "bat");
428    settings.beginGroup("Console");
429    settings.setValue("consoleFont", font.family());
430    settings.setValue("consolePointSize", font.pointSize());
431    settings.setValue("consoleFixedPitch", font.fixedPitch());
432    settings.endGroup();
433 }
434
435 /*
436  * Read and restore user settings associated with this console
437  */
438 void Console::readSettings()
439
440    QFont font = get_font();
441
442    QSettings settings(m_dir->name(), "bat");
443    settings.beginGroup("Console");
444    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
445    font.setPointSize(settings.value("consolePointSize", 10).toInt());
446    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
447    settings.endGroup();
448    m_textEdit->setFont(font);
449 }
450
451 /*
452  * Set the console textEdit font
453  */
454 void Console::set_font()
455 {
456    bool ok;
457    QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
458    if (ok) {
459       m_textEdit->setFont(font);
460    }
461 }
462
463 /*
464  * Get the console text edit font
465  */
466 const QFont Console::get_font()
467 {
468    return m_textEdit->font();
469 }
470
471 /*
472  * Slot for responding to status dir button on button bar
473  */
474 void Console::status_dir()
475 {
476    QString cmd("status dir");
477    consoleCommand(cmd);
478 }
479
480 /*
481  * Slot for responding to messages button on button bar
482  * Here we want to bring the console to the front so use pages' consoleCommand
483  */
484 void Console::messages()
485 {
486    QString cmd(".messages");
487    consoleCommand(cmd);
488    messagesPending(false);
489 }
490
491 /*
492  * Put text into the console window
493  */
494 void Console::display_textf(const char *fmt, ...)
495 {
496    va_list arg_ptr;
497    char buf[1000];
498    int len;
499    va_start(arg_ptr, fmt);
500    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
501    va_end(arg_ptr);
502    display_text(buf);
503 }
504
505 void Console::display_text(const QString buf)
506 {
507    m_cursor->insertText(buf);
508    update_cursor();
509 }
510
511
512 void Console::display_text(const char *buf)
513 {
514    m_cursor->insertText(buf);
515    update_cursor();
516 }
517
518 void Console::display_html(const QString buf)
519 {
520    m_cursor->insertHtml(buf);
521    update_cursor();
522 }
523
524 /* Position cursor to end of screen */
525 void Console::update_cursor()
526 {
527    QApplication::restoreOverrideCursor();
528    m_textEdit->moveCursor(QTextCursor::End);
529    m_textEdit->ensureCursorVisible();
530 }
531
532 /* 
533  * This should be moved into a bSocket class 
534  */
535 char *Console::msg()
536 {
537    if (m_sock) {
538       return m_sock->msg;
539    }
540    return NULL;
541 }
542
543 /* Send a command to the Director */
544 void Console::write_dir(const char *msg)
545 {
546    if (m_sock) {
547       mainWin->set_status(_("Processing command ..."));
548       QApplication::setOverrideCursor(Qt::WaitCursor);
549       write(msg);
550    } else {
551       mainWin->set_status( tr(" Director not connected. Click on connect button."));
552       mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
553       QBrush redBrush(Qt::red);
554       QTreeWidgetItem *item = mainWin->getFromHash(this);
555       item->setForeground(0, redBrush);
556       m_at_prompt = false;
557       m_at_main_prompt = false;
558    }
559 }
560
561 int Console::write(const QString msg)
562 {
563    return write(msg.toUtf8().data());
564 }
565
566 int Console::write(const char *msg)
567 {
568    if (!m_sock) {
569       return -1;
570    }
571    m_sock->msglen = pm_strcpy(m_sock->msg, msg);
572    m_at_prompt = false;
573    m_at_main_prompt = false;
574    if (mainWin->m_commDebug) Pmsg1(000, "send: %s\n", msg);
575    return m_sock->send();
576
577 }
578
579 /*
580  * Get to main command prompt -- i.e. abort any subcommand
581  */
582 void Console::beginNewCommand()
583 {
584    for (int i=0; i < 3; i++) {
585       write(".");
586       while (read() > 0) {
587          if (mainWin->m_displayAll) display_text(msg());
588       }
589       if (m_at_main_prompt) {
590          break;
591       }
592    }
593    display_text("\n");
594 }
595
596 void Console::displayToPrompt()
597
598    int stat = 0;
599    QString buf;
600    if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
601    while (!m_at_prompt) {
602       if ((stat=read()) > 0) {
603          buf += msg();
604          if (buf.size() >= 8196 || m_messages_pending) {
605             display_text(buf);
606             buf.clear();
607             messagesPending(false);
608          }
609       }
610    }
611    display_text(buf);
612    if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
613 }
614
615 void Console::discardToPrompt()
616
617    int stat = 0;
618    if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
619    if (mainWin->m_displayAll) {
620       displayToPrompt();
621    } else {
622       while (!m_at_prompt) {
623          stat=read();
624       }
625    }
626    if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
627 }
628
629 int Console::sock_read()
630 {
631    int stat;
632 #ifdef HAVE_WIN32
633    bool wasEnabled = notify(false);
634    stat = m_sock->recv();
635    notify(wasEnabled);
636 #else
637    stat = m_sock->recv();
638 #endif
639    return stat;
640 }
641
642 /* 
643  * Blocking read from director
644  */
645 int Console::read()
646 {
647    int stat = 0;
648    while (m_sock) {
649       for (;;) {
650          stat = m_sock->wait_data_intr(0, 50000);
651          if (stat > 0) {
652             break;
653          } 
654          app->processEvents();
655          if (m_api_set && m_messages_pending && is_notify_enabled() && hasFocus()) {
656             write_dir(".messages");
657             messagesPending(false);
658          }
659       }
660       m_sock->msg[0] = 0;
661       stat = sock_read();
662       if (stat >= 0) {
663          if (mainWin->m_commDebug) Pmsg1(000, "got: %s\n", m_sock->msg);
664          if (m_at_prompt) {
665             display_text("\n");
666             m_at_prompt = false;
667             m_at_main_prompt = false;
668          }
669       }
670       switch (m_sock->msglen) {
671       case BNET_MSGS_PENDING :
672          if (is_notify_enabled() && hasFocus()) {
673             if (mainWin->m_commDebug) Pmsg0(000, "MSGS PENDING\n");
674             write_dir(".messages");
675             displayToPrompt();
676             messagesPending(false);
677          }
678          messagesPending(true);
679          continue;
680       case BNET_CMD_OK:
681          if (mainWin->m_commDebug) Pmsg0(000, "CMD OK\n");
682          m_at_prompt = false;
683          m_at_main_prompt = false;
684          mainWin->set_status(_("Command completed ..."));
685          continue;
686       case BNET_CMD_BEGIN:
687          if (mainWin->m_commDebug) Pmsg0(000, "CMD BEGIN\n");
688          m_at_prompt = false;
689          m_at_main_prompt = false;
690          mainWin->set_status(_("Processing command ..."));
691          continue;
692       case BNET_MAIN_PROMPT:
693          if (mainWin->m_commDebug) Pmsg0(000, "MAIN PROMPT\n");
694          m_at_prompt = true;
695          m_at_main_prompt = true;
696          mainWin->set_status(_("At main prompt waiting for input ..."));
697          QApplication::restoreOverrideCursor();
698          break;
699       case BNET_PROMPT:
700          if (mainWin->m_commDebug) Pmsg0(000, "PROMPT\n");
701          m_at_prompt = true;
702          m_at_main_prompt = false;
703          mainWin->set_status(_("At prompt waiting for input ..."));
704          QApplication::restoreOverrideCursor();
705          break;
706       case BNET_CMD_FAILED:
707          if (mainWin->m_commDebug) Pmsg0(000, "CMD FAILED\n");
708          mainWin->set_status(_("Command failed."));
709          QApplication::restoreOverrideCursor();
710          break;
711       /* We should not get this one */
712       case BNET_EOD:
713          if (mainWin->m_commDebug) Pmsg0(000, "EOD\n");
714          mainWin->set_status_ready();
715          QApplication::restoreOverrideCursor();
716          if (!m_api_set) {
717             break;
718          }
719          continue;
720       case BNET_START_SELECT:
721          if (mainWin->m_commDebug) Pmsg0(000, "START SELECT\n");
722          new selectDialog(this);    
723          break;
724       case BNET_YESNO:
725          if (mainWin->m_commDebug) Pmsg0(000, "YESNO\n");
726          new yesnoPopUp(this);
727          break;
728       case BNET_RUN_CMD:
729          if (mainWin->m_commDebug) Pmsg0(000, "RUN CMD\n");
730          new runCmdPage();
731          break;
732       case BNET_START_RTREE:
733          if (mainWin->m_commDebug) Pmsg0(000, "START RTREE CMD\n");
734          new restorePage();
735          break;
736       case BNET_END_RTREE:
737          if (mainWin->m_commDebug) Pmsg0(000, "END RTREE CMD\n");
738          break;
739       case BNET_ERROR_MSG:
740          if (mainWin->m_commDebug) Pmsg0(000, "ERROR MSG\n");
741          stat = sock_read();          /* get the message */
742          display_text(msg());
743          QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
744          break;
745       case BNET_WARNING_MSG:
746          if (mainWin->m_commDebug) Pmsg0(000, "WARNING MSG\n");
747          stat = sock_read();          /* get the message */
748          display_text(msg());
749          QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
750          break;
751       case BNET_INFO_MSG:
752          if (mainWin->m_commDebug) Pmsg0(000, "INFO MSG\n");
753          stat = sock_read();          /* get the message */
754          display_text(msg());
755          mainWin->set_status(msg());
756          break;
757       }
758       if (is_bnet_stop(m_sock)) {         /* error or term request */
759          if (mainWin->m_commDebug) Pmsg0(000, "BNET STOP\n");
760          stopTimer();
761          m_sock->close();
762          m_sock = NULL;
763          mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
764          QBrush redBrush(Qt::red);
765          QTreeWidgetItem *item = mainWin->getFromHash(this);
766          item->setForeground(0, redBrush);
767          if (m_notifier) {
768             m_notifier->setEnabled(false);
769             delete m_notifier;
770             m_notifier = NULL;
771          }
772          mainWin->set_status(_("Director disconnected."));
773          QApplication::restoreOverrideCursor();
774          stat = BNET_HARDEOF;
775       }
776       break;
777    } 
778    return stat;
779 }
780
781 /* Called by signal when the Director has output for us */
782 void Console::read_dir(int /* fd */)
783 {
784    if (mainWin->m_commDebug) Pmsg0(000, "read_dir\n");
785    while (read() >= 0) {
786       display_text(msg());
787    }
788 }
789
790 /*
791  * When the notifier is enabled, read_dir() will automatically be
792  * called by the Qt event loop when ever there is any output 
793  * from the Directory, and read_dir() will then display it on
794  * the console.
795  *
796  * When we are in a bat dialog, we want to control *all* output
797  * from the Directory, so we set notify to off.
798  *    m_console->notifiy(false);
799  */
800 bool Console::notify(bool enable) 
801
802    bool prev_enabled = false;
803    if (m_notifier) {
804       prev_enabled = m_notifier->isEnabled();   
805       m_notifier->setEnabled(enable);   
806    }
807    return prev_enabled;
808 }
809
810 bool Console::is_notify_enabled() const
811 {
812    bool enabled = false;
813    if (m_notifier)
814       enabled = m_notifier->isEnabled();   
815    return enabled;
816 }
817
818 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
819 {
820    m_directorTreeItem = item;
821 }
822
823 void Console::setDirRes(DIRRES *dir) 
824
825    m_dir = dir;
826 }
827
828 /*
829  * To have the ability to get the name of the director resource.
830  */
831 void Console::getDirResName(QString &name_returned)
832 {
833    name_returned = m_dir->name();
834 }
835
836 bool Console::is_connectedGui()
837 {
838    if (is_connected()) {
839       return true;
840    } else {
841       QString message = tr("Director is currently disconnected\nPlease reconnect!");
842       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
843       return false;
844    }
845 }
846
847 /*
848  * A temporary function to prevent connecting to the director if the director
849  * is busy with a restore.
850  */
851 bool Console::preventInUseConnect()
852 {
853    if (!is_connected()) {
854       QString message = tr("Director %1 is currently disconnected\n"
855                            "Please reconnect!").arg(m_dir->name());
856       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
857       return false;
858    } else if (!m_at_main_prompt){
859       QString message = tr("Director %1 is currently busy\n  Please complete "
860                            "restore or other operation!  This is a limitation "
861                            "that will be resolved before a beta release.  "
862                            "This is currently an alpha release.").arg(m_dir->name());
863       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
864       return false;
865    } else if (!m_at_prompt){
866       QString message = tr("Director %1 is currently not at a prompt\n"
867                            "  Please try again!").arg(m_dir->name());
868       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
869       return false;
870    } else {
871       return true;
872    }
873 }
874
875 /*
876  * Call-back for reading a passphrase for an encrypted PEM file
877  * This function uses getpass(), 
878  *  which uses a static buffer and is NOT thread-safe.
879  */
880 static int tls_pem_callback(char *buf, int size, const void *userdata)
881 {
882    (void)size;
883    (void)userdata;
884 #ifdef HAVE_TLS
885    const char *prompt = (const char *)userdata;
886 # if defined(HAVE_WIN32)
887    //sendit(prompt);
888    if (win32_cgets(buf, size) == NULL) {
889       buf[0] = 0;
890       return 0;
891    } else {
892       return strlen(buf);
893    }
894 # else
895    char *passwd;
896
897    passwd = getpass(prompt);
898    bstrncpy(buf, passwd, size);
899    return strlen(buf);
900 # endif
901 #else
902    buf[0] = 0;
903    return 0;
904 #endif
905 }
906
907 /* Slot for responding to page selectors status help command */
908 void Console::consoleHelp()
909 {
910    QString cmd("help");
911    consoleCommand(cmd);
912 }
913
914 /* Slot for responding to page selectors reload bacula-dir.conf */
915 void Console::consoleReload()
916 {
917    QString cmd("reload");
918    consoleCommand(cmd);
919 }
920
921 /* Function to get a list of volumes */
922 void Console::getVolumeList(QStringList &volumeList)
923 {
924    QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
925    if (mainWin->m_sqlDebug) {
926       Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
927    }
928    QStringList results;
929    if (sql_cmd(query, results)) {
930       QString field;
931       QStringList fieldlist;
932       /* Iterate through the lines of results. */
933       foreach (QString resultline, results) {
934          fieldlist = resultline.split("\t");
935          volumeList.append(fieldlist[0]);
936       } /* foreach resultline */
937    } /* if results from query */
938 }
939
940 /* Function to get a list of volumes */
941 void Console::getStatusList(QStringList &statusLongList)
942 {
943    QString statusQuery("SELECT JobStatusLong FROM Status");
944    if (mainWin->m_sqlDebug) {
945       Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
946    }
947    QStringList statusResults;
948    if (sql_cmd(statusQuery, statusResults)) {
949       QString field;
950       QStringList fieldlist;
951       /* Iterate through the lines of results. */
952       foreach (QString resultline, statusResults) {
953          fieldlist = resultline.split("\t");
954          statusLongList.append(fieldlist[0]);
955       } /* foreach resultline */
956    } /* if results from statusquery */
957 }
958
959 /* For suppressing .messages
960  * This may be rendered not needed if the multiple connections feature gets working */
961 bool Console::hasFocus()
962 {
963    if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
964       return true;
965    else
966       return false;
967 }
968
969 /* For adding feature to have the gui's messages button change when 
970  * messages are pending */
971 bool Console::messagesPending(bool pend)
972 {
973    bool prev = m_messages_pending;
974    m_messages_pending = pend;
975    mainWin->setMessageIcon();
976    return prev;
977 }