2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
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
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.
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
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.
33 * Kern Sibbald, January MMVII
43 Console::Console(QTabWidget *parent)
46 m_name = tr("Console");
47 m_messages_pending = false;
51 m_warningPrevent = false;
55 * Create a connection to the Director and put it in a hash table
57 m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter));
60 m_textEdit = textEdit; /* our console screen */
61 m_cursor = new QTextCursor(m_textEdit->document());
62 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
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()));
79 void Console::startTimer()
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);
86 void Console::stopTimer()
89 QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
96 /* slot connected to the timer
97 * requires preferences of check messages and operates at interval */
98 void Console::poll_messages()
101 if (!availableDirComm(conn))
103 DirComm *dircomm = m_dircommHash.value(conn);
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);
114 * Connect to Director. This does not connect to the director, dircomm does.
115 * This creates the first and possibly 2nd dircomm instance
117 void Console::connect_dir()
119 DirComm *dircomm = m_dircommHash.value(0);
121 if (!m_console->m_dir) {
122 mainWin->set_status( tr("No Director found."));
126 m_textEdit = textEdit; /* our console screen */
128 if (dircomm->connect_dir()) {
129 if (mainWin->m_connDebug)
130 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
133 mainWin->set_status(_("Connected"));
135 startTimer(); /* start message timer */
139 * A function created to separate out the population of the lists
140 * from the Console::connect_dir function
142 void Console::populateLists(bool /*forcenew*/)
145 if (!availableDirComm(conn) && !newDirComm(conn)) {
146 Pmsg1(000, "newDirComm Seems to Failed to create a connection for populateLists %s\n", m_dir->name());
152 void Console::populateLists(int conn)
156 fileset_list.clear();
157 messages_list.clear();
159 storage_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);
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());
186 messages_list.sort();
194 * Overload function for dir_cmd with a QString
197 bool Console::dir_cmd(QString &cmd, QStringList &results)
199 return dir_cmd(cmd.toUtf8().data(), results);
203 * Overload function for dir_cmd, this is if connection is not worried about
205 bool Console::dir_cmd(const char *cmd, QStringList &results)
208 if (availableDirComm(conn)) {
209 dir_cmd(conn, cmd, results);
212 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
218 * Send a command to the Director, and return the
219 * results in a QStringList.
221 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
223 mainWin->waitEnter();
224 DirComm *dircomm = m_dircommHash.value(conn);
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());
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();
238 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
240 discardToPrompt(conn);
242 return true; /* ***FIXME*** return any command error */
246 * OverLoads for sql_cmd
248 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
250 return sql_cmd(conn, query.toUtf8().data(), results, false);
253 bool Console::sql_cmd(QString &query, QStringList &results)
256 if (!availableDirComm(conn))
258 return sql_cmd(conn, query.toUtf8().data(), results, true);
261 bool Console::sql_cmd(const char *query, QStringList &results)
264 if (!availableDirComm(conn))
266 return sql_cmd(conn, query, results, true);
270 * Send an sql query to the Director, and return the
271 * results in a QStringList.
273 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
275 DirComm *dircomm = m_dircommHash.value(conn);
277 POOL_MEM cmd(PM_MESSAGE);
279 if (!is_connectedGui()) {
283 if (mainWin->m_connDebug)
284 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
286 dircomm->notify(false);
287 mainWin->waitEnter();
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) {
295 if (mainWin->m_displayAll) {
296 display_text(dircomm->msg());
299 strip_trailing_junk(dircomm->msg());
300 bool doappend = true;
302 QString dum = dircomm->msg();
303 if ((dum.left(6) == "*None*")) doappend = false;
306 results << dircomm->msg();
310 dircomm->notify(true);
311 discardToPrompt(conn);
313 return true; /* ***FIXME*** return any command error */
318 * Sending a command to the Director
320 int Console::write_dir(const char *msg)
323 if (availableDirComm(conn))
324 write_dir(conn, msg);
328 int Console::write_dir(const char *msg, bool dowait)
331 if (availableDirComm(conn))
332 write_dir(conn, msg, dowait);
336 void Console::write_dir(int conn, const char *msg)
338 write_dir(conn, msg, true);
342 * Send a command to the Director
344 void Console::write_dir(int conn, const char *msg, bool dowait)
346 DirComm *dircomm = m_dircommHash.value(conn);
348 if (dircomm->m_sock) {
349 mainWin->set_status(_("Processing command ..."));
351 mainWin->waitEnter();
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;
367 * get_job_defaults overload
369 bool Console::get_job_defaults(struct job_defaults &job_defs)
372 return get_job_defaults(conn, job_defs, true);
375 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
377 return get_job_defaults(conn, job_defs, false);
381 * Send a job name to the director, and read all the resulting
384 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
392 beginNewCommand(conn);
393 DirComm *dircomm = m_dircommHash.value(conn);
394 bool prevWaitState = mainWin->getWaitState();
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(), '=');
407 /* Pointer to default value */
409 strip_trailing_junk(def);
411 if (strcmp(dircomm->msg(), "job") == 0) {
412 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
417 if (strcmp(dircomm->msg(), "pool") == 0) {
418 job_defs.pool_name = def;
421 if (strcmp(dircomm->msg(), "messages") == 0) {
422 job_defs.messages_name = def;
425 if (strcmp(dircomm->msg(), "client") == 0) {
426 job_defs.client_name = def;
429 if (strcmp(dircomm->msg(), "storage") == 0) {
430 job_defs.store_name = def;
433 if (strcmp(dircomm->msg(), "where") == 0) {
434 job_defs.where = def;
437 if (strcmp(dircomm->msg(), "level") == 0) {
438 job_defs.level = def;
441 if (strcmp(dircomm->msg(), "type") == 0) {
445 if (strcmp(dircomm->msg(), "fileset") == 0) {
446 job_defs.fileset_name = def;
449 if (strcmp(dircomm->msg(), "catalog") == 0) {
450 job_defs.catalog_name = def;
453 if (strcmp(dircomm->msg(), "enabled") == 0) {
454 job_defs.enabled = *def == '1' ? true : false;
475 * Save user settings associated with this console
477 void Console::writeSettings()
479 QFont font = get_font();
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());
490 * Read and restore user settings associated with this console
492 void Console::readSettings()
494 QFont font = get_font();
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());
502 m_textEdit->setFont(font);
506 * Set the console textEdit font
508 void Console::set_font()
511 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
513 m_textEdit->setFont(font);
518 * Get the console text edit font
520 const QFont Console::get_font()
522 return m_textEdit->font();
526 * Slot for responding to status dir button on button bar
528 void Console::status_dir()
530 QString cmd("status dir");
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
538 void Console::messages()
540 QString cmd(".messages");
542 messagesPending(false);
546 * Put text into the console window
548 void Console::display_textf(const char *fmt, ...)
553 va_start(arg_ptr, fmt);
554 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
559 void Console::display_text(const QString buf)
561 m_cursor->insertText(buf);
566 void Console::display_text(const char *buf)
568 m_cursor->insertText(buf);
572 void Console::display_html(const QString buf)
574 m_cursor->insertHtml(buf);
578 /* Position cursor to end of screen */
579 void Console::update_cursor()
581 m_textEdit->moveCursor(QTextCursor::End);
582 m_textEdit->ensureCursorVisible();
585 void Console::beginNewCommand(int conn)
587 DirComm *dircomm = m_dircommHash.value(conn);
589 for (int i=0; i < 3; i++) {
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());
595 if (dircomm->m_at_main_prompt) {
602 void Console::displayToPrompt(int conn)
604 DirComm *dircomm = m_dircommHash.value(conn);
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) {
615 messagesPending(false);
620 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
623 void Console::discardToPrompt(int conn)
625 DirComm *dircomm = m_dircommHash.value(conn);
628 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
629 if (mainWin->m_displayAll) {
630 displayToPrompt(conn);
632 while (!dircomm->m_at_prompt) {
633 stat = dircomm->read();
639 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
642 QString Console::returnFromPrompt(int conn)
644 DirComm *dircomm = m_dircommHash.value(conn);
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();
655 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
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
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);
670 /* dual purpose function to turn notify off and return an available connection */
671 int Console::notifyOff()
674 if (availableDirComm(conn))
679 /* knowing a connection, turn notify off or on */
680 bool Console::notify(int conn, bool enable)
682 DirComm *dircomm = m_dircommHash.value(conn);
683 return dircomm->notify(enable);
686 /* knowing a connection, return notify state */
687 bool Console::is_notify_enabled(int conn) const
689 DirComm *dircomm = m_dircommHash.value(conn);
690 return dircomm->is_notify_enabled();
693 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
695 m_directorTreeItem = item;
698 void Console::setDirRes(DIRRES *dir)
704 * To have the ability to get the name of the director resource.
706 void Console::getDirResName(QString &name_returned)
708 name_returned = m_dir->name();
711 /* Slot for responding to page selectors status help command */
712 void Console::consoleHelp()
718 /* Slot for responding to page selectors reload bacula-dir.conf */
719 void Console::consoleReload()
721 QString cmd("reload");
725 /* For suppressing .messages
726 * This may be rendered not needed if the multiple connections feature gets working */
727 bool Console::hasFocus()
729 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
735 /* For adding feature to have the gui's messages button change when
736 * messages are pending */
737 bool Console::messagesPending(bool pend)
739 bool prev = m_messages_pending;
740 m_messages_pending = pend;
741 mainWin->setMessageIcon();
745 /* terminate all existing connections */
746 void Console::terminate()
748 foreach(DirComm* dircomm, m_dircommHash) {
749 dircomm->terminate();
751 m_console->stopTimer();
754 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
755 bool Console::is_connectedGui()
757 if (is_connected(0)) {
760 QString message = tr("Director is currently disconnected\nPlease reconnect!");
761 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
766 int Console::read(int conn)
768 DirComm *dircomm = m_dircommHash.value(conn);
769 return dircomm->read();
772 char *Console::msg(int conn)
774 DirComm *dircomm = m_dircommHash.value(conn);
775 return dircomm->msg();
778 int Console::write(int conn, const QString msg)
780 DirComm *dircomm = m_dircommHash.value(conn);
781 mainWin->waitEnter();
782 int ret = dircomm->write(msg);
787 int Console::write(int conn, const char *msg)
789 DirComm *dircomm = m_dircommHash.value(conn);
790 mainWin->waitEnter();
791 int ret = dircomm->write(msg);
796 /* This checks to see if any is connected */
797 bool Console::is_connected()
799 bool connected = false;
800 foreach(DirComm* dircomm, m_dircommHash) {
801 if (dircomm->is_connected())
807 /* knowing the connection id, is it connected */
808 bool Console::is_connected(int conn)
810 DirComm *dircomm = m_dircommHash.value(conn);
811 return dircomm->is_connected();
815 * Need an available connection. Check existing connections or create one
817 bool Console::availableDirComm(int &conn)
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;
828 if (newDirComm(conn))
836 * Need current connection.
838 bool Console::currentDirComm(int &conn)
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;
853 * Create a new connection
855 bool Console::newDirComm(int &conn)
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) {
866 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
868 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());