2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2008 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()
94 int conn = availableDirComm();
95 DirComm *dircomm = m_dircommHash.value(conn);
97 if (mainWin->m_checkMessages && dircomm->m_at_main_prompt && hasFocus()){
98 messagesPending(true);
99 dircomm->write(".messages");
100 displayToPrompt(conn);
101 messagesPending(false);
106 * Connect to Director.
108 void Console::connect_dir()
110 DirComm *dircomm = m_dircommHash.value(0);
112 if (!m_console->m_dir) {
113 mainWin->set_status( tr("No Director found."));
117 m_textEdit = textEdit; /* our console screen */
119 if (dircomm->connect_dir()) {
120 if (mainWin->m_connDebug)
121 Pmsg0(000, "DirComm 0 Seems to have Connected\n");
125 fileset_list.clear();
126 fileset_list.clear();
127 messages_list.clear();
129 storage_list.clear();
134 /* this was added because I was getting job lists with 0 count, but not consistently*/
136 dir_cmd(".jobs", job_list);
138 if ((jl > 10) || job_list.count() > 0) done = true;
140 dir_cmd(".clients", client_list);
141 dir_cmd(".filesets", fileset_list);
142 dir_cmd(".msgs", messages_list);
143 dir_cmd(".pools", pool_list);
144 dir_cmd(".storage", storage_list);
145 dir_cmd(".types", type_list);
146 dir_cmd(".levels", level_list);
148 if (mainWin->m_connDebug) {
149 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8\n")
150 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
151 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count());
152 Pmsg1(000, "%s\n", dbgmsg.toUtf8().data());
155 mainWin->set_status(_("Connected"));
156 startTimer(); /* start message timer */
160 bool Console::dir_cmd(QString &cmd, QStringList &results)
162 return dir_cmd(cmd.toUtf8().data(), results);
166 * Send a command to the Director, and return the
167 * results in a QStringList.
169 bool Console::dir_cmd(const char *cmd, QStringList &results)
171 int conn = availableDirComm();
173 DirComm *dircomm = m_dircommHash.value(conn);
175 if (mainWin->m_connDebug)
176 Pmsg2(000, "dir_cmd conn %i %s\n", conn, cmd);
179 while ((stat = dircomm->read()) > 0) {
180 if (mainWin->m_displayAll) display_text(dircomm->msg());
181 strip_trailing_junk(dircomm->msg());
182 results << dircomm->msg();
185 discardToPrompt(conn);
186 return true; /* ***FIXME*** return any command error */
189 bool Console::sql_cmd(QString &query, QStringList &results)
191 return sql_cmd(query.toUtf8().data(), results);
195 * Send an sql query to the Director, and return the
196 * results in a QStringList.
198 bool Console::sql_cmd(const char *query, QStringList &results)
200 int conn = availableDirComm();
201 DirComm *dircomm = m_dircommHash.value(conn);
203 POOL_MEM cmd(PM_MESSAGE);
205 if (!is_connectedGui()) {
209 if (mainWin->m_connDebug)
210 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
213 pm_strcpy(cmd, ".sql query=\"");
214 pm_strcat(cmd, query);
215 pm_strcat(cmd, "\"");
216 dircomm->write(cmd.c_str());
217 while ((stat = dircomm->read()) > 0) {
219 if (mainWin->m_displayAll) {
220 display_text(dircomm->msg());
223 strip_trailing_junk(dircomm->msg());
224 bool doappend = true;
226 QString dum = dircomm->msg();
227 if ((dum.left(6) == "*None*")) doappend = false;
230 results << dircomm->msg();
234 discardToPrompt(conn);
235 return true; /* ***FIXME*** return any command error */
238 /* Send a command to the Director */
239 int Console::write_dir(const char *msg)
241 int conn = availableDirComm();
242 write_dir(conn, msg);
246 /* Send a command to the Director */
247 void Console::write_dir(int conn, const char *msg)
249 DirComm *dircomm = m_dircommHash.value(conn);
251 if (dircomm->m_sock) {
252 mainWin->set_status(_("Processing command ..."));
253 QApplication::setOverrideCursor(Qt::WaitCursor);
256 mainWin->set_status( tr(" Director not connected. Click on connect button."));
257 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
258 QBrush redBrush(Qt::red);
259 QTreeWidgetItem *item = mainWin->getFromHash(this);
260 item->setForeground(0, redBrush);
261 dircomm->m_at_prompt = false;
262 dircomm->m_at_main_prompt = false;
267 * Send a job name to the director, and read all the resulting
270 bool Console::get_job_defaults(struct job_defaults &job_defs)
276 int conn = notifyOff();
277 beginNewCommand(conn);
278 DirComm *dircomm = m_dircommHash.value(conn);
279 if (mainWin->m_connDebug)
280 Pmsg1(000, "job_defaults conn %i\n", conn);
281 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
282 dircomm->write(scmd);
283 while ((stat = dircomm->read()) > 0) {
284 if (mainWin->m_displayAll) display_text(dircomm->msg());
285 def = strchr(dircomm->msg(), '=');
289 /* Pointer to default value */
291 strip_trailing_junk(def);
293 if (strcmp(dircomm->msg(), "job") == 0) {
294 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
299 if (strcmp(dircomm->msg(), "pool") == 0) {
300 job_defs.pool_name = def;
303 if (strcmp(dircomm->msg(), "messages") == 0) {
304 job_defs.messages_name = def;
307 if (strcmp(dircomm->msg(), "client") == 0) {
308 job_defs.client_name = def;
311 if (strcmp(dircomm->msg(), "storage") == 0) {
312 job_defs.store_name = def;
315 if (strcmp(dircomm->msg(), "where") == 0) {
316 job_defs.where = def;
319 if (strcmp(dircomm->msg(), "level") == 0) {
320 job_defs.level = def;
323 if (strcmp(dircomm->msg(), "type") == 0) {
327 if (strcmp(dircomm->msg(), "fileset") == 0) {
328 job_defs.fileset_name = def;
331 if (strcmp(dircomm->msg(), "catalog") == 0) {
332 job_defs.catalog_name = def;
335 if (strcmp(dircomm->msg(), "enabled") == 0) {
336 job_defs.enabled = *def == '1' ? true : false;
351 * Save user settings associated with this console
353 void Console::writeSettings()
355 QFont font = get_font();
357 QSettings settings(m_dir->name(), "bat");
358 settings.beginGroup("Console");
359 settings.setValue("consoleFont", font.family());
360 settings.setValue("consolePointSize", font.pointSize());
361 settings.setValue("consoleFixedPitch", font.fixedPitch());
366 * Read and restore user settings associated with this console
368 void Console::readSettings()
370 QFont font = get_font();
372 QSettings settings(m_dir->name(), "bat");
373 settings.beginGroup("Console");
374 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
375 font.setPointSize(settings.value("consolePointSize", 10).toInt());
376 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
378 m_textEdit->setFont(font);
382 * Set the console textEdit font
384 void Console::set_font()
387 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
389 m_textEdit->setFont(font);
394 * Get the console text edit font
396 const QFont Console::get_font()
398 return m_textEdit->font();
402 * Slot for responding to status dir button on button bar
404 void Console::status_dir()
406 QString cmd("status dir");
411 * Slot for responding to messages button on button bar
412 * Here we want to bring the console to the front so use pages' consoleCommand
414 void Console::messages()
416 QString cmd(".messages");
418 messagesPending(false);
422 * Put text into the console window
424 void Console::display_textf(const char *fmt, ...)
429 va_start(arg_ptr, fmt);
430 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
435 void Console::display_text(const QString buf)
437 m_cursor->insertText(buf);
442 void Console::display_text(const char *buf)
444 m_cursor->insertText(buf);
448 void Console::display_html(const QString buf)
450 m_cursor->insertHtml(buf);
454 /* Position cursor to end of screen */
455 void Console::update_cursor()
457 QApplication::restoreOverrideCursor();
458 m_textEdit->moveCursor(QTextCursor::End);
459 m_textEdit->ensureCursorVisible();
462 void Console::beginNewCommand(int conn)
464 DirComm *dircomm = m_dircommHash.value(conn);
466 for (int i=0; i < 3; i++) {
468 while (dircomm->read() > 0) {
469 if (mainWin->m_displayAll) display_text(dircomm->msg());
471 if (dircomm->m_at_main_prompt) {
478 void Console::displayToPrompt(int conn)
480 DirComm *dircomm = m_dircommHash.value(conn);
484 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
485 while (!dircomm->m_at_prompt) {
486 if ((stat=dircomm->read()) > 0) {
487 buf += dircomm->msg();
488 if (buf.size() >= 8196 || m_messages_pending) {
491 messagesPending(false);
496 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
499 void Console::discardToPrompt(int conn)
501 DirComm *dircomm = m_dircommHash.value(conn);
504 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
505 if (mainWin->m_displayAll) {
506 displayToPrompt(conn);
508 while (!dircomm->m_at_prompt) {
509 stat=dircomm->read();
512 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
516 * When the notifier is enabled, read_dir() will automatically be
517 * called by the Qt event loop when ever there is any output
518 * from the Directory, and read_dir() will then display it on
521 * When we are in a bat dialog, we want to control *all* output
522 * from the Directory, so we set notify to off.
523 * m_console->notifiy(false);
526 /* dual purpose function to turn notify off and return an available connection */
527 int Console::notifyOff()
529 int conn = availableDirComm();
534 /* knowing a connection, turn notify off or on */
535 bool Console::notify(int conn, bool enable)
537 DirComm *dircomm = m_dircommHash.value(conn);
538 return dircomm->notify(enable);
541 /* knowing a connection, return notify state */
542 bool Console::is_notify_enabled(int conn) const
544 DirComm *dircomm = m_dircommHash.value(conn);
545 return dircomm->is_notify_enabled();
548 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
550 m_directorTreeItem = item;
553 void Console::setDirRes(DIRRES *dir)
559 * To have the ability to get the name of the director resource.
561 void Console::getDirResName(QString &name_returned)
563 name_returned = m_dir->name();
566 /* Slot for responding to page selectors status help command */
567 void Console::consoleHelp()
573 /* Slot for responding to page selectors reload bacula-dir.conf */
574 void Console::consoleReload()
576 QString cmd("reload");
580 /* Function to get a list of volumes */
581 void Console::getVolumeList(QStringList &volumeList)
583 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
584 if (mainWin->m_sqlDebug) {
585 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
588 if (sql_cmd(query, results)) {
590 QStringList fieldlist;
591 /* Iterate through the lines of results. */
592 foreach (QString resultline, results) {
593 fieldlist = resultline.split("\t");
594 volumeList.append(fieldlist[0]);
595 } /* foreach resultline */
596 } /* if results from query */
599 /* Function to get a list of volumes */
600 void Console::getStatusList(QStringList &statusLongList)
602 QString statusQuery("SELECT JobStatusLong FROM Status");
603 if (mainWin->m_sqlDebug) {
604 Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
606 QStringList statusResults;
607 if (sql_cmd(statusQuery, statusResults)) {
609 QStringList fieldlist;
610 /* Iterate through the lines of results. */
611 foreach (QString resultline, statusResults) {
612 fieldlist = resultline.split("\t");
613 statusLongList.append(fieldlist[0]);
614 } /* foreach resultline */
615 } /* if results from statusquery */
618 /* For suppressing .messages
619 * This may be rendered not needed if the multiple connections feature gets working */
620 bool Console::hasFocus()
622 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
628 /* For adding feature to have the gui's messages button change when
629 * messages are pending */
630 bool Console::messagesPending(bool pend)
632 bool prev = m_messages_pending;
633 m_messages_pending = pend;
634 mainWin->setMessageIcon();
638 /* terminate all existing connections */
639 void Console::terminate()
641 foreach(DirComm* dircomm, m_dircommHash) {
642 dircomm->terminate();
644 m_console->stopTimer();
647 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
648 bool Console::is_connectedGui()
650 if (is_connected(0)) {
653 QString message = tr("Director is currently disconnected\nPlease reconnect!");
654 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
659 int Console::read(int conn)
661 DirComm *dircomm = m_dircommHash.value(conn);
662 return dircomm->read();
665 char *Console::msg(int conn)
667 DirComm *dircomm = m_dircommHash.value(conn);
668 return dircomm->msg();
671 int Console::write(int conn, const QString msg)
673 DirComm *dircomm = m_dircommHash.value(conn);
674 return dircomm->write(msg);
677 int Console::write(int conn, const char *msg)
679 DirComm *dircomm = m_dircommHash.value(conn);
680 return dircomm->write(msg);
683 /* This checks to see if any is connected */
684 bool Console::is_connected()
686 bool connected = false;
687 foreach(DirComm* dircomm, m_dircommHash) {
688 if (dircomm->is_connected())
694 /* knowing the connection id, is it connected */
695 bool Console::is_connected(int conn)
697 DirComm *dircomm = m_dircommHash.value(conn);
698 return dircomm->is_connected();
702 * Need an available connection. Check existing connections or create one
704 int Console::availableDirComm()
706 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
707 while (iter != m_dircommHash.constEnd()) {
708 DirComm *dircomm = iter.value();
709 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled())
710 return dircomm->m_conn;
717 * Create a new connection
719 int Console::newDirComm()
721 m_dircommCounter += 1;
722 if (mainWin->m_connDebug)
723 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
724 DirComm *dircomm = new DirComm(this, m_dircommCounter);
725 m_dircommHash.insert(m_dircommCounter, dircomm);
726 bool success = dircomm->connect_dir();
727 if (mainWin->m_connDebug)
729 Pmsg1(000, "DirComm %i Connected\n", m_dircommCounter);
731 Pmsg1(000, "DirComm %i NOT Connected\n", m_dircommCounter);
732 return m_dircommCounter;