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