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