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)
50 m_textEdit = textEdit; /* our console screen */
51 m_cursor = new QTextCursor(m_textEdit->document());
52 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
55 /* Check for messages every 5 seconds */
56 // m_timer = new QTimer(this);
57 // QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
58 // m_timer->start(5000);
62 void Console::poll_messages()
64 m_messages_pending = true;
67 /* Terminate any open socket */
68 void Console::terminate()
78 * Connect to Director. If there are more than one, put up
79 * a modal dialog so that the user chooses one.
81 void Console::connect()
85 m_textEdit = textEdit; /* our console screen */
88 mainWin->set_status("No Director found.");
92 mainWin->set_status("Already connected.");
96 memset(&jcr, 0, sizeof(jcr));
98 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
99 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
101 /* Give GUI a chance */
102 app->processEvents();
105 /* If cons==NULL, default console will be used */
106 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
109 m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
110 NULL, m_dir->DIRport, 0);
111 if (m_sock == NULL) {
112 mainWin->set_status("Connection failed");
115 /* Update page selector to green to indicate that Console is connected */
116 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
117 QBrush greenBrush(Qt::green);
118 m_consoleItem->setForeground(0, greenBrush);
121 jcr.dir_bsock = m_sock;
123 if (!authenticate_director(&jcr, m_dir, cons)) {
124 display_text(m_sock->msg);
128 /* Give GUI a chance */
129 app->processEvents();
131 mainWin->set_status(_("Initializing ..."));
133 /* Set up input notifier */
134 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
135 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
141 job_list = get_list(".jobs");
142 client_list = get_list(".clients");
143 fileset_list = get_list(".filesets");
144 messages_list = get_list(".messages");
145 pool_list = get_list(".pools");
146 storage_list = get_list(".storage");
147 type_list = get_list(".types");
148 level_list = get_list(".levels");
150 mainWin->set_status(_("Connected"));
156 * Send a command to the director, and read all the resulting
157 * output into a list.
159 QStringList Console::get_list(char *cmd)
166 while ((stat = read()) > 0) {
167 strip_trailing_junk(msg());
175 * Send a job name to the director, and read all the resulting
178 bool Console::get_job_defaults(struct job_defaults &job_defs)
186 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
188 while ((stat = read()) > 0) {
189 def = strchr(msg(), '=');
193 /* Pointer to default value */
195 strip_trailing_junk(def);
197 if (strcmp(msg(), "job") == 0) {
198 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
203 if (strcmp(msg(), "pool") == 0) {
204 job_defs.pool_name = def;
207 if (strcmp(msg(), "messages") == 0) {
208 job_defs.messages_name = def;
211 if (strcmp(msg(), "client") == 0) {
212 job_defs.client_name = def;
215 if (strcmp(msg(), "storage") == 0) {
216 job_defs.store_name = def;
219 if (strcmp(msg(), "where") == 0) {
220 job_defs.where = def;
223 if (strcmp(msg(), "level") == 0) {
224 job_defs.level = def;
227 if (strcmp(msg(), "type") == 0) {
231 if (strcmp(msg(), "fileset") == 0) {
232 job_defs.fileset_name = def;
235 if (strcmp(msg(), "catalog") == 0) {
236 job_defs.catalog_name = def;
239 if (strcmp(msg(), "enabled") == 0) {
240 job_defs.enabled = *def == '1' ? true : false;
246 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
247 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
248 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
249 job_defs.client_name.toUtf8().data(),
250 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
251 job_defs.store_name.toUtf8().data(),
252 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
253 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
254 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
267 * Save user settings associated with this console
269 void Console::writeSettings()
271 QFont font = get_font();
273 QSettings settings("bacula.org", "bat");
274 /* ***FIXME*** make console name unique */
275 settings.beginGroup("Console");
276 settings.setValue("consoleFont", font.family());
277 settings.setValue("consolePointSize", font.pointSize());
278 settings.setValue("consoleFixedPitch", font.fixedPitch());
283 * Read and restore user settings associated with this console
285 void Console::readSettings()
287 QFont font = get_font();
289 QSettings settings("bacula.org", "bat");
290 settings.beginGroup("Console");
291 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
292 font.setPointSize(settings.value("consolePointSize", 10).toInt());
293 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
295 m_textEdit->setFont(font);
299 * Set the console textEdit font
301 void Console::set_font()
304 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
306 m_textEdit->setFont(font);
311 * Get the console text edit font
313 const QFont Console::get_font()
315 return m_textEdit->font();
319 void Console::status_dir()
321 write_dir("status dir\n");
326 * Put text into the console window
328 void Console::display_textf(const char *fmt, ...)
333 va_start(arg_ptr, fmt);
334 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
339 void Console::display_text(const QString buf)
341 m_cursor->movePosition(QTextCursor::End);
342 m_cursor->insertText(buf);
346 void Console::display_text(const char *buf)
348 m_cursor->movePosition(QTextCursor::End);
349 m_cursor->insertText(buf);
352 /* Position cursor to end of screen */
353 void Console::update_cursor()
355 QApplication::restoreOverrideCursor();
356 m_textEdit->moveCursor(QTextCursor::End);
357 m_textEdit->ensureCursorVisible();
361 * This should be moved into a bSocket class
371 /* Send a command to the Director */
372 void Console::write_dir(const char *msg)
375 mainWin->set_status(_("Processing command ..."));
376 QApplication::setOverrideCursor(Qt::WaitCursor);
379 mainWin->set_status(" Director not connected. Click on connect button.");
380 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
381 QBrush redBrush(Qt::red);
382 m_consoleItem->setForeground(0, redBrush);
387 int Console::write(const QString msg)
389 return write(msg.toUtf8().data());
392 int Console::write(const char *msg)
394 m_sock->msglen = strlen(msg);
395 pm_strcpy(&m_sock->msg, msg);
397 if (commDebug) Pmsg1(000, "send: %s\n", msg);
398 return m_sock->send();
402 * Get to main command prompt
404 void Console::beginNewCommand()
418 void Console::displayToPrompt()
421 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
422 while (!m_at_prompt) {
423 if ((stat=read()) > 0) {
427 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
430 void Console::discardToPrompt()
433 if (commDebug) Pmsg0(000, "discardToPrompt\n");
434 while (!m_at_prompt) {
437 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
442 * Blocking read from director
449 stat = bnet_wait_data_intr(m_sock, 1);
453 app->processEvents();
454 if (m_api_set && m_messages_pending) {
455 write_dir(".messages");
456 m_messages_pending = false;
459 stat = m_sock->recv();
465 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
467 switch (m_sock->msglen) {
468 case BNET_SERVER_READY:
469 if (m_api_set && m_messages_pending) {
470 write_dir(".messages");
471 m_messages_pending = false;
475 case BNET_MSGS_PENDING:
476 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
477 m_messages_pending = true;
480 if (commDebug) Pmsg0(000, "CMD OK\n");
484 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
488 if (commDebug) Pmsg0(000, "PROMPT\n");
490 mainWin->set_status(_("At prompt waiting for input ..."));
492 QApplication::restoreOverrideCursor();
494 case BNET_CMD_FAILED:
495 if (commDebug) Pmsg0(000, "CMD FAIL\n");
496 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
498 QApplication::restoreOverrideCursor();
500 /* We should not get this one */
502 if (commDebug) Pmsg0(000, "EOD\n");
503 mainWin->set_status_ready();
505 QApplication::restoreOverrideCursor();
510 case BNET_START_SELECT:
511 new selectDialog(this);
514 new runCmdDialog(this);
517 m_sock->recv(); /* get the message */
519 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
521 case BNET_WARNING_MSG:
522 m_sock->recv(); /* get the message */
524 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
527 m_sock->recv(); /* get the message */
529 mainWin->set_status(msg());
532 if (is_bnet_stop(m_sock)) { /* error or term request */
535 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
536 QBrush redBrush(Qt::red);
537 m_consoleItem->setForeground(0, redBrush);
538 m_notifier->setEnabled(false);
541 mainWin->set_status(_("Director disconnected."));
542 QApplication::restoreOverrideCursor();
550 /* Called by signal when the Director has output for us */
551 void Console::read_dir(int fd)
556 if (commDebug) Pmsg0(000, "read_dir\n");
557 while ((stat = read()) >= 0) {
563 * When the notifier is enabled, read_dir() will automatically be
564 * called by the Qt event loop when ever there is any output
565 * from the Directory, and read_dir() will then display it on
568 * When we are in a bat dialog, we want to control *all* output
569 * from the Directory, so we set notify to off.
570 * m_console->notifiy(false);
572 void Console::notify(bool enable)
574 m_notifier->setEnabled(enable);
577 void Console::setTreeItem(QTreeWidgetItem *item)
579 m_consoleItem = item;
582 void Console::setDirRes(DIRRES *dir)