]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
Tweak bat console code
[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) : Pages()
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*30000);
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       dircomm->write(".messages");
116       displayToPrompt(conn);
117       messagesPending(false);
118    }
119 }
120
121 /*
122  * Connect to Director.  This does not connect to the director, dircomm does.
123  * This creates the first and possibly 2nd dircomm instance
124  */
125 void Console::connect_dir()
126 {
127    DirComm *dircomm = m_dircommHash.value(0);
128
129    if (!m_console->m_dir) {
130       mainWin->set_status( tr("No Director found."));
131       return;
132    }
133
134    m_textEdit = textEdit;   /* our console screen */
135
136    if (dircomm->connect_dir()) {
137       if (mainWin->m_connDebug) {
138          Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
139       }
140       beginNewCommand(0);
141    }
142    mainWin->set_status(_("Connected"));
143    
144    startTimer();                      /* start message timer */
145 }
146
147 /*
148  * A function created to separate out the population of the lists
149  * from the Console::connect_dir function
150  */
151 void Console::populateLists(bool /*forcenew*/)
152 {
153    int conn;
154    if (!getDirComm(conn)) {
155       if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n");
156       if (!newDirComm(conn)) {
157          Emsg1(M_ABORT, 0, "Failed to connect to %s for populateLists.\n", m_dir->name());
158          return;
159       }
160    }
161    populateLists(conn);
162 }
163
164 void Console::populateLists(int conn)
165 {
166    job_list.clear();
167    restore_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, ".jobs type=R", restore_list);
179    dir_cmd(conn, ".clients", client_list);
180    dir_cmd(conn, ".filesets", fileset_list);  
181    dir_cmd(conn, ".msgs", messages_list);
182    dir_cmd(conn, ".pools", pool_list);
183    dir_cmd(conn, ".storage", storage_list);
184    dir_cmd(conn, ".types", type_list);
185    dir_cmd(conn, ".levels", level_list);
186    dir_cmd(conn, ".volstatus", volstatus_list);
187    dir_cmd(conn, ".mediatypes", mediatype_list);
188    dir_cmd(conn, ".locations", location_list);
189
190    if (mainWin->m_connDebug) {
191       QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
192         .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
193         .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
194         .arg(conn).arg(m_dir->name());
195       Pmsg1(000, "%s", dbgmsg.toUtf8().data());
196    }
197    job_list.sort();
198    client_list.sort();
199    fileset_list.sort();
200    messages_list.sort();
201    pool_list.sort();
202    storage_list.sort();
203    type_list.sort();
204    level_list.sort();
205 }
206
207 /*
208  *  Overload function for dir_cmd with a QString
209  *  Ease of use
210  */
211 bool Console::dir_cmd(QString &cmd, QStringList &results)
212 {
213    return dir_cmd(cmd.toUtf8().data(), results);
214 }
215
216 /*
217  *  Overload function for dir_cmd, this is if connection is not worried about
218  */
219 bool Console::dir_cmd(const char *cmd, QStringList &results)
220 {
221    int conn;
222    if (getDirComm(conn)) {
223       dir_cmd(conn, cmd, results);
224       return true;
225    } else {
226       Pmsg1(000, "dir_cmd failed to connect to %s\n", m_dir->name());
227       return false;
228    }
229 }
230
231 /*
232  * Send a command to the Director, and return the
233  *  results in a QStringList.  
234  */
235 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
236 {
237    mainWin->waitEnter();
238    DirComm *dircomm = m_dircommHash.value(conn);
239    int stat;
240    bool prev_notify = mainWin->m_notify;
241
242    if (mainWin->m_connDebug) {
243       QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
244       Pmsg1(000, "%s", dbgmsg.toUtf8().data());
245    }
246    notify(conn, false);
247    dircomm->write(cmd);
248    while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
249       if (mainWin->m_displayAll) display_text(dircomm->msg());
250       strip_trailing_junk(dircomm->msg());
251       results << dircomm->msg();
252    }
253    if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
254    if (prev_notify) {
255       notify(conn, true);         /* turn it back on */
256    }
257    discardToPrompt(conn);
258    mainWin->waitExit();
259    return true;                  /* ***FIXME*** return any command error */
260 }
261
262 /*
263  * OverLoads for sql_cmd
264  */
265 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
266 {
267    return sql_cmd(conn, query.toUtf8().data(), results, false);
268 }
269
270 bool Console::sql_cmd(QString &query, QStringList &results)
271 {
272    int conn;
273    if (!getDirComm(conn)) {
274       return false;
275    }
276    return sql_cmd(conn, query.toUtf8().data(), results, true);
277 }
278
279 bool Console::sql_cmd(const char *query, QStringList &results)
280 {
281    int conn;
282    if (!getDirComm(conn)) {
283       return false;
284    }
285    return sql_cmd(conn, query, results, true);
286 }
287
288 /*
289  * Send an sql query to the Director, and return the
290  *  results in a QStringList.  
291  */
292 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
293 {
294    DirComm *dircomm = m_dircommHash.value(conn);
295    int stat;
296    POOL_MEM cmd(PM_MESSAGE);
297    bool prev_notify = mainWin->m_notify;
298
299    if (!is_connectedGui()) {
300       return false;
301    }
302
303    if (mainWin->m_connDebug) Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
304    if (donotify) {
305       dircomm->notify(false);
306    }
307    mainWin->waitEnter();
308    
309    pm_strcpy(cmd, ".sql query=\"");
310    pm_strcat(cmd, query);
311    pm_strcat(cmd, "\"");
312    dircomm->write(cmd.c_str());
313    while ((stat = dircomm->read()) > 0) {
314       bool first = true;
315       if (mainWin->m_displayAll) {
316          display_text(dircomm->msg());
317          display_text("\n");
318       }
319       strip_trailing_junk(dircomm->msg());
320       bool doappend = true;
321       if (first) {
322          QString dum = dircomm->msg();
323          if ((dum.left(6) == "*None*")) doappend = false;
324       }
325       if (doappend) {
326          results << dircomm->msg();
327       }
328       first = false;
329    }
330    if (donotify && prev_notify) {
331       dircomm->notify(true);
332    }
333    discardToPrompt(conn);
334    mainWin->waitExit();
335    return !mainWin->isClosing();      /* return false if closing */
336 }
337
338 /* 
339  * Overloads for
340  * Sending a command to the Director
341  */
342 int Console::write_dir(const char *msg)
343 {
344    int conn;
345    if (getDirComm(conn)) {
346       write_dir(conn, msg);
347    }
348    return conn;
349 }
350
351 int Console::write_dir(const char *msg, bool dowait)
352 {
353    int conn;
354    if (getDirComm(conn)) {
355       write_dir(conn, msg, dowait);
356    }
357    return conn;
358 }
359
360 void Console::write_dir(int conn, const char *msg)
361 {
362    write_dir(conn, msg, true);
363 }
364
365 /*
366  * Send a command to the Director
367  */
368 void Console::write_dir(int conn, const char *msg, bool dowait)
369 {
370    DirComm *dircomm = m_dircommHash.value(conn);
371
372    if (dircomm->m_sock) {
373       mainWin->set_status(_("Processing command ..."));
374       if (dowait)
375          mainWin->waitEnter();
376       dircomm->write(msg);
377       if (dowait)
378          mainWin->waitExit();
379    } else {
380       mainWin->set_status( tr(" Director not connected. Click on connect button."));
381       mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
382       QBrush redBrush(Qt::red);
383       QTreeWidgetItem *item = mainWin->getFromHash(this);
384       item->setForeground(0, redBrush);
385       dircomm->m_at_prompt = false;
386       dircomm->m_at_main_prompt = false;
387    }
388 }
389
390 /*
391  * get_job_defaults overload
392  */
393 bool Console::get_job_defaults(struct job_defaults &job_defs)
394 {
395    int conn;
396    return get_job_defaults(conn, job_defs, true);
397 }
398
399 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
400 {
401    return get_job_defaults(conn, job_defs, false);
402 }
403
404 /*  
405  * Send a job name to the director, and read all the resulting
406  *  defaults. 
407  */
408 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
409 {
410    QString scmd;
411    int stat;
412    char *def;
413    bool prev_notify = mainWin->m_notify;
414    bool rtn = false;
415
416    if (donotify) {
417       conn = notifyOff();
418    }
419    beginNewCommand(conn);
420    DirComm *dircomm = m_dircommHash.value(conn);
421    bool prevWaitState = mainWin->getWaitState();
422    if (!prevWaitState)
423       mainWin->waitEnter();
424    if (mainWin->m_connDebug)
425       Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
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  */
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  */
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  */
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  */
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  */
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  */
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  */
572 void Console::display_textf(const char *fmt, ...)
573 {
574    va_list arg_ptr;
575    char buf[1000];
576    int len;
577    va_start(arg_ptr, fmt);
578    len = 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 (buf.size() != 0) {
586       m_cursor->insertText(buf);
587       update_cursor();
588    }
589 }
590
591
592 void Console::display_text(const char *buf)
593 {
594    if (*buf != 0) {
595       m_cursor->insertText(buf);
596       update_cursor();
597    }
598 }
599
600 void Console::display_html(const QString buf)
601 {
602    if (buf.size() != 0) {
603       m_cursor->insertHtml(buf);
604       update_cursor();
605    }
606 }
607
608 /* Position cursor to end of screen */
609 void Console::update_cursor()
610 {
611    m_textEdit->moveCursor(QTextCursor::End);
612    m_textEdit->ensureCursorVisible();
613 }
614
615 void Console::beginNewCommand(int conn)
616 {
617    DirComm *dircomm = m_dircommHash.value(conn);
618
619    for (int i=0; i < 3; i++) {
620       dircomm->write(".");
621       while (dircomm->read() > 0) {
622          if (mainWin->m_commDebug) Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
623          if (mainWin->m_displayAll) display_text(dircomm->msg());
624       }
625       if (dircomm->m_at_main_prompt) {
626          break;
627       }
628    }
629    display_text("\n");
630 }
631
632 void Console::displayToPrompt(int conn)
633
634    DirComm *dircomm = m_dircommHash.value(conn);
635
636    int stat = 0;
637    QString buf;
638    if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
639    while (!dircomm->m_at_prompt) {
640       if ((stat=dircomm->read()) > 0) {
641          buf += dircomm->msg();
642          if (buf.size() >= 8196 || m_messages_pending) {
643             display_text(buf);
644             buf.clear();
645             messagesPending(false);
646          }
647       }
648    }
649    display_text(buf);
650    if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
651 }
652
653 void Console::discardToPrompt(int conn)
654 {
655    DirComm *dircomm = m_dircommHash.value(conn);
656
657    int stat = 0;
658    if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
659    if (mainWin->m_displayAll) {
660       displayToPrompt(conn);
661    } else {
662       while (!dircomm->m_at_prompt) {
663          stat = dircomm->read();
664          if (stat < 0) {
665             break;
666          }
667       }
668    }
669    if (mainWin->m_commDebug) {
670       Pmsg2(000, "endDiscardToPrompt conn=%i %s\n", conn, m_dir->name());
671    }
672 }
673
674 QString Console::returnFromPrompt(int conn)
675
676    DirComm *dircomm = m_dircommHash.value(conn);
677    QString text("");
678
679    int stat = 0;
680    text = "";
681    dircomm->read();
682    text += dircomm->msg();
683    if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
684    while (!dircomm->m_at_prompt) {
685       if ((stat=dircomm->read()) > 0) {
686          text += dircomm->msg();
687       }
688    }
689    if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
690    return text;
691 }
692
693 /*
694  * When the notifier is enabled, read_dir() will automatically be
695  * called by the Qt event loop when ever there is any output 
696  * from the Director, and read_dir() will then display it on
697  * the console.
698  *
699  * When we are in a bat dialog, we want to control *all* output
700  * from the Director, so we set notify to off.
701  *    m_console->notifiy(false);
702  */
703
704 /* dual purpose function to turn notify off and return a connection */
705 int Console::notifyOff()
706
707    int conn = 0;
708    if (getDirComm(conn)) {
709       notify(conn, false);
710    }
711    return conn;
712 }
713
714 /* knowing a connection, turn notify off or on */
715 bool Console::notify(int conn, bool enable)
716
717    DirComm *dircomm = m_dircommHash.value(conn);
718    return dircomm->notify(enable);
719 }
720
721 /* knowing a connection, return notify state */
722 bool Console::is_notify_enabled(int conn) const
723 {
724    DirComm *dircomm = m_dircommHash.value(conn);
725    return dircomm->is_notify_enabled();
726 }
727
728 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
729 {
730    m_directorTreeItem = item;
731 }
732
733 void Console::setDirRes(DIRRES *dir) 
734
735    m_dir = dir;
736 }
737
738 /*
739  * To have the ability to get the name of the director resource.
740  */
741 void Console::getDirResName(QString &name_returned)
742 {
743    name_returned = m_dir->name();
744 }
745
746 /* Slot for responding to page selectors status help command */
747 void Console::consoleHelp()
748 {
749    QString cmd("help");
750    consoleCommand(cmd);
751 }
752
753 /* Slot for responding to page selectors reload bacula-dir.conf */
754 void Console::consoleReload()
755 {
756    QString cmd("reload");
757    consoleCommand(cmd);
758 }
759
760 /* For suppressing .messages
761  * This may be rendered not needed if the multiple connections feature gets working */
762 bool Console::hasFocus()
763 {
764    if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
765       return true;
766    else
767       return false;
768 }
769
770 /* For adding feature to have the gui's messages button change when 
771  * messages are pending */
772 bool Console::messagesPending(bool pend)
773 {
774    bool prev = m_messages_pending;
775    m_messages_pending = pend;
776    mainWin->setMessageIcon();
777    return prev;
778 }
779
780 /* terminate all existing connections */
781 void Console::terminate()
782 {
783    foreach(DirComm* dircomm,  m_dircommHash) {
784       dircomm->terminate();
785    }
786    m_console->stopTimer();
787 }
788
789 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
790 bool Console::is_connectedGui()
791 {
792    if (is_connected(0)) {
793       return true;
794    } else {
795       QString message = tr("Director is currently disconnected\nPlease reconnect!");
796       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
797       return false;
798    }
799 }
800
801 int Console::read(int conn)
802 {
803    DirComm *dircomm = m_dircommHash.value(conn);
804    return dircomm->read();
805 }
806
807 char *Console::msg(int conn)
808 {
809    DirComm *dircomm = m_dircommHash.value(conn);
810    return dircomm->msg();
811 }
812
813 int Console::write(int conn, const QString msg)
814 {
815    DirComm *dircomm = m_dircommHash.value(conn);
816    mainWin->waitEnter();
817    int ret = dircomm->write(msg);
818    mainWin->waitExit();
819    return ret;
820 }
821
822 int Console::write(int conn, const char *msg)
823 {
824    DirComm *dircomm = m_dircommHash.value(conn);
825    mainWin->waitEnter();
826    int ret = dircomm->write(msg);
827    mainWin->waitExit();
828    return ret;
829 }
830
831 /* This checks to see if any is connected */
832 bool Console::is_connected()
833 {
834    bool connected = false;
835    foreach(DirComm* dircomm,  m_dircommHash) {
836       if (dircomm->is_connected())
837          return true;
838    }
839    return connected;
840 }
841
842 /* knowing the connection id, is it connected */
843 bool Console::is_connected(int conn)
844 {
845    DirComm *dircomm = m_dircommHash.value(conn);
846    return dircomm->is_connected();
847 }
848
849 /*
850  * Need a connection.  Check existing connections or create one
851  */
852 bool Console::getDirComm(int &conn)
853 {
854    if (findDirComm(conn)) {
855       return true;
856    }
857    if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n");
858    return newDirComm(conn);
859 }
860
861
862 /*
863  * Try to find a free (unused but established) connection
864  * KES: Note, I think there is a problem here because for
865  *   some reason, the notifier is often turned off on file  
866  *   descriptors that seem to me to be available.  That means
867  *   that we do not use a free descriptor and thus we will create
868  *   a new connection that is maybe not necessary.  Someone needs
869  *   to look into whether or not notify() is correctly turned on
870  *   when we are back at the command prompt and idle.
871  *                         
872  */
873 bool Console::findDirComm(int &conn)
874 {
875    int i = 1;
876    QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
877    while (iter != m_dircommHash.constEnd()) {
878       DirComm *dircomm = iter.value();
879       if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
880          conn = dircomm->m_conn;
881          return true;
882       }
883       if (mainWin->m_connDebug) {
884          Pmsg4(000, "currentDirComm=%d at_prompt=%d at_main=%d && notify=%d\n",                                      
885             i, dircomm->m_at_prompt, dircomm->m_at_main_prompt, dircomm->is_notify_enabled());
886          i++;
887       }
888       ++iter;
889    }
890    return false;
891 }
892
893 /*
894  *  Create a new connection
895  */
896 bool Console::newDirComm(int &conn)
897 {
898    m_dircommCounter++;
899    if (mainWin->m_connDebug) {
900       Pmsg2(000, "newDirComm=%i to: %s\n", m_dircommCounter, m_dir->name());
901    }
902    DirComm *dircomm = new DirComm(this, m_dircommCounter);
903    m_dircommHash.insert(m_dircommCounter, dircomm);
904    bool success = dircomm->connect_dir();
905    if (mainWin->m_connDebug) {
906       if (success) {
907          Pmsg2(000, "newDirComm=%i Connected %s\n", m_dircommCounter, m_dir->name());
908       } else {
909          Emsg2(M_ERROR, 0, "DirComm=%i. Unable to connect to %s\n",
910                m_dircommCounter, m_dir->name());
911       }
912    }
913    if (!success) {
914       m_dircommHash.remove(m_dircommCounter);
915       delete dircomm;
916       m_dircommCounter--;
917    }
918    conn = m_dircommCounter;
919    return success;
920 }