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() && !mainWin->getWaitState()){
100 messagesPending(true);
101 dircomm->write(".messages");
102 displayToPrompt(conn);
103 messagesPending(false);
108 * Connect to Director. This does not connect to the director, dircomm does.
109 * This creates the first and possibly 2nd dircomm instance
111 void Console::connect_dir()
113 DirComm *dircomm = m_dircommHash.value(0);
115 if (!m_console->m_dir) {
116 mainWin->set_status( tr("No Director found."));
120 m_textEdit = textEdit; /* our console screen */
122 if (dircomm->connect_dir()) {
123 if (mainWin->m_connDebug)
124 Pmsg1(000, "DirComm 0 Seems to have Connected %s\n", m_dir->name());
127 mainWin->set_status(_("Connected"));
129 startTimer(); /* start message timer */
133 * A function created to separate out the population of the lists
134 * from the Console::connect_dir function
136 void Console::populateLists(bool forcenew)
140 if (!newDirComm(conn)) {
141 Pmsg1(000, "newDirComm Seems to Failed to create a connection for populateLists %s\n", m_dir->name());
145 if(!availableDirComm(conn)) {
146 Pmsg1(000, "availableDirComm Seems to Failed to find a connection for populateListsi %s\n", m_dir->name());
153 void Console::populateLists(int conn)
157 fileset_list.clear();
158 fileset_list.clear();
159 messages_list.clear();
161 storage_list.clear();
164 dir_cmd(conn, ".jobs", job_list);
165 dir_cmd(conn, ".clients", client_list);
166 dir_cmd(conn, ".filesets", fileset_list);
167 dir_cmd(conn, ".msgs", messages_list);
168 dir_cmd(conn, ".pools", pool_list);
169 dir_cmd(conn, ".storage", storage_list);
170 dir_cmd(conn, ".types", type_list);
171 dir_cmd(conn, ".levels", level_list);
173 if (mainWin->m_connDebug) {
174 QString dbgmsg = QString("jobs=%1 clients=%2 filesets=%3 msgs=%4 pools=%5 storage=%6 types=%7 levels=%8 conn=%9 %10\n")
175 .arg(job_list.count()).arg(client_list.count()).arg(fileset_list.count()).arg(messages_list.count())
176 .arg(pool_list.count()).arg(storage_list.count()).arg(type_list.count()).arg(level_list.count())
177 .arg(conn).arg(m_dir->name());
178 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
183 * Overload function for dir_cmd with a QString
186 bool Console::dir_cmd(QString &cmd, QStringList &results)
188 return dir_cmd(cmd.toUtf8().data(), results);
192 * Overload function for dir_cmd, this is if connection is not worried about
194 bool Console::dir_cmd(const char *cmd, QStringList &results)
197 if (availableDirComm(conn)) {
198 dir_cmd(conn, cmd, results);
201 Pmsg1(000, "dir_cmd Seems to Failed to find a connection %s\n", m_dir->name());
207 * Send a command to the Director, and return the
208 * results in a QStringList.
210 bool Console::dir_cmd(int conn, const char *cmd, QStringList &results)
212 mainWin->waitEnter();
213 DirComm *dircomm = m_dircommHash.value(conn);
216 if (mainWin->m_connDebug) {
217 QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd);
218 Pmsg1(000, "%s", dbgmsg.toUtf8().data());
222 while ((stat = dircomm->read()) > 0 && dircomm->is_in_command()) {
223 if (mainWin->m_displayAll) display_text(dircomm->msg());
224 strip_trailing_junk(dircomm->msg());
225 results << dircomm->msg();
227 if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg());
229 discardToPrompt(conn);
231 return true; /* ***FIXME*** return any command error */
235 * OverLoads for sql_cmd
237 bool Console::sql_cmd(int &conn, QString &query, QStringList &results)
239 return sql_cmd(conn, query.toUtf8().data(), results, false);
242 bool Console::sql_cmd(QString &query, QStringList &results)
245 if (!availableDirComm(conn))
247 return sql_cmd(conn, query.toUtf8().data(), results, true);
250 bool Console::sql_cmd(const char *query, QStringList &results)
253 if (!availableDirComm(conn))
255 return sql_cmd(conn, query, results, true);
259 * Send an sql query to the Director, and return the
260 * results in a QStringList.
262 bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool donotify)
264 DirComm *dircomm = m_dircommHash.value(conn);
266 POOL_MEM cmd(PM_MESSAGE);
268 if (!is_connectedGui()) {
272 if (mainWin->m_connDebug)
273 Pmsg2(000, "sql_cmd conn %i %s\n", conn, query);
275 dircomm->notify(false);
276 mainWin->waitEnter();
278 pm_strcpy(cmd, ".sql query=\"");
279 pm_strcat(cmd, query);
280 pm_strcat(cmd, "\"");
281 dircomm->write(cmd.c_str());
282 while ((stat = dircomm->read()) > 0) {
284 if (mainWin->m_displayAll) {
285 display_text(dircomm->msg());
288 strip_trailing_junk(dircomm->msg());
289 bool doappend = true;
291 QString dum = dircomm->msg();
292 if ((dum.left(6) == "*None*")) doappend = false;
295 results << dircomm->msg();
299 dircomm->notify(true);
300 discardToPrompt(conn);
302 return true; /* ***FIXME*** return any command error */
307 * Sending a command to the Director
309 int Console::write_dir(const char *msg)
312 if (availableDirComm(conn))
313 write_dir(conn, msg);
317 int Console::write_dir(const char *msg, bool dowait)
320 if (availableDirComm(conn))
321 write_dir(conn, msg, dowait);
325 void Console::write_dir(int conn, const char *msg)
327 write_dir(conn, msg, true);
331 * Send a command to the Director
333 void Console::write_dir(int conn, const char *msg, bool dowait)
335 DirComm *dircomm = m_dircommHash.value(conn);
337 if (dircomm->m_sock) {
338 mainWin->set_status(_("Processing command ..."));
340 mainWin->waitEnter();
345 mainWin->set_status( tr(" Director not connected. Click on connect button."));
346 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
347 QBrush redBrush(Qt::red);
348 QTreeWidgetItem *item = mainWin->getFromHash(this);
349 item->setForeground(0, redBrush);
350 dircomm->m_at_prompt = false;
351 dircomm->m_at_main_prompt = false;
356 * get_job_defaults overload
358 bool Console::get_job_defaults(struct job_defaults &job_defs)
361 return get_job_defaults(conn, job_defs, true);
364 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs)
366 return get_job_defaults(conn, job_defs, false);
370 * Send a job name to the director, and read all the resulting
373 bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool donotify)
381 beginNewCommand(conn);
382 DirComm *dircomm = m_dircommHash.value(conn);
383 bool prevWaitState = mainWin->getWaitState();
385 mainWin->waitEnter();
386 if (mainWin->m_connDebug)
387 Pmsg2(000, "job_defaults conn %i %s\n", conn, m_dir->name());
388 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
389 dircomm->write(scmd);
390 while ((stat = dircomm->read()) > 0) {
391 if (mainWin->m_displayAll) display_text(dircomm->msg());
392 def = strchr(dircomm->msg(), '=');
396 /* Pointer to default value */
398 strip_trailing_junk(def);
400 if (strcmp(dircomm->msg(), "job") == 0) {
401 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
406 if (strcmp(dircomm->msg(), "pool") == 0) {
407 job_defs.pool_name = def;
410 if (strcmp(dircomm->msg(), "messages") == 0) {
411 job_defs.messages_name = def;
414 if (strcmp(dircomm->msg(), "client") == 0) {
415 job_defs.client_name = def;
418 if (strcmp(dircomm->msg(), "storage") == 0) {
419 job_defs.store_name = def;
422 if (strcmp(dircomm->msg(), "where") == 0) {
423 job_defs.where = def;
426 if (strcmp(dircomm->msg(), "level") == 0) {
427 job_defs.level = def;
430 if (strcmp(dircomm->msg(), "type") == 0) {
434 if (strcmp(dircomm->msg(), "fileset") == 0) {
435 job_defs.fileset_name = def;
438 if (strcmp(dircomm->msg(), "catalog") == 0) {
439 job_defs.catalog_name = def;
442 if (strcmp(dircomm->msg(), "enabled") == 0) {
443 job_defs.enabled = *def == '1' ? true : false;
464 * Save user settings associated with this console
466 void Console::writeSettings()
468 QFont font = get_font();
470 QSettings settings(m_dir->name(), "bat");
471 settings.beginGroup("Console");
472 settings.setValue("consoleFont", font.family());
473 settings.setValue("consolePointSize", font.pointSize());
474 settings.setValue("consoleFixedPitch", font.fixedPitch());
479 * Read and restore user settings associated with this console
481 void Console::readSettings()
483 QFont font = get_font();
485 QSettings settings(m_dir->name(), "bat");
486 settings.beginGroup("Console");
487 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
488 font.setPointSize(settings.value("consolePointSize", 10).toInt());
489 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
491 m_textEdit->setFont(font);
495 * Set the console textEdit font
497 void Console::set_font()
500 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
502 m_textEdit->setFont(font);
507 * Get the console text edit font
509 const QFont Console::get_font()
511 return m_textEdit->font();
515 * Slot for responding to status dir button on button bar
517 void Console::status_dir()
519 QString cmd("status dir");
524 * Slot for responding to messages button on button bar
525 * Here we want to bring the console to the front so use pages' consoleCommand
527 void Console::messages()
529 QString cmd(".messages");
531 messagesPending(false);
535 * Put text into the console window
537 void Console::display_textf(const char *fmt, ...)
542 va_start(arg_ptr, fmt);
543 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
548 void Console::display_text(const QString buf)
550 m_cursor->insertText(buf);
555 void Console::display_text(const char *buf)
557 m_cursor->insertText(buf);
561 void Console::display_html(const QString buf)
563 m_cursor->insertHtml(buf);
567 /* Position cursor to end of screen */
568 void Console::update_cursor()
570 m_textEdit->moveCursor(QTextCursor::End);
571 m_textEdit->ensureCursorVisible();
574 void Console::beginNewCommand(int conn)
576 DirComm *dircomm = m_dircommHash.value(conn);
578 for (int i=0; i < 3; i++) {
580 while (dircomm->read() > 0) {
581 Pmsg2(000, "begin new command loop %i %s\n", i, m_dir->name());
582 if (mainWin->m_displayAll) display_text(dircomm->msg());
584 if (dircomm->m_at_main_prompt) {
591 void Console::displayToPrompt(int conn)
593 DirComm *dircomm = m_dircommHash.value(conn);
597 if (mainWin->m_commDebug) Pmsg1(000, "DisplaytoPrompt %s\n", m_dir->name());
598 while (!dircomm->m_at_prompt) {
599 if ((stat=dircomm->read()) > 0) {
600 buf += dircomm->msg();
601 if (buf.size() >= 8196 || m_messages_pending) {
604 messagesPending(false);
609 if (mainWin->m_commDebug) Pmsg2(000, "endDisplaytoPrompt=%d %s\n", stat, m_dir->name());
612 void Console::discardToPrompt(int conn)
614 DirComm *dircomm = m_dircommHash.value(conn);
617 if (mainWin->m_commDebug) Pmsg1(000, "discardToPrompt %s\n", m_dir->name());
618 if (mainWin->m_displayAll) {
619 displayToPrompt(conn);
621 while (!dircomm->m_at_prompt) {
622 stat = dircomm->read();
628 if (mainWin->m_commDebug) Pmsg2(000, "endDiscardToPrompt=%d %s\n", stat, m_dir->name());
632 * When the notifier is enabled, read_dir() will automatically be
633 * called by the Qt event loop when ever there is any output
634 * from the Directory, and read_dir() will then display it on
637 * When we are in a bat dialog, we want to control *all* output
638 * from the Directory, so we set notify to off.
639 * m_console->notifiy(false);
642 /* dual purpose function to turn notify off and return an available connection */
643 int Console::notifyOff()
646 if (availableDirComm(conn))
651 /* knowing a connection, turn notify off or on */
652 bool Console::notify(int conn, bool enable)
654 DirComm *dircomm = m_dircommHash.value(conn);
655 return dircomm->notify(enable);
658 /* knowing a connection, return notify state */
659 bool Console::is_notify_enabled(int conn) const
661 DirComm *dircomm = m_dircommHash.value(conn);
662 return dircomm->is_notify_enabled();
665 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
667 m_directorTreeItem = item;
670 void Console::setDirRes(DIRRES *dir)
676 * To have the ability to get the name of the director resource.
678 void Console::getDirResName(QString &name_returned)
680 name_returned = m_dir->name();
683 /* Slot for responding to page selectors status help command */
684 void Console::consoleHelp()
690 /* Slot for responding to page selectors reload bacula-dir.conf */
691 void Console::consoleReload()
693 QString cmd("reload");
697 /* For suppressing .messages
698 * This may be rendered not needed if the multiple connections feature gets working */
699 bool Console::hasFocus()
701 if (mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this))
707 /* For adding feature to have the gui's messages button change when
708 * messages are pending */
709 bool Console::messagesPending(bool pend)
711 bool prev = m_messages_pending;
712 m_messages_pending = pend;
713 mainWin->setMessageIcon();
717 /* terminate all existing connections */
718 void Console::terminate()
720 foreach(DirComm* dircomm, m_dircommHash) {
721 dircomm->terminate();
723 m_console->stopTimer();
726 /* Maybe this should be checking the list, for the moment lets check 0 which should be connected */
727 bool Console::is_connectedGui()
729 if (is_connected(0)) {
732 QString message = tr("Director is currently disconnected\nPlease reconnect!");
733 QMessageBox::warning(this, "Bat", message, QMessageBox::Ok );
738 int Console::read(int conn)
740 DirComm *dircomm = m_dircommHash.value(conn);
741 return dircomm->read();
744 char *Console::msg(int conn)
746 DirComm *dircomm = m_dircommHash.value(conn);
747 return dircomm->msg();
750 int Console::write(int conn, const QString msg)
752 DirComm *dircomm = m_dircommHash.value(conn);
753 mainWin->waitEnter();
754 int ret = dircomm->write(msg);
759 int Console::write(int conn, const char *msg)
761 DirComm *dircomm = m_dircommHash.value(conn);
762 mainWin->waitEnter();
763 int ret = dircomm->write(msg);
768 /* This checks to see if any is connected */
769 bool Console::is_connected()
771 bool connected = false;
772 foreach(DirComm* dircomm, m_dircommHash) {
773 if (dircomm->is_connected())
779 /* knowing the connection id, is it connected */
780 bool Console::is_connected(int conn)
782 DirComm *dircomm = m_dircommHash.value(conn);
783 return dircomm->is_connected();
787 * Need an available connection. Check existing connections or create one
789 bool Console::availableDirComm(int &conn)
791 QHash<int, DirComm*>::const_iterator iter = m_dircommHash.constBegin();
792 while (iter != m_dircommHash.constEnd()) {
793 DirComm *dircomm = iter.value();
794 if (dircomm->m_at_prompt && dircomm->m_at_main_prompt && dircomm->is_notify_enabled()) {
795 conn = dircomm->m_conn;
800 if (newDirComm(conn))
807 * Create a new connection
809 bool Console::newDirComm(int &conn)
811 m_dircommCounter += 1;
812 conn = m_dircommCounter;
813 if (mainWin->m_connDebug)
814 Pmsg2(000, "DirComm %i About to Create and Connect %s\n", m_dircommCounter, m_dir->name());
815 DirComm *dircomm = new DirComm(this, m_dircommCounter);
816 m_dircommHash.insert(m_dircommCounter, dircomm);
817 bool success = dircomm->connect_dir();
818 if (mainWin->m_connDebug) {
820 Pmsg2(000, "DirComm %i Connected %s\n", conn, m_dir->name());
822 Pmsg2(000, "DirComm %i NOT Connected %s\n", conn, m_dir->name());