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()){
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 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 * Overload function for dir_cmd with a QString
186 bool Console::dir_cmd(QString &cmd, QStringList &results)
188 return dir_cmd(cmd.toUtf8().data(), results);
192 * Overload function for dir_cmd, this is if connection is not worried about
194 bool Console::dir_cmd(const char *cmd, QStringList &results)
197 if (availableDirComm(conn)) {
198 dir_cmd(conn, cmd, results);
201 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
207 * Send a command to the Director, and return the
208 * results in a QStringList.
210 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
212 mainWin->waitEnter();
213 DirComm *dircomm = m_dircommHash.value(conn);
216 if (mainWin->m_connDebug) {
217 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
218 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
222 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
223 if (mainWin->m_displayAll) display_text(dircomm->msg());
224 strip_trailing_junk(dircomm->msg());
225 results << dircomm->msg();
227 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
229 discardToPrompt(conn);
231 return true; /* ***FIXME*** return any command error */
235 * OverLoads for sql_cmd
237 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
239 return sql_cmd(conn, query.toUtf8().data(), results, false);
242 bool Console::sql_cmd(QString &query, QStringList &results)
245 if (!availableDirComm(conn))
247 return sql_cmd(conn, query.toUtf8().data(), results, true);
250 bool Console::sql_cmd(const char *query, QStringList &results)
253 if (!availableDirComm(conn))
255 return sql_cmd(conn, query, results, true);
259 * Send an sql query to the Director, and return the
260 * results in a QStringList.
262 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
264 DirComm *dircomm = m_dircommHash.value(conn);
266 POOL_MEM cmd(PM_MESSAGE);
268 if (!is_connectedGui()) {
272 if (mainWin->m_connDebug)
273 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
275 dircomm->notify(false);
276 mainWin->waitEnter();
278 pm_strcpy(cmd, ".sql query=\"");
279 pm_strcat(cmd, query);
280 pm_strcat(cmd, "\"");
281 dircomm->write(cmd.c_str());
282 while ((stat = dircomm->read()) > 0) {
284 if (mainWin->m_displayAll) {
285 display_text(dircomm->msg());
288 strip_trailing_junk(dircomm->msg());
289 bool doappend = true;
291 QString dum = dircomm->msg();
292 if ((dum.left(6) == "*None*")) doappend = false;
295 results << dircomm->msg();
299 dircomm->notify(true);
300 discardToPrompt(conn);
302 return true; /* ***FIXME*** return any command error */
305 /* Send a command to the Director */
306 int Console::write_dir(const char *msg)
309 if (availableDirComm(conn))
310 write_dir(conn, msg);
314 /* Send a command to the Director */
315 void Console::write_dir(int conn, const char *msg)
317 DirComm *dircomm = m_dircommHash.value(conn);
319 if (dircomm->m_sock) {
320 mainWin->set_status(_("Processing command ..."));
321 mainWin->waitEnter();
325 mainWin->set_status( tr(" Director not connected. Click on connect button."));
326 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
327 QBrush redBrush(Qt::red);
328 QTreeWidgetItem *item = mainWin->getFromHash(this);
329 item->setForeground(0, redBrush);
330 dircomm->m_at_prompt = false;
331 dircomm->m_at_main_prompt = false;
336 * get_job_defaults overload
338 bool Console::get_job_defaults(struct job_defaults &job_defs)
341 return get_job_defaults(conn, job_defs, true);
344 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
346 return get_job_defaults(conn, job_defs, false);
350 * Send a job name to the director, and read all the resulting
353 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
361 beginNewCommand(conn);
362 DirComm *dircomm = m_dircommHash.value(conn);
363 bool prevWaitState = mainWin->getWaitState();
365 mainWin->waitEnter();
366 if (mainWin->m_connDebug)
367 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
368 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
369 dircomm->write(scmd);
370 while ((stat = dircomm->read()) > 0) {
371 if (mainWin->m_displayAll) display_text(dircomm->msg());
372 def = strchr(dircomm->msg(), '=');
376 /* Pointer to default value */
378 strip_trailing_junk(def);
380 if (strcmp(dircomm->msg(), "job") == 0) {
381 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
386 if (strcmp(dircomm->msg(), "pool") == 0) {
387 job_defs.pool_name = def;
390 if (strcmp(dircomm->msg(), "messages") == 0) {
391 job_defs.messages_name = def;
394 if (strcmp(dircomm->msg(), "client") == 0) {
395 job_defs.client_name = def;
398 if (strcmp(dircomm->msg(), "storage") == 0) {
399 job_defs.store_name = def;
402 if (strcmp(dircomm->msg(), "where") == 0) {
403 job_defs.where = def;
406 if (strcmp(dircomm->msg(), "level") == 0) {
407 job_defs.level = def;
410 if (strcmp(dircomm->msg(), "type") == 0) {
414 if (strcmp(dircomm->msg(), "fileset") == 0) {
415 job_defs.fileset_name = def;
418 if (strcmp(dircomm->msg(), "catalog") == 0) {
419 job_defs.catalog_name = def;
422 if (strcmp(dircomm->msg(), "enabled") == 0) {
423 job_defs.enabled = *def == '1' ? true : false;
444 * Save user settings associated with this console
446 void Console::writeSettings()
448 QFont font = get_font();
450 QSettings settings(m_dir->name(), "bat");
451 settings.beginGroup("Console");
452 settings.setValue("consoleFont", font.family());
453 settings.setValue("consolePointSize", font.pointSize());
454 settings.setValue("consoleFixedPitch", font.fixedPitch());
459 * Read and restore user settings associated with this console
461 void Console::readSettings()
463 QFont font = get_font();
465 QSettings settings(m_dir->name(), "bat");
466 settings.beginGroup("Console");
467 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
468 font.setPointSize(settings.value("consolePointSize", 10).toInt());
469 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
471 m_textEdit->setFont(font);
475 * Set the console textEdit font
477 void Console::set_font()
480 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
482 m_textEdit->setFont(font);
487 * Get the console text edit font
489 const QFont Console::get_font()
491 return m_textEdit->font();
495 * Slot for responding to status dir button on button bar
497 void Console::status_dir()
499 QString cmd("status dir");
504 * Slot for responding to messages button on button bar
505 * Here we want to bring the console to the front so use pages' consoleCommand
507 void Console::messages()
509 QString cmd(".messages");
511 messagesPending(false);
515 * Put text into the console window
517 void Console::display_textf(const char *fmt, ...)
522 va_start(arg_ptr, fmt);
523 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
528 void Console::display_text(const QString buf)
530 m_cursor->insertText(buf);
535 void Console::display_text(const char *buf)
537 m_cursor->insertText(buf);
541 void Console::display_html(const QString buf)
543 m_cursor->insertHtml(buf);
547 /* Position cursor to end of screen */
548 void Console::update_cursor()
550 // QApplication::restoreOverrideCursor();
551 m_textEdit->moveCursor(QTextCursor::End);
552 m_textEdit->ensureCursorVisible();
555 void Console::beginNewCommand(int conn)
557 DirComm *dircomm = m_dircommHash.value(conn);
559 for (int i=0; i < 3; i++) {
561 while (dircomm->read() > 0) {
562 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
563 if (mainWin->m_displayAll) display_text(dircomm->msg());
565 if (dircomm->m_at_main_prompt) {
572 void Console::displayToPrompt(int conn)
574 DirComm *dircomm = m_dircommHash.value(conn);
578 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
579 while (!dircomm->m_at_prompt) {
580 if ((stat=dircomm->read()) > 0) {
581 buf += dircomm->msg();
582 if (buf.size() >= 8196 || m_messages_pending) {
585 messagesPending(false);
590 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
593 void Console::discardToPrompt(int conn)
595 DirComm *dircomm = m_dircommHash.value(conn);
598 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
599 if (mainWin->m_displayAll) {
600 displayToPrompt(conn);
602 while (!dircomm->m_at_prompt) {
603 stat = dircomm->read();
609 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
613 * When the notifier is enabled, read_dir() will automatically be
614 * called by the Qt event loop when ever there is any output
615 * from the Directory, and read_dir() will then display it on
618 * When we are in a bat dialog, we want to control *all* output
619 * from the Directory, so we set notify to off.
620 * m_console->notifiy(false);
623 /* dual purpose function to turn notify off and return an available connection */
624 int Console::notifyOff()
627 if (availableDirComm(conn))
632 /* knowing a connection, turn notify off or on */
633 bool Console::notify(int conn, bool enable)
635 DirComm *dircomm = m_dircommHash.value(conn);
636 return dircomm->notify(enable);
639 /* knowing a connection, return notify state */
640 bool Console::is_notify_enabled(int conn) const
642 DirComm *dircomm = m_dircommHash.value(conn);
643 return dircomm->is_notify_enabled();
646 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
648 m_directorTreeItem = item;
651 void Console::setDirRes(DIRRES *dir)
657 * To have the ability to get the name of the director resource.
659 void Console::getDirResName(QString &name_returned)
661 name_returned = m_dir->name();
664 /* Slot for responding to page selectors status help command */
665 void Console::consoleHelp()
671 /* Slot for responding to page selectors reload bacula-dir.conf */
672 void Console::consoleReload()
674 QString cmd("reload");
678 /* For suppressing .messages
679 * This may be rendered not needed if the multiple connections feature gets working */
680 bool Console::hasFocus()
682 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
688 /* For adding feature to have the gui's messages button change when
689 * messages are pending */
690 bool Console::messagesPending(bool pend)
692 bool prev = m_messages_pending;
693 m_messages_pending = pend;
694 mainWin->setMessageIcon();
698 /* terminate all existing connections */
699 void Console::terminate()
701 foreach(DirComm* dircomm, m_dircommHash) {
702 dircomm->terminate();
704 m_console->stopTimer();
707 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
708 bool Console::is_connectedGui()
710 if (is_connected(0)) {
713 QString message = tr("Director is currently disconnected\nPlease reconnect!");
714 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
719 int Console::read(int conn)
721 DirComm *dircomm = m_dircommHash.value(conn);
722 return dircomm->read();
725 char *Console::msg(int conn)
727 DirComm *dircomm = m_dircommHash.value(conn);
728 return dircomm->msg();
731 int Console::write(int conn, const QString msg)
733 DirComm *dircomm = m_dircommHash.value(conn);
734 mainWin->waitEnter();
735 int ret = dircomm->write(msg);
740 int Console::write(int conn, const char *msg)
742 DirComm *dircomm = m_dircommHash.value(conn);
743 mainWin->waitEnter();
744 int ret = dircomm->write(msg);
749 /* This checks to see if any is connected */
750 bool Console::is_connected()
752 bool connected = false;
753 foreach(DirComm* dircomm, m_dircommHash) {
754 if (dircomm->is_connected())
760 /* knowing the connection id, is it connected */
761 bool Console::is_connected(int conn)
763 DirComm *dircomm = m_dircommHash.value(conn);
764 return dircomm->is_connected();
768 * Need an available connection. Check existing connections or create one
770 bool Console::availableDirComm(int &conn)
772 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
773 while (iter != m_dircommHash.constEnd()) {
774 DirComm *dircomm = iter.value();
775 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
776 conn = dircomm->m_conn;
781 if (newDirComm(conn))
788 * Create a new connection
790 bool Console::newDirComm(int &conn)
792 m_dircommCounter += 1;
793 conn = m_dircommCounter;
794 if (mainWin->m_connDebug)
795 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
796 DirComm *dircomm = new DirComm(this, m_dircommCounter);
797 m_dircommHash.insert(m_dircommCounter, dircomm);
798 bool success = dircomm->connect_dir();
799 if (mainWin->m_connDebug) {
801 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
803 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());