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>
44 Console::Console(QStackedWidget *parent)
55 m_textEdit = textEdit; /* our console screen */
56 m_cursor = new QTextCursor(m_textEdit->document());
57 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
59 /* Check for messages every 5 seconds */
60 // m_timer = new QTimer(this);
61 // QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
62 // m_timer->start(5000);
69 void Console::poll_messages()
71 m_messages_pending = true;
74 /* Terminate any open socket */
75 void Console::terminate()
85 * Connect to Director. If there are more than one, put up
86 * a modal dialog so that the user chooses one.
88 void Console::connect()
93 m_textEdit = textEdit; /* our console screen */
96 mainWin->set_status("No Director found.");
100 mainWin->set_status("Already connected.");
104 memset(&jcr, 0, sizeof(jcr));
106 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
107 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
109 /* Give GUI a chance */
110 app->processEvents();
113 /* If cons==NULL, default console will be used */
114 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
117 if (m_dir->heartbeat_interval) {
118 heart_beat = m_dir->heartbeat_interval;
120 heart_beat = cons->heartbeat_interval;
125 m_sock = bnet_connect(NULL, 5, 15, heart_beat,
126 _("Director daemon"), m_dir->address,
127 NULL, m_dir->DIRport, 0);
128 if (m_sock == NULL) {
129 mainWin->set_status("Connection failed");
132 /* Update page selector to green to indicate that Console is connected */
133 mainWin->actionConnect->setIcon(QIcon(":images/connected.png"));
134 QBrush greenBrush(Qt::green);
135 QTreeWidgetItem *item = mainWin->getFromHash(this);
136 item->setForeground(0, greenBrush);
139 jcr.dir_bsock = m_sock;
141 if (!authenticate_director(&jcr, m_dir, cons)) {
142 display_text(m_sock->msg);
146 /* Give GUI a chance */
147 app->processEvents();
149 mainWin->set_status(_("Initializing ..."));
151 /* Set up input notifier */
152 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
153 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
159 dir_cmd(".jobs", job_list);
160 dir_cmd(".clients", client_list);
161 dir_cmd(".filesets", fileset_list);
162 dir_cmd(".messages", messages_list);
163 dir_cmd(".pools", pool_list);
164 dir_cmd(".storage", storage_list);
165 dir_cmd(".types", type_list);
166 dir_cmd(".levels", level_list);
168 mainWin->set_status(_("Connected"));
172 bool Console::dir_cmd(QString &cmd, QStringList &results)
174 return dir_cmd(cmd.toUtf8().data(), results);
178 * Send a command to the Director, and return the
179 * results in a QStringList.
181 bool Console::dir_cmd(const char *cmd, QStringList &results)
187 while ((stat = read()) > 0) {
188 strip_trailing_junk(msg());
193 return true; /* ***FIXME*** return any command error */
196 bool Console::sql_cmd(QString &query, QStringList &results)
198 return sql_cmd(query.toUtf8().data(), results);
202 * Send an sql query to the Director, and return the
203 * results in a QStringList.
205 bool Console::sql_cmd(const char *query, QStringList &results)
207 if (!is_connectedGui())
210 POOL_MEM cmd(PM_MESSAGE);
214 pm_strcpy(cmd, ".sql query=\"");
215 pm_strcat(cmd, query);
216 pm_strcat(cmd, "\"");
218 while ((stat = read()) > 0) {
219 strip_trailing_junk(msg());
224 return true; /* ***FIXME*** return any command error */
229 * Send a job name to the director, and read all the resulting
232 bool Console::get_job_defaults(struct job_defaults &job_defs)
240 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
242 while ((stat = read()) > 0) {
243 def = strchr(msg(), '=');
247 /* Pointer to default value */
249 strip_trailing_junk(def);
251 if (strcmp(msg(), "job") == 0) {
252 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
257 if (strcmp(msg(), "pool") == 0) {
258 job_defs.pool_name = def;
261 if (strcmp(msg(), "messages") == 0) {
262 job_defs.messages_name = def;
265 if (strcmp(msg(), "client") == 0) {
266 job_defs.client_name = def;
269 if (strcmp(msg(), "storage") == 0) {
270 job_defs.store_name = def;
273 if (strcmp(msg(), "where") == 0) {
274 job_defs.where = def;
277 if (strcmp(msg(), "level") == 0) {
278 job_defs.level = def;
281 if (strcmp(msg(), "type") == 0) {
285 if (strcmp(msg(), "fileset") == 0) {
286 job_defs.fileset_name = def;
289 if (strcmp(msg(), "catalog") == 0) {
290 job_defs.catalog_name = def;
293 if (strcmp(msg(), "enabled") == 0) {
294 job_defs.enabled = *def == '1' ? true : false;
300 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
301 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
302 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
303 job_defs.client_name.toUtf8().data(),
304 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
305 job_defs.store_name.toUtf8().data(),
306 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
307 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
308 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
321 * Save user settings associated with this console
323 void Console::writeSettings()
325 QFont font = get_font();
327 QSettings settings(m_dir->name(), "bat");
328 settings.beginGroup("Console");
329 settings.setValue("consoleFont", font.family());
330 settings.setValue("consolePointSize", font.pointSize());
331 settings.setValue("consoleFixedPitch", font.fixedPitch());
336 * Read and restore user settings associated with this console
338 void Console::readSettings()
340 QFont font = get_font();
342 QSettings settings(m_dir->name(), "bat");
343 settings.beginGroup("Console");
344 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
345 font.setPointSize(settings.value("consolePointSize", 10).toInt());
346 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
348 m_textEdit->setFont(font);
352 * Set the console textEdit font
354 void Console::set_font()
357 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
359 m_textEdit->setFont(font);
364 * Get the console text edit font
366 const QFont Console::get_font()
368 return m_textEdit->font();
372 * Slot for responding to status dir button on button bar
374 void Console::status_dir()
376 QString cmd("status dir");
381 * Slot for responding to messages button on button bar
383 void Console::messages()
385 QString cmd(".messages");
390 * Put text into the console window
392 void Console::display_textf(const char *fmt, ...)
397 va_start(arg_ptr, fmt);
398 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
403 void Console::display_text(const QString buf)
405 m_cursor->movePosition(QTextCursor::End);
406 m_cursor->insertText(buf);
410 void Console::display_text(const char *buf)
412 m_cursor->movePosition(QTextCursor::End);
413 m_cursor->insertText(buf);
416 /* Position cursor to end of screen */
417 void Console::update_cursor()
419 QApplication::restoreOverrideCursor();
420 m_textEdit->moveCursor(QTextCursor::End);
421 m_textEdit->ensureCursorVisible();
425 * This should be moved into a bSocket class
435 /* Send a command to the Director */
436 void Console::write_dir(const char *msg)
439 mainWin->set_status(_("Processing command ..."));
440 QApplication::setOverrideCursor(Qt::WaitCursor);
443 mainWin->set_status(" Director not connected. Click on connect button.");
444 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
445 QBrush redBrush(Qt::red);
446 QTreeWidgetItem *item = mainWin->getFromHash(this);
447 item->setForeground(0, redBrush);
452 int Console::write(const QString msg)
454 return write(msg.toUtf8().data());
457 int Console::write(const char *msg)
459 m_sock->msglen = pm_strcpy(m_sock->msg, msg);
461 if (commDebug) Pmsg1(000, "send: %s\n", msg);
462 return m_sock->send();
466 * Get to main command prompt
468 void Console::beginNewCommand()
482 void Console::displayToPrompt()
485 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
486 while (!m_at_prompt) {
487 if ((stat=read()) > 0) {
491 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
494 void Console::discardToPrompt()
497 if (commDebug) Pmsg0(000, "discardToPrompt\n");
498 while (!m_at_prompt) {
501 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
506 * Blocking read from director
513 stat = bnet_wait_data_intr(m_sock, 1);
517 app->processEvents();
518 if (m_api_set && m_messages_pending) {
519 write_dir(".messages");
520 m_messages_pending = false;
523 stat = m_sock->recv();
529 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
531 switch (m_sock->msglen) {
532 case BNET_SERVER_READY:
533 if (m_api_set && m_messages_pending) {
534 write_dir(".messages");
535 m_messages_pending = false;
539 case BNET_MSGS_PENDING:
540 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
541 m_messages_pending = true;
544 if (commDebug) Pmsg0(000, "CMD OK\n");
548 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
552 if (commDebug) Pmsg0(000, "PROMPT\n");
554 mainWin->set_status(_("At prompt waiting for input ..."));
556 QApplication::restoreOverrideCursor();
558 case BNET_CMD_FAILED:
559 if (commDebug) Pmsg0(000, "CMD FAIL\n");
560 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
562 QApplication::restoreOverrideCursor();
564 /* We should not get this one */
566 if (commDebug) Pmsg0(000, "EOD\n");
567 mainWin->set_status_ready();
569 QApplication::restoreOverrideCursor();
574 case BNET_START_SELECT:
575 new selectDialog(this);
578 new runCmdDialog(this);
581 m_sock->recv(); /* get the message */
583 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
585 case BNET_WARNING_MSG:
586 m_sock->recv(); /* get the message */
588 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
591 m_sock->recv(); /* get the message */
593 mainWin->set_status(msg());
596 if (is_bnet_stop(m_sock)) { /* error or term request */
599 mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
600 QBrush redBrush(Qt::red);
601 QTreeWidgetItem *item = mainWin->getFromHash(this);
602 item->setForeground(0, redBrush);
603 m_notifier->setEnabled(false);
606 mainWin->set_status(_("Director disconnected."));
607 QApplication::restoreOverrideCursor();
615 /* Called by signal when the Director has output for us */
616 void Console::read_dir(int fd)
621 if (commDebug) Pmsg0(000, "read_dir\n");
622 while ((stat = read()) >= 0) {
628 * When the notifier is enabled, read_dir() will automatically be
629 * called by the Qt event loop when ever there is any output
630 * from the Directory, and read_dir() will then display it on
633 * When we are in a bat dialog, we want to control *all* output
634 * from the Directory, so we set notify to off.
635 * m_console->notifiy(false);
637 void Console::notify(bool enable)
639 m_notifier->setEnabled(enable);
642 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
644 m_directorTreeItem = item;
647 void Console::setDirRes(DIRRES *dir)
653 * To have the ability to get the name of the director resource.
655 void Console::getDirResName(QString &name_returned)
657 name_returned = m_dir->name();
660 bool Console::is_connectedGui()
662 if (is_connected()) {
665 QString message("Director ");
666 message += m_dir->name();
667 message += " is curerntly disconnected\n Please reconnect!!";
668 QMessageBox::warning(this, tr("Bat"),
669 tr(message.toUtf8().data()), QMessageBox::Ok );