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(QStackedWidget *parent)
46 m_messages_pending = false;
50 m_warningPrevent = false;
52 m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter));
55 m_textEdit = textEdit; /* our console screen */
56 m_cursor = new QTextCursor(m_textEdit->document());
57 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
60 m_contextActions.append(actionStatusDir);
61 m_contextActions.append(actionConsoleHelp);
62 m_contextActions.append(actionRequestMessages);
63 m_contextActions.append(actionConsoleReload);
64 connect(actionStatusDir, SIGNAL(triggered()), this, SLOT(status_dir()));
65 connect(actionConsoleHelp, SIGNAL(triggered()), this, SLOT(consoleHelp()));
66 connect(actionConsoleReload, SIGNAL(triggered()), this, SLOT(consoleReload()));
67 connect(actionRequestMessages, SIGNAL(triggered()), this, SLOT(messages()));
74 void Console::startTimer()
76 m_timer = new QTimer(this);
77 QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
78 m_timer->start(mainWin->m_checkMessagesInterval*1000);
81 void Console::stopTimer()
84 QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
91 /* slot connected to the timer
92 * requires preferences of check messages and operates at interval */
93 void Console::poll_messages()
96 if (!availableDirComm(conn))
98 DirComm *dircomm = m_dircommHash.value(conn);
100 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){
101 messagesPending(true);
102 dircomm->write(".messages");
103 displayToPrompt(conn);
104 messagesPending(false);
109 * Connect to Director. This does not connect to the director, dircomm does.
110 * This creates the first and possibly 2nd dircomm instance
112 void Console::connect_dir()
114 DirComm *dircomm = m_dircommHash.value(0);
116 if (!m_console->m_dir) {
117 mainWin->set_status( tr("No Director found."));
121 m_textEdit = textEdit; /* our console screen */
123 if (dircomm->connect_dir()) {
124 if (mainWin->m_connDebug)
125 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
128 mainWin->set_status(_("Connected"));
130 startTimer(); /* start message timer */
134 * A function created to separate out the population of the lists
135 * from the Console::connect_dir function
137 void Console::populateLists(bool forcenew)
141 if (!newDirComm(conn)) {
142 Pmsg1(000, "newDirComm Seems to Failed to create a connection for populateLists %s\n", m_dir->name());
146 if(!availableDirComm(conn)) {
147 Pmsg1(000, "availableDirComm Seems to Failed to find a connection for populateListsi %s\n", m_dir->name());
154 void Console::populateLists(int conn)
158 fileset_list.clear();
159 messages_list.clear();
161 storage_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);
173 if (mainWin->m_connDebug) {
174 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
175 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
176 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
177 .arg(conn).arg(m_dir->name());
178 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
183 messages_list.sort();
191 * Overload function for dir_cmd with a QString
194 bool Console::dir_cmd(QString &cmd, QStringList &results)
196 return dir_cmd(cmd.toUtf8().data(), results);
200 * Overload function for dir_cmd, this is if connection is not worried about
202 bool Console::dir_cmd(const char *cmd, QStringList &results)
205 if (availableDirComm(conn)) {
206 dir_cmd(conn, cmd, results);
209 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
215 * Send a command to the Director, and return the
216 * results in a QStringList.
218 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
220 mainWin->waitEnter();
221 DirComm *dircomm = m_dircommHash.value(conn);
224 if (mainWin->m_connDebug) {
225 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
226 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
230 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
231 if (mainWin->m_displayAll) display_text(dircomm->msg());
232 strip_trailing_junk(dircomm->msg());
233 results << dircomm->msg();
235 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
237 discardToPrompt(conn);
239 return true; /* ***FIXME*** return any command error */
243 * OverLoads for sql_cmd
245 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
247 return sql_cmd(conn, query.toUtf8().data(), results, false);
250 bool Console::sql_cmd(QString &query, QStringList &results)
253 if (!availableDirComm(conn))
255 return sql_cmd(conn, query.toUtf8().data(), results, true);
258 bool Console::sql_cmd(const char *query, QStringList &results)
261 if (!availableDirComm(conn))
263 return sql_cmd(conn, query, results, true);
267 * Send an sql query to the Director, and return the
268 * results in a QStringList.
270 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
272 DirComm *dircomm = m_dircommHash.value(conn);
274 POOL_MEM cmd(PM_MESSAGE);
276 if (!is_connectedGui()) {
280 if (mainWin->m_connDebug)
281 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
283 dircomm->notify(false);
284 mainWin->waitEnter();
286 pm_strcpy(cmd, ".sql query=\"");
287 pm_strcat(cmd, query);
288 pm_strcat(cmd, "\"");
289 dircomm->write(cmd.c_str());
290 while ((stat = dircomm->read()) > 0) {
292 if (mainWin->m_displayAll) {
293 display_text(dircomm->msg());
296 strip_trailing_junk(dircomm->msg());
297 bool doappend = true;
299 QString dum = dircomm->msg();
300 if ((dum.left(6) == "*None*")) doappend = false;
303 results << dircomm->msg();
307 dircomm->notify(true);
308 discardToPrompt(conn);
310 return true; /* ***FIXME*** return any command error */
315 * Sending a command to the Director
317 int Console::write_dir(const char *msg)
320 if (availableDirComm(conn))
321 write_dir(conn, msg);
325 int Console::write_dir(const char *msg, bool dowait)
328 if (availableDirComm(conn))
329 write_dir(conn, msg, dowait);
333 void Console::write_dir(int conn, const char *msg)
335 write_dir(conn, msg, true);
339 * Send a command to the Director
341 void Console::write_dir(int conn, const char *msg, bool dowait)
343 DirComm *dircomm = m_dircommHash.value(conn);
345 if (dircomm->m_sock) {
346 mainWin->set_status(_("Processing command ..."));
348 mainWin->waitEnter();
353 mainWin->set_status( tr(" Director not connected. Click on connect button."));
354 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
355 QBrush redBrush(Qt::red);
356 QTreeWidgetItem *item = mainWin->getFromHash(this);
357 item->setForeground(0, redBrush);
358 dircomm->m_at_prompt = false;
359 dircomm->m_at_main_prompt = false;
364 * get_job_defaults overload
366 bool Console::get_job_defaults(struct job_defaults &job_defs)
369 return get_job_defaults(conn, job_defs, true);
372 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
374 return get_job_defaults(conn, job_defs, false);
378 * Send a job name to the director, and read all the resulting
381 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
389 beginNewCommand(conn);
390 DirComm *dircomm = m_dircommHash.value(conn);
391 bool prevWaitState = mainWin->getWaitState();
393 mainWin->waitEnter();
394 if (mainWin->m_connDebug)
395 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
396 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
397 dircomm->write(scmd);
398 while ((stat = dircomm->read()) > 0) {
399 if (mainWin->m_displayAll) display_text(dircomm->msg());
400 def = strchr(dircomm->msg(), '=');
404 /* Pointer to default value */
406 strip_trailing_junk(def);
408 if (strcmp(dircomm->msg(), "job") == 0) {
409 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
414 if (strcmp(dircomm->msg(), "pool") == 0) {
415 job_defs.pool_name = def;
418 if (strcmp(dircomm->msg(), "messages") == 0) {
419 job_defs.messages_name = def;
422 if (strcmp(dircomm->msg(), "client") == 0) {
423 job_defs.client_name = def;
426 if (strcmp(dircomm->msg(), "storage") == 0) {
427 job_defs.store_name = def;
430 if (strcmp(dircomm->msg(), "where") == 0) {
431 job_defs.where = def;
434 if (strcmp(dircomm->msg(), "level") == 0) {
435 job_defs.level = def;
438 if (strcmp(dircomm->msg(), "type") == 0) {
442 if (strcmp(dircomm->msg(), "fileset") == 0) {
443 job_defs.fileset_name = def;
446 if (strcmp(dircomm->msg(), "catalog") == 0) {
447 job_defs.catalog_name = def;
450 if (strcmp(dircomm->msg(), "enabled") == 0) {
451 job_defs.enabled = *def == '1' ? true : false;
472 * Save user settings associated with this console
474 void Console::writeSettings()
476 QFont font = get_font();
478 QSettings settings(m_dir->name(), "bat");
479 settings.beginGroup("Console");
480 settings.setValue("consoleFont", font.family());
481 settings.setValue("consolePointSize", font.pointSize());
482 settings.setValue("consoleFixedPitch", font.fixedPitch());
487 * Read and restore user settings associated with this console
489 void Console::readSettings()
491 QFont font = get_font();
493 QSettings settings(m_dir->name(), "bat");
494 settings.beginGroup("Console");
495 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
496 font.setPointSize(settings.value("consolePointSize", 10).toInt());
497 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
499 m_textEdit->setFont(font);
503 * Set the console textEdit font
505 void Console::set_font()
508 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
510 m_textEdit->setFont(font);
515 * Get the console text edit font
517 const QFont Console::get_font()
519 return m_textEdit->font();
523 * Slot for responding to status dir button on button bar
525 void Console::status_dir()
527 QString cmd("status dir");
532 * Slot for responding to messages button on button bar
533 * Here we want to bring the console to the front so use pages' consoleCommand
535 void Console::messages()
537 QString cmd(".messages");
539 messagesPending(false);
543 * Put text into the console window
545 void Console::display_textf(const char *fmt, ...)
550 va_start(arg_ptr, fmt);
551 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
556 void Console::display_text(const QString buf)
558 m_cursor->insertText(buf);
563 void Console::display_text(const char *buf)
565 m_cursor->insertText(buf);
569 void Console::display_html(const QString buf)
571 m_cursor->insertHtml(buf);
575 /* Position cursor to end of screen */
576 void Console::update_cursor()
578 m_textEdit->moveCursor(QTextCursor::End);
579 m_textEdit->ensureCursorVisible();
582 void Console::beginNewCommand(int conn)
584 DirComm *dircomm = m_dircommHash.value(conn);
586 for (int i=0; i < 3; i++) {
588 while (dircomm->read() > 0) {
589 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
590 if (mainWin->m_displayAll) display_text(dircomm->msg());
592 if (dircomm->m_at_main_prompt) {
599 void Console::displayToPrompt(int conn)
601 DirComm *dircomm = m_dircommHash.value(conn);
605 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
606 while (!dircomm->m_at_prompt) {
607 if ((stat=dircomm->read()) > 0) {
608 buf += dircomm->msg();
609 if (buf.size() >= 8196 || m_messages_pending) {
612 messagesPending(false);
617 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
620 void Console::discardToPrompt(int conn)
622 DirComm *dircomm = m_dircommHash.value(conn);
625 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
626 if (mainWin->m_displayAll) {
627 displayToPrompt(conn);
629 while (!dircomm->m_at_prompt) {
630 stat = dircomm->read();
636 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
640 * When the notifier is enabled, read_dir() will automatically be
641 * called by the Qt event loop when ever there is any output
642 * from the Directory, and read_dir() will then display it on
645 * When we are in a bat dialog, we want to control *all* output
646 * from the Directory, so we set notify to off.
647 * m_console->notifiy(false);
650 /* dual purpose function to turn notify off and return an available connection */
651 int Console::notifyOff()
654 if (availableDirComm(conn))
659 /* knowing a connection, turn notify off or on */
660 bool Console::notify(int conn, bool enable)
662 DirComm *dircomm = m_dircommHash.value(conn);
663 return dircomm->notify(enable);
666 /* knowing a connection, return notify state */
667 bool Console::is_notify_enabled(int conn) const
669 DirComm *dircomm = m_dircommHash.value(conn);
670 return dircomm->is_notify_enabled();
673 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
675 m_directorTreeItem = item;
678 void Console::setDirRes(DIRRES *dir)
684 * To have the ability to get the name of the director resource.
686 void Console::getDirResName(QString &name_returned)
688 name_returned = m_dir->name();
691 /* Slot for responding to page selectors status help command */
692 void Console::consoleHelp()
698 /* Slot for responding to page selectors reload bacula-dir.conf */
699 void Console::consoleReload()
701 QString cmd("reload");
705 /* For suppressing .messages
706 * This may be rendered not needed if the multiple connections feature gets working */
707 bool Console::hasFocus()
709 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
715 /* For adding feature to have the gui's messages button change when
716 * messages are pending */
717 bool Console::messagesPending(bool pend)
719 bool prev = m_messages_pending;
720 m_messages_pending = pend;
721 mainWin->setMessageIcon();
725 /* terminate all existing connections */
726 void Console::terminate()
728 foreach(DirComm* dircomm, m_dircommHash) {
729 dircomm->terminate();
731 m_console->stopTimer();
734 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
735 bool Console::is_connectedGui()
737 if (is_connected(0)) {
740 QString message = tr("Director is currently disconnected\nPlease reconnect!");
741 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
746 int Console::read(int conn)
748 DirComm *dircomm = m_dircommHash.value(conn);
749 return dircomm->read();
752 char *Console::msg(int conn)
754 DirComm *dircomm = m_dircommHash.value(conn);
755 return dircomm->msg();
758 int Console::write(int conn, const QString msg)
760 DirComm *dircomm = m_dircommHash.value(conn);
761 mainWin->waitEnter();
762 int ret = dircomm->write(msg);
767 int Console::write(int conn, const char *msg)
769 DirComm *dircomm = m_dircommHash.value(conn);
770 mainWin->waitEnter();
771 int ret = dircomm->write(msg);
776 /* This checks to see if any is connected */
777 bool Console::is_connected()
779 bool connected = false;
780 foreach(DirComm* dircomm, m_dircommHash) {
781 if (dircomm->is_connected())
787 /* knowing the connection id, is it connected */
788 bool Console::is_connected(int conn)
790 DirComm *dircomm = m_dircommHash.value(conn);
791 return dircomm->is_connected();
795 * Need an available connection. Check existing connections or create one
797 bool Console::availableDirComm(int &conn)
799 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
800 while (iter != m_dircommHash.constEnd()) {
801 DirComm *dircomm = iter.value();
802 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
803 conn = dircomm->m_conn;
808 if (newDirComm(conn))
815 * Create a new connection
817 bool Console::newDirComm(int &conn)
819 m_dircommCounter += 1;
820 conn = m_dircommCounter;
821 if (mainWin->m_connDebug)
822 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
823 DirComm *dircomm = new DirComm(this, m_dircommCounter);
824 m_dircommHash.insert(m_dircommCounter, dircomm);
825 bool success = dircomm->connect_dir();
826 if (mainWin->m_connDebug) {
828 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
830 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());