2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2010 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.
31 * Kern Sibbald, January MMVII
41 Console::Console(QTabWidget *parent)
44 m_name = tr("Console");
45 m_messages_pending = false;
49 m_warningPrevent = false;
53 * Create a connection to the Director and put it in a hash table
55 m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter));
58 m_textEdit = textEdit; /* our console screen */
59 m_cursor = new QTextCursor(m_textEdit->document());
60 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
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()));
77 void Console::startTimer()
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);
84 void Console::stopTimer()
87 QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
94 /* slot connected to the timer
95 * requires preferences of check messages and operates at interval */
96 void Console::poll_messages()
99 if (!availableDirComm(conn))
101 DirComm *dircomm = m_dircommHash.value(conn);
103 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){
104 messagesPending(true);
105 dircomm->write(".messages");
106 displayToPrompt(conn);
107 messagesPending(false);
112 * Connect to Director. This does not connect to the director, dircomm does.
113 * This creates the first and possibly 2nd dircomm instance
115 void Console::connect_dir()
117 DirComm *dircomm = m_dircommHash.value(0);
119 if (!m_console->m_dir) {
120 mainWin->set_status( tr("No Director found."));
124 m_textEdit = textEdit; /* our console screen */
126 if (dircomm->connect_dir()) {
127 if (mainWin->m_connDebug)
128 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
131 mainWin->set_status(_("Connected"));
133 startTimer(); /* start message timer */
137 * A function created to separate out the population of the lists
138 * from the Console::connect_dir function
140 void Console::populateLists(bool /*forcenew*/)
143 if (!availableDirComm(conn) && !newDirComm(conn)) {
144 Emsg1(M_ABORT, 0, "Failed to connect to %s for populateLists.\n", m_dir->name());
150 void Console::populateLists(int conn)
154 fileset_list.clear();
155 messages_list.clear();
157 storage_list.clear();
160 volstatus_list.clear();
161 mediatype_list.clear();
162 dir_cmd(conn, ".jobs", job_list);
163 dir_cmd(conn, ".clients", client_list);
164 dir_cmd(conn, ".filesets", fileset_list);
165 dir_cmd(conn, ".msgs", messages_list);
166 dir_cmd(conn, ".pools", pool_list);
167 dir_cmd(conn, ".storage", storage_list);
168 dir_cmd(conn, ".types", type_list);
169 dir_cmd(conn, ".levels", level_list);
170 dir_cmd(conn, ".volstatus", volstatus_list);
171 dir_cmd(conn, ".mediatypes", mediatype_list);
172 dir_cmd(conn, ".locations", location_list);
174 if (mainWin->m_connDebug) {
175 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
176 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
177 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
178 .arg(conn).arg(m_dir->name());
179 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
184 messages_list.sort();
192 * Overload function for dir_cmd with a QString
195 bool Console::dir_cmd(QString &cmd, QStringList &results)
197 return dir_cmd(cmd.toUtf8().data(), results);
201 * Overload function for dir_cmd, this is if connection is not worried about
203 bool Console::dir_cmd(const char *cmd, QStringList &results)
206 if (availableDirComm(conn)) {
207 dir_cmd(conn, cmd, results);
210 Pmsg1(000, "dir_cmd failed to connect to %s\n", m_dir->name());
216 * Send a command to the Director, and return the
217 * results in a QStringList.
219 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
221 mainWin->waitEnter();
222 DirComm *dircomm = m_dircommHash.value(conn);
225 if (mainWin->m_connDebug) {
226 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
227 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
231 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
232 if (mainWin->m_displayAll) display_text(dircomm->msg());
233 strip_trailing_junk(dircomm->msg());
234 results << dircomm->msg();
236 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
238 discardToPrompt(conn);
240 return true; /* ***FIXME*** return any command error */
244 * OverLoads for sql_cmd
246 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
248 return sql_cmd(conn, query.toUtf8().data(), results, false);
251 bool Console::sql_cmd(QString &query, QStringList &results)
254 if (!availableDirComm(conn))
256 return sql_cmd(conn, query.toUtf8().data(), results, true);
259 bool Console::sql_cmd(const char *query, QStringList &results)
262 if (!availableDirComm(conn))
264 return sql_cmd(conn, query, results, true);
268 * Send an sql query to the Director, and return the
269 * results in a QStringList.
271 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
273 DirComm *dircomm = m_dircommHash.value(conn);
275 POOL_MEM cmd(PM_MESSAGE);
277 if (!is_connectedGui()) {
281 if (mainWin->m_connDebug)
282 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
284 dircomm->notify(false);
285 mainWin->waitEnter();
287 pm_strcpy(cmd, ".sql query=\"");
288 pm_strcat(cmd, query);
289 pm_strcat(cmd, "\"");
290 dircomm->write(cmd.c_str());
291 while ((stat = dircomm->read()) > 0) {
293 if (mainWin->m_displayAll) {
294 display_text(dircomm->msg());
297 strip_trailing_junk(dircomm->msg());
298 bool doappend = true;
300 QString dum = dircomm->msg();
301 if ((dum.left(6) == "*None*")) doappend = false;
304 results << dircomm->msg();
308 dircomm->notify(true);
309 discardToPrompt(conn);
311 return true; /* ***FIXME*** return any command error */
316 * Sending a command to the Director
318 int Console::write_dir(const char *msg)
321 if (availableDirComm(conn))
322 write_dir(conn, msg);
326 int Console::write_dir(const char *msg, bool dowait)
329 if (availableDirComm(conn))
330 write_dir(conn, msg, dowait);
334 void Console::write_dir(int conn, const char *msg)
336 write_dir(conn, msg, true);
340 * Send a command to the Director
342 void Console::write_dir(int conn, const char *msg, bool dowait)
344 DirComm *dircomm = m_dircommHash.value(conn);
346 if (dircomm->m_sock) {
347 mainWin->set_status(_("Processing command ..."));
349 mainWin->waitEnter();
354 mainWin->set_status( tr(" Director not connected. Click on connect button."));
355 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
356 QBrush redBrush(Qt::red);
357 QTreeWidgetItem *item = mainWin->getFromHash(this);
358 item->setForeground(0, redBrush);
359 dircomm->m_at_prompt = false;
360 dircomm->m_at_main_prompt = false;
365 * get_job_defaults overload
367 bool Console::get_job_defaults(struct job_defaults &job_defs)
370 return get_job_defaults(conn, job_defs, true);
373 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
375 return get_job_defaults(conn, job_defs, false);
379 * Send a job name to the director, and read all the resulting
382 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
390 beginNewCommand(conn);
391 DirComm *dircomm = m_dircommHash.value(conn);
392 bool prevWaitState = mainWin->getWaitState();
394 mainWin->waitEnter();
395 if (mainWin->m_connDebug)
396 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
397 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
398 dircomm->write(scmd);
399 while ((stat = dircomm->read()) > 0) {
400 if (mainWin->m_displayAll) display_text(dircomm->msg());
401 def = strchr(dircomm->msg(), '=');
405 /* Pointer to default value */
407 strip_trailing_junk(def);
409 if (strcmp(dircomm->msg(), "job") == 0) {
410 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
415 if (strcmp(dircomm->msg(), "pool") == 0) {
416 job_defs.pool_name = def;
419 if (strcmp(dircomm->msg(), "messages") == 0) {
420 job_defs.messages_name = def;
423 if (strcmp(dircomm->msg(), "client") == 0) {
424 job_defs.client_name = def;
427 if (strcmp(dircomm->msg(), "storage") == 0) {
428 job_defs.store_name = def;
431 if (strcmp(dircomm->msg(), "where") == 0) {
432 job_defs.where = def;
435 if (strcmp(dircomm->msg(), "level") == 0) {
436 job_defs.level = def;
439 if (strcmp(dircomm->msg(), "type") == 0) {
443 if (strcmp(dircomm->msg(), "fileset") == 0) {
444 job_defs.fileset_name = def;
447 if (strcmp(dircomm->msg(), "catalog") == 0) {
448 job_defs.catalog_name = def;
451 if (strcmp(dircomm->msg(), "enabled") == 0) {
452 job_defs.enabled = *def == '1' ? true : false;
473 * Save user settings associated with this console
475 void Console::writeSettings()
477 QFont font = get_font();
479 QSettings settings(m_dir->name(), "bat");
480 settings.beginGroup("Console");
481 settings.setValue("consoleFont", font.family());
482 settings.setValue("consolePointSize", font.pointSize());
483 settings.setValue("consoleFixedPitch", font.fixedPitch());
488 * Read and restore user settings associated with this console
490 void Console::readSettings()
492 QFont font = get_font();
494 QSettings settings(m_dir->name(), "bat");
495 settings.beginGroup("Console");
496 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
497 font.setPointSize(settings.value("consolePointSize", 10).toInt());
498 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
500 m_textEdit->setFont(font);
504 * Set the console textEdit font
506 void Console::set_font()
509 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
511 m_textEdit->setFont(font);
516 * Get the console text edit font
518 const QFont Console::get_font()
520 return m_textEdit->font();
524 * Slot for responding to status dir button on button bar
526 void Console::status_dir()
528 QString cmd("status dir");
533 * Slot for responding to messages button on button bar
534 * Here we want to bring the console to the front so use pages' consoleCommand
536 void Console::messages()
538 QString cmd(".messages");
540 messagesPending(false);
544 * Put text into the console window
546 void Console::display_textf(const char *fmt, ...)
551 va_start(arg_ptr, fmt);
552 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
557 void Console::display_text(const QString buf)
559 m_cursor->insertText(buf);
564 void Console::display_text(const char *buf)
566 m_cursor->insertText(buf);
570 void Console::display_html(const QString buf)
572 m_cursor->insertHtml(buf);
576 /* Position cursor to end of screen */
577 void Console::update_cursor()
579 m_textEdit->moveCursor(QTextCursor::End);
580 m_textEdit->ensureCursorVisible();
583 void Console::beginNewCommand(int conn)
585 DirComm *dircomm = m_dircommHash.value(conn);
587 for (int i=0; i < 3; i++) {
589 while (dircomm->read() > 0) {
590 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
591 if (mainWin->m_displayAll) display_text(dircomm->msg());
593 if (dircomm->m_at_main_prompt) {
600 void Console::displayToPrompt(int conn)
602 DirComm *dircomm = m_dircommHash.value(conn);
606 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
607 while (!dircomm->m_at_prompt) {
608 if ((stat=dircomm->read()) > 0) {
609 buf += dircomm->msg();
610 if (buf.size() >= 8196 || m_messages_pending) {
613 messagesPending(false);
618 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
621 void Console::discardToPrompt(int conn)
623 DirComm *dircomm = m_dircommHash.value(conn);
626 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
627 if (mainWin->m_displayAll) {
628 displayToPrompt(conn);
630 while (!dircomm->m_at_prompt) {
631 stat = dircomm->read();
637 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
640 QString Console::returnFromPrompt(int conn)
642 DirComm *dircomm = m_dircommHash.value(conn);
647 if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
648 while (!dircomm->m_at_prompt) {
649 if ((stat=dircomm->read()) > 0) {
650 text += dircomm->msg();
653 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
658 * When the notifier is enabled, read_dir() will automatically be
659 * called by the Qt event loop when ever there is any output
660 * from the Director, and read_dir() will then display it on
663 * When we are in a bat dialog, we want to control *all* output
664 * from the Director, so we set notify to off.
665 * m_console->notifiy(false);
668 /* dual purpose function to turn notify off and return an available connection */
669 int Console::notifyOff()
672 if (availableDirComm(conn))
677 /* knowing a connection, turn notify off or on */
678 bool Console::notify(int conn, bool enable)
680 DirComm *dircomm = m_dircommHash.value(conn);
681 return dircomm->notify(enable);
684 /* knowing a connection, return notify state */
685 bool Console::is_notify_enabled(int conn) const
687 DirComm *dircomm = m_dircommHash.value(conn);
688 return dircomm->is_notify_enabled();
691 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
693 m_directorTreeItem = item;
696 void Console::setDirRes(DIRRES *dir)
702 * To have the ability to get the name of the director resource.
704 void Console::getDirResName(QString &name_returned)
706 name_returned = m_dir->name();
709 /* Slot for responding to page selectors status help command */
710 void Console::consoleHelp()
716 /* Slot for responding to page selectors reload bacula-dir.conf */
717 void Console::consoleReload()
719 QString cmd("reload");
723 /* For suppressing .messages
724 * This may be rendered not needed if the multiple connections feature gets working */
725 bool Console::hasFocus()
727 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
733 /* For adding feature to have the gui's messages button change when
734 * messages are pending */
735 bool Console::messagesPending(bool pend)
737 bool prev = m_messages_pending;
738 m_messages_pending = pend;
739 mainWin->setMessageIcon();
743 /* terminate all existing connections */
744 void Console::terminate()
746 foreach(DirComm* dircomm, m_dircommHash) {
747 dircomm->terminate();
749 m_console->stopTimer();
752 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
753 bool Console::is_connectedGui()
755 if (is_connected(0)) {
758 QString message = tr("Director is currently disconnected\nPlease reconnect!");
759 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
764 int Console::read(int conn)
766 DirComm *dircomm = m_dircommHash.value(conn);
767 return dircomm->read();
770 char *Console::msg(int conn)
772 DirComm *dircomm = m_dircommHash.value(conn);
773 return dircomm->msg();
776 int Console::write(int conn, const QString msg)
778 DirComm *dircomm = m_dircommHash.value(conn);
779 mainWin->waitEnter();
780 int ret = dircomm->write(msg);
785 int Console::write(int conn, const char *msg)
787 DirComm *dircomm = m_dircommHash.value(conn);
788 mainWin->waitEnter();
789 int ret = dircomm->write(msg);
794 /* This checks to see if any is connected */
795 bool Console::is_connected()
797 bool connected = false;
798 foreach(DirComm* dircomm, m_dircommHash) {
799 if (dircomm->is_connected())
805 /* knowing the connection id, is it connected */
806 bool Console::is_connected(int conn)
808 DirComm *dircomm = m_dircommHash.value(conn);
809 return dircomm->is_connected();
813 * Need an available connection. Check existing connections or create one
815 bool Console::availableDirComm(int &conn)
817 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
818 while (iter != m_dircommHash.constEnd()) {
819 DirComm *dircomm = iter.value();
820 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
821 conn = dircomm->m_conn;
826 if (newDirComm(conn))
834 * Need current connection.
836 bool Console::currentDirComm(int &conn)
838 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
839 while (iter != m_dircommHash.constEnd()) {
840 DirComm *dircomm = iter.value();
841 if (dircomm->m_at_prompt && !dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
842 conn = dircomm->m_conn;
851 * Create a new connection
853 bool Console::newDirComm(int &conn)
855 m_dircommCounter += 1;
856 conn = m_dircommCounter;
857 if (mainWin->m_connDebug)
858 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
859 DirComm *dircomm = new DirComm(this, m_dircommCounter);
860 m_dircommHash.insert(m_dircommCounter, dircomm);
861 bool success = dircomm->connect_dir();
862 if (mainWin->m_connDebug) {
864 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
866 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());