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 */
213 * OverLoads for sql_cmd
215 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
217 return sql_cmd(conn, query.toUtf8().data(), results, false);
220 bool Console::sql_cmd(QString &query, QStringList &results)
223 if (!availableDirComm(conn))
225 return sql_cmd(conn, query.toUtf8().data(), results, true);
228 bool Console::sql_cmd(const char *query, QStringList &results)
231 if (!availableDirComm(conn))
233 return sql_cmd(conn, query, results, true);
237 * Send an sql query to the Director, and return the
238 * results in a QStringList.
240 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
242 DirComm *dircomm = m_dircommHash.value(conn);
244 POOL_MEM cmd(PM_MESSAGE);
246 if (!is_connectedGui()) {
250 if (mainWin->m_connDebug)
251 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
253 dircomm->notify(false);
255 pm_strcpy(cmd, ".sql query=\"");
256 pm_strcat(cmd, query);
257 pm_strcat(cmd, "\"");
258 dircomm->write(cmd.c_str());
259 while ((stat = dircomm->read()) > 0) {
261 if (mainWin->m_displayAll) {
262 display_text(dircomm->msg());
265 strip_trailing_junk(dircomm->msg());
266 bool doappend = true;
268 QString dum = dircomm->msg();
269 if ((dum.left(6) == "*None*")) doappend = false;
272 results << dircomm->msg();
276 dircomm->notify(true);
277 discardToPrompt(conn);
278 return true; /* ***FIXME*** return any command error */
281 /* Send a command to the Director */
282 int Console::write_dir(const char *msg)
285 if(availableDirComm(conn))
286 write_dir(conn, msg);
290 /* Send a command to the Director */
291 void Console::write_dir(int conn, const char *msg)
293 DirComm *dircomm = m_dircommHash.value(conn);
295 if (dircomm->m_sock) {
296 mainWin->set_status(_("Processing command ..."));
297 QApplication::setOverrideCursor(Qt::WaitCursor);
300 mainWin->set_status( tr(" Director not connected. Click on connect button."));
301 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
302 QBrush redBrush(Qt::red);
303 QTreeWidgetItem *item = mainWin->getFromHash(this);
304 item->setForeground(0, redBrush);
305 dircomm->m_at_prompt = false;
306 dircomm->m_at_main_prompt = false;
311 * get_job_defaults overload
313 bool Console::get_job_defaults(struct job_defaults &job_defs)
316 return get_job_defaults(conn, job_defs, true);
319 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
321 return get_job_defaults(conn, job_defs, false);
325 * Send a job name to the director, and read all the resulting
328 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
336 beginNewCommand(conn);
337 DirComm *dircomm = m_dircommHash.value(conn);
338 if (mainWin->m_connDebug)
339 Pmsg1(000, "job_defaults conn %i\n", conn);
340 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
341 dircomm->write(scmd);
342 while ((stat = dircomm->read()) > 0) {
343 if (mainWin->m_displayAll) display_text(dircomm->msg());
344 def = strchr(dircomm->msg(), '=');
348 /* Pointer to default value */
350 strip_trailing_junk(def);
352 if (strcmp(dircomm->msg(), "job") == 0) {
353 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
358 if (strcmp(dircomm->msg(), "pool") == 0) {
359 job_defs.pool_name = def;
362 if (strcmp(dircomm->msg(), "messages") == 0) {
363 job_defs.messages_name = def;
366 if (strcmp(dircomm->msg(), "client") == 0) {
367 job_defs.client_name = def;
370 if (strcmp(dircomm->msg(), "storage") == 0) {
371 job_defs.store_name = def;
374 if (strcmp(dircomm->msg(), "where") == 0) {
375 job_defs.where = def;
378 if (strcmp(dircomm->msg(), "level") == 0) {
379 job_defs.level = def;
382 if (strcmp(dircomm->msg(), "type") == 0) {
386 if (strcmp(dircomm->msg(), "fileset") == 0) {
387 job_defs.fileset_name = def;
390 if (strcmp(dircomm->msg(), "catalog") == 0) {
391 job_defs.catalog_name = def;
394 if (strcmp(dircomm->msg(), "enabled") == 0) {
395 job_defs.enabled = *def == '1' ? true : false;
412 * Save user settings associated with this console
414 void Console::writeSettings()
416 QFont font = get_font();
418 QSettings settings(m_dir->name(), "bat");
419 settings.beginGroup("Console");
420 settings.setValue("consoleFont", font.family());
421 settings.setValue("consolePointSize", font.pointSize());
422 settings.setValue("consoleFixedPitch", font.fixedPitch());
427 * Read and restore user settings associated with this console
429 void Console::readSettings()
431 QFont font = get_font();
433 QSettings settings(m_dir->name(), "bat");
434 settings.beginGroup("Console");
435 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
436 font.setPointSize(settings.value("consolePointSize", 10).toInt());
437 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
439 m_textEdit->setFont(font);
443 * Set the console textEdit font
445 void Console::set_font()
448 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
450 m_textEdit->setFont(font);
455 * Get the console text edit font
457 const QFont Console::get_font()
459 return m_textEdit->font();
463 * Slot for responding to status dir button on button bar
465 void Console::status_dir()
467 QString cmd("status dir");
472 * Slot for responding to messages button on button bar
473 * Here we want to bring the console to the front so use pages' consoleCommand
475 void Console::messages()
477 QString cmd(".messages");
479 messagesPending(false);
483 * Put text into the console window
485 void Console::display_textf(const char *fmt, ...)
490 va_start(arg_ptr, fmt);
491 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
496 void Console::display_text(const QString buf)
498 m_cursor->insertText(buf);
503 void Console::display_text(const char *buf)
505 m_cursor->insertText(buf);
509 void Console::display_html(const QString buf)
511 m_cursor->insertHtml(buf);
515 /* Position cursor to end of screen */
516 void Console::update_cursor()
518 QApplication::restoreOverrideCursor();
519 m_textEdit->moveCursor(QTextCursor::End);
520 m_textEdit->ensureCursorVisible();
523 void Console::beginNewCommand(int conn)
525 DirComm *dircomm = m_dircommHash.value(conn);
527 for (int i=0; i < 3; i++) {
529 while (dircomm->read() > 0) {
530 if (mainWin->m_displayAll) display_text(dircomm->msg());
532 if (dircomm->m_at_main_prompt) {
539 void Console::displayToPrompt(int conn)
541 DirComm *dircomm = m_dircommHash.value(conn);
545 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
546 while (!dircomm->m_at_prompt) {
547 if ((stat=dircomm->read()) > 0) {
548 buf += dircomm->msg();
549 if (buf.size() >= 8196 || m_messages_pending) {
552 messagesPending(false);
557 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
560 void Console::discardToPrompt(int conn)
562 DirComm *dircomm = m_dircommHash.value(conn);
565 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
566 if (mainWin->m_displayAll) {
567 displayToPrompt(conn);
569 while (!dircomm->m_at_prompt) {
570 stat=dircomm->read();
573 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
577 * When the notifier is enabled, read_dir() will automatically be
578 * called by the Qt event loop when ever there is any output
579 * from the Directory, and read_dir() will then display it on
582 * When we are in a bat dialog, we want to control *all* output
583 * from the Directory, so we set notify to off.
584 * m_console->notifiy(false);
587 /* dual purpose function to turn notify off and return an available connection */
588 int Console::notifyOff()
591 if(availableDirComm(conn))
596 /* knowing a connection, turn notify off or on */
597 bool Console::notify(int conn, bool enable)
599 DirComm *dircomm = m_dircommHash.value(conn);
600 return dircomm->notify(enable);
603 /* knowing a connection, return notify state */
604 bool Console::is_notify_enabled(int conn) const
606 DirComm *dircomm = m_dircommHash.value(conn);
607 return dircomm->is_notify_enabled();
610 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
612 m_directorTreeItem = item;
615 void Console::setDirRes(DIRRES *dir)
621 * To have the ability to get the name of the director resource.
623 void Console::getDirResName(QString &name_returned)
625 name_returned = m_dir->name();
628 /* Slot for responding to page selectors status help command */
629 void Console::consoleHelp()
635 /* Slot for responding to page selectors reload bacula-dir.conf */
636 void Console::consoleReload()
638 QString cmd("reload");
642 /* Function to get a list of volumes */
643 void Console::getVolumeList(QStringList &volumeList)
645 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
646 if (mainWin->m_sqlDebug) {
647 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
650 if (sql_cmd(query, results)) {
652 QStringList fieldlist;
653 /* Iterate through the lines of results. */
654 foreach (QString resultline, results) {
655 fieldlist = resultline.split("\t");
656 volumeList.append(fieldlist[0]);
657 } /* foreach resultline */
658 } /* if results from query */
661 /* Function to get a list of volumes */
662 void Console::getStatusList(QStringList &statusLongList)
664 QString statusQuery("SELECT JobStatusLong FROM Status");
665 if (mainWin->m_sqlDebug) {
666 Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
668 QStringList statusResults;
669 if (sql_cmd(statusQuery, statusResults)) {
671 QStringList fieldlist;
672 /* Iterate through the lines of results. */
673 foreach (QString resultline, statusResults) {
674 fieldlist = resultline.split("\t");
675 statusLongList.append(fieldlist[0]);
676 } /* foreach resultline */
677 } /* if results from statusquery */
680 /* For suppressing .messages
681 * This may be rendered not needed if the multiple connections feature gets working */
682 bool Console::hasFocus()
684 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
690 /* For adding feature to have the gui's messages button change when
691 * messages are pending */
692 bool Console::messagesPending(bool pend)
694 bool prev = m_messages_pending;
695 m_messages_pending = pend;
696 mainWin->setMessageIcon();
700 /* terminate all existing connections */
701 void Console::terminate()
703 foreach(DirComm* dircomm, m_dircommHash) {
704 dircomm->terminate();
706 m_console->stopTimer();
709 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
710 bool Console::is_connectedGui()
712 if (is_connected(0)) {
715 QString message = tr("Director is currently disconnected\nPlease reconnect!");
716 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
721 int Console::read(int conn)
723 DirComm *dircomm = m_dircommHash.value(conn);
724 return dircomm->read();
727 char *Console::msg(int conn)
729 DirComm *dircomm = m_dircommHash.value(conn);
730 return dircomm->msg();
733 int Console::write(int conn, const QString msg)
735 DirComm *dircomm = m_dircommHash.value(conn);
736 return dircomm->write(msg);
739 int Console::write(int conn, const char *msg)
741 DirComm *dircomm = m_dircommHash.value(conn);
742 return dircomm->write(msg);
745 /* This checks to see if any is connected */
746 bool Console::is_connected()
748 bool connected = false;
749 foreach(DirComm* dircomm, m_dircommHash) {
750 if (dircomm->is_connected())
756 /* knowing the connection id, is it connected */
757 bool Console::is_connected(int conn)
759 DirComm *dircomm = m_dircommHash.value(conn);
760 return dircomm->is_connected();
764 * Need an available connection. Check existing connections or create one
766 bool Console::availableDirComm(int &conn)
768 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
769 while (iter != m_dircommHash.constEnd()) {
770 DirComm *dircomm = iter.value();
771 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
772 conn = dircomm->m_conn;
777 if (newDirComm(conn))
784 * Create a new connection
786 bool Console::newDirComm(int &conn)
788 m_dircommCounter += 1;
789 conn = m_dircommCounter;
790 if (mainWin->m_connDebug)
791 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
792 DirComm *dircomm = new DirComm(this, m_dircommCounter);
793 m_dircommHash.insert(m_dircommCounter, dircomm);
794 bool success = dircomm->connect_dir();
795 if (mainWin->m_connDebug)
797 Pmsg1(000, "DirComm %i Connected\n", conn);
799 Pmsg1(000, "DirComm %i NOT Connected\n", conn);