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)) {
102 DirComm *dircomm = m_dircommHash.value(conn);
104 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){
105 messagesPending(true);
106 dircomm->write(".messages");
107 displayToPrompt(conn);
108 messagesPending(false);
113 * Connect to Director. This does not connect to the director, dircomm does.
114 * This creates the first and possibly 2nd dircomm instance
116 void Console::connect_dir()
118 DirComm *dircomm = m_dircommHash.value(0);
120 if (!m_console->m_dir) {
121 mainWin->set_status( tr("No Director found."));
125 m_textEdit = textEdit; /* our console screen */
127 if (dircomm->connect_dir()) {
128 if (mainWin->m_connDebug)
129 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
132 mainWin->set_status(_("Connected"));
134 startTimer(); /* start message timer */
138 * A function created to separate out the population of the lists
139 * from the Console::connect_dir function
141 void Console::populateLists(bool /*forcenew*/)
144 if (!availableDirComm(conn) && !newDirComm(conn)) {
145 Emsg1(M_ABORT, 0, "Failed to connect to %s for populateLists.\n", m_dir->name());
151 void Console::populateLists(int conn)
155 fileset_list.clear();
156 messages_list.clear();
158 storage_list.clear();
161 volstatus_list.clear();
162 mediatype_list.clear();
163 dir_cmd(conn, ".jobs", job_list);
164 dir_cmd(conn, ".clients", client_list);
165 dir_cmd(conn, ".filesets", fileset_list);
166 dir_cmd(conn, ".msgs", messages_list);
167 dir_cmd(conn, ".pools", pool_list);
168 dir_cmd(conn, ".storage", storage_list);
169 dir_cmd(conn, ".types", type_list);
170 dir_cmd(conn, ".levels", level_list);
171 dir_cmd(conn, ".volstatus", volstatus_list);
172 dir_cmd(conn, ".mediatypes", mediatype_list);
173 dir_cmd(conn, ".locations", location_list);
175 if (mainWin->m_connDebug) {
176 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
177 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
178 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
179 .arg(conn).arg(m_dir->name());
180 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
185 messages_list.sort();
193 * Overload function for dir_cmd with a QString
196 bool Console::dir_cmd(QString &cmd, QStringList &results)
198 return dir_cmd(cmd.toUtf8().data(), results);
202 * Overload function for dir_cmd, this is if connection is not worried about
204 bool Console::dir_cmd(const char *cmd, QStringList &results)
207 if (availableDirComm(conn)) {
208 dir_cmd(conn, cmd, results);
211 Pmsg1(000, "dir_cmd failed to connect to %s\n", m_dir->name());
217 * Send a command to the Director, and return the
218 * results in a QStringList.
220 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
222 mainWin->waitEnter();
223 DirComm *dircomm = m_dircommHash.value(conn);
226 if (mainWin->m_connDebug) {
227 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
228 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
232 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
233 if (mainWin->m_displayAll) display_text(dircomm->msg());
234 strip_trailing_junk(dircomm->msg());
235 results << dircomm->msg();
237 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
239 discardToPrompt(conn);
241 return true; /* ***FIXME*** return any command error */
245 * OverLoads for sql_cmd
247 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
249 return sql_cmd(conn, query.toUtf8().data(), results, false);
252 bool Console::sql_cmd(QString &query, QStringList &results)
255 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)) {
267 return sql_cmd(conn, query, results, true);
271 * Send an sql query to the Director, and return the
272 * results in a QStringList.
274 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
276 DirComm *dircomm = m_dircommHash.value(conn);
278 POOL_MEM cmd(PM_MESSAGE);
280 if (!is_connectedGui()) {
284 if (mainWin->m_connDebug)
285 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
287 dircomm->notify(false);
288 mainWin->waitEnter();
290 pm_strcpy(cmd, ".sql query=\"");
291 pm_strcat(cmd, query);
292 pm_strcat(cmd, "\"");
293 dircomm->write(cmd.c_str());
294 while ((stat = dircomm->read()) > 0) {
296 if (mainWin->m_displayAll) {
297 display_text(dircomm->msg());
300 strip_trailing_junk(dircomm->msg());
301 bool doappend = true;
303 QString dum = dircomm->msg();
304 if ((dum.left(6) == "*None*")) doappend = false;
307 results << dircomm->msg();
311 dircomm->notify(true);
312 discardToPrompt(conn);
314 return true; /* ***FIXME*** return any command error */
319 * Sending a command to the Director
321 int Console::write_dir(const char *msg)
324 if (availableDirComm(conn)) {
325 write_dir(conn, msg);
330 int Console::write_dir(const char *msg, bool dowait)
333 if (availableDirComm(conn)) {
334 write_dir(conn, msg, dowait);
339 void Console::write_dir(int conn, const char *msg)
341 write_dir(conn, msg, true);
345 * Send a command to the Director
347 void Console::write_dir(int conn, const char *msg, bool dowait)
349 DirComm *dircomm = m_dircommHash.value(conn);
351 if (dircomm->m_sock) {
352 mainWin->set_status(_("Processing command ..."));
354 mainWin->waitEnter();
359 mainWin->set_status( tr(" Director not connected. Click on connect button."));
360 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
361 QBrush redBrush(Qt::red);
362 QTreeWidgetItem *item = mainWin->getFromHash(this);
363 item->setForeground(0, redBrush);
364 dircomm->m_at_prompt = false;
365 dircomm->m_at_main_prompt = false;
370 * get_job_defaults overload
372 bool Console::get_job_defaults(struct job_defaults &job_defs)
375 return get_job_defaults(conn, job_defs, true);
378 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
380 return get_job_defaults(conn, job_defs, false);
384 * Send a job name to the director, and read all the resulting
387 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
395 beginNewCommand(conn);
396 DirComm *dircomm = m_dircommHash.value(conn);
397 bool prevWaitState = mainWin->getWaitState();
399 mainWin->waitEnter();
400 if (mainWin->m_connDebug)
401 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
402 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
403 dircomm->write(scmd);
404 while ((stat = dircomm->read()) > 0) {
405 if (mainWin->m_displayAll) display_text(dircomm->msg());
406 def = strchr(dircomm->msg(), '=');
410 /* Pointer to default value */
412 strip_trailing_junk(def);
414 if (strcmp(dircomm->msg(), "job") == 0) {
415 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
420 if (strcmp(dircomm->msg(), "pool") == 0) {
421 job_defs.pool_name = def;
424 if (strcmp(dircomm->msg(), "messages") == 0) {
425 job_defs.messages_name = def;
428 if (strcmp(dircomm->msg(), "client") == 0) {
429 job_defs.client_name = def;
432 if (strcmp(dircomm->msg(), "storage") == 0) {
433 job_defs.store_name = def;
436 if (strcmp(dircomm->msg(), "where") == 0) {
437 job_defs.where = def;
440 if (strcmp(dircomm->msg(), "level") == 0) {
441 job_defs.level = def;
444 if (strcmp(dircomm->msg(), "type") == 0) {
448 if (strcmp(dircomm->msg(), "fileset") == 0) {
449 job_defs.fileset_name = def;
452 if (strcmp(dircomm->msg(), "catalog") == 0) {
453 job_defs.catalog_name = def;
456 if (strcmp(dircomm->msg(), "enabled") == 0) {
457 job_defs.enabled = *def == '1' ? true : false;
478 * Save user settings associated with this console
480 void Console::writeSettings()
482 QFont font = get_font();
484 QSettings settings(m_dir->name(), "bat");
485 settings.beginGroup("Console");
486 settings.setValue("consoleFont", font.family());
487 settings.setValue("consolePointSize", font.pointSize());
488 settings.setValue("consoleFixedPitch", font.fixedPitch());
493 * Read and restore user settings associated with this console
495 void Console::readSettings()
497 QFont font = get_font();
499 QSettings settings(m_dir->name(), "bat");
500 settings.beginGroup("Console");
501 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
502 font.setPointSize(settings.value("consolePointSize", 10).toInt());
503 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
505 m_textEdit->setFont(font);
509 * Set the console textEdit font
511 void Console::set_font()
514 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
516 m_textEdit->setFont(font);
521 * Get the console text edit font
523 const QFont Console::get_font()
525 return m_textEdit->font();
529 * Slot for responding to status dir button on button bar
531 void Console::status_dir()
533 QString cmd("status dir");
538 * Slot for responding to messages button on button bar
539 * Here we want to bring the console to the front so use pages' consoleCommand
541 void Console::messages()
543 QString cmd(".messages");
545 messagesPending(false);
549 * Put text into the console window
551 void Console::display_textf(const char *fmt, ...)
556 va_start(arg_ptr, fmt);
557 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
562 void Console::display_text(const QString buf)
564 m_cursor->insertText(buf);
569 void Console::display_text(const char *buf)
571 m_cursor->insertText(buf);
575 void Console::display_html(const QString buf)
577 m_cursor->insertHtml(buf);
581 /* Position cursor to end of screen */
582 void Console::update_cursor()
584 m_textEdit->moveCursor(QTextCursor::End);
585 m_textEdit->ensureCursorVisible();
588 void Console::beginNewCommand(int conn)
590 DirComm *dircomm = m_dircommHash.value(conn);
592 for (int i=0; i < 3; i++) {
594 while (dircomm->read() > 0) {
595 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
596 if (mainWin->m_displayAll) display_text(dircomm->msg());
598 if (dircomm->m_at_main_prompt) {
605 void Console::displayToPrompt(int conn)
607 DirComm *dircomm = m_dircommHash.value(conn);
611 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
612 while (!dircomm->m_at_prompt) {
613 if ((stat=dircomm->read()) > 0) {
614 buf += dircomm->msg();
615 if (buf.size() >= 8196 || m_messages_pending) {
618 messagesPending(false);
623 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
626 void Console::discardToPrompt(int conn)
628 DirComm *dircomm = m_dircommHash.value(conn);
631 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
632 if (mainWin->m_displayAll) {
633 displayToPrompt(conn);
635 while (!dircomm->m_at_prompt) {
636 stat = dircomm->read();
642 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
645 QString Console::returnFromPrompt(int conn)
647 DirComm *dircomm = m_dircommHash.value(conn);
652 if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
653 while (!dircomm->m_at_prompt) {
654 if ((stat=dircomm->read()) > 0) {
655 text += dircomm->msg();
658 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
663 * When the notifier is enabled, read_dir() will automatically be
664 * called by the Qt event loop when ever there is any output
665 * from the Director, and read_dir() will then display it on
668 * When we are in a bat dialog, we want to control *all* output
669 * from the Director, so we set notify to off.
670 * m_console->notifiy(false);
673 /* dual purpose function to turn notify off and return an available connection */
674 int Console::notifyOff()
677 if (availableDirComm(conn)) {
683 /* knowing a connection, turn notify off or on */
684 bool Console::notify(int conn, bool enable)
686 DirComm *dircomm = m_dircommHash.value(conn);
687 return dircomm->notify(enable);
690 /* knowing a connection, return notify state */
691 bool Console::is_notify_enabled(int conn) const
693 DirComm *dircomm = m_dircommHash.value(conn);
694 return dircomm->is_notify_enabled();
697 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
699 m_directorTreeItem = item;
702 void Console::setDirRes(DIRRES *dir)
708 * To have the ability to get the name of the director resource.
710 void Console::getDirResName(QString &name_returned)
712 name_returned = m_dir->name();
715 /* Slot for responding to page selectors status help command */
716 void Console::consoleHelp()
722 /* Slot for responding to page selectors reload bacula-dir.conf */
723 void Console::consoleReload()
725 QString cmd("reload");
729 /* For suppressing .messages
730 * This may be rendered not needed if the multiple connections feature gets working */
731 bool Console::hasFocus()
733 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
739 /* For adding feature to have the gui's messages button change when
740 * messages are pending */
741 bool Console::messagesPending(bool pend)
743 bool prev = m_messages_pending;
744 m_messages_pending = pend;
745 mainWin->setMessageIcon();
749 /* terminate all existing connections */
750 void Console::terminate()
752 foreach(DirComm* dircomm, m_dircommHash) {
753 dircomm->terminate();
755 m_console->stopTimer();
758 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
759 bool Console::is_connectedGui()
761 if (is_connected(0)) {
764 QString message = tr("Director is currently disconnected\nPlease reconnect!");
765 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
770 int Console::read(int conn)
772 DirComm *dircomm = m_dircommHash.value(conn);
773 return dircomm->read();
776 char *Console::msg(int conn)
778 DirComm *dircomm = m_dircommHash.value(conn);
779 return dircomm->msg();
782 int Console::write(int conn, const QString msg)
784 DirComm *dircomm = m_dircommHash.value(conn);
785 mainWin->waitEnter();
786 int ret = dircomm->write(msg);
791 int Console::write(int conn, const char *msg)
793 DirComm *dircomm = m_dircommHash.value(conn);
794 mainWin->waitEnter();
795 int ret = dircomm->write(msg);
800 /* This checks to see if any is connected */
801 bool Console::is_connected()
803 bool connected = false;
804 foreach(DirComm* dircomm, m_dircommHash) {
805 if (dircomm->is_connected())
811 /* knowing the connection id, is it connected */
812 bool Console::is_connected(int conn)
814 DirComm *dircomm = m_dircommHash.value(conn);
815 return dircomm->is_connected();
819 * Need an available connection. Check existing connections or create one
821 bool Console::availableDirComm(int &conn)
823 if (currentDirComm(conn)) {
826 return newDirComm(conn);
831 * Need current connection.
833 bool Console::currentDirComm(int &conn)
836 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
837 while (iter != m_dircommHash.constEnd()) {
838 DirComm *dircomm = iter.value();
839 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
840 conn = dircomm->m_conn;
843 if (mainWin->m_connDebug) {
844 Pmsg4(000, "currentDirComm=%d at_prompt=%d at_main=%d && notify=%d\n",
845 i, dircomm->m_at_prompt, dircomm->m_at_main_prompt, dircomm->is_notify_enabled());
854 * Create a new connection
856 bool Console::newDirComm(int &conn)
859 if (mainWin->m_connDebug) {
860 Pmsg2(000, "newDirComm=%i to: %s\n", m_dircommCounter, m_dir->name());
862 DirComm *dircomm = new DirComm(this, m_dircommCounter);
863 m_dircommHash.insert(m_dircommCounter, dircomm);
864 bool success = dircomm->connect_dir();
865 if (mainWin->m_connDebug) {
867 Pmsg2(000, "newDirComm=%i Connected %s\n", m_dircommCounter, m_dir->name());
869 Emsg2(M_ERROR, 0, "DirComm=%i. Unable to connect to %s\n",
870 m_dircommCounter, m_dir->name());
874 m_dircommHash.remove(m_dircommCounter);
878 conn = m_dircommCounter;