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 dir_cmd(conn, ".jobs", job_list);
170 dir_cmd(conn, ".clients", client_list);
171 dir_cmd(conn, ".filesets", fileset_list);
172 dir_cmd(conn, ".msgs", messages_list);
173 dir_cmd(conn, ".pools", pool_list);
174 dir_cmd(conn, ".storage", storage_list);
175 dir_cmd(conn, ".types", type_list);
176 dir_cmd(conn, ".levels", level_list);
178 if (mainWin->m_connDebug) {
179 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
180 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
181 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
182 .arg(conn).arg(m_dir->name());
183 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
188 messages_list.sort();
196 * Overload function for dir_cmd with a QString
199 bool Console::dir_cmd(QString &cmd, QStringList &results)
201 return dir_cmd(cmd.toUtf8().data(), results);
205 * Overload function for dir_cmd, this is if connection is not worried about
207 bool Console::dir_cmd(const char *cmd, QStringList &results)
210 if (availableDirComm(conn)) {
211 dir_cmd(conn, cmd, results);
214 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
220 * Send a command to the Director, and return the
221 * results in a QStringList.
223 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
225 mainWin->waitEnter();
226 DirComm *dircomm = m_dircommHash.value(conn);
229 if (mainWin->m_connDebug) {
230 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
231 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
235 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
236 if (mainWin->m_displayAll) display_text(dircomm->msg());
237 strip_trailing_junk(dircomm->msg());
238 results << dircomm->msg();
240 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
242 discardToPrompt(conn);
244 return true; /* ***FIXME*** return any command error */
248 * OverLoads for sql_cmd
250 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
252 return sql_cmd(conn, query.toUtf8().data(), results, false);
255 bool Console::sql_cmd(QString &query, QStringList &results)
258 if (!availableDirComm(conn))
260 return sql_cmd(conn, query.toUtf8().data(), results, true);
263 bool Console::sql_cmd(const char *query, QStringList &results)
266 if (!availableDirComm(conn))
268 return sql_cmd(conn, query, results, true);
272 * Send an sql query to the Director, and return the
273 * results in a QStringList.
275 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
277 DirComm *dircomm = m_dircommHash.value(conn);
279 POOL_MEM cmd(PM_MESSAGE);
281 if (!is_connectedGui()) {
285 if (mainWin->m_connDebug)
286 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
288 dircomm->notify(false);
289 mainWin->waitEnter();
291 pm_strcpy(cmd, ".sql query=\"");
292 pm_strcat(cmd, query);
293 pm_strcat(cmd, "\"");
294 dircomm->write(cmd.c_str());
295 while ((stat = dircomm->read()) > 0) {
297 if (mainWin->m_displayAll) {
298 display_text(dircomm->msg());
301 strip_trailing_junk(dircomm->msg());
302 bool doappend = true;
304 QString dum = dircomm->msg();
305 if ((dum.left(6) == "*None*")) doappend = false;
308 results << dircomm->msg();
312 dircomm->notify(true);
313 discardToPrompt(conn);
315 return true; /* ***FIXME*** return any command error */
320 * Sending a command to the Director
322 int Console::write_dir(const char *msg)
325 if (availableDirComm(conn))
326 write_dir(conn, msg);
330 int Console::write_dir(const char *msg, bool dowait)
333 if (availableDirComm(conn))
334 write_dir(conn, msg, dowait);
338 void Console::write_dir(int conn, const char *msg)
340 write_dir(conn, msg, true);
344 * Send a command to the Director
346 void Console::write_dir(int conn, const char *msg, bool dowait)
348 DirComm *dircomm = m_dircommHash.value(conn);
350 if (dircomm->m_sock) {
351 mainWin->set_status(_("Processing command ..."));
353 mainWin->waitEnter();
358 mainWin->set_status( tr(" Director not connected. Click on connect button."));
359 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
360 QBrush redBrush(Qt::red);
361 QTreeWidgetItem *item = mainWin->getFromHash(this);
362 item->setForeground(0, redBrush);
363 dircomm->m_at_prompt = false;
364 dircomm->m_at_main_prompt = false;
369 * get_job_defaults overload
371 bool Console::get_job_defaults(struct job_defaults &job_defs)
374 return get_job_defaults(conn, job_defs, true);
377 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
379 return get_job_defaults(conn, job_defs, false);
383 * Send a job name to the director, and read all the resulting
386 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
394 beginNewCommand(conn);
395 DirComm *dircomm = m_dircommHash.value(conn);
396 bool prevWaitState = mainWin->getWaitState();
398 mainWin->waitEnter();
399 if (mainWin->m_connDebug)
400 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
401 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
402 dircomm->write(scmd);
403 while ((stat = dircomm->read()) > 0) {
404 if (mainWin->m_displayAll) display_text(dircomm->msg());
405 def = strchr(dircomm->msg(), '=');
409 /* Pointer to default value */
411 strip_trailing_junk(def);
413 if (strcmp(dircomm->msg(), "job") == 0) {
414 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
419 if (strcmp(dircomm->msg(), "pool") == 0) {
420 job_defs.pool_name = def;
423 if (strcmp(dircomm->msg(), "messages") == 0) {
424 job_defs.messages_name = def;
427 if (strcmp(dircomm->msg(), "client") == 0) {
428 job_defs.client_name = def;
431 if (strcmp(dircomm->msg(), "storage") == 0) {
432 job_defs.store_name = def;
435 if (strcmp(dircomm->msg(), "where") == 0) {
436 job_defs.where = def;
439 if (strcmp(dircomm->msg(), "level") == 0) {
440 job_defs.level = def;
443 if (strcmp(dircomm->msg(), "type") == 0) {
447 if (strcmp(dircomm->msg(), "fileset") == 0) {
448 job_defs.fileset_name = def;
451 if (strcmp(dircomm->msg(), "catalog") == 0) {
452 job_defs.catalog_name = def;
455 if (strcmp(dircomm->msg(), "enabled") == 0) {
456 job_defs.enabled = *def == '1' ? true : false;
477 * Save user settings associated with this console
479 void Console::writeSettings()
481 QFont font = get_font();
483 QSettings settings(m_dir->name(), "bat");
484 settings.beginGroup("Console");
485 settings.setValue("consoleFont", font.family());
486 settings.setValue("consolePointSize", font.pointSize());
487 settings.setValue("consoleFixedPitch", font.fixedPitch());
492 * Read and restore user settings associated with this console
494 void Console::readSettings()
496 QFont font = get_font();
498 QSettings settings(m_dir->name(), "bat");
499 settings.beginGroup("Console");
500 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
501 font.setPointSize(settings.value("consolePointSize", 10).toInt());
502 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
504 m_textEdit->setFont(font);
508 * Set the console textEdit font
510 void Console::set_font()
513 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
515 m_textEdit->setFont(font);
520 * Get the console text edit font
522 const QFont Console::get_font()
524 return m_textEdit->font();
528 * Slot for responding to status dir button on button bar
530 void Console::status_dir()
532 QString cmd("status dir");
537 * Slot for responding to messages button on button bar
538 * Here we want to bring the console to the front so use pages' consoleCommand
540 void Console::messages()
542 QString cmd(".messages");
544 messagesPending(false);
548 * Put text into the console window
550 void Console::display_textf(const char *fmt, ...)
555 va_start(arg_ptr, fmt);
556 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
561 void Console::display_text(const QString buf)
563 m_cursor->insertText(buf);
568 void Console::display_text(const char *buf)
570 m_cursor->insertText(buf);
574 void Console::display_html(const QString buf)
576 m_cursor->insertHtml(buf);
580 /* Position cursor to end of screen */
581 void Console::update_cursor()
583 m_textEdit->moveCursor(QTextCursor::End);
584 m_textEdit->ensureCursorVisible();
587 void Console::beginNewCommand(int conn)
589 DirComm *dircomm = m_dircommHash.value(conn);
591 for (int i=0; i < 3; i++) {
593 while (dircomm->read() > 0) {
594 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
595 if (mainWin->m_displayAll) display_text(dircomm->msg());
597 if (dircomm->m_at_main_prompt) {
604 void Console::displayToPrompt(int conn)
606 DirComm *dircomm = m_dircommHash.value(conn);
610 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
611 while (!dircomm->m_at_prompt) {
612 if ((stat=dircomm->read()) > 0) {
613 buf += dircomm->msg();
614 if (buf.size() >= 8196 || m_messages_pending) {
617 messagesPending(false);
622 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
625 void Console::discardToPrompt(int conn)
627 DirComm *dircomm = m_dircommHash.value(conn);
630 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
631 if (mainWin->m_displayAll) {
632 displayToPrompt(conn);
634 while (!dircomm->m_at_prompt) {
635 stat = dircomm->read();
641 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
644 QString Console::returnFromPrompt(int conn)
646 DirComm *dircomm = m_dircommHash.value(conn);
651 if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name());
652 while (!dircomm->m_at_prompt) {
653 if ((stat=dircomm->read()) > 0) {
654 text += dircomm->msg();
657 if (mainWin->m_commDebug) Pmsg2(000, "endreturnFromPrompt=%d %s\n", stat, m_dir->name());
662 * When the notifier is enabled, read_dir() will automatically be
663 * called by the Qt event loop when ever there is any output
664 * from the Director, and read_dir() will then display it on
667 * When we are in a bat dialog, we want to control *all* output
668 * from the Director, so we set notify to off.
669 * m_console->notifiy(false);
672 /* dual purpose function to turn notify off and return an available connection */
673 int Console::notifyOff()
676 if (availableDirComm(conn))
681 /* knowing a connection, turn notify off or on */
682 bool Console::notify(int conn, bool enable)
684 DirComm *dircomm = m_dircommHash.value(conn);
685 return dircomm->notify(enable);
688 /* knowing a connection, return notify state */
689 bool Console::is_notify_enabled(int conn) const
691 DirComm *dircomm = m_dircommHash.value(conn);
692 return dircomm->is_notify_enabled();
695 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
697 m_directorTreeItem = item;
700 void Console::setDirRes(DIRRES *dir)
706 * To have the ability to get the name of the director resource.
708 void Console::getDirResName(QString &name_returned)
710 name_returned = m_dir->name();
713 /* Slot for responding to page selectors status help command */
714 void Console::consoleHelp()
720 /* Slot for responding to page selectors reload bacula-dir.conf */
721 void Console::consoleReload()
723 QString cmd("reload");
727 /* For suppressing .messages
728 * This may be rendered not needed if the multiple connections feature gets working */
729 bool Console::hasFocus()
731 if (mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this))
737 /* For adding feature to have the gui's messages button change when
738 * messages are pending */
739 bool Console::messagesPending(bool pend)
741 bool prev = m_messages_pending;
742 m_messages_pending = pend;
743 mainWin->setMessageIcon();
747 /* terminate all existing connections */
748 void Console::terminate()
750 foreach(DirComm* dircomm, m_dircommHash) {
751 dircomm->terminate();
753 m_console->stopTimer();
756 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
757 bool Console::is_connectedGui()
759 if (is_connected(0)) {
762 QString message = tr("Director is currently disconnected\nPlease reconnect!");
763 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
768 int Console::read(int conn)
770 DirComm *dircomm = m_dircommHash.value(conn);
771 return dircomm->read();
774 char *Console::msg(int conn)
776 DirComm *dircomm = m_dircommHash.value(conn);
777 return dircomm->msg();
780 int Console::write(int conn, const QString msg)
782 DirComm *dircomm = m_dircommHash.value(conn);
783 mainWin->waitEnter();
784 int ret = dircomm->write(msg);
789 int Console::write(int conn, const char *msg)
791 DirComm *dircomm = m_dircommHash.value(conn);
792 mainWin->waitEnter();
793 int ret = dircomm->write(msg);
798 /* This checks to see if any is connected */
799 bool Console::is_connected()
801 bool connected = false;
802 foreach(DirComm* dircomm, m_dircommHash) {
803 if (dircomm->is_connected())
809 /* knowing the connection id, is it connected */
810 bool Console::is_connected(int conn)
812 DirComm *dircomm = m_dircommHash.value(conn);
813 return dircomm->is_connected();
817 * Need an available connection. Check existing connections or create one
819 bool Console::availableDirComm(int &conn)
821 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
822 while (iter != m_dircommHash.constEnd()) {
823 DirComm *dircomm = iter.value();
824 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
825 conn = dircomm->m_conn;
830 if (newDirComm(conn))
838 * Need current connection.
840 bool Console::currentDirComm(int &conn)
842 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
843 while (iter != m_dircommHash.constEnd()) {
844 DirComm *dircomm = iter.value();
845 if (dircomm->m_at_prompt && !dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
846 conn = dircomm->m_conn;
855 * Create a new connection
857 bool Console::newDirComm(int &conn)
859 m_dircommCounter += 1;
860 conn = m_dircommCounter;
861 if (mainWin->m_connDebug)
862 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
863 DirComm *dircomm = new DirComm(this, m_dircommCounter);
864 m_dircommHash.insert(m_dircommCounter, dircomm);
865 bool success = dircomm->connect_dir();
866 if (mainWin->m_connDebug) {
868 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
870 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());