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;
51 m_dircommHash.insert(m_dircommCounter, new DirComm(this, m_dircommCounter));
54 m_textEdit = textEdit; /* our console screen */
55 m_cursor = new QTextCursor(m_textEdit->document());
56 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
59 m_contextActions.append(actionStatusDir);
60 m_contextActions.append(actionConsoleHelp);
61 m_contextActions.append(actionRequestMessages);
62 m_contextActions.append(actionConsoleReload);
63 connect(actionStatusDir, SIGNAL(triggered()), this, SLOT(status_dir()));
64 connect(actionConsoleHelp, SIGNAL(triggered()), this, SLOT(consoleHelp()));
65 connect(actionConsoleReload, SIGNAL(triggered()), this, SLOT(consoleReload()));
66 connect(actionRequestMessages, SIGNAL(triggered()), this, SLOT(messages()));
73 void Console::startTimer()
75 m_timer = new QTimer(this);
76 QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
77 m_timer->start(mainWin->m_checkMessagesInterval*1000);
80 void Console::stopTimer()
83 QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
90 /* slot connected to the timer
91 * requires preferences of check messages and operates at interval */
92 void Console::poll_messages()
95 if (!availableDirComm(conn))
97 DirComm *dircomm = m_dircommHash.value(conn);
99 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus() && !mainWin->getWaitState()){
100 messagesPending(true);
101 dircomm->write(".messages");
102 displayToPrompt(conn);
103 messagesPending(false);
108 * Connect to Director. This does not connect to the director, dircomm does.
109 * This creates the first and possibly 2nd dircomm instance
111 void Console::connect_dir()
113 DirComm *dircomm = m_dircommHash.value(0);
115 if (!m_console->m_dir) {
116 mainWin->set_status( tr("No Director found."));
120 m_textEdit = textEdit; /* our console screen */
122 if (dircomm->connect_dir()) {
123 if (mainWin->m_connDebug)
124 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
127 mainWin->set_status(_("Connected"));
129 startTimer(); /* start message timer */
133 * A function created to separate out the population of the lists
134 * from the Console::connect_dir function
136 void Console::populateLists(bool forcenew)
140 if (!newDirComm(conn)) {
141 Pmsg1(000, "newDirComm Seems to Failed to create a connection for populateLists %s\n", m_dir->name());
145 if(!availableDirComm(conn)) {
146 Pmsg1(000, "availableDirComm Seems to Failed to find a connection for populateListsi %s\n", m_dir->name());
153 void Console::populateLists(int conn)
157 fileset_list.clear();
158 messages_list.clear();
160 storage_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);
172 if (mainWin->m_connDebug) {
173 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
174 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
175 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
176 .arg(conn).arg(m_dir->name());
177 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
182 messages_list.sort();
190 * Overload function for dir_cmd with a QString
193 bool Console::dir_cmd(QString &cmd, QStringList &results)
195 return dir_cmd(cmd.toUtf8().data(), results);
199 * Overload function for dir_cmd, this is if connection is not worried about
201 bool Console::dir_cmd(const char *cmd, QStringList &results)
204 if (availableDirComm(conn)) {
205 dir_cmd(conn, cmd, results);
208 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
214 * Send a command to the Director, and return the
215 * results in a QStringList.
217 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
219 mainWin->waitEnter();
220 DirComm *dircomm = m_dircommHash.value(conn);
223 if (mainWin->m_connDebug) {
224 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
225 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
229 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
230 if (mainWin->m_displayAll) display_text(dircomm->msg());
231 strip_trailing_junk(dircomm->msg());
232 results << dircomm->msg();
234 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
236 discardToPrompt(conn);
238 return true; /* ***FIXME*** return any command error */
242 * OverLoads for sql_cmd
244 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
246 return sql_cmd(conn, query.toUtf8().data(), results, false);
249 bool Console::sql_cmd(QString &query, QStringList &results)
252 if (!availableDirComm(conn))
254 return sql_cmd(conn, query.toUtf8().data(), results, true);
257 bool Console::sql_cmd(const char *query, QStringList &results)
260 if (!availableDirComm(conn))
262 return sql_cmd(conn, query, results, true);
266 * Send an sql query to the Director, and return the
267 * results in a QStringList.
269 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
271 DirComm *dircomm = m_dircommHash.value(conn);
273 POOL_MEM cmd(PM_MESSAGE);
275 if (!is_connectedGui()) {
279 if (mainWin->m_connDebug)
280 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
282 dircomm->notify(false);
283 mainWin->waitEnter();
285 pm_strcpy(cmd, ".sql query=\"");
286 pm_strcat(cmd, query);
287 pm_strcat(cmd, "\"");
288 dircomm->write(cmd.c_str());
289 while ((stat = dircomm->read()) > 0) {
291 if (mainWin->m_displayAll) {
292 display_text(dircomm->msg());
295 strip_trailing_junk(dircomm->msg());
296 bool doappend = true;
298 QString dum = dircomm->msg();
299 if ((dum.left(6) == "*None*")) doappend = false;
302 results << dircomm->msg();
306 dircomm->notify(true);
307 discardToPrompt(conn);
309 return true; /* ***FIXME*** return any command error */
314 * Sending a command to the Director
316 int Console::write_dir(const char *msg)
319 if (availableDirComm(conn))
320 write_dir(conn, msg);
324 int Console::write_dir(const char *msg, bool dowait)
327 if (availableDirComm(conn))
328 write_dir(conn, msg, dowait);
332 void Console::write_dir(int conn, const char *msg)
334 write_dir(conn, msg, true);
338 * Send a command to the Director
340 void Console::write_dir(int conn, const char *msg, bool dowait)
342 DirComm *dircomm = m_dircommHash.value(conn);
344 if (dircomm->m_sock) {
345 mainWin->set_status(_("Processing command ..."));
347 mainWin->waitEnter();
352 mainWin->set_status( tr(" Director not connected. Click on connect button."));
353 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
354 QBrush redBrush(Qt::red);
355 QTreeWidgetItem *item = mainWin->getFromHash(this);
356 item->setForeground(0, redBrush);
357 dircomm->m_at_prompt = false;
358 dircomm->m_at_main_prompt = false;
363 * get_job_defaults overload
365 bool Console::get_job_defaults(struct job_defaults &job_defs)
368 return get_job_defaults(conn, job_defs, true);
371 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
373 return get_job_defaults(conn, job_defs, false);
377 * Send a job name to the director, and read all the resulting
380 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
388 beginNewCommand(conn);
389 DirComm *dircomm = m_dircommHash.value(conn);
390 bool prevWaitState = mainWin->getWaitState();
392 mainWin->waitEnter();
393 if (mainWin->m_connDebug)
394 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
395 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
396 dircomm->write(scmd);
397 while ((stat = dircomm->read()) > 0) {
398 if (mainWin->m_displayAll) display_text(dircomm->msg());
399 def = strchr(dircomm->msg(), '=');
403 /* Pointer to default value */
405 strip_trailing_junk(def);
407 if (strcmp(dircomm->msg(), "job") == 0) {
408 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
413 if (strcmp(dircomm->msg(), "pool") == 0) {
414 job_defs.pool_name = def;
417 if (strcmp(dircomm->msg(), "messages") == 0) {
418 job_defs.messages_name = def;
421 if (strcmp(dircomm->msg(), "client") == 0) {
422 job_defs.client_name = def;
425 if (strcmp(dircomm->msg(), "storage") == 0) {
426 job_defs.store_name = def;
429 if (strcmp(dircomm->msg(), "where") == 0) {
430 job_defs.where = def;
433 if (strcmp(dircomm->msg(), "level") == 0) {
434 job_defs.level = def;
437 if (strcmp(dircomm->msg(), "type") == 0) {
441 if (strcmp(dircomm->msg(), "fileset") == 0) {
442 job_defs.fileset_name = def;
445 if (strcmp(dircomm->msg(), "catalog") == 0) {
446 job_defs.catalog_name = def;
449 if (strcmp(dircomm->msg(), "enabled") == 0) {
450 job_defs.enabled = *def == '1' ? true : false;
471 * Save user settings associated with this console
473 void Console::writeSettings()
475 QFont font = get_font();
477 QSettings settings(m_dir->name(), "bat");
478 settings.beginGroup("Console");
479 settings.setValue("consoleFont", font.family());
480 settings.setValue("consolePointSize", font.pointSize());
481 settings.setValue("consoleFixedPitch", font.fixedPitch());
486 * Read and restore user settings associated with this console
488 void Console::readSettings()
490 QFont font = get_font();
492 QSettings settings(m_dir->name(), "bat");
493 settings.beginGroup("Console");
494 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
495 font.setPointSize(settings.value("consolePointSize", 10).toInt());
496 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
498 m_textEdit->setFont(font);
502 * Set the console textEdit font
504 void Console::set_font()
507 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
509 m_textEdit->setFont(font);
514 * Get the console text edit font
516 const QFont Console::get_font()
518 return m_textEdit->font();
522 * Slot for responding to status dir button on button bar
524 void Console::status_dir()
526 QString cmd("status dir");
531 * Slot for responding to messages button on button bar
532 * Here we want to bring the console to the front so use pages' consoleCommand
534 void Console::messages()
536 QString cmd(".messages");
538 messagesPending(false);
542 * Put text into the console window
544 void Console::display_textf(const char *fmt, ...)
549 va_start(arg_ptr, fmt);
550 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
555 void Console::display_text(const QString buf)
557 m_cursor->insertText(buf);
562 void Console::display_text(const char *buf)
564 m_cursor->insertText(buf);
568 void Console::display_html(const QString buf)
570 m_cursor->insertHtml(buf);
574 /* Position cursor to end of screen */
575 void Console::update_cursor()
577 m_textEdit->moveCursor(QTextCursor::End);
578 m_textEdit->ensureCursorVisible();
581 void Console::beginNewCommand(int conn)
583 DirComm *dircomm = m_dircommHash.value(conn);
585 for (int i=0; i < 3; i++) {
587 while (dircomm->read() > 0) {
588 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
589 if (mainWin->m_displayAll) display_text(dircomm->msg());
591 if (dircomm->m_at_main_prompt) {
598 void Console::displayToPrompt(int conn)
600 DirComm *dircomm = m_dircommHash.value(conn);
604 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
605 while (!dircomm->m_at_prompt) {
606 if ((stat=dircomm->read()) > 0) {
607 buf += dircomm->msg();
608 if (buf.size() >= 8196 || m_messages_pending) {
611 messagesPending(false);
616 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
619 void Console::discardToPrompt(int conn)
621 DirComm *dircomm = m_dircommHash.value(conn);
624 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
625 if (mainWin->m_displayAll) {
626 displayToPrompt(conn);
628 while (!dircomm->m_at_prompt) {
629 stat = dircomm->read();
635 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
639 * When the notifier is enabled, read_dir() will automatically be
640 * called by the Qt event loop when ever there is any output
641 * from the Directory, and read_dir() will then display it on
644 * When we are in a bat dialog, we want to control *all* output
645 * from the Directory, so we set notify to off.
646 * m_console->notifiy(false);
649 /* dual purpose function to turn notify off and return an available connection */
650 int Console::notifyOff()
653 if (availableDirComm(conn))
658 /* knowing a connection, turn notify off or on */
659 bool Console::notify(int conn, bool enable)
661 DirComm *dircomm = m_dircommHash.value(conn);
662 return dircomm->notify(enable);
665 /* knowing a connection, return notify state */
666 bool Console::is_notify_enabled(int conn) const
668 DirComm *dircomm = m_dircommHash.value(conn);
669 return dircomm->is_notify_enabled();
672 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
674 m_directorTreeItem = item;
677 void Console::setDirRes(DIRRES *dir)
683 * To have the ability to get the name of the director resource.
685 void Console::getDirResName(QString &name_returned)
687 name_returned = m_dir->name();
690 /* Slot for responding to page selectors status help command */
691 void Console::consoleHelp()
697 /* Slot for responding to page selectors reload bacula-dir.conf */
698 void Console::consoleReload()
700 QString cmd("reload");
704 /* For suppressing .messages
705 * This may be rendered not needed if the multiple connections feature gets working */
706 bool Console::hasFocus()
708 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
714 /* For adding feature to have the gui's messages button change when
715 * messages are pending */
716 bool Console::messagesPending(bool pend)
718 bool prev = m_messages_pending;
719 m_messages_pending = pend;
720 mainWin->setMessageIcon();
724 /* terminate all existing connections */
725 void Console::terminate()
727 foreach(DirComm* dircomm, m_dircommHash) {
728 dircomm->terminate();
730 m_console->stopTimer();
733 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
734 bool Console::is_connectedGui()
736 if (is_connected(0)) {
739 QString message = tr("Director is currently disconnected\nPlease reconnect!");
740 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
745 int Console::read(int conn)
747 DirComm *dircomm = m_dircommHash.value(conn);
748 return dircomm->read();
751 char *Console::msg(int conn)
753 DirComm *dircomm = m_dircommHash.value(conn);
754 return dircomm->msg();
757 int Console::write(int conn, const QString msg)
759 DirComm *dircomm = m_dircommHash.value(conn);
760 mainWin->waitEnter();
761 int ret = dircomm->write(msg);
766 int Console::write(int conn, const char *msg)
768 DirComm *dircomm = m_dircommHash.value(conn);
769 mainWin->waitEnter();
770 int ret = dircomm->write(msg);
775 /* This checks to see if any is connected */
776 bool Console::is_connected()
778 bool connected = false;
779 foreach(DirComm* dircomm, m_dircommHash) {
780 if (dircomm->is_connected())
786 /* knowing the connection id, is it connected */
787 bool Console::is_connected(int conn)
789 DirComm *dircomm = m_dircommHash.value(conn);
790 return dircomm->is_connected();
794 * Need an available connection. Check existing connections or create one
796 bool Console::availableDirComm(int &conn)
798 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
799 while (iter != m_dircommHash.constEnd()) {
800 DirComm *dircomm = iter.value();
801 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
802 conn = dircomm->m_conn;
807 if (newDirComm(conn))
814 * Create a new connection
816 bool Console::newDirComm(int &conn)
818 m_dircommCounter += 1;
819 conn = m_dircommCounter;
820 if (mainWin->m_connDebug)
821 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
822 DirComm *dircomm = new DirComm(this, m_dircommCounter);
823 m_dircommHash.insert(m_dircommCounter, dircomm);
824 bool success = dircomm->connect_dir();
825 if (mainWin->m_connDebug) {
827 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
829 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());