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 DirComm *dircomm = m_dircommHash.value(conn);
197 if (mainWin->m_connDebug)
198 Pmsg2(000, "dir_cmd conn %i %s\n", conn, cmd);
201 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
202 if (mainWin->m_displayAll) display_text(dircomm->msg());
203 strip_trailing_junk(dircomm->msg());
204 results << dircomm->msg();
206 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
208 discardToPrompt(conn);
209 return true; /* ***FIXME*** return any command error */
212 bool Console::sql_cmd(QString &query, QStringList &results)
214 return sql_cmd(query.toUtf8().data(), results);
218 * Send an sql query to the Director, and return the
219 * results in a QStringList.
221 bool Console::sql_cmd(const char *query, QStringList &results)
224 if (!availableDirComm(conn))
227 DirComm *dircomm = m_dircommHash.value(conn);
229 POOL_MEM cmd(PM_MESSAGE);
231 if (!is_connectedGui()) {
235 if (mainWin->m_connDebug)
236 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
239 pm_strcpy(cmd, ".sql query=\"");
240 pm_strcat(cmd, query);
241 pm_strcat(cmd, "\"");
242 dircomm->write(cmd.c_str());
243 while ((stat = dircomm->read()) > 0) {
245 if (mainWin->m_displayAll) {
246 display_text(dircomm->msg());
249 strip_trailing_junk(dircomm->msg());
250 bool doappend = true;
252 QString dum = dircomm->msg();
253 if ((dum.left(6) == "*None*")) doappend = false;
256 results << dircomm->msg();
260 discardToPrompt(conn);
261 return true; /* ***FIXME*** return any command error */
264 /* Send a command to the Director */
265 int Console::write_dir(const char *msg)
268 if(availableDirComm(conn))
269 write_dir(conn, msg);
273 /* Send a command to the Director */
274 void Console::write_dir(int conn, const char *msg)
276 DirComm *dircomm = m_dircommHash.value(conn);
278 if (dircomm->m_sock) {
279 mainWin->set_status(_("Processing command ..."));
280 QApplication::setOverrideCursor(Qt::WaitCursor);
283 mainWin->set_status( tr(" Director not connected. Click on connect button."));
284 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
285 QBrush redBrush(Qt::red);
286 QTreeWidgetItem *item = mainWin->getFromHash(this);
287 item->setForeground(0, redBrush);
288 dircomm->m_at_prompt = false;
289 dircomm->m_at_main_prompt = false;
294 * Send a job name to the director, and read all the resulting
297 bool Console::get_job_defaults(struct job_defaults &job_defs)
303 int conn = notifyOff();
304 beginNewCommand(conn);
305 DirComm *dircomm = m_dircommHash.value(conn);
306 if (mainWin->m_connDebug)
307 Pmsg1(000, "job_defaults conn %i\n", conn);
308 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
309 dircomm->write(scmd);
310 while ((stat = dircomm->read()) > 0) {
311 if (mainWin->m_displayAll) display_text(dircomm->msg());
312 def = strchr(dircomm->msg(), '=');
316 /* Pointer to default value */
318 strip_trailing_junk(def);
320 if (strcmp(dircomm->msg(), "job") == 0) {
321 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
326 if (strcmp(dircomm->msg(), "pool") == 0) {
327 job_defs.pool_name = def;
330 if (strcmp(dircomm->msg(), "messages") == 0) {
331 job_defs.messages_name = def;
334 if (strcmp(dircomm->msg(), "client") == 0) {
335 job_defs.client_name = def;
338 if (strcmp(dircomm->msg(), "storage") == 0) {
339 job_defs.store_name = def;
342 if (strcmp(dircomm->msg(), "where") == 0) {
343 job_defs.where = def;
346 if (strcmp(dircomm->msg(), "level") == 0) {
347 job_defs.level = def;
350 if (strcmp(dircomm->msg(), "type") == 0) {
354 if (strcmp(dircomm->msg(), "fileset") == 0) {
355 job_defs.fileset_name = def;
358 if (strcmp(dircomm->msg(), "catalog") == 0) {
359 job_defs.catalog_name = def;
362 if (strcmp(dircomm->msg(), "enabled") == 0) {
363 job_defs.enabled = *def == '1' ? true : false;
378 * Save user settings associated with this console
380 void Console::writeSettings()
382 QFont font = get_font();
384 QSettings settings(m_dir->name(), "bat");
385 settings.beginGroup("Console");
386 settings.setValue("consoleFont", font.family());
387 settings.setValue("consolePointSize", font.pointSize());
388 settings.setValue("consoleFixedPitch", font.fixedPitch());
393 * Read and restore user settings associated with this console
395 void Console::readSettings()
397 QFont font = get_font();
399 QSettings settings(m_dir->name(), "bat");
400 settings.beginGroup("Console");
401 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
402 font.setPointSize(settings.value("consolePointSize", 10).toInt());
403 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
405 m_textEdit->setFont(font);
409 * Set the console textEdit font
411 void Console::set_font()
414 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
416 m_textEdit->setFont(font);
421 * Get the console text edit font
423 const QFont Console::get_font()
425 return m_textEdit->font();
429 * Slot for responding to status dir button on button bar
431 void Console::status_dir()
433 QString cmd("status dir");
438 * Slot for responding to messages button on button bar
439 * Here we want to bring the console to the front so use pages' consoleCommand
441 void Console::messages()
443 QString cmd(".messages");
445 messagesPending(false);
449 * Put text into the console window
451 void Console::display_textf(const char *fmt, ...)
456 va_start(arg_ptr, fmt);
457 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
462 void Console::display_text(const QString buf)
464 m_cursor->insertText(buf);
469 void Console::display_text(const char *buf)
471 m_cursor->insertText(buf);
475 void Console::display_html(const QString buf)
477 m_cursor->insertHtml(buf);
481 /* Position cursor to end of screen */
482 void Console::update_cursor()
484 QApplication::restoreOverrideCursor();
485 m_textEdit->moveCursor(QTextCursor::End);
486 m_textEdit->ensureCursorVisible();
489 void Console::beginNewCommand(int conn)
491 DirComm *dircomm = m_dircommHash.value(conn);
493 for (int i=0; i < 3; i++) {
495 while (dircomm->read() > 0) {
496 if (mainWin->m_displayAll) display_text(dircomm->msg());
498 if (dircomm->m_at_main_prompt) {
505 void Console::displayToPrompt(int conn)
507 DirComm *dircomm = m_dircommHash.value(conn);
511 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
512 while (!dircomm->m_at_prompt) {
513 if ((stat=dircomm->read()) > 0) {
514 buf += dircomm->msg();
515 if (buf.size() >= 8196 || m_messages_pending) {
518 messagesPending(false);
523 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
526 void Console::discardToPrompt(int conn)
528 DirComm *dircomm = m_dircommHash.value(conn);
531 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
532 if (mainWin->m_displayAll) {
533 displayToPrompt(conn);
535 while (!dircomm->m_at_prompt) {
536 stat=dircomm->read();
539 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
543 * When the notifier is enabled, read_dir() will automatically be
544 * called by the Qt event loop when ever there is any output
545 * from the Directory, and read_dir() will then display it on
548 * When we are in a bat dialog, we want to control *all* output
549 * from the Directory, so we set notify to off.
550 * m_console->notifiy(false);
553 /* dual purpose function to turn notify off and return an available connection */
554 int Console::notifyOff()
557 if(availableDirComm(conn))
562 /* knowing a connection, turn notify off or on */
563 bool Console::notify(int conn, bool enable)
565 DirComm *dircomm = m_dircommHash.value(conn);
566 return dircomm->notify(enable);
569 /* knowing a connection, return notify state */
570 bool Console::is_notify_enabled(int conn) const
572 DirComm *dircomm = m_dircommHash.value(conn);
573 return dircomm->is_notify_enabled();
576 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
578 m_directorTreeItem = item;
581 void Console::setDirRes(DIRRES *dir)
587 * To have the ability to get the name of the director resource.
589 void Console::getDirResName(QString &name_returned)
591 name_returned = m_dir->name();
594 /* Slot for responding to page selectors status help command */
595 void Console::consoleHelp()
601 /* Slot for responding to page selectors reload bacula-dir.conf */
602 void Console::consoleReload()
604 QString cmd("reload");
608 /* Function to get a list of volumes */
609 void Console::getVolumeList(QStringList &volumeList)
611 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
612 if (mainWin->m_sqlDebug) {
613 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
616 if (sql_cmd(query, results)) {
618 QStringList fieldlist;
619 /* Iterate through the lines of results. */
620 foreach (QString resultline, results) {
621 fieldlist = resultline.split("\t");
622 volumeList.append(fieldlist[0]);
623 } /* foreach resultline */
624 } /* if results from query */
627 /* Function to get a list of volumes */
628 void Console::getStatusList(QStringList &statusLongList)
630 QString statusQuery("SELECT JobStatusLong FROM Status");
631 if (mainWin->m_sqlDebug) {
632 Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
634 QStringList statusResults;
635 if (sql_cmd(statusQuery, statusResults)) {
637 QStringList fieldlist;
638 /* Iterate through the lines of results. */
639 foreach (QString resultline, statusResults) {
640 fieldlist = resultline.split("\t");
641 statusLongList.append(fieldlist[0]);
642 } /* foreach resultline */
643 } /* if results from statusquery */
646 /* For suppressing .messages
647 * This may be rendered not needed if the multiple connections feature gets working */
648 bool Console::hasFocus()
650 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
656 /* For adding feature to have the gui's messages button change when
657 * messages are pending */
658 bool Console::messagesPending(bool pend)
660 bool prev = m_messages_pending;
661 m_messages_pending = pend;
662 mainWin->setMessageIcon();
666 /* terminate all existing connections */
667 void Console::terminate()
669 foreach(DirComm* dircomm, m_dircommHash) {
670 dircomm->terminate();
672 m_console->stopTimer();
675 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
676 bool Console::is_connectedGui()
678 if (is_connected(0)) {
681 QString message = tr("Director is currently disconnected\nPlease reconnect!");
682 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
687 int Console::read(int conn)
689 DirComm *dircomm = m_dircommHash.value(conn);
690 return dircomm->read();
693 char *Console::msg(int conn)
695 DirComm *dircomm = m_dircommHash.value(conn);
696 return dircomm->msg();
699 int Console::write(int conn, const QString msg)
701 DirComm *dircomm = m_dircommHash.value(conn);
702 return dircomm->write(msg);
705 int Console::write(int conn, const char *msg)
707 DirComm *dircomm = m_dircommHash.value(conn);
708 return dircomm->write(msg);
711 /* This checks to see if any is connected */
712 bool Console::is_connected()
714 bool connected = false;
715 foreach(DirComm* dircomm, m_dircommHash) {
716 if (dircomm->is_connected())
722 /* knowing the connection id, is it connected */
723 bool Console::is_connected(int conn)
725 DirComm *dircomm = m_dircommHash.value(conn);
726 return dircomm->is_connected();
730 * Need an available connection. Check existing connections or create one
732 bool Console::availableDirComm(int &conn)
734 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
735 while (iter != m_dircommHash.constEnd()) {
736 DirComm *dircomm = iter.value();
737 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
738 conn = dircomm->m_conn;
743 if (newDirComm(conn))
750 * Create a new connection
752 bool Console::newDirComm(int &conn)
754 m_dircommCounter += 1;
755 conn = m_dircommCounter;
756 if (mainWin->m_connDebug)
757 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
758 DirComm *dircomm = new DirComm(this, m_dircommCounter);
759 m_dircommHash.insert(m_dircommCounter, dircomm);
760 bool success = dircomm->connect_dir();
761 if (mainWin->m_connDebug)
763 Pmsg1(000, "DirComm %i Connected\n", conn);
765 Pmsg1(000, "DirComm %i NOT Connected\n", conn);