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