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