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)
52 m_textEdit = textEdit; /* our console screen */
53 m_cursor = new QTextCursor(m_textEdit->document());
54 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);
66 void Console::poll_messages()
68 m_messages_pending = true;
71 /* Terminate any open socket */
72 void Console::terminate()
82 * Connect to Director. If there are more than one, put up
83 * a modal dialog so that the user chooses one.
85 void Console::connect()
89 m_textEdit = textEdit; /* our console screen */
92 mainWin->set_status("No Director found.");
96 mainWin->set_status("Already connected.");
100 memset(&jcr, 0, sizeof(jcr));
102 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
103 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
105 /* Give GUI a chance */
106 app->processEvents();
109 /* If cons==NULL, default console will be used */
110 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
113 m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
114 NULL, m_dir->DIRport, 0);
115 if (m_sock == NULL) {
116 mainWin->set_status("Connection failed");
119 /* Update page selector to green to indicate that Console is connected */
120 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
121 QBrush greenBrush(Qt::green);
122 QTreeWidgetItem *item = mainWin->getFromHash(this);
123 item->setForeground(0, greenBrush);
126 jcr.dir_bsock = m_sock;
128 if (!authenticate_director(&jcr, m_dir, cons)) {
129 display_text(m_sock->msg);
133 /* Give GUI a chance */
134 app->processEvents();
136 mainWin->set_status(_("Initializing ..."));
138 /* Set up input notifier */
139 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
140 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
146 dir_cmd(".jobs", job_list);
147 dir_cmd(".clients", client_list);
148 dir_cmd(".filesets", fileset_list);
149 dir_cmd(".messages", messages_list);
150 dir_cmd(".pools", pool_list);
151 dir_cmd(".storage", storage_list);
152 dir_cmd(".types", type_list);
153 dir_cmd(".levels", level_list);
155 mainWin->set_status(_("Connected"));
159 bool Console::dir_cmd(QString &cmd, QStringList &results)
161 return dir_cmd(cmd.toUtf8().data(), results);
165 * Send a command to the Director, and return the
166 * results in a QStringList.
168 bool Console::dir_cmd(const char *cmd, QStringList &results)
174 while ((stat = read()) > 0) {
175 strip_trailing_junk(msg());
180 return true; /* ***FIXME*** return any command error */
183 bool Console::sql_cmd(QString &query, QStringList &results)
185 return sql_cmd(query.toUtf8().data(), results);
189 * Send an sql query to the Director, and return the
190 * results in a QStringList.
192 bool Console::sql_cmd(const char *query, QStringList &results)
195 POOL_MEM cmd(PM_MESSAGE);
199 pm_strcpy(cmd, ".sql query=\"");
200 pm_strcat(cmd, query);
201 pm_strcat(cmd, "\"");
203 while ((stat = read()) > 0) {
204 strip_trailing_junk(msg());
209 return true; /* ***FIXME*** return any command error */
214 * Send a job name to the director, and read all the resulting
217 bool Console::get_job_defaults(struct job_defaults &job_defs)
225 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
227 while ((stat = read()) > 0) {
228 def = strchr(msg(), '=');
232 /* Pointer to default value */
234 strip_trailing_junk(def);
236 if (strcmp(msg(), "job") == 0) {
237 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
242 if (strcmp(msg(), "pool") == 0) {
243 job_defs.pool_name = def;
246 if (strcmp(msg(), "messages") == 0) {
247 job_defs.messages_name = def;
250 if (strcmp(msg(), "client") == 0) {
251 job_defs.client_name = def;
254 if (strcmp(msg(), "storage") == 0) {
255 job_defs.store_name = def;
258 if (strcmp(msg(), "where") == 0) {
259 job_defs.where = def;
262 if (strcmp(msg(), "level") == 0) {
263 job_defs.level = def;
266 if (strcmp(msg(), "type") == 0) {
270 if (strcmp(msg(), "fileset") == 0) {
271 job_defs.fileset_name = def;
274 if (strcmp(msg(), "catalog") == 0) {
275 job_defs.catalog_name = def;
278 if (strcmp(msg(), "enabled") == 0) {
279 job_defs.enabled = *def == '1' ? true : false;
285 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
286 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
287 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
288 job_defs.client_name.toUtf8().data(),
289 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
290 job_defs.store_name.toUtf8().data(),
291 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
292 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
293 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
306 * Save user settings associated with this console
308 void Console::writeSettings()
310 QFont font = get_font();
312 QSettings settings(m_dir->name(), "bat");
313 settings.beginGroup("Console");
314 settings.setValue("consoleFont", font.family());
315 settings.setValue("consolePointSize", font.pointSize());
316 settings.setValue("consoleFixedPitch", font.fixedPitch());
321 * Read and restore user settings associated with this console
323 void Console::readSettings()
325 QFont font = get_font();
327 QSettings settings(m_dir->name(), "bat");
328 settings.beginGroup("Console");
329 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
330 font.setPointSize(settings.value("consolePointSize", 10).toInt());
331 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
333 m_textEdit->setFont(font);
337 * Set the console textEdit font
339 void Console::set_font()
342 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
344 m_textEdit->setFont(font);
349 * Get the console text edit font
351 const QFont Console::get_font()
353 return m_textEdit->font();
357 void Console::status_dir()
359 write_dir("status dir\n");
364 * Put text into the console window
366 void Console::display_textf(const char *fmt, ...)
371 va_start(arg_ptr, fmt);
372 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
377 void Console::display_text(const QString buf)
379 m_cursor->movePosition(QTextCursor::End);
380 m_cursor->insertText(buf);
384 void Console::display_text(const char *buf)
386 m_cursor->movePosition(QTextCursor::End);
387 m_cursor->insertText(buf);
390 /* Position cursor to end of screen */
391 void Console::update_cursor()
393 QApplication::restoreOverrideCursor();
394 m_textEdit->moveCursor(QTextCursor::End);
395 m_textEdit->ensureCursorVisible();
399 * This should be moved into a bSocket class
409 /* Send a command to the Director */
410 void Console::write_dir(const char *msg)
413 mainWin->set_status(_("Processing command ..."));
414 QApplication::setOverrideCursor(Qt::WaitCursor);
417 mainWin->set_status(" Director not connected. Click on connect button.");
418 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
419 QBrush redBrush(Qt::red);
420 QTreeWidgetItem *item = mainWin->getFromHash(this);
421 item->setForeground(0, redBrush);
426 int Console::write(const QString msg)
428 return write(msg.toUtf8().data());
431 int Console::write(const char *msg)
433 m_sock->msglen = pm_strcpy(m_sock->msg, msg);
435 if (commDebug) Pmsg1(000, "send: %s\n", msg);
436 return m_sock->send();
440 * Get to main command prompt
442 void Console::beginNewCommand()
456 void Console::displayToPrompt()
459 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
460 while (!m_at_prompt) {
461 if ((stat=read()) > 0) {
465 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
468 void Console::discardToPrompt()
471 if (commDebug) Pmsg0(000, "discardToPrompt\n");
472 while (!m_at_prompt) {
475 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
480 * Blocking read from director
487 stat = bnet_wait_data_intr(m_sock, 1);
491 app->processEvents();
492 if (m_api_set && m_messages_pending) {
493 write_dir(".messages");
494 m_messages_pending = false;
497 stat = m_sock->recv();
503 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
505 switch (m_sock->msglen) {
506 case BNET_SERVER_READY:
507 if (m_api_set && m_messages_pending) {
508 write_dir(".messages");
509 m_messages_pending = false;
513 case BNET_MSGS_PENDING:
514 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
515 m_messages_pending = true;
518 if (commDebug) Pmsg0(000, "CMD OK\n");
522 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
526 if (commDebug) Pmsg0(000, "PROMPT\n");
528 mainWin->set_status(_("At prompt waiting for input ..."));
530 QApplication::restoreOverrideCursor();
532 case BNET_CMD_FAILED:
533 if (commDebug) Pmsg0(000, "CMD FAIL\n");
534 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
536 QApplication::restoreOverrideCursor();
538 /* We should not get this one */
540 if (commDebug) Pmsg0(000, "EOD\n");
541 mainWin->set_status_ready();
543 QApplication::restoreOverrideCursor();
548 case BNET_START_SELECT:
549 new selectDialog(this);
552 new runCmdDialog(this);
555 m_sock->recv(); /* get the message */
557 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
559 case BNET_WARNING_MSG:
560 m_sock->recv(); /* get the message */
562 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
565 m_sock->recv(); /* get the message */
567 mainWin->set_status(msg());
570 if (is_bnet_stop(m_sock)) { /* error or term request */
573 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
574 QBrush redBrush(Qt::red);
575 QTreeWidgetItem *item = mainWin->getFromHash(this);
576 item->setForeground(0, redBrush);
577 m_notifier->setEnabled(false);
580 mainWin->set_status(_("Director disconnected."));
581 QApplication::restoreOverrideCursor();
589 /* Called by signal when the Director has output for us */
590 void Console::read_dir(int fd)
595 if (commDebug) Pmsg0(000, "read_dir\n");
596 while ((stat = read()) >= 0) {
602 * When the notifier is enabled, read_dir() will automatically be
603 * called by the Qt event loop when ever there is any output
604 * from the Directory, and read_dir() will then display it on
607 * When we are in a bat dialog, we want to control *all* output
608 * from the Directory, so we set notify to off.
609 * m_console->notifiy(false);
611 void Console::notify(bool enable)
613 m_notifier->setEnabled(enable);
616 void Console::setDirectorTreeItem(QTreeWidgetItem *item)
618 m_directorTreeItem = item;
621 void Console::setDirRes(DIRRES *dir)
627 * To have the ability to get the name of the director resource.
629 void Console::getDirResName(QString &name_returned)
631 name_returned = m_dir->name();