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)
49 m_textEdit = textEdit; /* our console screen */
50 m_cursor = new QTextCursor(m_textEdit->document());
51 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
54 /* Check for messages every 5 seconds */
55 // m_timer = new QTimer(this);
56 // QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
57 // m_timer->start(5000);
61 void Console::poll_messages()
63 m_messages_pending = true;
66 /* Terminate any open socket */
67 void Console::terminate()
77 * Connect to Director. If there are more than one, put up
78 * a modal dialog so that the user chooses one.
80 void Console::connect()
84 m_textEdit = textEdit; /* our console screen */
87 mainWin->set_status("No Director found.");
91 mainWin->set_status("Already connected.");
95 memset(&jcr, 0, sizeof(jcr));
97 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
98 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
100 /* Give GUI a chance */
101 app->processEvents();
104 /* If cons==NULL, default console will be used */
105 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
108 m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
109 NULL, m_dir->DIRport, 0);
110 if (m_sock == NULL) {
111 mainWin->set_status("Connection failed");
114 /* Update page selector to green to indicate that Console is connected */
115 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
116 QBrush greenBrush(Qt::green);
117 m_consoleItem->setForeground(0, greenBrush);
120 jcr.dir_bsock = m_sock;
122 if (!authenticate_director(&jcr, m_dir, cons)) {
123 display_text(m_sock->msg);
127 /* Give GUI a chance */
128 app->processEvents();
130 mainWin->set_status(_("Initializing ..."));
132 /* Set up input notifier */
133 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
134 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
140 job_list = get_list(".jobs");
141 client_list = get_list(".clients");
142 fileset_list = get_list(".filesets");
143 messages_list = get_list(".messages");
144 pool_list = get_list(".pools");
145 storage_list = get_list(".storage");
146 type_list = get_list(".types");
147 level_list = get_list(".levels");
149 mainWin->set_status(_("Connected"));
155 * Send a command to the director, and read all the resulting
156 * output into a list.
158 QStringList Console::get_list(char *cmd)
165 while ((stat = read()) > 0) {
166 strip_trailing_junk(msg());
174 * Send a job name to the director, and read all the resulting
177 bool Console::get_job_defaults(struct job_defaults &job_defs)
185 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
187 while ((stat = read()) > 0) {
188 def = strchr(msg(), '=');
192 /* Pointer to default value */
194 strip_trailing_junk(def);
196 if (strcmp(msg(), "job") == 0) {
197 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
202 if (strcmp(msg(), "pool") == 0) {
203 job_defs.pool_name = def;
206 if (strcmp(msg(), "messages") == 0) {
207 job_defs.messages_name = def;
210 if (strcmp(msg(), "client") == 0) {
211 job_defs.client_name = def;
214 if (strcmp(msg(), "storage") == 0) {
215 job_defs.store_name = def;
218 if (strcmp(msg(), "where") == 0) {
219 job_defs.where = def;
222 if (strcmp(msg(), "level") == 0) {
223 job_defs.level = def;
226 if (strcmp(msg(), "type") == 0) {
230 if (strcmp(msg(), "fileset") == 0) {
231 job_defs.fileset_name = def;
234 if (strcmp(msg(), "catalog") == 0) {
235 job_defs.catalog_name = def;
238 if (strcmp(msg(), "enabled") == 0) {
239 job_defs.enabled = *def == '1' ? true : false;
245 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
246 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
247 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
248 job_defs.client_name.toUtf8().data(),
249 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
250 job_defs.store_name.toUtf8().data(),
251 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
252 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
253 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
266 * Save user settings associated with this console
268 void Console::writeSettings()
270 QFont font = get_font();
272 QSettings settings("bacula.org", "bat");
273 /* ***FIXME*** make console name unique */
274 settings.beginGroup("Console");
275 settings.setValue("consoleFont", font.family());
276 settings.setValue("consolePointSize", font.pointSize());
277 settings.setValue("consoleFixedPitch", font.fixedPitch());
282 * Read and restore user settings associated with this console
284 void Console::readSettings()
286 QFont font = get_font();
288 QSettings settings("bacula.org", "bat");
289 settings.beginGroup("Console");
290 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
291 font.setPointSize(settings.value("consolePointSize", 10).toInt());
292 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
294 m_textEdit->setFont(font);
298 * Set the console textEdit font
300 void Console::set_font()
303 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
305 m_textEdit->setFont(font);
310 * Get the console text edit font
312 const QFont Console::get_font()
314 return m_textEdit->font();
318 void Console::status_dir()
320 write_dir("status dir\n");
325 * Put text into the console window
327 void Console::display_textf(const char *fmt, ...)
332 va_start(arg_ptr, fmt);
333 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
338 void Console::display_text(const QString buf)
340 m_cursor->movePosition(QTextCursor::End);
341 m_cursor->insertText(buf);
345 void Console::display_text(const char *buf)
347 m_cursor->movePosition(QTextCursor::End);
348 m_cursor->insertText(buf);
351 /* Position cursor to end of screen */
352 void Console::update_cursor()
354 QApplication::restoreOverrideCursor();
355 m_textEdit->moveCursor(QTextCursor::End);
356 m_textEdit->ensureCursorVisible();
360 * This should be moved into a bSocket class
370 /* Send a command to the Director */
371 void Console::write_dir(const char *msg)
374 mainWin->set_status(_("Processing command ..."));
375 QApplication::setOverrideCursor(Qt::WaitCursor);
378 mainWin->set_status(" Director not connected. Click on connect button.");
379 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
380 QBrush redBrush(Qt::red);
381 m_consoleItem->setForeground(0, redBrush);
386 int Console::write(const QString msg)
388 return write(msg.toUtf8().data());
391 int Console::write(const char *msg)
393 m_sock->msglen = strlen(msg);
394 pm_strcpy(&m_sock->msg, msg);
396 if (commDebug) Pmsg1(000, "send: %s\n", msg);
397 return m_sock->send();
401 * Get to main command prompt
403 void Console::beginNewCommand()
417 void Console::displayToPrompt()
420 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
421 while (!m_at_prompt) {
422 if ((stat=read()) > 0) {
426 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
429 void Console::discardToPrompt()
432 if (commDebug) Pmsg0(000, "discardToPrompt\n");
433 while (!m_at_prompt) {
436 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
441 * Blocking read from director
448 stat = bnet_wait_data_intr(m_sock, 1);
452 app->processEvents();
453 if (m_api_set && m_messages_pending) {
454 write_dir(".messages");
455 m_messages_pending = false;
458 stat = m_sock->recv();
464 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
466 switch (m_sock->msglen) {
467 case BNET_SERVER_READY:
468 if (m_api_set && m_messages_pending) {
469 write_dir(".messages");
470 m_messages_pending = false;
474 case BNET_MSGS_PENDING:
475 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
476 m_messages_pending = true;
479 if (commDebug) Pmsg0(000, "CMD OK\n");
483 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
487 if (commDebug) Pmsg0(000, "PROMPT\n");
489 mainWin->set_status(_("At prompt waiting for input ..."));
491 QApplication::restoreOverrideCursor();
493 case BNET_CMD_FAILED:
494 if (commDebug) Pmsg0(000, "CMD FAIL\n");
495 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
497 QApplication::restoreOverrideCursor();
499 /* We should not get this one */
501 if (commDebug) Pmsg0(000, "EOD\n");
502 mainWin->set_status_ready();
504 QApplication::restoreOverrideCursor();
509 case BNET_START_SELECT:
510 new selectDialog(this);
513 new runCmdDialog(this);
516 m_sock->recv(); /* get the message */
518 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
520 case BNET_WARNING_MSG:
521 m_sock->recv(); /* get the message */
523 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
526 m_sock->recv(); /* get the message */
528 mainWin->set_status(msg());
531 if (is_bnet_stop(m_sock)) { /* error or term request */
534 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
535 QBrush redBrush(Qt::red);
536 m_consoleItem->setForeground(0, redBrush);
537 m_notifier->setEnabled(false);
540 mainWin->set_status(_("Director disconnected."));
541 QApplication::restoreOverrideCursor();
549 /* Called by signal when the Director has output for us */
550 void Console::read_dir(int fd)
555 if (commDebug) Pmsg0(000, "read_dir\n");
556 while ((stat = read()) >= 0) {
562 * When the notifier is enabled, read_dir() will automatically be
563 * called by the Qt event loop when ever there is any output
564 * from the Directory, and read_dir() will then display it on
567 * When we are in a bat dialog, we want to control *all* output
568 * from the Directory, so we set notify to off.
569 * m_console->notifiy(false);
571 void Console::notify(bool enable)
573 m_notifier->setEnabled(enable);
576 void Console::setTreeItem(QTreeWidgetItem *item)
578 m_consoleItem = item;
581 void Console::setDirRes(DIRRES *dir)