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(":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(":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)
204 if (!is_connectedGui())
207 POOL_MEM cmd(PM_MESSAGE);
211 pm_strcpy(cmd, ".sql query=\"");
212 pm_strcat(cmd, query);
213 pm_strcat(cmd, "\"");
215 while ((stat = read()) > 0) {
216 strip_trailing_junk(msg());
221 return true; /* ***FIXME*** return any command error */
226 * Send a job name to the director, and read all the resulting
229 bool Console::get_job_defaults(struct job_defaults &job_defs)
237 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
239 while ((stat = read()) > 0) {
240 def = strchr(msg(), '=');
244 /* Pointer to default value */
246 strip_trailing_junk(def);
248 if (strcmp(msg(), "job") == 0) {
249 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
254 if (strcmp(msg(), "pool") == 0) {
255 job_defs.pool_name = def;
258 if (strcmp(msg(), "messages") == 0) {
259 job_defs.messages_name = def;
262 if (strcmp(msg(), "client") == 0) {
263 job_defs.client_name = def;
266 if (strcmp(msg(), "storage") == 0) {
267 job_defs.store_name = def;
270 if (strcmp(msg(), "where") == 0) {
271 job_defs.where = def;
274 if (strcmp(msg(), "level") == 0) {
275 job_defs.level = def;
278 if (strcmp(msg(), "type") == 0) {
282 if (strcmp(msg(), "fileset") == 0) {
283 job_defs.fileset_name = def;
286 if (strcmp(msg(), "catalog") == 0) {
287 job_defs.catalog_name = def;
290 if (strcmp(msg(), "enabled") == 0) {
291 job_defs.enabled = *def == '1' ? true : false;
297 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
298 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
299 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
300 job_defs.client_name.toUtf8().data(),
301 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
302 job_defs.store_name.toUtf8().data(),
303 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
304 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
305 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
318 * Save user settings associated with this console
320 void Console::writeSettings()
322 QFont font = get_font();
324 QSettings settings(m_dir->name(), "bat");
325 settings.beginGroup("Console");
326 settings.setValue("consoleFont", font.family());
327 settings.setValue("consolePointSize", font.pointSize());
328 settings.setValue("consoleFixedPitch", font.fixedPitch());
333 * Read and restore user settings associated with this console
335 void Console::readSettings()
337 QFont font = get_font();
339 QSettings settings(m_dir->name(), "bat");
340 settings.beginGroup("Console");
341 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
342 font.setPointSize(settings.value("consolePointSize", 10).toInt());
343 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
345 m_textEdit->setFont(font);
349 * Set the console textEdit font
351 void Console::set_font()
354 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
356 m_textEdit->setFont(font);
361 * Get the console text edit font
363 const QFont Console::get_font()
365 return m_textEdit->font();
369 void Console::status_dir()
371 QString cmd("status dir");
376 * Put text into the console window
378 void Console::display_textf(const char *fmt, ...)
383 va_start(arg_ptr, fmt);
384 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
389 void Console::display_text(const QString buf)
391 m_cursor->movePosition(QTextCursor::End);
392 m_cursor->insertText(buf);
396 void Console::display_text(const char *buf)
398 m_cursor->movePosition(QTextCursor::End);
399 m_cursor->insertText(buf);
402 /* Position cursor to end of screen */
403 void Console::update_cursor()
405 QApplication::restoreOverrideCursor();
406 m_textEdit->moveCursor(QTextCursor::End);
407 m_textEdit->ensureCursorVisible();
411 * This should be moved into a bSocket class
421 /* Send a command to the Director */
422 void Console::write_dir(const char *msg)
425 mainWin->set_status(_("Processing command ..."));
426 QApplication::setOverrideCursor(Qt::WaitCursor);
429 mainWin->set_status(" Director not connected. Click on connect button.");
430 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
431 QBrush redBrush(Qt::red);
432 QTreeWidgetItem *item = mainWin->getFromHash(this);
433 item->setForeground(0, redBrush);
438 int Console::write(const QString msg)
440 return write(msg.toUtf8().data());
443 int Console::write(const char *msg)
445 m_sock->msglen = pm_strcpy(m_sock->msg, msg);
447 if (commDebug) Pmsg1(000, "send: %s\n", msg);
448 return m_sock->send();
452 * Get to main command prompt
454 void Console::beginNewCommand()
468 void Console::displayToPrompt()
471 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
472 while (!m_at_prompt) {
473 if ((stat=read()) > 0) {
477 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
480 void Console::discardToPrompt()
483 if (commDebug) Pmsg0(000, "discardToPrompt\n");
484 while (!m_at_prompt) {
487 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
492 * Blocking read from director
499 stat = bnet_wait_data_intr(m_sock, 1);
503 app->processEvents();
504 if (m_api_set && m_messages_pending) {
505 write_dir(".messages");
506 m_messages_pending = false;
509 stat = m_sock->recv();
515 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
517 switch (m_sock->msglen) {
518 case BNET_SERVER_READY:
519 if (m_api_set && m_messages_pending) {
520 write_dir(".messages");
521 m_messages_pending = false;
525 case BNET_MSGS_PENDING:
526 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
527 m_messages_pending = true;
530 if (commDebug) Pmsg0(000, "CMD OK\n");
534 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
538 if (commDebug) Pmsg0(000, "PROMPT\n");
540 mainWin->set_status(_("At prompt waiting for input ..."));
542 QApplication::restoreOverrideCursor();
544 case BNET_CMD_FAILED:
545 if (commDebug) Pmsg0(000, "CMD FAIL\n");
546 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
548 QApplication::restoreOverrideCursor();
550 /* We should not get this one */
552 if (commDebug) Pmsg0(000, "EOD\n");
553 mainWin->set_status_ready();
555 QApplication::restoreOverrideCursor();
560 case BNET_START_SELECT:
561 new selectDialog(this);
564 new runCmdDialog(this);
567 m_sock->recv(); /* get the message */
569 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
571 case BNET_WARNING_MSG:
572 m_sock->recv(); /* get the message */
574 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
577 m_sock->recv(); /* get the message */
579 mainWin->set_status(msg());
582 if (is_bnet_stop(m_sock)) { /* error or term request */
585 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
586 QBrush redBrush(Qt::red);
587 QTreeWidgetItem *item = mainWin->getFromHash(this);
588 item->setForeground(0, redBrush);
589 m_notifier->setEnabled(false);
592 mainWin->set_status(_("Director disconnected."));
593 QApplication::restoreOverrideCursor();
601 /* Called by signal when the Director has output for us */
602 void Console::read_dir(int fd)
607 if (commDebug) Pmsg0(000, "read_dir\n");
608 while ((stat = read()) >= 0) {
614 * When the notifier is enabled, read_dir() will automatically be
615 * called by the Qt event loop when ever there is any output
616 * from the Directory, and read_dir() will then display it on
619 * When we are in a bat dialog, we want to control *all* output
620 * from the Directory, so we set notify to off.
621 * m_console->notifiy(false);
623 void Console::notify(bool enable)
625 m_notifier->setEnabled(enable);
628 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
630 m_directorTreeItem = item;
633 void Console::setDirRes(DIRRES *dir)
639 * To have the ability to get the name of the director resource.
641 void Console::getDirResName(QString &name_returned)
643 name_returned = m_dir->name();
646 bool Console::is_connectedGui()
648 if (is_connected()) {
651 QString message("Director ");
652 message += m_dir->name();
653 message += " is curerntly disconnected\n Please reconnect!!";
654 QMessageBox::warning(this, tr("Bat"),
655 tr(message.toUtf8().data()), QMessageBox::Ok );