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_treeItem->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 dir_cmd(".jobs", job_list);
142 dir_cmd(".clients", client_list);
143 dir_cmd(".filesets", fileset_list);
144 dir_cmd(".messages", messages_list);
145 dir_cmd(".pools", pool_list);
146 dir_cmd(".storage", storage_list);
147 dir_cmd(".types", type_list);
148 dir_cmd(".levels", level_list);
150 mainWin->set_status(_("Connected"));
154 bool Console::dir_cmd(const char *cmd, QStringList &results)
160 while ((stat = read()) > 0) {
161 strip_trailing_junk(msg());
166 return true; /* ***FIXME*** return any command error */
171 * Send a job name to the director, and read all the resulting
174 bool Console::get_job_defaults(struct job_defaults &job_defs)
182 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
184 while ((stat = read()) > 0) {
185 def = strchr(msg(), '=');
189 /* Pointer to default value */
191 strip_trailing_junk(def);
193 if (strcmp(msg(), "job") == 0) {
194 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
199 if (strcmp(msg(), "pool") == 0) {
200 job_defs.pool_name = def;
203 if (strcmp(msg(), "messages") == 0) {
204 job_defs.messages_name = def;
207 if (strcmp(msg(), "client") == 0) {
208 job_defs.client_name = def;
211 if (strcmp(msg(), "storage") == 0) {
212 job_defs.store_name = def;
215 if (strcmp(msg(), "where") == 0) {
216 job_defs.where = def;
219 if (strcmp(msg(), "level") == 0) {
220 job_defs.level = def;
223 if (strcmp(msg(), "type") == 0) {
227 if (strcmp(msg(), "fileset") == 0) {
228 job_defs.fileset_name = def;
231 if (strcmp(msg(), "catalog") == 0) {
232 job_defs.catalog_name = def;
235 if (strcmp(msg(), "enabled") == 0) {
236 job_defs.enabled = *def == '1' ? true : false;
242 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
243 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
244 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
245 job_defs.client_name.toUtf8().data(),
246 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
247 job_defs.store_name.toUtf8().data(),
248 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
249 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
250 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
263 * Save user settings associated with this console
265 void Console::writeSettings()
267 QFont font = get_font();
269 QSettings settings("bacula.org", "bat");
270 /* ***FIXME*** make console name unique */
271 settings.beginGroup("Console");
272 settings.setValue("consoleFont", font.family());
273 settings.setValue("consolePointSize", font.pointSize());
274 settings.setValue("consoleFixedPitch", font.fixedPitch());
279 * Read and restore user settings associated with this console
281 void Console::readSettings()
283 QFont font = get_font();
285 QSettings settings("bacula.org", "bat");
286 settings.beginGroup("Console");
287 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
288 font.setPointSize(settings.value("consolePointSize", 10).toInt());
289 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
291 m_textEdit->setFont(font);
295 * Set the console textEdit font
297 void Console::set_font()
300 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
302 m_textEdit->setFont(font);
307 * Get the console text edit font
309 const QFont Console::get_font()
311 return m_textEdit->font();
315 void Console::status_dir()
317 write_dir("status dir\n");
322 * Put text into the console window
324 void Console::display_textf(const char *fmt, ...)
329 va_start(arg_ptr, fmt);
330 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
335 void Console::display_text(const QString buf)
337 m_cursor->movePosition(QTextCursor::End);
338 m_cursor->insertText(buf);
342 void Console::display_text(const char *buf)
344 m_cursor->movePosition(QTextCursor::End);
345 m_cursor->insertText(buf);
348 /* Position cursor to end of screen */
349 void Console::update_cursor()
351 QApplication::restoreOverrideCursor();
352 m_textEdit->moveCursor(QTextCursor::End);
353 m_textEdit->ensureCursorVisible();
357 * This should be moved into a bSocket class
367 /* Send a command to the Director */
368 void Console::write_dir(const char *msg)
371 mainWin->set_status(_("Processing command ..."));
372 QApplication::setOverrideCursor(Qt::WaitCursor);
375 mainWin->set_status(" Director not connected. Click on connect button.");
376 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
377 QBrush redBrush(Qt::red);
378 m_treeItem->setForeground(0, redBrush);
383 int Console::write(const QString msg)
385 return write(msg.toUtf8().data());
388 int Console::write(const char *msg)
390 m_sock->msglen = strlen(msg);
391 pm_strcpy(&m_sock->msg, msg);
393 if (commDebug) Pmsg1(000, "send: %s\n", msg);
394 return m_sock->send();
398 * Get to main command prompt
400 void Console::beginNewCommand()
414 void Console::displayToPrompt()
417 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
418 while (!m_at_prompt) {
419 if ((stat=read()) > 0) {
423 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
426 void Console::discardToPrompt()
429 if (commDebug) Pmsg0(000, "discardToPrompt\n");
430 while (!m_at_prompt) {
433 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
438 * Blocking read from director
445 stat = bnet_wait_data_intr(m_sock, 1);
449 app->processEvents();
450 if (m_api_set && m_messages_pending) {
451 write_dir(".messages");
452 m_messages_pending = false;
455 stat = m_sock->recv();
461 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
463 switch (m_sock->msglen) {
464 case BNET_SERVER_READY:
465 if (m_api_set && m_messages_pending) {
466 write_dir(".messages");
467 m_messages_pending = false;
471 case BNET_MSGS_PENDING:
472 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
473 m_messages_pending = true;
476 if (commDebug) Pmsg0(000, "CMD OK\n");
480 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
484 if (commDebug) Pmsg0(000, "PROMPT\n");
486 mainWin->set_status(_("At prompt waiting for input ..."));
488 QApplication::restoreOverrideCursor();
490 case BNET_CMD_FAILED:
491 if (commDebug) Pmsg0(000, "CMD FAIL\n");
492 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
494 QApplication::restoreOverrideCursor();
496 /* We should not get this one */
498 if (commDebug) Pmsg0(000, "EOD\n");
499 mainWin->set_status_ready();
501 QApplication::restoreOverrideCursor();
506 case BNET_START_SELECT:
507 new selectDialog(this);
510 new runCmdDialog(this);
513 m_sock->recv(); /* get the message */
515 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
517 case BNET_WARNING_MSG:
518 m_sock->recv(); /* get the message */
520 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
523 m_sock->recv(); /* get the message */
525 mainWin->set_status(msg());
528 if (is_bnet_stop(m_sock)) { /* error or term request */
531 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
532 QBrush redBrush(Qt::red);
533 m_treeItem->setForeground(0, redBrush);
534 m_notifier->setEnabled(false);
537 mainWin->set_status(_("Director disconnected."));
538 QApplication::restoreOverrideCursor();
546 /* Called by signal when the Director has output for us */
547 void Console::read_dir(int fd)
552 if (commDebug) Pmsg0(000, "read_dir\n");
553 while ((stat = read()) >= 0) {
559 * When the notifier is enabled, read_dir() will automatically be
560 * called by the Qt event loop when ever there is any output
561 * from the Directory, and read_dir() will then display it on
564 * When we are in a bat dialog, we want to control *all* output
565 * from the Directory, so we set notify to off.
566 * m_console->notifiy(false);
568 void Console::notify(bool enable)
570 m_notifier->setEnabled(enable);
573 void Console::setDirRes(DIRRES *dir)
578 void Console::dosql(QString* sqlcmd, QStringList& strlstret)
581 /* don't effect the string coming in */
582 QString cmd(*sqlcmd);
584 cmd = ".sql \"" + cmd + "\"";
586 write_dir(cmd.toUtf8().data());
587 while ((stat=read()) > 0) {
588 QString line = msg();
589 QRegExp regex("^Using Catalog");
590 if ( regex.indexIn(line) < 0 ){
591 strlstret.append(line);