2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2007 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 plus additions
11 that are listed in the file LICENSE.
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 John Walker.
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
37 #include <QAbstractEventDispatcher>
41 Console::Console(QStackedWidget *parent)
52 m_textEdit = textEdit; /* our console screen */
53 m_cursor = new QTextCursor(m_textEdit->document());
54 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
56 /* Check for messages every 5 seconds */
57 // m_timer = new QTimer(this);
58 // QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
59 // m_timer->start(5000);
66 void Console::poll_messages()
68 m_messages_pending = true;
71 /* Terminate any open socket */
72 void Console::terminate()
82 * Connect to Director. If there are more than one, put up
83 * a modal dialog so that the user chooses one.
85 void Console::connect()
90 m_textEdit = textEdit; /* our console screen */
93 mainWin->set_status("No Director found.");
97 mainWin->set_status("Already connected.");
101 memset(&jcr, 0, sizeof(jcr));
103 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
104 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
106 /* Give GUI a chance */
107 app->processEvents();
110 /* If cons==NULL, default console will be used */
111 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
114 if (m_dir->heartbeat_interval) {
115 heart_beat = m_dir->heartbeat_interval;
117 heart_beat = cons->heartbeat_interval;
122 m_sock = bnet_connect(NULL, 5, 15, heart_beat,
123 _("Director daemon"), m_dir->address,
124 NULL, m_dir->DIRport, 0);
125 if (m_sock == NULL) {
126 mainWin->set_status("Connection failed");
129 /* Update page selector to green to indicate that Console is connected */
130 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
131 QBrush greenBrush(Qt::green);
132 QTreeWidgetItem *item = mainWin->getFromHash(this);
133 item->setForeground(0, greenBrush);
136 jcr.dir_bsock = m_sock;
138 if (!authenticate_director(&jcr, m_dir, cons)) {
139 display_text(m_sock->msg);
143 /* Give GUI a chance */
144 app->processEvents();
146 mainWin->set_status(_("Initializing ..."));
148 /* Set up input notifier */
149 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
150 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
156 dir_cmd(".jobs", job_list);
157 dir_cmd(".clients", client_list);
158 dir_cmd(".filesets", fileset_list);
159 dir_cmd(".messages", messages_list);
160 dir_cmd(".pools", pool_list);
161 dir_cmd(".storage", storage_list);
162 dir_cmd(".types", type_list);
163 dir_cmd(".levels", level_list);
165 mainWin->set_status(_("Connected"));
169 bool Console::dir_cmd(QString &cmd, QStringList &results)
171 return dir_cmd(cmd.toUtf8().data(), results);
175 * Send a command to the Director, and return the
176 * results in a QStringList.
178 bool Console::dir_cmd(const char *cmd, QStringList &results)
184 while ((stat = read()) > 0) {
185 strip_trailing_junk(msg());
190 return true; /* ***FIXME*** return any command error */
193 bool Console::sql_cmd(QString &query, QStringList &results)
195 return sql_cmd(query.toUtf8().data(), results);
199 * Send an sql query to the Director, and return the
200 * results in a QStringList.
202 bool Console::sql_cmd(const char *query, QStringList &results)
205 POOL_MEM cmd(PM_MESSAGE);
209 pm_strcpy(cmd, ".sql query=\"");
210 pm_strcat(cmd, query);
211 pm_strcat(cmd, "\"");
213 while ((stat = read()) > 0) {
214 strip_trailing_junk(msg());
219 return true; /* ***FIXME*** return any command error */
224 * Send a job name to the director, and read all the resulting
227 bool Console::get_job_defaults(struct job_defaults &job_defs)
235 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
237 while ((stat = read()) > 0) {
238 def = strchr(msg(), '=');
242 /* Pointer to default value */
244 strip_trailing_junk(def);
246 if (strcmp(msg(), "job") == 0) {
247 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
252 if (strcmp(msg(), "pool") == 0) {
253 job_defs.pool_name = def;
256 if (strcmp(msg(), "messages") == 0) {
257 job_defs.messages_name = def;
260 if (strcmp(msg(), "client") == 0) {
261 job_defs.client_name = def;
264 if (strcmp(msg(), "storage") == 0) {
265 job_defs.store_name = def;
268 if (strcmp(msg(), "where") == 0) {
269 job_defs.where = def;
272 if (strcmp(msg(), "level") == 0) {
273 job_defs.level = def;
276 if (strcmp(msg(), "type") == 0) {
280 if (strcmp(msg(), "fileset") == 0) {
281 job_defs.fileset_name = def;
284 if (strcmp(msg(), "catalog") == 0) {
285 job_defs.catalog_name = def;
288 if (strcmp(msg(), "enabled") == 0) {
289 job_defs.enabled = *def == '1' ? true : false;
295 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
296 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
297 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
298 job_defs.client_name.toUtf8().data(),
299 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
300 job_defs.store_name.toUtf8().data(),
301 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
302 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
303 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
316 * Save user settings associated with this console
318 void Console::writeSettings()
320 QFont font = get_font();
322 QSettings settings(m_dir->name(), "bat");
323 settings.beginGroup("Console");
324 settings.setValue("consoleFont", font.family());
325 settings.setValue("consolePointSize", font.pointSize());
326 settings.setValue("consoleFixedPitch", font.fixedPitch());
331 * Read and restore user settings associated with this console
333 void Console::readSettings()
335 QFont font = get_font();
337 QSettings settings(m_dir->name(), "bat");
338 settings.beginGroup("Console");
339 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
340 font.setPointSize(settings.value("consolePointSize", 10).toInt());
341 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
343 m_textEdit->setFont(font);
347 * Set the console textEdit font
349 void Console::set_font()
352 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
354 m_textEdit->setFont(font);
359 * Get the console text edit font
361 const QFont Console::get_font()
363 return m_textEdit->font();
367 void Console::status_dir()
369 QString cmd("status dir");
374 * Put text into the console window
376 void Console::display_textf(const char *fmt, ...)
381 va_start(arg_ptr, fmt);
382 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
387 void Console::display_text(const QString buf)
389 m_cursor->movePosition(QTextCursor::End);
390 m_cursor->insertText(buf);
394 void Console::display_text(const char *buf)
396 m_cursor->movePosition(QTextCursor::End);
397 m_cursor->insertText(buf);
400 /* Position cursor to end of screen */
401 void Console::update_cursor()
403 QApplication::restoreOverrideCursor();
404 m_textEdit->moveCursor(QTextCursor::End);
405 m_textEdit->ensureCursorVisible();
409 * This should be moved into a bSocket class
419 /* Send a command to the Director */
420 void Console::write_dir(const char *msg)
423 mainWin->set_status(_("Processing command ..."));
424 QApplication::setOverrideCursor(Qt::WaitCursor);
427 mainWin->set_status(" Director not connected. Click on connect button.");
428 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
429 QBrush redBrush(Qt::red);
430 QTreeWidgetItem *item = mainWin->getFromHash(this);
431 item->setForeground(0, redBrush);
436 int Console::write(const QString msg)
438 return write(msg.toUtf8().data());
441 int Console::write(const char *msg)
443 m_sock->msglen = pm_strcpy(m_sock->msg, msg);
445 if (commDebug) Pmsg1(000, "send: %s\n", msg);
446 return m_sock->send();
450 * Get to main command prompt
452 void Console::beginNewCommand()
466 void Console::displayToPrompt()
469 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
470 while (!m_at_prompt) {
471 if ((stat=read()) > 0) {
475 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
478 void Console::discardToPrompt()
481 if (commDebug) Pmsg0(000, "discardToPrompt\n");
482 while (!m_at_prompt) {
485 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
490 * Blocking read from director
497 stat = bnet_wait_data_intr(m_sock, 1);
501 app->processEvents();
502 if (m_api_set && m_messages_pending) {
503 write_dir(".messages");
504 m_messages_pending = false;
507 stat = m_sock->recv();
513 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
515 switch (m_sock->msglen) {
516 case BNET_SERVER_READY:
517 if (m_api_set && m_messages_pending) {
518 write_dir(".messages");
519 m_messages_pending = false;
523 case BNET_MSGS_PENDING:
524 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
525 m_messages_pending = true;
528 if (commDebug) Pmsg0(000, "CMD OK\n");
532 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
536 if (commDebug) Pmsg0(000, "PROMPT\n");
538 mainWin->set_status(_("At prompt waiting for input ..."));
540 QApplication::restoreOverrideCursor();
542 case BNET_CMD_FAILED:
543 if (commDebug) Pmsg0(000, "CMD FAIL\n");
544 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
546 QApplication::restoreOverrideCursor();
548 /* We should not get this one */
550 if (commDebug) Pmsg0(000, "EOD\n");
551 mainWin->set_status_ready();
553 QApplication::restoreOverrideCursor();
558 case BNET_START_SELECT:
559 new selectDialog(this);
562 new runCmdDialog(this);
565 m_sock->recv(); /* get the message */
567 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
569 case BNET_WARNING_MSG:
570 m_sock->recv(); /* get the message */
572 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
575 m_sock->recv(); /* get the message */
577 mainWin->set_status(msg());
580 if (is_bnet_stop(m_sock)) { /* error or term request */
583 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
584 QBrush redBrush(Qt::red);
585 QTreeWidgetItem *item = mainWin->getFromHash(this);
586 item->setForeground(0, redBrush);
587 m_notifier->setEnabled(false);
590 mainWin->set_status(_("Director disconnected."));
591 QApplication::restoreOverrideCursor();
599 /* Called by signal when the Director has output for us */
600 void Console::read_dir(int fd)
605 if (commDebug) Pmsg0(000, "read_dir\n");
606 while ((stat = read()) >= 0) {
612 * When the notifier is enabled, read_dir() will automatically be
613 * called by the Qt event loop when ever there is any output
614 * from the Directory, and read_dir() will then display it on
617 * When we are in a bat dialog, we want to control *all* output
618 * from the Directory, so we set notify to off.
619 * m_console->notifiy(false);
621 void Console::notify(bool enable)
623 m_notifier->setEnabled(enable);
626 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
628 m_directorTreeItem = item;
631 void Console::setDirRes(DIRRES *dir)
637 * To have the ability to get the name of the director resource.
639 void Console::getDirResName(QString &name_returned)
641 name_returned = m_dir->name();