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 Pmsg0(000, "DirComm 0 Seems to have Connected\n");
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 Pmsg0(000, "newDirComm Seems to Failed to create a connection for populateLists\n");
146 if(!availableDirComm(conn)) {
147 Pmsg0(000, "availableDirComm Seems to Failed to find a connection for populateLists\n");
154 void Console::populateLists(int conn)
158 fileset_list.clear();
159 fileset_list.clear();
160 messages_list.clear();
162 storage_list.clear();
165 dir_cmd(conn, ".jobs", job_list);
166 dir_cmd(conn, ".clients", client_list);
167 dir_cmd(conn, ".filesets", fileset_list);
168 dir_cmd(conn, ".msgs", messages_list);
169 dir_cmd(conn, ".pools", pool_list);
170 dir_cmd(conn, ".storage", storage_list);
171 dir_cmd(conn, ".types", type_list);
172 dir_cmd(conn, ".levels", level_list);
174 if (mainWin->m_connDebug) {
175 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9\n")
176 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
177 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
179 Pmsg1(000, "%s\n", dbgmsg.toUtf8().data());
184 * Overload function for dir_cmd with a QString
187 bool Console::dir_cmd(QString &cmd, QStringList &results)
189 return dir_cmd(cmd.toUtf8().data(), results);
193 * Overload function for dir_cmd, this is if connection is not worried about
195 bool Console::dir_cmd(const char *cmd, QStringList &results)
198 if(availableDirComm(conn)) {
199 dir_cmd(conn, cmd, results);
202 Pmsg0(000, "dir_cmd Seems to Failed to find a connection\n");
208 * Send a command to the Director, and return the
209 * results in a QStringList.
211 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
213 mainWin->waitEnter();
214 DirComm *dircomm = m_dircommHash.value(conn);
217 if (mainWin->m_connDebug)
218 Pmsg2(000, "dir_cmd conn %i %s\n", conn, cmd);
221 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
222 if (mainWin->m_displayAll) display_text(dircomm->msg());
223 strip_trailing_junk(dircomm->msg());
224 results << dircomm->msg();
226 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
228 discardToPrompt(conn);
230 return true; /* ***FIXME*** return any command error */
234 * OverLoads for sql_cmd
236 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
238 return sql_cmd(conn, query.toUtf8().data(), results, false);
241 bool Console::sql_cmd(QString &query, QStringList &results)
244 if (!availableDirComm(conn))
246 return sql_cmd(conn, query.toUtf8().data(), results, true);
249 bool Console::sql_cmd(const char *query, QStringList &results)
252 if (!availableDirComm(conn))
254 return sql_cmd(conn, query, results, true);
258 * Send an sql query to the Director, and return the
259 * results in a QStringList.
261 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
263 DirComm *dircomm = m_dircommHash.value(conn);
265 POOL_MEM cmd(PM_MESSAGE);
267 if (!is_connectedGui()) {
271 if (mainWin->m_connDebug)
272 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
274 dircomm->notify(false);
275 mainWin->waitEnter();
277 pm_strcpy(cmd, ".sql query=\"");
278 pm_strcat(cmd, query);
279 pm_strcat(cmd, "\"");
280 dircomm->write(cmd.c_str());
281 while ((stat = dircomm->read()) > 0) {
283 if (mainWin->m_displayAll) {
284 display_text(dircomm->msg());
287 strip_trailing_junk(dircomm->msg());
288 bool doappend = true;
290 QString dum = dircomm->msg();
291 if ((dum.left(6) == "*None*")) doappend = false;
294 results << dircomm->msg();
298 dircomm->notify(true);
299 discardToPrompt(conn);
301 return true; /* ***FIXME*** return any command error */
304 /* Send a command to the Director */
305 int Console::write_dir(const char *msg)
308 if(availableDirComm(conn))
309 write_dir(conn, msg);
313 /* Send a command to the Director */
314 void Console::write_dir(int conn, const char *msg)
316 DirComm *dircomm = m_dircommHash.value(conn);
318 if (dircomm->m_sock) {
319 mainWin->set_status(_("Processing command ..."));
320 mainWin->waitEnter();
324 mainWin->set_status( tr(" Director not connected. Click on connect button."));
325 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
326 QBrush redBrush(Qt::red);
327 QTreeWidgetItem *item = mainWin->getFromHash(this);
328 item->setForeground(0, redBrush);
329 dircomm->m_at_prompt = false;
330 dircomm->m_at_main_prompt = false;
335 * get_job_defaults overload
337 bool Console::get_job_defaults(struct job_defaults &job_defs)
340 return get_job_defaults(conn, job_defs, true);
343 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
345 return get_job_defaults(conn, job_defs, false);
349 * Send a job name to the director, and read all the resulting
352 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
360 beginNewCommand(conn);
361 DirComm *dircomm = m_dircommHash.value(conn);
362 if (mainWin->m_connDebug)
363 Pmsg1(000, "job_defaults conn %i\n", conn);
364 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
365 dircomm->write(scmd);
366 while ((stat = dircomm->read()) > 0) {
367 if (mainWin->m_displayAll) display_text(dircomm->msg());
368 def = strchr(dircomm->msg(), '=');
372 /* Pointer to default value */
374 strip_trailing_junk(def);
376 if (strcmp(dircomm->msg(), "job") == 0) {
377 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
382 if (strcmp(dircomm->msg(), "pool") == 0) {
383 job_defs.pool_name = def;
386 if (strcmp(dircomm->msg(), "messages") == 0) {
387 job_defs.messages_name = def;
390 if (strcmp(dircomm->msg(), "client") == 0) {
391 job_defs.client_name = def;
394 if (strcmp(dircomm->msg(), "storage") == 0) {
395 job_defs.store_name = def;
398 if (strcmp(dircomm->msg(), "where") == 0) {
399 job_defs.where = def;
402 if (strcmp(dircomm->msg(), "level") == 0) {
403 job_defs.level = def;
406 if (strcmp(dircomm->msg(), "type") == 0) {
410 if (strcmp(dircomm->msg(), "fileset") == 0) {
411 job_defs.fileset_name = def;
414 if (strcmp(dircomm->msg(), "catalog") == 0) {
415 job_defs.catalog_name = def;
418 if (strcmp(dircomm->msg(), "enabled") == 0) {
419 job_defs.enabled = *def == '1' ? true : false;
436 * Save user settings associated with this console
438 void Console::writeSettings()
440 QFont font = get_font();
442 QSettings settings(m_dir->name(), "bat");
443 settings.beginGroup("Console");
444 settings.setValue("consoleFont", font.family());
445 settings.setValue("consolePointSize", font.pointSize());
446 settings.setValue("consoleFixedPitch", font.fixedPitch());
451 * Read and restore user settings associated with this console
453 void Console::readSettings()
455 QFont font = get_font();
457 QSettings settings(m_dir->name(), "bat");
458 settings.beginGroup("Console");
459 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
460 font.setPointSize(settings.value("consolePointSize", 10).toInt());
461 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
463 m_textEdit->setFont(font);
467 * Set the console textEdit font
469 void Console::set_font()
472 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
474 m_textEdit->setFont(font);
479 * Get the console text edit font
481 const QFont Console::get_font()
483 return m_textEdit->font();
487 * Slot for responding to status dir button on button bar
489 void Console::status_dir()
491 QString cmd("status dir");
496 * Slot for responding to messages button on button bar
497 * Here we want to bring the console to the front so use pages' consoleCommand
499 void Console::messages()
501 QString cmd(".messages");
503 messagesPending(false);
507 * Put text into the console window
509 void Console::display_textf(const char *fmt, ...)
514 va_start(arg_ptr, fmt);
515 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
520 void Console::display_text(const QString buf)
522 m_cursor->insertText(buf);
527 void Console::display_text(const char *buf)
529 m_cursor->insertText(buf);
533 void Console::display_html(const QString buf)
535 m_cursor->insertHtml(buf);
539 /* Position cursor to end of screen */
540 void Console::update_cursor()
542 QApplication::restoreOverrideCursor();
543 m_textEdit->moveCursor(QTextCursor::End);
544 m_textEdit->ensureCursorVisible();
547 void Console::beginNewCommand(int conn)
549 DirComm *dircomm = m_dircommHash.value(conn);
551 for (int i=0; i < 3; i++) {
553 while (dircomm->read() > 0) {
554 if (mainWin->m_displayAll) display_text(dircomm->msg());
556 if (dircomm->m_at_main_prompt) {
563 void Console::displayToPrompt(int conn)
565 DirComm *dircomm = m_dircommHash.value(conn);
569 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
570 while (!dircomm->m_at_prompt) {
571 if ((stat=dircomm->read()) > 0) {
572 buf += dircomm->msg();
573 if (buf.size() >= 8196 || m_messages_pending) {
576 messagesPending(false);
581 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
584 void Console::discardToPrompt(int conn)
586 DirComm *dircomm = m_dircommHash.value(conn);
589 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
590 if (mainWin->m_displayAll) {
591 displayToPrompt(conn);
593 while (!dircomm->m_at_prompt) {
594 stat=dircomm->read();
597 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
601 * When the notifier is enabled, read_dir() will automatically be
602 * called by the Qt event loop when ever there is any output
603 * from the Directory, and read_dir() will then display it on
606 * When we are in a bat dialog, we want to control *all* output
607 * from the Directory, so we set notify to off.
608 * m_console->notifiy(false);
611 /* dual purpose function to turn notify off and return an available connection */
612 int Console::notifyOff()
615 if(availableDirComm(conn))
620 /* knowing a connection, turn notify off or on */
621 bool Console::notify(int conn, bool enable)
623 DirComm *dircomm = m_dircommHash.value(conn);
624 return dircomm->notify(enable);
627 /* knowing a connection, return notify state */
628 bool Console::is_notify_enabled(int conn) const
630 DirComm *dircomm = m_dircommHash.value(conn);
631 return dircomm->is_notify_enabled();
634 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
636 m_directorTreeItem = item;
639 void Console::setDirRes(DIRRES *dir)
645 * To have the ability to get the name of the director resource.
647 void Console::getDirResName(QString &name_returned)
649 name_returned = m_dir->name();
652 /* Slot for responding to page selectors status help command */
653 void Console::consoleHelp()
659 /* Slot for responding to page selectors reload bacula-dir.conf */
660 void Console::consoleReload()
662 QString cmd("reload");
666 /* For suppressing .messages
667 * This may be rendered not needed if the multiple connections feature gets working */
668 bool Console::hasFocus()
670 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
676 /* For adding feature to have the gui's messages button change when
677 * messages are pending */
678 bool Console::messagesPending(bool pend)
680 bool prev = m_messages_pending;
681 m_messages_pending = pend;
682 mainWin->setMessageIcon();
686 /* terminate all existing connections */
687 void Console::terminate()
689 foreach(DirComm* dircomm, m_dircommHash) {
690 dircomm->terminate();
692 m_console->stopTimer();
695 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
696 bool Console::is_connectedGui()
698 if (is_connected(0)) {
701 QString message = tr("Director is currently disconnected\nPlease reconnect!");
702 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
707 int Console::read(int conn)
709 DirComm *dircomm = m_dircommHash.value(conn);
710 return dircomm->read();
713 char *Console::msg(int conn)
715 DirComm *dircomm = m_dircommHash.value(conn);
716 return dircomm->msg();
719 int Console::write(int conn, const QString msg)
721 DirComm *dircomm = m_dircommHash.value(conn);
722 mainWin->waitEnter();
723 int ret = dircomm->write(msg);
728 int Console::write(int conn, const char *msg)
730 DirComm *dircomm = m_dircommHash.value(conn);
731 mainWin->waitEnter();
732 int ret = dircomm->write(msg);
737 /* This checks to see if any is connected */
738 bool Console::is_connected()
740 bool connected = false;
741 foreach(DirComm* dircomm, m_dircommHash) {
742 if (dircomm->is_connected())
748 /* knowing the connection id, is it connected */
749 bool Console::is_connected(int conn)
751 DirComm *dircomm = m_dircommHash.value(conn);
752 return dircomm->is_connected();
756 * Need an available connection. Check existing connections or create one
758 bool Console::availableDirComm(int &conn)
760 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
761 while (iter != m_dircommHash.constEnd()) {
762 DirComm *dircomm = iter.value();
763 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
764 conn = dircomm->m_conn;
769 if (newDirComm(conn))
776 * Create a new connection
778 bool Console::newDirComm(int &conn)
780 m_dircommCounter += 1;
781 conn = m_dircommCounter;
782 if (mainWin->m_connDebug)
783 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
784 DirComm *dircomm = new DirComm(this, m_dircommCounter);
785 m_dircommHash.insert(m_dircommCounter, dircomm);
786 bool success = dircomm->connect_dir();
787 if (mainWin->m_connDebug)
789 Pmsg1(000, "DirComm %i Connected\n", conn);
791 Pmsg1(000, "DirComm %i NOT Connected\n", conn);