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