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)
146 if (!newDirComm(conn)) {
147 Pmsg1(000, "newDirComm Seems to Failed to create a connection for populateLists %s\n", m_dir->name());
151 if (!availableDirComm(conn)) {
152 Pmsg1(000, "availableDirComm Seems to Failed to find a connection for populateListsi %s\n", m_dir->name());
159 void Console::populateLists(int conn)
163 fileset_list.clear();
164 messages_list.clear();
166 storage_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);
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());
193 messages_list.sort();
201 * Overload function for dir_cmd with a QString
204 bool Console::dir_cmd(QString &cmd, QStringList &results)
206 return dir_cmd(cmd.toUtf8().data(), results);
210 * Overload function for dir_cmd, this is if connection is not worried about
212 bool Console::dir_cmd(const char *cmd, QStringList &results)
215 if (availableDirComm(conn)) {
216 dir_cmd(conn, cmd, results);
219 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
225 * Send a command to the Director, and return the
226 * results in a QStringList.
228 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
230 mainWin->waitEnter();
231 DirComm *dircomm = m_dircommHash.value(conn);
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());
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();
245 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
247 discardToPrompt(conn);
249 return true; /* ***FIXME*** return any command error */
253 * OverLoads for sql_cmd
255 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
257 return sql_cmd(conn, query.toUtf8().data(), results, false);
260 bool Console::sql_cmd(QString &query, QStringList &results)
263 if (!availableDirComm(conn))
265 return sql_cmd(conn, query.toUtf8().data(), results, true);
268 bool Console::sql_cmd(const char *query, QStringList &results)
271 if (!availableDirComm(conn))
273 return sql_cmd(conn, query, results, true);
277 * Send an sql query to the Director, and return the
278 * results in a QStringList.
280 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
282 DirComm *dircomm = m_dircommHash.value(conn);
284 POOL_MEM cmd(PM_MESSAGE);
286 if (!is_connectedGui()) {
290 if (mainWin->m_connDebug)
291 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
293 dircomm->notify(false);
294 mainWin->waitEnter();
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) {
302 if (mainWin->m_displayAll) {
303 display_text(dircomm->msg());
306 strip_trailing_junk(dircomm->msg());
307 bool doappend = true;
309 QString dum = dircomm->msg();
310 if ((dum.left(6) == "*None*")) doappend = false;
313 results << dircomm->msg();
317 dircomm->notify(true);
318 discardToPrompt(conn);
320 return true; /* ***FIXME*** return any command error */
325 * Sending a command to the Director
327 int Console::write_dir(const char *msg)
330 if (availableDirComm(conn))
331 write_dir(conn, msg);
335 int Console::write_dir(const char *msg, bool dowait)
338 if (availableDirComm(conn))
339 write_dir(conn, msg, dowait);
343 void Console::write_dir(int conn, const char *msg)
345 write_dir(conn, msg, true);
349 * Send a command to the Director
351 void Console::write_dir(int conn, const char *msg, bool dowait)
353 DirComm *dircomm = m_dircommHash.value(conn);
355 if (dircomm->m_sock) {
356 mainWin->set_status(_("Processing command ..."));
358 mainWin->waitEnter();
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;
374 * get_job_defaults overload
376 bool Console::get_job_defaults(struct job_defaults &job_defs)
379 return get_job_defaults(conn, job_defs, true);
382 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
384 return get_job_defaults(conn, job_defs, false);
388 * Send a job name to the director, and read all the resulting
391 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
399 beginNewCommand(conn);
400 DirComm *dircomm = m_dircommHash.value(conn);
401 bool prevWaitState = mainWin->getWaitState();
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(), '=');
414 /* Pointer to default value */
416 strip_trailing_junk(def);
418 if (strcmp(dircomm->msg(), "job") == 0) {
419 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
424 if (strcmp(dircomm->msg(), "pool") == 0) {
425 job_defs.pool_name = def;
428 if (strcmp(dircomm->msg(), "messages") == 0) {
429 job_defs.messages_name = def;
432 if (strcmp(dircomm->msg(), "client") == 0) {
433 job_defs.client_name = def;
436 if (strcmp(dircomm->msg(), "storage") == 0) {
437 job_defs.store_name = def;
440 if (strcmp(dircomm->msg(), "where") == 0) {
441 job_defs.where = def;
444 if (strcmp(dircomm->msg(), "level") == 0) {
445 job_defs.level = def;
448 if (strcmp(dircomm->msg(), "type") == 0) {
452 if (strcmp(dircomm->msg(), "fileset") == 0) {
453 job_defs.fileset_name = def;
456 if (strcmp(dircomm->msg(), "catalog") == 0) {
457 job_defs.catalog_name = def;
460 if (strcmp(dircomm->msg(), "enabled") == 0) {
461 job_defs.enabled = *def == '1' ? true : false;
482 * Save user settings associated with this console
484 void Console::writeSettings()
486 QFont font = get_font();
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());
497 * Read and restore user settings associated with this console
499 void Console::readSettings()
501 QFont font = get_font();
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());
509 m_textEdit->setFont(font);
513 * Set the console textEdit font
515 void Console::set_font()
518 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
520 m_textEdit->setFont(font);
525 * Get the console text edit font
527 const QFont Console::get_font()
529 return m_textEdit->font();
533 * Slot for responding to status dir button on button bar
535 void Console::status_dir()
537 QString cmd("status dir");
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
545 void Console::messages()
547 QString cmd(".messages");
549 messagesPending(false);
553 * Put text into the console window
555 void Console::display_textf(const char *fmt, ...)
560 va_start(arg_ptr, fmt);
561 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
566 void Console::display_text(const QString buf)
568 m_cursor->insertText(buf);
573 void Console::display_text(const char *buf)
575 m_cursor->insertText(buf);
579 void Console::display_html(const QString buf)
581 m_cursor->insertHtml(buf);
585 /* Position cursor to end of screen */
586 void Console::update_cursor()
588 m_textEdit->moveCursor(QTextCursor::End);
589 m_textEdit->ensureCursorVisible();
592 void Console::beginNewCommand(int conn)
594 DirComm *dircomm = m_dircommHash.value(conn);
596 for (int i=0; i < 3; i++) {
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());
602 if (dircomm->m_at_main_prompt) {
609 void Console::displayToPrompt(int conn)
611 DirComm *dircomm = m_dircommHash.value(conn);
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) {
622 messagesPending(false);
627 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
630 void Console::discardToPrompt(int conn)
632 DirComm *dircomm = m_dircommHash.value(conn);
635 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
636 if (mainWin->m_displayAll) {
637 displayToPrompt(conn);
639 while (!dircomm->m_at_prompt) {
640 stat = dircomm->read();
646 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
649 QString Console::returnFromPrompt(int conn)
651 DirComm *dircomm = m_dircommHash.value(conn);
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();
662 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
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
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);
677 /* dual purpose function to turn notify off and return an available connection */
678 int Console::notifyOff()
681 if (availableDirComm(conn))
686 /* knowing a connection, turn notify off or on */
687 bool Console::notify(int conn, bool enable)
689 DirComm *dircomm = m_dircommHash.value(conn);
690 return dircomm->notify(enable);
693 /* knowing a connection, return notify state */
694 bool Console::is_notify_enabled(int conn) const
696 DirComm *dircomm = m_dircommHash.value(conn);
697 return dircomm->is_notify_enabled();
700 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
702 m_directorTreeItem = item;
705 void Console::setDirRes(DIRRES *dir)
711 * To have the ability to get the name of the director resource.
713 void Console::getDirResName(QString &name_returned)
715 name_returned = m_dir->name();
718 /* Slot for responding to page selectors status help command */
719 void Console::consoleHelp()
725 /* Slot for responding to page selectors reload bacula-dir.conf */
726 void Console::consoleReload()
728 QString cmd("reload");
732 /* For suppressing .messages
733 * This may be rendered not needed if the multiple connections feature gets working */
734 bool Console::hasFocus()
736 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
742 /* For adding feature to have the gui's messages button change when
743 * messages are pending */
744 bool Console::messagesPending(bool pend)
746 bool prev = m_messages_pending;
747 m_messages_pending = pend;
748 mainWin->setMessageIcon();
752 /* terminate all existing connections */
753 void Console::terminate()
755 foreach(DirComm* dircomm, m_dircommHash) {
756 dircomm->terminate();
758 m_console->stopTimer();
761 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
762 bool Console::is_connectedGui()
764 if (is_connected(0)) {
767 QString message = tr("Director is currently disconnected\nPlease reconnect!");
768 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
773 int Console::read(int conn)
775 DirComm *dircomm = m_dircommHash.value(conn);
776 return dircomm->read();
779 char *Console::msg(int conn)
781 DirComm *dircomm = m_dircommHash.value(conn);
782 return dircomm->msg();
785 int Console::write(int conn, const QString msg)
787 DirComm *dircomm = m_dircommHash.value(conn);
788 mainWin->waitEnter();
789 int ret = dircomm->write(msg);
794 int Console::write(int conn, const char *msg)
796 DirComm *dircomm = m_dircommHash.value(conn);
797 mainWin->waitEnter();
798 int ret = dircomm->write(msg);
803 /* This checks to see if any is connected */
804 bool Console::is_connected()
806 bool connected = false;
807 foreach(DirComm* dircomm, m_dircommHash) {
808 if (dircomm->is_connected())
814 /* knowing the connection id, is it connected */
815 bool Console::is_connected(int conn)
817 DirComm *dircomm = m_dircommHash.value(conn);
818 return dircomm->is_connected();
822 * Need an available connection. Check existing connections or create one
824 bool Console::availableDirComm(int &conn)
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;
835 if (newDirComm(conn))
843 * Need current connection.
845 bool Console::currentDirComm(int &conn)
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;
860 * Create a new connection
862 bool Console::newDirComm(int &conn)
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) {
873 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
875 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());