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