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()
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 && dircomm->is_in_command()) {
180 if (mainWin->m_displayAll) display_text(dircomm->msg());
181 strip_trailing_junk(dircomm->msg());
182 results << dircomm->msg();
184 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
186 discardToPrompt(conn);
187 return true; /* ***FIXME*** return any command error */
190 bool Console::sql_cmd(QString &query, QStringList &results)
192 return sql_cmd(query.toUtf8().data(), results);
196 * Send an sql query to the Director, and return the
197 * results in a QStringList.
199 bool Console::sql_cmd(const char *query, QStringList &results)
201 int conn = availableDirComm();
202 DirComm *dircomm = m_dircommHash.value(conn);
204 POOL_MEM cmd(PM_MESSAGE);
206 if (!is_connectedGui()) {
210 if (mainWin->m_connDebug)
211 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
214 pm_strcpy(cmd, ".sql query=\"");
215 pm_strcat(cmd, query);
216 pm_strcat(cmd, "\"");
217 dircomm->write(cmd.c_str());
218 while ((stat = dircomm->read()) > 0) {
220 if (mainWin->m_displayAll) {
221 display_text(dircomm->msg());
224 strip_trailing_junk(dircomm->msg());
225 bool doappend = true;
227 QString dum = dircomm->msg();
228 if ((dum.left(6) == "*None*")) doappend = false;
231 results << dircomm->msg();
235 discardToPrompt(conn);
236 return true; /* ***FIXME*** return any command error */
239 /* Send a command to the Director */
240 int Console::write_dir(const char *msg)
242 int conn = availableDirComm();
243 write_dir(conn, msg);
247 /* Send a command to the Director */
248 void Console::write_dir(int conn, const char *msg)
250 DirComm *dircomm = m_dircommHash.value(conn);
252 if (dircomm->m_sock) {
253 mainWin->set_status(_("Processing command ..."));
254 QApplication::setOverrideCursor(Qt::WaitCursor);
257 mainWin->set_status( tr(" Director not connected. Click on connect button."));
258 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
259 QBrush redBrush(Qt::red);
260 QTreeWidgetItem *item = mainWin->getFromHash(this);
261 item->setForeground(0, redBrush);
262 dircomm->m_at_prompt = false;
263 dircomm->m_at_main_prompt = false;
268 * Send a job name to the director, and read all the resulting
271 bool Console::get_job_defaults(struct job_defaults &job_defs)
277 int conn = notifyOff();
278 beginNewCommand(conn);
279 DirComm *dircomm = m_dircommHash.value(conn);
280 if (mainWin->m_connDebug)
281 Pmsg1(000, "job_defaults conn %i\n", conn);
282 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
283 dircomm->write(scmd);
284 while ((stat = dircomm->read()) > 0) {
285 if (mainWin->m_displayAll) display_text(dircomm->msg());
286 def = strchr(dircomm->msg(), '=');
290 /* Pointer to default value */
292 strip_trailing_junk(def);
294 if (strcmp(dircomm->msg(), "job") == 0) {
295 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
300 if (strcmp(dircomm->msg(), "pool") == 0) {
301 job_defs.pool_name = def;
304 if (strcmp(dircomm->msg(), "messages") == 0) {
305 job_defs.messages_name = def;
308 if (strcmp(dircomm->msg(), "client") == 0) {
309 job_defs.client_name = def;
312 if (strcmp(dircomm->msg(), "storage") == 0) {
313 job_defs.store_name = def;
316 if (strcmp(dircomm->msg(), "where") == 0) {
317 job_defs.where = def;
320 if (strcmp(dircomm->msg(), "level") == 0) {
321 job_defs.level = def;
324 if (strcmp(dircomm->msg(), "type") == 0) {
328 if (strcmp(dircomm->msg(), "fileset") == 0) {
329 job_defs.fileset_name = def;
332 if (strcmp(dircomm->msg(), "catalog") == 0) {
333 job_defs.catalog_name = def;
336 if (strcmp(dircomm->msg(), "enabled") == 0) {
337 job_defs.enabled = *def == '1' ? true : false;
352 * Save user settings associated with this console
354 void Console::writeSettings()
356 QFont font = get_font();
358 QSettings settings(m_dir->name(), "bat");
359 settings.beginGroup("Console");
360 settings.setValue("consoleFont", font.family());
361 settings.setValue("consolePointSize", font.pointSize());
362 settings.setValue("consoleFixedPitch", font.fixedPitch());
367 * Read and restore user settings associated with this console
369 void Console::readSettings()
371 QFont font = get_font();
373 QSettings settings(m_dir->name(), "bat");
374 settings.beginGroup("Console");
375 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
376 font.setPointSize(settings.value("consolePointSize", 10).toInt());
377 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
379 m_textEdit->setFont(font);
383 * Set the console textEdit font
385 void Console::set_font()
388 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
390 m_textEdit->setFont(font);
395 * Get the console text edit font
397 const QFont Console::get_font()
399 return m_textEdit->font();
403 * Slot for responding to status dir button on button bar
405 void Console::status_dir()
407 QString cmd("status dir");
412 * Slot for responding to messages button on button bar
413 * Here we want to bring the console to the front so use pages' consoleCommand
415 void Console::messages()
417 QString cmd(".messages");
419 messagesPending(false);
423 * Put text into the console window
425 void Console::display_textf(const char *fmt, ...)
430 va_start(arg_ptr, fmt);
431 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
436 void Console::display_text(const QString buf)
438 m_cursor->insertText(buf);
443 void Console::display_text(const char *buf)
445 m_cursor->insertText(buf);
449 void Console::display_html(const QString buf)
451 m_cursor->insertHtml(buf);
455 /* Position cursor to end of screen */
456 void Console::update_cursor()
458 QApplication::restoreOverrideCursor();
459 m_textEdit->moveCursor(QTextCursor::End);
460 m_textEdit->ensureCursorVisible();
463 void Console::beginNewCommand(int conn)
465 DirComm *dircomm = m_dircommHash.value(conn);
467 for (int i=0; i < 3; i++) {
469 while (dircomm->read() > 0) {
470 if (mainWin->m_displayAll) display_text(dircomm->msg());
472 if (dircomm->m_at_main_prompt) {
479 void Console::displayToPrompt(int conn)
481 DirComm *dircomm = m_dircommHash.value(conn);
485 if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
486 while (!dircomm->m_at_prompt) {
487 if ((stat=dircomm->read()) > 0) {
488 buf += dircomm->msg();
489 if (buf.size() >= 8196 || m_messages_pending) {
492 messagesPending(false);
497 if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
500 void Console::discardToPrompt(int conn)
502 DirComm *dircomm = m_dircommHash.value(conn);
505 if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
506 if (mainWin->m_displayAll) {
507 displayToPrompt(conn);
509 while (!dircomm->m_at_prompt) {
510 stat=dircomm->read();
513 if (mainWin->m_commDebug) Pmsg1(000, "endDiscardToPrompt=%d\n", stat);
517 * When the notifier is enabled, read_dir() will automatically be
518 * called by the Qt event loop when ever there is any output
519 * from the Directory, and read_dir() will then display it on
522 * When we are in a bat dialog, we want to control *all* output
523 * from the Directory, so we set notify to off.
524 * m_console->notifiy(false);
527 /* dual purpose function to turn notify off and return an available connection */
528 int Console::notifyOff()
530 int conn = availableDirComm();
535 /* knowing a connection, turn notify off or on */
536 bool Console::notify(int conn, bool enable)
538 DirComm *dircomm = m_dircommHash.value(conn);
539 return dircomm->notify(enable);
542 /* knowing a connection, return notify state */
543 bool Console::is_notify_enabled(int conn) const
545 DirComm *dircomm = m_dircommHash.value(conn);
546 return dircomm->is_notify_enabled();
549 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
551 m_directorTreeItem = item;
554 void Console::setDirRes(DIRRES *dir)
560 * To have the ability to get the name of the director resource.
562 void Console::getDirResName(QString &name_returned)
564 name_returned = m_dir->name();
567 /* Slot for responding to page selectors status help command */
568 void Console::consoleHelp()
574 /* Slot for responding to page selectors reload bacula-dir.conf */
575 void Console::consoleReload()
577 QString cmd("reload");
581 /* Function to get a list of volumes */
582 void Console::getVolumeList(QStringList &volumeList)
584 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
585 if (mainWin->m_sqlDebug) {
586 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
589 if (sql_cmd(query, results)) {
591 QStringList fieldlist;
592 /* Iterate through the lines of results. */
593 foreach (QString resultline, results) {
594 fieldlist = resultline.split("\t");
595 volumeList.append(fieldlist[0]);
596 } /* foreach resultline */
597 } /* if results from query */
600 /* Function to get a list of volumes */
601 void Console::getStatusList(QStringList &statusLongList)
603 QString statusQuery("SELECT JobStatusLong FROM Status");
604 if (mainWin->m_sqlDebug) {
605 Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
607 QStringList statusResults;
608 if (sql_cmd(statusQuery, statusResults)) {
610 QStringList fieldlist;
611 /* Iterate through the lines of results. */
612 foreach (QString resultline, statusResults) {
613 fieldlist = resultline.split("\t");
614 statusLongList.append(fieldlist[0]);
615 } /* foreach resultline */
616 } /* if results from statusquery */
619 /* For suppressing .messages
620 * This may be rendered not needed if the multiple connections feature gets working */
621 bool Console::hasFocus()
623 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
629 /* For adding feature to have the gui's messages button change when
630 * messages are pending */
631 bool Console::messagesPending(bool pend)
633 bool prev = m_messages_pending;
634 m_messages_pending = pend;
635 mainWin->setMessageIcon();
639 /* terminate all existing connections */
640 void Console::terminate()
642 foreach(DirComm* dircomm, m_dircommHash) {
643 dircomm->terminate();
645 m_console->stopTimer();
648 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
649 bool Console::is_connectedGui()
651 if (is_connected(0)) {
654 QString message = tr("Director is currently disconnected\nPlease reconnect!");
655 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
660 int Console::read(int conn)
662 DirComm *dircomm = m_dircommHash.value(conn);
663 return dircomm->read();
666 char *Console::msg(int conn)
668 DirComm *dircomm = m_dircommHash.value(conn);
669 return dircomm->msg();
672 int Console::write(int conn, const QString msg)
674 DirComm *dircomm = m_dircommHash.value(conn);
675 return dircomm->write(msg);
678 int Console::write(int conn, const char *msg)
680 DirComm *dircomm = m_dircommHash.value(conn);
681 return dircomm->write(msg);
684 /* This checks to see if any is connected */
685 bool Console::is_connected()
687 bool connected = false;
688 foreach(DirComm* dircomm, m_dircommHash) {
689 if (dircomm->is_connected())
695 /* knowing the connection id, is it connected */
696 bool Console::is_connected(int conn)
698 DirComm *dircomm = m_dircommHash.value(conn);
699 return dircomm->is_connected();
703 * Need an available connection. Check existing connections or create one
705 int Console::availableDirComm()
707 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
708 while (iter != m_dircommHash.constEnd()) {
709 DirComm *dircomm = iter.value();
710 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled())
711 return dircomm->m_conn;
718 * Create a new connection
720 int Console::newDirComm()
722 m_dircommCounter += 1;
723 if (mainWin->m_connDebug)
724 Pmsg1(000, "DirComm %i About to Create and Connect\n", m_dircommCounter);
725 DirComm *dircomm = new DirComm(this, m_dircommCounter);
726 m_dircommHash.insert(m_dircommCounter, dircomm);
727 bool success = dircomm->connect_dir();
728 if (mainWin->m_connDebug)
730 Pmsg1(000, "DirComm %i Connected\n", m_dircommCounter);
732 Pmsg1(000, "DirComm %i NOT Connected\n", m_dircommCounter);
733 return m_dircommCounter;