1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Console Class
21 *
22 * Written by Kern Sibbald, January MMVII
23 *
24 */
25
26 #include "bat.h"
27 #include "console.h"
28 #include "restore.h"
29 #include "select.h"
30 #include "run/run.h"
31
Console(QTabWidget * parent)32 Console::Console(QTabWidget *parent) : Pages()
33 {
34 QFont font;
35 m_name = tr("Console");
36 m_messages_pending = false;
37 m_parent = parent;
38 m_closeable = false;
39 m_console = this;
40 m_warningPrevent = false;
41 m_dircommCounter = 0;
42
43 /*
44 * Create a connection to the Director and put it in a hash table
45 */
46 m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter));
47
48 setupUi(this);
49 m_textEdit = textEdit; /* our console screen */
50 m_cursor = new QTextCursor(m_textEdit->document());
51 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
52
53 m_timer = NULL;
54 m_contextActions.append(actionStatusDir);
55 m_contextActions.append(actionConsoleHelp);
56 m_contextActions.append(actionRequestMessages);
57 m_contextActions.append(actionConsoleReload);
58 connect(actionStatusDir, SIGNAL(triggered()), this, SLOT(status_dir()));
59 connect(actionConsoleHelp, SIGNAL(triggered()), this, SLOT(consoleHelp()));
60 connect(actionConsoleReload, SIGNAL(triggered()), this, SLOT(consoleReload()));
61 connect(actionRequestMessages, SIGNAL(triggered()), this, SLOT(messages()));
62 }
63
~Console()64 Console::~Console()
65 {
66 }
67
startTimer()68 void Console::startTimer()
69 {
70 m_timer = new QTimer(this);
71 QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
72 m_timer->start(mainWin->m_checkMessagesInterval*30000);
73 }
74
stopTimer()75 void Console::stopTimer()
76 {
77 if (m_timer) {
78 QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
79 m_timer->stop();
80 delete m_timer;
81 m_timer = NULL;
82 }
83 }
84
85 /* slot connected to the timer
86 * requires preferences of check messages and operates at interval */
poll_messages()87 void Console::poll_messages()
88 {
89 int conn;
90
91 /* Do not poll if notifier off */
92 if (!mainWin->m_notify) {
93 return;
94 }
95
96 /*
97 * Note if we call getDirComm here, we continuously consume
98 * file descriptors.
99 */
100 if (!findDirComm(conn)) { /* find a free DirComm */
101 return; /* try later */
102 }
103
104 DirComm *dircomm = m_dircommHash.value(conn);
105 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){
106 dircomm->write(".messages");
107 displayToPrompt(conn);
108 messagesPending(false);
109 }
110 }
111
112 /*
113 * Connect to Director. This does not connect to the director, dircomm does.
114 * This creates the first and possibly 2nd dircomm instance
115 */
connect_dir()116 void Console::connect_dir()
117 {
118 DirComm *dircomm = m_dircommHash.value(0);
119
120 if (!m_console->m_dir) {
121 mainWin->set_status( tr("No Director found."));
122 return;
123 }
124
125 m_textEdit = textEdit; /* our console screen */
126
127 if (dircomm->connect_dir()) {
128 if (mainWin->m_connDebug) {
129 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
130 }
131 beginNewCommand(0);
132 }
133 mainWin->set_status(_("Connected"));
134
135 startTimer(); /* start message timer */
136 }
137
138 /*
139 * A function created to separate out the population of the lists
140 * from the Console::connect_dir function
141 */
populateLists(bool)142 void Console::populateLists(bool /*forcenew*/)
143 {
144 int conn;
145 if (!getDirComm(conn)) {
146 if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n");
147 if (!newDirComm(conn)) {
148 Emsg1(M_INFO, 0, "Failed to connect to %s for populateLists.\n", m_dir->name());
149 return;
150 }
151 }
152 populateLists(conn);
153 notify(conn, true);
154 }
155
populateLists(int conn)156 void Console::populateLists(int conn)
157 {
158 job_list.clear();
159 restore_list.clear();
160 client_list.clear();
161 fileset_list.clear();
162 messages_list.clear();
163 pool_list.clear();
164 storage_list.clear();
165 type_list.clear();
166 level_list.clear();
167 volstatus_list.clear();
168 mediatype_list.clear();
169 dir_cmd(conn, ".jobs", job_list);
170 dir_cmd(conn, ".jobs type=R", restore_list);
171 dir_cmd(conn, ".clients", client_list);
172 dir_cmd(conn, ".filesets", fileset_list);
173 dir_cmd(conn, ".msgs", messages_list);
174 dir_cmd(conn, ".pools", pool_list);
175 dir_cmd(conn, ".storage", storage_list);
176 dir_cmd(conn, ".types", type_list);
177 dir_cmd(conn, ".levels", level_list);
178 dir_cmd(conn, ".volstatus", volstatus_list);
179 dir_cmd(conn, ".mediatypes", mediatype_list);
180 dir_cmd(conn, ".locations", location_list);
181
182 if (mainWin->m_connDebug) {
183 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
184 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
185 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
186 .arg(conn).arg(m_dir->name());
187 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
188 }
189 job_list.sort();
190 client_list.sort();
191 fileset_list.sort();
192 messages_list.sort();
193 pool_list.sort();
194 storage_list.sort();
195 type_list.sort();
196 level_list.sort();
197 }
198
199 /*
200 * Overload function for dir_cmd with a QString
201 * Ease of use
202 */
dir_cmd(QString & cmd,QStringList & results)203 bool Console::dir_cmd(QString &cmd, QStringList &results)
204 {
205 return dir_cmd(cmd.toUtf8().data(), results);
206 }
207
208 /*
209 * Overload function for dir_cmd, this is if connection is not worried about
210 */
dir_cmd(const char * cmd,QStringList & results)211 bool Console::dir_cmd(const char *cmd, QStringList &results)
212 {
213 int conn;
214 if (getDirComm(conn)) {
215 dir_cmd(conn, cmd, results);
216 return true;
217 } else {
218 Pmsg1(000, "dir_cmd failed to connect to %s\n", m_dir->name());
219 return false;
220 }
221 }
222
223 /*
224 * Send a command to the Director, and return the
225 * results in a QStringList.
226 */
dir_cmd(int conn,const char * cmd,QStringList & results)227 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
228 {
229 mainWin->waitEnter();
230 DirComm *dircomm = m_dircommHash.value(conn);
231 int stat;
232 bool prev_notify = is_notify_enabled(conn);
233
234 if (mainWin->m_connDebug) {
235 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
236 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
237 }
238 if (prev_notify) {
239 notify(conn, false);
240 }
241 dircomm->write(cmd);
242 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
243 if (mainWin->m_displayAll) display_text(dircomm->msg());
244 strip_trailing_junk(dircomm->msg());
245 results << dircomm->msg();
246 }
247 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
248 if (prev_notify) {
249 notify(conn, true); /* turn it back on */
250 }
251 discardToPrompt(conn);
252 mainWin->waitExit();
253 return true; /* ***FIXME*** return any command error */
254 }
255
256 /*
257 * OverLoads for sql_cmd
258 */
sql_cmd(int & conn,QString & query,QStringList & results)259 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
260 {
261 return sql_cmd(conn, query.toUtf8().data(), results, false);
262 }
263
sql_cmd(QString & query,QStringList & results)264 bool Console::sql_cmd(QString &query, QStringList &results)
265 {
266 int conn;
267 if (!getDirComm(conn)) {
268 return false;
269 }
270 return sql_cmd(conn, query.toUtf8().data(), results, true);
271 }
272
sql_cmd(const char * query,QStringList & results)273 bool Console::sql_cmd(const char *query, QStringList &results)
274 {
275 int conn;
276 if (!getDirComm(conn)) {
277 return false;
278 }
279 return sql_cmd(conn, query, results, true);
280 }
281
282 /*
283 * Send an sql query to the Director, and return the
284 * results in a QStringList.
285 */
sql_cmd(int & conn,const char * query,QStringList & results,bool donotify)286 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
287 {
288 DirComm *dircomm = m_dircommHash.value(conn);
289 int stat;
290 POOL_MEM cmd(PM_MESSAGE);
291 bool prev_notify = is_notify_enabled(conn);
292
293 if (!is_connectedGui()) {
294 return false;
295 }
296
297 if (mainWin->m_connDebug) Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
298 if (donotify) {
299 dircomm->notify(false);
300 }
301 mainWin->waitEnter();
302
303 pm_strcpy(cmd, ".sql query=\"");
304 pm_strcat(cmd, query);
305 pm_strcat(cmd, "\"");
306 dircomm->write(cmd.c_str());
307 while ((stat = dircomm->read()) > 0) {
308 bool first = true;
309 if (mainWin->m_displayAll) {
310 display_text(dircomm->msg());
311 display_text("\n");
312 }
313 strip_trailing_junk(dircomm->msg());
314 bool doappend = true;
315 if (first) {
316 QString dum = dircomm->msg();
317 if ((dum.left(6) == "*None*")) doappend = false;
318 }
319 if (doappend) {
320 results << dircomm->msg();
321 }
322 first = false;
323 }
324 if (donotify && prev_notify) {
325 dircomm->notify(true);
326 }
327 discardToPrompt(conn);
328 mainWin->waitExit();
329 if (donotify && prev_notify) {
330 dircomm->notify(true);
331 }
332 return !mainWin->isClosing(); /* return false if closing */
333 }
334
335 /*
336 * Overloads for
337 * Sending a command to the Director
338 */
write_dir(const char * msg)339 int Console::write_dir(const char *msg)
340 {
341 int conn;
342 if (getDirComm(conn)) {
343 write_dir(conn, msg);
344 }
345 return conn;
346 }
347
write_dir(const char * msg,bool dowait)348 int Console::write_dir(const char *msg, bool dowait)
349 {
350 int conn;
351 if (getDirComm(conn)) {
352 write_dir(conn, msg, dowait);
353 }
354 return conn;
355 }
356
write_dir(int conn,const char * msg)357 void Console::write_dir(int conn, const char *msg)
358 {
359 write_dir(conn, msg, true);
360 }
361
362 /*
363 * Send a command to the Director
364 */
write_dir(int conn,const char * msg,bool dowait)365 void Console::write_dir(int conn, const char *msg, bool dowait)
366 {
367 DirComm *dircomm = m_dircommHash.value(conn);
368
369 if (dircomm->m_sock) {
370 mainWin->set_status(_("Processing command ..."));
371 if (dowait)
372 mainWin->waitEnter();
373 dircomm->write(msg);
374 if (dowait)
375 mainWin->waitExit();
376 } else {
377 mainWin->set_status( tr(" Director not connected. Click on connect button."));
378 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
379 QBrush redBrush(Qt::red);
380 QTreeWidgetItem *item = mainWin->getFromHash(this);
381 item->setForeground(0, redBrush);
382 dircomm->m_at_prompt = false;
383 dircomm->m_at_main_prompt = false;
384 }
385 }
386
387 /*
388 * get_job_defaults overload
389 */
get_job_defaults(struct job_defaults & job_defs)390 bool Console::get_job_defaults(struct job_defaults &job_defs)
391 {
392 int conn;
393 getDirComm(conn);
394 return get_job_defaults(conn, job_defs, true);
395 }
396
get_job_defaults(int & conn,struct job_defaults & job_defs)397 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
398 {
399 return get_job_defaults(conn, job_defs, true);
400 }
401
402 /*
403 * Send a job name to the director, and read all the resulting
404 * defaults.
405 */
get_job_defaults(int & conn,struct job_defaults & job_defs,bool donotify)406 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
407 {
408 QString scmd;
409 int stat;
410 char *def;
411 bool prev_notify = is_notify_enabled(conn);
412 bool rtn = false;
413 DirComm *dircomm = m_dircommHash.value(conn);
414
415 if (donotify) {
416 dircomm->notify(false);
417 }
418 beginNewCommand(conn);
419 bool prevWaitState = mainWin->getWaitState();
420 if (!prevWaitState) {
421 mainWin->waitEnter();
422 }
423 if (mainWin->m_connDebug) {
424 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
425 }
426 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
427 dircomm->write(scmd);
428 while ((stat = dircomm->read()) > 0) {
429 if (mainWin->m_displayAll) display_text(dircomm->msg());
430 def = strchr(dircomm->msg(), '=');
431 if (!def) {
432 continue;
433 }
434 /* Pointer to default value */
435 *def++ = 0;
436 strip_trailing_junk(def);
437
438 if (strcmp(dircomm->msg(), "job") == 0) {
439 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
440 goto bail_out;
441 }
442 continue;
443 }
444 if (strcmp(dircomm->msg(), "pool") == 0) {
445 job_defs.pool_name = def;
446 continue;
447 }
448 if (strcmp(dircomm->msg(), "messages") == 0) {
449 job_defs.messages_name = def;
450 continue;
451 }
452 if (strcmp(dircomm->msg(), "client") == 0) {
453 job_defs.client_name = def;
454 continue;
455 }
456 if (strcmp(dircomm->msg(), "storage") == 0) {
457 job_defs.store_name = def;
458 continue;
459 }
460 if (strcmp(dircomm->msg(), "where") == 0) {
461 job_defs.where = def;
462 continue;
463 }
464 if (strcmp(dircomm->msg(), "level") == 0) {
465 job_defs.level = def;
466 continue;
467 }
468 if (strcmp(dircomm->msg(), "type") == 0) {
469 job_defs.type = def;
470 continue;
471 }
472 if (strcmp(dircomm->msg(), "fileset") == 0) {
473 job_defs.fileset_name = def;
474 continue;
475 }
476 if (strcmp(dircomm->msg(), "catalog") == 0) {
477 job_defs.catalog_name = def;
478 continue;
479 }
480 if (strcmp(dircomm->msg(), "enabled") == 0) {
481 job_defs.enabled = *def == '1' ? true : false;
482 continue;
483 }
484 }
485 rtn = true;
486 /* Fall through wanted */
487 bail_out:
488 if (donotify && prev_notify) {
489 notify(conn, true);
490 }
491 if (!prevWaitState) {
492 mainWin->waitExit();
493 }
494 return rtn;
495 }
496
497
498 /*
499 * Save user settings associated with this console
500 */
writeSettings()501 void Console::writeSettings()
502 {
503 QFont font = get_font();
504
505 QSettings settings(m_dir->name(), "bat");
506 settings.beginGroup("Console");
507 settings.setValue("consoleFont", font.family());
508 settings.setValue("consolePointSize", font.pointSize());
509 settings.setValue("consoleFixedPitch", font.fixedPitch());
510 settings.endGroup();
511 }
512
513 /*
514 * Read and restore user settings associated with this console
515 */
readSettings()516 void Console::readSettings()
517 {
518 QFont font = get_font();
519
520 QSettings settings(m_dir->name(), "bat");
521 settings.beginGroup("Console");
522 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
523 font.setPointSize(settings.value("consolePointSize", 10).toInt());
524 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
525 settings.endGroup();
526 m_textEdit->setFont(font);
527 }
528
529 /*
530 * Set the console textEdit font
531 */
set_font()532 void Console::set_font()
533 {
534 bool ok;
535 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
536 if (ok) {
537 m_textEdit->setFont(font);
538 }
539 }
540
541 /*
542 * Get the console text edit font
543 */
get_font()544 const QFont Console::get_font()
545 {
546 return m_textEdit->font();
547 }
548
549 /*
550 * Slot for responding to status dir button on button bar
551 */
status_dir()552 void Console::status_dir()
553 {
554 QString cmd("status dir");
555 consoleCommand(cmd);
556 }
557
558 /*
559 * Slot for responding to messages button on button bar
560 * Here we want to bring the console to the front so use pages' consoleCommand
561 */
messages()562 void Console::messages()
563 {
564 QString cmd(".messages");
565 consoleCommand(cmd);
566 messagesPending(false);
567 }
568
569 /*
570 * Put text into the console window
571 */
display_textf(const char * fmt,...)572 void Console::display_textf(const char *fmt, ...)
573 {
574 va_list arg_ptr;
575 char buf[1000];
576 va_start(arg_ptr, fmt);
577 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
578 va_end(arg_ptr);
579 display_text(buf);
580 }
581
display_text(const QString buf)582 void Console::display_text(const QString buf)
583 {
584 if (mainWin->isClosing()) return;
585 if (buf.size() != 0) {
586 m_cursor->insertText(buf);
587 update_cursor();
588 }
589 }
590
591
display_text(const char * buf)592 void Console::display_text(const char *buf)
593 {
594 if (mainWin->isClosing()) return;
595 if (*buf != 0) {
596 m_cursor->insertText(buf);
597 update_cursor();
598 }
599 }
600
display_html(const QString buf)601 void Console::display_html(const QString buf)
602 {
603 if (mainWin->isClosing()) return;
604 if (buf.size() != 0) {
605 m_cursor->insertHtml(buf);
606 update_cursor();
607 }
608 }
609
610 /* Position cursor to end of screen */
update_cursor()611 void Console::update_cursor()
612 {
613 m_textEdit->moveCursor(QTextCursor::End);
614 m_textEdit->ensureCursorVisible();
615 }
616
beginNewCommand(int conn)617 void Console::beginNewCommand(int conn)
618 {
619 DirComm *dircomm = m_dircommHash.value(conn);
620
621 if (dircomm->m_at_main_prompt) {
622 return;
623 }
624 for (int i=0; i < 3; i++) {
625 dircomm->write(".");
626 while (dircomm->read() > 0) {
627 if (mainWin->m_commDebug) Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
628 if (mainWin->m_displayAll) display_text(dircomm->msg());
629 }
630 if (dircomm->m_at_main_prompt) {
631 break;
632 }
633 }
634 //display_text("\n");
635 }
636
displayToPrompt(int conn)637 void Console::displayToPrompt(int conn)
638 {
639 DirComm *dircomm = m_dircommHash.value(conn);
640
641 int stat = 0;
642 QString buf;
643 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
644 while (!dircomm->m_at_prompt) {
645 if ((stat=dircomm->read()) > 0) {
646 buf += dircomm->msg();
647 if (buf.size() >= 8196 || m_messages_pending) {
648 display_text(buf);
649 buf.clear();
650 messagesPending(false);
651 }
652 }
653 }
654 display_text(buf);
655 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
656 }
657
discardToPrompt(int conn)658 void Console::discardToPrompt(int conn)
659 {
660 DirComm *dircomm = m_dircommHash.value(conn);
661
662 int stat = 0;
663 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
664 if (mainWin->m_displayAll) {
665 displayToPrompt(conn);
666 } else {
667 while (!dircomm->m_at_prompt) {
668 stat = dircomm->read();
669 if (stat < 0) {
670 break;
671 }
672 }
673 }
674 if (mainWin->m_commDebug) {
675 Pmsg2(000, "endDiscardToPrompt conn=%i %s\n", conn, m_dir->name());
676 }
677 }
678
returnFromPrompt(int conn)679 QString Console::returnFromPrompt(int conn)
680 {
681 DirComm *dircomm = m_dircommHash.value(conn);
682 QString text("");
683
684 int stat = 0;
685 text = "";
686 dircomm->read();
687 text += dircomm->msg();
688 if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
689 while (!dircomm->m_at_prompt) {
690 if ((stat=dircomm->read()) > 0) {
691 text += dircomm->msg();
692 }
693 }
694 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
695 return text;
696 }
697
698 /*
699 * When the notifier is enabled, read_dir() will automatically be
700 * called by the Qt event loop when ever there is any output
701 * from the Director, and read_dir() will then display it on
702 * the console.
703 *
704 * When we are in a bat dialog, we want to control *all* output
705 * from the Director, so we set notify to off.
706 * m_console->notifiy(false);
707 */
708
709 /* dual purpose function to turn notify off and return a connection */
notifyOff()710 int Console::notifyOff()
711 {
712 int conn = 0;
713 if (getDirComm(conn)) {
714 notify(conn, false);
715 }
716 return conn;
717 }
718
719 /* knowing a connection, turn notify off or on */
notify(int conn,bool enable)720 bool Console::notify(int conn, bool enable)
721 {
722 DirComm *dircomm = m_dircommHash.value(conn);
723 if (dircomm) {
724 return dircomm->notify(enable);
725 } else {
726 return false;
727 }
728 }
729
730 /* knowing a connection, return notify state */
is_notify_enabled(int conn) const731 bool Console::is_notify_enabled(int conn) const
732 {
733 DirComm *dircomm = m_dircommHash.value(conn);
734 if (dircomm) {
735 return dircomm->is_notify_enabled();
736 } else {
737 return false;
738 }
739 }
740
setDirectorTreeItem(QTreeWidgetItem * item)741 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
742 {
743 m_directorTreeItem = item;
744 }
745
setDirRes(DIRRES * dir)746 void Console::setDirRes(DIRRES *dir)
747 {
748 m_dir = dir;
749 }
750
751 /*
752 * To have the ability to get the name of the director resource.
753 */
getDirResName(QString & name_returned)754 void Console::getDirResName(QString &name_returned)
755 {
756 name_returned = m_dir->name();
757 }
758
759 /* Slot for responding to page selectors status help command */
consoleHelp()760 void Console::consoleHelp()
761 {
762 QString cmd("help");
763 consoleCommand(cmd);
764 }
765
766 /* Slot for responding to page selectors reload bacula-dir.conf */
consoleReload()767 void Console::consoleReload()
768 {
769 QString cmd("reload");
770 consoleCommand(cmd);
771 }
772
773 /* For suppressing .messages
774 * This may be rendered not needed if the multiple connections feature gets working */
hasFocus()775 bool Console::hasFocus()
776 {
777 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
778 return true;
779 else
780 return false;
781 }
782
783 /* For adding feature to have the gui's messages button change when
784 * messages are pending */
messagesPending(bool pend)785 bool Console::messagesPending(bool pend)
786 {
787 bool prev = m_messages_pending;
788 m_messages_pending = pend;
789 mainWin->setMessageIcon();
790 return prev;
791 }
792
793 /* terminate all existing connections */
terminate()794 void Console::terminate()
795 {
796 foreach(DirComm* dircomm, m_dircommHash) {
797 dircomm->terminate();
798 }
799 m_console->stopTimer();
800 }
801
802 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
is_connectedGui()803 bool Console::is_connectedGui()
804 {
805 if (is_connected(0)) {
806 return true;
807 } else {
808 QString message = tr("Director is currently disconnected\nPlease reconnect!");
809 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
810 return false;
811 }
812 }
813
read(int conn)814 int Console::read(int conn)
815 {
816 DirComm *dircomm = m_dircommHash.value(conn);
817 return dircomm->read();
818 }
819
msg(int conn)820 char *Console::msg(int conn)
821 {
822 DirComm *dircomm = m_dircommHash.value(conn);
823 return dircomm->msg();
824 }
825
write(int conn,const QString msg)826 int Console::write(int conn, const QString msg)
827 {
828 DirComm *dircomm = m_dircommHash.value(conn);
829 mainWin->waitEnter();
830 int ret = dircomm->write(msg);
831 mainWin->waitExit();
832 return ret;
833 }
834
write(int conn,const char * msg)835 int Console::write(int conn, const char *msg)
836 {
837 DirComm *dircomm = m_dircommHash.value(conn);
838 mainWin->waitEnter();
839 int ret = dircomm->write(msg);
840 mainWin->waitExit();
841 return ret;
842 }
843
844 /* This checks to see if any is connected */
is_connected()845 bool Console::is_connected()
846 {
847 bool connected = false;
848 foreach(DirComm* dircomm, m_dircommHash) {
849 if (dircomm->is_connected())
850 return true;
851 }
852 return connected;
853 }
854
855 /* knowing the connection id, is it connected */
is_connected(int conn)856 bool Console::is_connected(int conn)
857 {
858 DirComm *dircomm = m_dircommHash.value(conn);
859 return dircomm->is_connected();
860 }
861
862 /*
863 * Need a connection. Check existing connections or create one
864 */
getDirComm(int & conn)865 bool Console::getDirComm(int &conn)
866 {
867 if (findDirComm(conn)) {
868 return true;
869 }
870 if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n");
871 return newDirComm(conn);
872 }
873
874
875 /*
876 * Try to find a free (unused but established) connection
877 * KES: Note, I think there is a problem here because for
878 * some reason, the notifier is often turned off on file
879 * descriptors that seem to me to be available. That means
880 * that we do not use a free descriptor and thus we will create
881 * a new connection that is maybe not necessary. Someone needs
882 * to look into whether or not notify() is correctly turned on
883 * when we are back at the command prompt and idle.
884 *
885 */
findDirComm(int & conn)886 bool Console::findDirComm(int &conn)
887 {
888 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
889 while (iter != m_dircommHash.constEnd()) {
890 DirComm *dircomm = iter.value();
891 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
892 conn = dircomm->m_conn;
893 return true;
894 }
895 if (mainWin->m_connDebug) {
896 Pmsg4(000, "currentDirComm=%d at_prompt=%d at_main=%d && notify=%d\n",
897 dircomm->m_conn, dircomm->m_at_prompt, dircomm->m_at_main_prompt, dircomm->is_notify_enabled());
898 }
899 ++iter;
900 }
901 return false;
902 }
903
904 /*
905 * Create a new connection
906 */
newDirComm(int & conn)907 bool Console::newDirComm(int &conn)
908 {
909 m_dircommCounter++;
910 if (mainWin->m_connDebug) {
911 Pmsg2(000, "newDirComm=%i to: %s\n", m_dircommCounter, m_dir->name());
912 }
913 DirComm *dircomm = new DirComm(this, m_dircommCounter);
914 m_dircommHash.insert(m_dircommCounter, dircomm);
915 bool success = dircomm->connect_dir();
916 if (mainWin->m_connDebug) {
917 if (success) {
918 Pmsg2(000, "newDirComm=%i Connected %s\n", m_dircommCounter, m_dir->name());
919 } else {
920 Emsg2(M_ERROR, 0, "DirComm=%i. Unable to connect to %s\n",
921 m_dircommCounter, m_dir->name());
922 }
923 }
924 if (!success) {
925 m_dircommHash.remove(m_dircommCounter);
926 delete dircomm;
927 m_dircommCounter--;
928 }
929 conn = m_dircommCounter;
930 return success;
931 }
932