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")));
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);
63 void Console::poll_messages()
65 m_messages_pending = true;
68 /* Terminate any open socket */
69 void Console::terminate()
79 * Connect to Director. If there are more than one, put up
80 * a modal dialog so that the user chooses one.
82 void Console::connect()
86 m_textEdit = textEdit; /* our console screen */
89 mainWin->set_status("No Director found.");
93 mainWin->set_status("Already connected.");
97 memset(&jcr, 0, sizeof(jcr));
99 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
100 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
102 /* Give GUI a chance */
103 app->processEvents();
106 /* If cons==NULL, default console will be used */
107 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
110 m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
111 NULL, m_dir->DIRport, 0);
112 if (m_sock == NULL) {
113 mainWin->set_status("Connection failed");
116 /* Update page selector to green to indicate that Console is connected */
117 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
118 QBrush greenBrush(Qt::green);
119 m_consoleItem->setForeground(0, greenBrush);
122 jcr.dir_bsock = m_sock;
124 if (!authenticate_director(&jcr, m_dir, cons)) {
125 display_text(m_sock->msg);
129 /* Give GUI a chance */
130 app->processEvents();
132 mainWin->set_status(_("Initializing ..."));
134 /* Set up input notifier */
135 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
136 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
142 job_list = get_list(".jobs");
143 client_list = get_list(".clients");
144 fileset_list = get_list(".filesets");
145 messages_list = get_list(".messages");
146 pool_list = get_list(".pools");
147 storage_list = get_list(".storage");
148 type_list = get_list(".types");
149 level_list = get_list(".levels");
151 mainWin->set_status(_("Connected"));
157 * Send a command to the director, and read all the resulting
158 * output into a list.
160 QStringList Console::get_list(char *cmd)
167 while ((stat = read()) > 0) {
168 strip_trailing_junk(msg());
176 * Send a job name to the director, and read all the resulting
179 bool Console::get_job_defaults(struct job_defaults &job_defs)
187 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
189 while ((stat = read()) > 0) {
190 def = strchr(msg(), '=');
194 /* Pointer to default value */
196 strip_trailing_junk(def);
198 if (strcmp(msg(), "job") == 0) {
199 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
204 if (strcmp(msg(), "pool") == 0) {
205 job_defs.pool_name = def;
208 if (strcmp(msg(), "messages") == 0) {
209 job_defs.messages_name = def;
212 if (strcmp(msg(), "client") == 0) {
213 job_defs.client_name = def;
216 if (strcmp(msg(), "storage") == 0) {
217 job_defs.store_name = def;
220 if (strcmp(msg(), "where") == 0) {
221 job_defs.where = def;
224 if (strcmp(msg(), "level") == 0) {
225 job_defs.level = def;
228 if (strcmp(msg(), "type") == 0) {
232 if (strcmp(msg(), "fileset") == 0) {
233 job_defs.fileset_name = def;
236 if (strcmp(msg(), "catalog") == 0) {
237 job_defs.catalog_name = def;
240 if (strcmp(msg(), "enabled") == 0) {
241 job_defs.enabled = *def == '1' ? true : false;
247 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
248 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
249 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
250 job_defs.client_name.toUtf8().data(),
251 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
252 job_defs.store_name.toUtf8().data(),
253 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
254 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
255 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
268 * Save user settings associated with this console
270 void Console::writeSettings()
272 QFont font = get_font();
274 QSettings settings("bacula.org", "bat");
275 /* ***FIXME*** make console name unique */
276 settings.beginGroup("Console");
277 settings.setValue("consoleFont", font.family());
278 settings.setValue("consolePointSize", font.pointSize());
279 settings.setValue("consoleFixedPitch", font.fixedPitch());
284 * Read and restore user settings associated with this console
286 void Console::readSettings()
288 QFont font = get_font();
290 QSettings settings("bacula.org", "bat");
291 settings.beginGroup("Console");
292 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
293 font.setPointSize(settings.value("consolePointSize", 10).toInt());
294 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
296 m_textEdit->setFont(font);
300 * Set the console textEdit font
302 void Console::set_font()
305 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
307 m_textEdit->setFont(font);
312 * Get the console text edit font
314 const QFont Console::get_font()
316 return m_textEdit->font();
320 void Console::status_dir()
322 write_dir("status dir\n");
327 * Put text into the console window
329 void Console::display_textf(const char *fmt, ...)
334 va_start(arg_ptr, fmt);
335 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
340 void Console::display_text(const QString buf)
342 m_cursor->movePosition(QTextCursor::End);
343 m_cursor->insertText(buf);
347 void Console::display_text(const char *buf)
349 m_cursor->movePosition(QTextCursor::End);
350 m_cursor->insertText(buf);
353 /* Position cursor to end of screen */
354 void Console::update_cursor()
356 QApplication::restoreOverrideCursor();
357 m_textEdit->moveCursor(QTextCursor::End);
358 m_textEdit->ensureCursorVisible();
362 * This should be moved into a bSocket class
372 /* Send a command to the Director */
373 void Console::write_dir(const char *msg)
376 mainWin->set_status(_("Processing command ..."));
377 QApplication::setOverrideCursor(Qt::WaitCursor);
380 mainWin->set_status(" Director not connected. Click on connect button.");
381 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
382 QBrush redBrush(Qt::red);
383 m_consoleItem->setForeground(0, redBrush);
388 int Console::write(const QString msg)
390 return write(msg.toUtf8().data());
393 int Console::write(const char *msg)
395 m_sock->msglen = strlen(msg);
396 pm_strcpy(&m_sock->msg, msg);
398 if (commDebug) Pmsg1(000, "send: %s\n", msg);
399 return m_sock->send();
403 * Get to main command prompt
405 void Console::beginNewCommand()
419 void Console::displayToPrompt()
422 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
423 while (!m_at_prompt) {
424 if ((stat=read()) > 0) {
428 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
431 void Console::discardToPrompt()
434 if (commDebug) Pmsg0(000, "discardToPrompt\n");
435 while (!m_at_prompt) {
438 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
443 * Blocking read from director
450 stat = bnet_wait_data_intr(m_sock, 1);
454 app->processEvents();
455 if (m_api_set && m_messages_pending) {
456 write_dir(".messages");
457 m_messages_pending = false;
460 stat = m_sock->recv();
466 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
468 switch (m_sock->msglen) {
469 case BNET_SERVER_READY:
470 if (m_api_set && m_messages_pending) {
471 write_dir(".messages");
472 m_messages_pending = false;
476 case BNET_MSGS_PENDING:
477 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
478 m_messages_pending = true;
481 if (commDebug) Pmsg0(000, "CMD OK\n");
485 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
489 if (commDebug) Pmsg0(000, "PROMPT\n");
491 mainWin->set_status(_("At prompt waiting for input ..."));
493 QApplication::restoreOverrideCursor();
495 case BNET_CMD_FAILED:
496 if (commDebug) Pmsg0(000, "CMD FAIL\n");
497 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
499 QApplication::restoreOverrideCursor();
501 /* We should not get this one */
503 if (commDebug) Pmsg0(000, "EOD\n");
504 mainWin->set_status_ready();
506 QApplication::restoreOverrideCursor();
511 case BNET_START_SELECT:
512 new selectDialog(this);
515 new runCmdDialog(this);
518 m_sock->recv(); /* get the message */
520 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
522 case BNET_WARNING_MSG:
523 m_sock->recv(); /* get the message */
525 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
528 m_sock->recv(); /* get the message */
530 mainWin->set_status(msg());
533 if (is_bnet_stop(m_sock)) { /* error or term request */
536 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
537 QBrush redBrush(Qt::red);
538 m_consoleItem->setForeground(0, redBrush);
539 m_notifier->setEnabled(false);
542 mainWin->set_status(_("Director disconnected."));
543 QApplication::restoreOverrideCursor();
551 /* Called by signal when the Director has output for us */
552 void Console::read_dir(int fd)
557 if (commDebug) Pmsg0(000, "read_dir\n");
558 while ((stat = read()) >= 0) {
564 * When the notifier is enabled, read_dir() will automatically be
565 * called by the Qt event loop when ever there is any output
566 * from the Directory, and read_dir() will then display it on
569 * When we are in a bat dialog, we want to control *all* output
570 * from the Directory, so we set notify to off.
571 * m_console->notifiy(false);
573 void Console::notify(bool enable)
575 m_notifier->setEnabled(enable);
578 void Console::setTreeItem(QTreeWidgetItem *item)
580 m_consoleItem = item;
583 void Console::setDirRes(DIRRES *dir)