]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
7c1d9d5a9838d8b5d5573ca3656390cccf9cc568
[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    m_cursor->insertText(buf);
585    update_cursor();
586 }
587
588
589 void Console::display_text(const char *buf)
590 {
591    m_cursor->insertText(buf);
592    update_cursor();
593 }
594
595 void Console::display_html(const QString buf)
596 {
597    m_cursor->insertHtml(buf);
598    update_cursor();
599 }
600
601 /* Position cursor to end of screen */
602 void Console::update_cursor()
603 {
604    m_textEdit->moveCursor(QTextCursor::End);
605    m_textEdit->ensureCursorVisible();
606 }
607
608 void Console::beginNewCommand(int conn)
609 {
610    DirComm *dircomm = m_dircommHash.value(conn);
611
612    for (int i=0; i < 3; i++) {
613       dircomm->write(".");
614       while (dircomm->read() > 0) {
615          if (mainWin->m_commDebug) Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
616          if (mainWin->m_displayAll) display_text(dircomm->msg());
617       }
618       if (dircomm->m_at_main_prompt) {
619          break;
620       }
621    }
622    display_text("\n");
623 }
624
625 void Console::displayToPrompt(int conn)
626
627    DirComm *dircomm = m_dircommHash.value(conn);
628
629    int stat = 0;
630    QString buf;
631    if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
632    while (!dircomm->m_at_prompt) {
633       if ((stat=dircomm->read()) > 0) {
634          buf += dircomm->msg();
635          if (buf.size() >= 8196 || m_messages_pending) {
636             display_text(buf);
637             buf.clear();
638             messagesPending(false);
639          }
640       }
641    }
642    display_text(buf);
643    if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
644 }
645
646 void Console::discardToPrompt(int conn)
647 {
648    DirComm *dircomm = m_dircommHash.value(conn);
649
650    int stat = 0;
651    if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
652    if (mainWin->m_displayAll) {
653       displayToPrompt(conn);
654    } else {
655       while (!dircomm->m_at_prompt) {
656          stat = dircomm->read();
657          if (stat < 0) {
658             break;
659          }
660       }
661    }
662    if (mainWin->m_commDebug) {
663       Pmsg2(000, "endDiscardToPrompt conn=%i %s\n", conn, m_dir->name());
664    }
665 }
666
667 QString Console::returnFromPrompt(int conn)
668
669    DirComm *dircomm = m_dircommHash.value(conn);
670    QString text("");
671
672    int stat = 0;
673    text = "";
674    dircomm->read();
675    text += dircomm->msg();
676    if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
677    while (!dircomm->m_at_prompt) {
678       if ((stat=dircomm->read()) > 0) {
679          text += dircomm->msg();
680       }
681    }
682    if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
683    return text;
684 }
685
686 /*
687  * When the notifier is enabled, read_dir() will automatically be
688  * called by the Qt event loop when ever there is any output 
689  * from the Director, and read_dir() will then display it on
690  * the console.
691  *
692  * When we are in a bat dialog, we want to control *all* output
693  * from the Director, so we set notify to off.
694  *    m_console->notifiy(false);
695  */
696
697 /* dual purpose function to turn notify off and return a connection */
698 int Console::notifyOff()
699
700    int conn = 0;
701    if (getDirComm(conn)) {
702       notify(conn, false);
703    }
704    return conn;
705 }
706
707 /* knowing a connection, turn notify off or on */
708 bool Console::notify(int conn, bool enable)
709
710    DirComm *dircomm = m_dircommHash.value(conn);
711    return dircomm->notify(enable);
712 }
713
714 /* knowing a connection, return notify state */
715 bool Console::is_notify_enabled(int conn) const
716 {
717    DirComm *dircomm = m_dircommHash.value(conn);
718    return dircomm->is_notify_enabled();
719 }
720
721 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
722 {
723    m_directorTreeItem = item;
724 }
725
726 void Console::setDirRes(DIRRES *dir) 
727
728    m_dir = dir;
729 }
730
731 /*
732  * To have the ability to get the name of the director resource.
733  */
734 void Console::getDirResName(QString &name_returned)
735 {
736    name_returned = m_dir->name();
737 }
738
739 /* Slot for responding to page selectors status help command */
740 void Console::consoleHelp()
741 {
742    QString cmd("help");
743    consoleCommand(cmd);
744 }
745
746 /* Slot for responding to page selectors reload bacula-dir.conf */
747 void Console::consoleReload()
748 {
749    QString cmd("reload");
750    consoleCommand(cmd);
751 }
752
753 /* For suppressing .messages
754  * This may be rendered not needed if the multiple connections feature gets working */
755 bool Console::hasFocus()
756 {
757    if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
758       return true;
759    else
760       return false;
761 }
762
763 /* For adding feature to have the gui's messages button change when 
764  * messages are pending */
765 bool Console::messagesPending(bool pend)
766 {
767    bool prev = m_messages_pending;
768    m_messages_pending = pend;
769    mainWin->setMessageIcon();
770    return prev;
771 }
772
773 /* terminate all existing connections */
774 void Console::terminate()
775 {
776    foreach(DirComm* dircomm,  m_dircommHash) {
777       dircomm->terminate();
778    }
779    m_console->stopTimer();
780 }
781
782 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
783 bool Console::is_connectedGui()
784 {
785    if (is_connected(0)) {
786       return true;
787    } else {
788       QString message = tr("Director is currently disconnected\nPlease reconnect!");
789       QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
790       return false;
791    }
792 }
793
794 int Console::read(int conn)
795 {
796    DirComm *dircomm = m_dircommHash.value(conn);
797    return dircomm->read();
798 }
799
800 char *Console::msg(int conn)
801 {
802    DirComm *dircomm = m_dircommHash.value(conn);
803    return dircomm->msg();
804 }
805
806 int Console::write(int conn, const QString msg)
807 {
808    DirComm *dircomm = m_dircommHash.value(conn);
809    mainWin->waitEnter();
810    int ret = dircomm->write(msg);
811    mainWin->waitExit();
812    return ret;
813 }
814
815 int Console::write(int conn, const char *msg)
816 {
817    DirComm *dircomm = m_dircommHash.value(conn);
818    mainWin->waitEnter();
819    int ret = dircomm->write(msg);
820    mainWin->waitExit();
821    return ret;
822 }
823
824 /* This checks to see if any is connected */
825 bool Console::is_connected()
826 {
827    bool connected = false;
828    foreach(DirComm* dircomm,  m_dircommHash) {
829       if (dircomm->is_connected())
830          return true;
831    }
832    return connected;
833 }
834
835 /* knowing the connection id, is it connected */
836 bool Console::is_connected(int conn)
837 {
838    DirComm *dircomm = m_dircommHash.value(conn);
839    return dircomm->is_connected();
840 }
841
842 /*
843  * Need a connection.  Check existing connections or create one
844  */
845 bool Console::getDirComm(int &conn)
846 {
847    if (findDirComm(conn)) {
848       return true;
849    }
850    if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n");
851    return newDirComm(conn);
852 }
853
854
855 /*
856  * Try to find a free (unused but established) connection
857  * KES: Note, I think there is a problem here because for
858  *   some reason, the notifier is often turned off on file  
859  *   descriptors that seem to me to be available.  That means
860  *   that we do not use a free descriptor and thus we will create
861  *   a new connection that is maybe not necessary.  Someone needs
862  *   to look into whether or not notify() is correctly turned on
863  *   when we are back at the command prompt and idle.
864  *                         
865  */
866 bool Console::findDirComm(int &conn)
867 {
868    int i = 1;
869    QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
870    while (iter != m_dircommHash.constEnd()) {
871       DirComm *dircomm = iter.value();
872       if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
873          conn = dircomm->m_conn;
874          return true;
875       }
876       if (mainWin->m_connDebug) {
877          Pmsg4(000, "currentDirComm=%d at_prompt=%d at_main=%d && notify=%d\n",                                      
878             i, dircomm->m_at_prompt, dircomm->m_at_main_prompt, dircomm->is_notify_enabled());
879          i++;
880       }
881       ++iter;
882    }
883    return false;
884 }
885
886 /*
887  *  Create a new connection
888  */
889 bool Console::newDirComm(int &conn)
890 {
891    m_dircommCounter++;
892    if (mainWin->m_connDebug) {
893       Pmsg2(000, "newDirComm=%i to: %s\n", m_dircommCounter, m_dir->name());
894    }
895    DirComm *dircomm = new DirComm(this, m_dircommCounter);
896    m_dircommHash.insert(m_dircommCounter, dircomm);
897    bool success = dircomm->connect_dir();
898    if (mainWin->m_connDebug) {
899       if (success) {
900          Pmsg2(000, "newDirComm=%i Connected %s\n", m_dircommCounter, m_dir->name());
901       } else {
902          Emsg2(M_ERROR, 0, "DirComm=%i. Unable to connect to %s\n",
903                m_dircommCounter, m_dir->name());
904       }
905    }
906    if (!success) {
907       m_dircommHash.remove(m_dircommCounter);
908       delete dircomm;
909       m_dircommCounter--;
910    }
911    conn = m_dircommCounter;
912    return success;
913 }