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.
110 void Console::connect_dir()
112 DirComm *dircomm = m_dircommHash.value(0);
114 if (!m_console->m_dir) {
115 mainWin->set_status( tr("No Director found."));
119 m_textEdit = textEdit; /* our console screen */
121 if (dircomm->connect_dir()) {
122 if (mainWin->m_connDebug)
123 Pmsg0(000, "DirComm 0 Seems to have Connected\n");
128 if (newDirComm(ndc)) {
129 if (mainWin->m_connDebug)
130 Pmsg1(000, "DirComm %i Seems to have Connected\n", ndc);
131 dircomm = m_dircommHash.value(ndc);
134 fileset_list.clear();
135 fileset_list.clear();
136 messages_list.clear();
138 storage_list.clear();
141 dir_cmd(ndc, ".jobs", job_list);
142 dir_cmd(ndc, ".clients", client_list);
143 dir_cmd(ndc, ".filesets", fileset_list);
144 dir_cmd(ndc, ".msgs", messages_list);
145 dir_cmd(ndc, ".pools", pool_list);
146 dir_cmd(ndc, ".storage", storage_list);
147 dir_cmd(ndc, ".types", type_list);
148 dir_cmd(ndc, ".levels", level_list);
150 if (mainWin->m_connDebug) {
151 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8\n")
152 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
153 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count());
154 Pmsg1(000, "%s\n", dbgmsg.toUtf8().data());
156 if (mainWin->m_connDebug)
157 Pmsg0(000, "DirComm 1 Seems to Failed\n");
159 mainWin->set_status(_("Connected"));
160 startTimer(); /* start message timer */
165 * Overload function for dir_cmd with a QString
168 bool Console::dir_cmd(QString &cmd, QStringList &results)
170 return dir_cmd(cmd.toUtf8().data(), results);
174 * Overload function for dir_cmd, this is if connection is not worried about
176 bool Console::dir_cmd(const char *cmd, QStringList &results)
179 if(availableDirComm(conn)) {
180 dir_cmd(conn, cmd, results);
183 Pmsg0(000, "dir_cmd Seems to Failed to find a connection\n");
189 * Send a command to the Director, and return the
190 * results in a QStringList.
192 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
194 mainWin->waitEnter();
195 DirComm *dircomm = m_dircommHash.value(conn);
198 if (mainWin->m_connDebug)
199 Pmsg2(000, "dir_cmd conn %i %s\n", conn, cmd);
202 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
203 if (mainWin->m_displayAll) display_text(dircomm->msg());
204 strip_trailing_junk(dircomm->msg());
205 results << dircomm->msg();
207 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
209 discardToPrompt(conn);
211 return true; /* ***FIXME*** return any command error */
215 * OverLoads for sql_cmd
217 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
219 return sql_cmd(conn, query.toUtf8().data(), results, false);
222 bool Console::sql_cmd(QString &query, QStringList &results)
225 if (!availableDirComm(conn))
227 return sql_cmd(conn, query.toUtf8().data(), results, true);
230 bool Console::sql_cmd(const char *query, QStringList &results)
233 if (!availableDirComm(conn))
235 return sql_cmd(conn, query, results, true);
239 * Send an sql query to the Director, and return the
240 * results in a QStringList.
242 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
244 DirComm *dircomm = m_dircommHash.value(conn);
246 POOL_MEM cmd(PM_MESSAGE);
248 if (!is_connectedGui()) {
252 if (mainWin->m_connDebug)
253 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
255 dircomm->notify(false);
256 mainWin->waitEnter();
258 pm_strcpy(cmd, ".sql query=\"");
259 pm_strcat(cmd, query);
260 pm_strcat(cmd, "\"");
261 dircomm->write(cmd.c_str());
262 while ((stat = dircomm->read()) > 0) {
264 if (mainWin->m_displayAll) {
265 display_text(dircomm->msg());
268 strip_trailing_junk(dircomm->msg());
269 bool doappend = true;
271 QString dum = dircomm->msg();
272 if ((dum.left(6) == "*None*")) doappend = false;
275 results << dircomm->msg();
279 dircomm->notify(true);
280 discardToPrompt(conn);
282 return true; /* ***FIXME*** return any command error */
285 /* Send a command to the Director */
286 int Console::write_dir(const char *msg)
289 if(availableDirComm(conn))
290 write_dir(conn, msg);
294 /* Send a command to the Director */
295 void Console::write_dir(int conn, const char *msg)
297 DirComm *dircomm = m_dircommHash.value(conn);
299 if (dircomm->m_sock) {
300 mainWin->set_status(_("Processing command ..."));
301 mainWin->waitEnter();
305 mainWin->set_status( tr(" Director not connected. Click on connect button."));
306 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
307 QBrush redBrush(Qt::red);
308 QTreeWidgetItem *item = mainWin->getFromHash(this);
309 item->setForeground(0, redBrush);
310 dircomm->m_at_prompt = false;
311 dircomm->m_at_main_prompt = false;
316 * get_job_defaults overload
318 bool Console::get_job_defaults(struct job_defaults &job_defs)
321 return get_job_defaults(conn, job_defs, true);
324 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
326 return get_job_defaults(conn, job_defs, false);
330 * Send a job name to the director, and read all the resulting
333 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
341 beginNewCommand(conn);
342 DirComm *dircomm = m_dircommHash.value(conn);
343 if (mainWin->m_connDebug)
344 Pmsg1(000, "job_defaults conn %i\n", conn);
345 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
346 dircomm->write(scmd);
347 while ((stat = dircomm->read()) > 0) {
348 if (mainWin->m_displayAll) display_text(dircomm->msg());
349 def = strchr(dircomm->msg(), '=');
353 /* Pointer to default value */
355 strip_trailing_junk(def);
357 if (strcmp(dircomm->msg(), "job") == 0) {
358 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
363 if (strcmp(dircomm->msg(), "pool") == 0) {
364 job_defs.pool_name = def;
367 if (strcmp(dircomm->msg(), "messages") == 0) {
368 job_defs.messages_name = def;
371 if (strcmp(dircomm->msg(), "client") == 0) {
372 job_defs.client_name = def;
375 if (strcmp(dircomm->msg(), "storage") == 0) {
376 job_defs.store_name = def;
379 if (strcmp(dircomm->msg(), "where") == 0) {
380 job_defs.where = def;
383 if (strcmp(dircomm->msg(), "level") == 0) {
384 job_defs.level = def;
387 if (strcmp(dircomm->msg(), "type") == 0) {
391 if (strcmp(dircomm->msg(), "fileset") == 0) {
392 job_defs.fileset_name = def;
395 if (strcmp(dircomm->msg(), "catalog") == 0) {
396 job_defs.catalog_name = def;
399 if (strcmp(dircomm->msg(), "enabled") == 0) {
400 job_defs.enabled = *def == '1' ? true : false;
417 * Save user settings associated with this console
419 void Console::writeSettings()
421 QFont font = get_font();
423 QSettings settings(m_dir->name(), "bat");
424 settings.beginGroup("Console");
425 settings.setValue("consoleFont", font.family());
426 settings.setValue("consolePointSize", font.pointSize());
427 settings.setValue("consoleFixedPitch", font.fixedPitch());
432 * Read and restore user settings associated with this console
434 void Console::readSettings()
436 QFont font = get_font();
438 QSettings settings(m_dir->name(), "bat");
439 settings.beginGroup("Console");
440 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
441 font.setPointSize(settings.value("consolePointSize", 10).toInt());
442 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
444 m_textEdit->setFont(font);
448 * Set the console textEdit font
450 void Console::set_font()
453 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
455 m_textEdit->setFont(font);
460 * Get the console text edit font
462 const QFont Console::get_font()
464 return m_textEdit->font();
468 * Slot for responding to status dir button on button bar
470 void Console::status_dir()
472 QString cmd("status dir");
477 * Slot for responding to messages button on button bar
478 * Here we want to bring the console to the front so use pages' consoleCommand
480 void Console::messages()
482 QString cmd(".messages");
484 messagesPending(false);
488 * Put text into the console window
490 void Console::display_textf(const char *fmt, ...)
495 va_start(arg_ptr, fmt);
496 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
501 void Console::display_text(const QString buf)
503 m_cursor->insertText(buf);
508 void Console::display_text(const char *buf)
510 m_cursor->insertText(buf);
514 void Console::display_html(const QString buf)
516 m_cursor->insertHtml(buf);
520 /* Position cursor to end of screen */
521 void Console::update_cursor()
523 QApplication::restoreOverrideCursor();
524 m_textEdit->moveCursor(QTextCursor::End);
525 m_textEdit->ensureCursorVisible();
528 void Console::beginNewCommand(int conn)
530 DirComm *dircomm = m_dircommHash.value(conn);
532 for (int i=0; i < 3; i++) {
534 while (dircomm->read() > 0) {
535 if (mainWin->m_displayAll) display_text(dircomm->msg());
537 if (dircomm->m_at_main_prompt) {
544 void Console::displayToPrompt(int conn)
546 DirComm *dircomm = m_dircommHash.value(conn);
550 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
551 while (!dircomm->m_at_prompt) {
552 if ((stat=dircomm->read()) > 0) {
553 buf += dircomm->msg();
554 if (buf.size() >= 8196 || m_messages_pending) {
557 messagesPending(false);
562 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
565 void Console::discardToPrompt(int conn)
567 DirComm *dircomm = m_dircommHash.value(conn);
570 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
571 if (mainWin->m_displayAll) {
572 displayToPrompt(conn);
574 while (!dircomm->m_at_prompt) {
575 stat=dircomm->read();
578 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
582 * When the notifier is enabled, read_dir() will automatically be
583 * called by the Qt event loop when ever there is any output
584 * from the Directory, and read_dir() will then display it on
587 * When we are in a bat dialog, we want to control *all* output
588 * from the Directory, so we set notify to off.
589 * m_console->notifiy(false);
592 /* dual purpose function to turn notify off and return an available connection */
593 int Console::notifyOff()
596 if(availableDirComm(conn))
601 /* knowing a connection, turn notify off or on */
602 bool Console::notify(int conn, bool enable)
604 DirComm *dircomm = m_dircommHash.value(conn);
605 return dircomm->notify(enable);
608 /* knowing a connection, return notify state */
609 bool Console::is_notify_enabled(int conn) const
611 DirComm *dircomm = m_dircommHash.value(conn);
612 return dircomm->is_notify_enabled();
615 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
617 m_directorTreeItem = item;
620 void Console::setDirRes(DIRRES *dir)
626 * To have the ability to get the name of the director resource.
628 void Console::getDirResName(QString &name_returned)
630 name_returned = m_dir->name();
633 /* Slot for responding to page selectors status help command */
634 void Console::consoleHelp()
640 /* Slot for responding to page selectors reload bacula-dir.conf */
641 void Console::consoleReload()
643 QString cmd("reload");
647 /* For suppressing .messages
648 * This may be rendered not needed if the multiple connections feature gets working */
649 bool Console::hasFocus()
651 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
657 /* For adding feature to have the gui's messages button change when
658 * messages are pending */
659 bool Console::messagesPending(bool pend)
661 bool prev = m_messages_pending;
662 m_messages_pending = pend;
663 mainWin->setMessageIcon();
667 /* terminate all existing connections */
668 void Console::terminate()
670 foreach(DirComm* dircomm, m_dircommHash) {
671 dircomm->terminate();
673 m_console->stopTimer();
676 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
677 bool Console::is_connectedGui()
679 if (is_connected(0)) {
682 QString message = tr("Director is currently disconnected\nPlease reconnect!");
683 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
688 int Console::read(int conn)
690 DirComm *dircomm = m_dircommHash.value(conn);
691 return dircomm->read();
694 char *Console::msg(int conn)
696 DirComm *dircomm = m_dircommHash.value(conn);
697 return dircomm->msg();
700 int Console::write(int conn, const QString msg)
702 DirComm *dircomm = m_dircommHash.value(conn);
703 mainWin->waitEnter();
704 int ret = dircomm->write(msg);
709 int Console::write(int conn, const char *msg)
711 DirComm *dircomm = m_dircommHash.value(conn);
712 mainWin->waitEnter();
713 int ret = dircomm->write(msg);
718 /* This checks to see if any is connected */
719 bool Console::is_connected()
721 bool connected = false;
722 foreach(DirComm* dircomm, m_dircommHash) {
723 if (dircomm->is_connected())
729 /* knowing the connection id, is it connected */
730 bool Console::is_connected(int conn)
732 DirComm *dircomm = m_dircommHash.value(conn);
733 return dircomm->is_connected();
737 * Need an available connection. Check existing connections or create one
739 bool Console::availableDirComm(int &conn)
741 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
742 while (iter != m_dircommHash.constEnd()) {
743 DirComm *dircomm = iter.value();
744 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
745 conn = dircomm->m_conn;
750 if (newDirComm(conn))
757 * Create a new connection
759 bool Console::newDirComm(int &conn)
761 m_dircommCounter += 1;
762 conn = m_dircommCounter;
763 if (mainWin->m_connDebug)
764 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
765 DirComm *dircomm = new DirComm(this, m_dircommCounter);
766 m_dircommHash.insert(m_dircommCounter, dircomm);
767 bool success = dircomm->connect_dir();
768 if (mainWin->m_connDebug)
770 Pmsg1(000, "DirComm %i Connected\n", conn);
772 Pmsg1(000, "DirComm %i NOT Connected\n", conn);