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