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);
65 void Console::poll_messages()
67 m_messages_pending = true;
70 /* Terminate any open socket */
71 void Console::terminate()
81 * Connect to Director. If there are more than one, put up
82 * a modal dialog so that the user chooses one.
84 void Console::connect()
88 m_textEdit = textEdit; /* our console screen */
91 mainWin->set_status("No Director found.");
95 mainWin->set_status("Already connected.");
99 memset(&jcr, 0, sizeof(jcr));
101 mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
102 display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
104 /* Give GUI a chance */
105 app->processEvents();
108 /* If cons==NULL, default console will be used */
109 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
112 m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
113 NULL, m_dir->DIRport, 0);
114 if (m_sock == NULL) {
115 mainWin->set_status("Connection failed");
118 /* Update page selector to green to indicate that Console is connected */
119 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
120 QBrush greenBrush(Qt::green);
121 m_treeItem->setForeground(0, greenBrush);
124 jcr.dir_bsock = m_sock;
126 if (!authenticate_director(&jcr, m_dir, cons)) {
127 display_text(m_sock->msg);
131 /* Give GUI a chance */
132 app->processEvents();
134 mainWin->set_status(_("Initializing ..."));
136 /* Set up input notifier */
137 m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
138 QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
144 dir_cmd(".jobs", job_list);
145 dir_cmd(".clients", client_list);
146 dir_cmd(".filesets", fileset_list);
147 dir_cmd(".messages", messages_list);
148 dir_cmd(".pools", pool_list);
149 dir_cmd(".storage", storage_list);
150 dir_cmd(".types", type_list);
151 dir_cmd(".levels", level_list);
153 mainWin->set_status(_("Connected"));
157 bool Console::dir_cmd(QString &cmd, QStringList &results)
159 return dir_cmd(cmd.toUtf8().data(), results);
162 bool Console::dir_cmd(const char *cmd, QStringList &results)
168 while ((stat = read()) > 0) {
169 strip_trailing_junk(msg());
174 return true; /* ***FIXME*** return any command error */
179 * Send a job name to the director, and read all the resulting
182 bool Console::get_job_defaults(struct job_defaults &job_defs)
190 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
192 while ((stat = read()) > 0) {
193 def = strchr(msg(), '=');
197 /* Pointer to default value */
199 strip_trailing_junk(def);
201 if (strcmp(msg(), "job") == 0) {
202 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
207 if (strcmp(msg(), "pool") == 0) {
208 job_defs.pool_name = def;
211 if (strcmp(msg(), "messages") == 0) {
212 job_defs.messages_name = def;
215 if (strcmp(msg(), "client") == 0) {
216 job_defs.client_name = def;
219 if (strcmp(msg(), "storage") == 0) {
220 job_defs.store_name = def;
223 if (strcmp(msg(), "where") == 0) {
224 job_defs.where = def;
227 if (strcmp(msg(), "level") == 0) {
228 job_defs.level = def;
231 if (strcmp(msg(), "type") == 0) {
235 if (strcmp(msg(), "fileset") == 0) {
236 job_defs.fileset_name = def;
239 if (strcmp(msg(), "catalog") == 0) {
240 job_defs.catalog_name = def;
243 if (strcmp(msg(), "enabled") == 0) {
244 job_defs.enabled = *def == '1' ? true : false;
250 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
251 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
252 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
253 job_defs.client_name.toUtf8().data(),
254 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
255 job_defs.store_name.toUtf8().data(),
256 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
257 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
258 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
271 * Save user settings associated with this console
273 void Console::writeSettings()
275 QFont font = get_font();
277 QSettings settings("bacula.org", "bat");
278 /* ***FIXME*** make console name unique */
279 settings.beginGroup("Console");
280 settings.setValue("consoleFont", font.family());
281 settings.setValue("consolePointSize", font.pointSize());
282 settings.setValue("consoleFixedPitch", font.fixedPitch());
287 * Read and restore user settings associated with this console
289 void Console::readSettings()
291 QFont font = get_font();
293 QSettings settings("bacula.org", "bat");
294 settings.beginGroup("Console");
295 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
296 font.setPointSize(settings.value("consolePointSize", 10).toInt());
297 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
299 m_textEdit->setFont(font);
303 * Set the console textEdit font
305 void Console::set_font()
308 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
310 m_textEdit->setFont(font);
315 * Get the console text edit font
317 const QFont Console::get_font()
319 return m_textEdit->font();
323 void Console::status_dir()
325 write_dir("status dir\n");
330 * Put text into the console window
332 void Console::display_textf(const char *fmt, ...)
337 va_start(arg_ptr, fmt);
338 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
343 void Console::display_text(const QString buf)
345 m_cursor->movePosition(QTextCursor::End);
346 m_cursor->insertText(buf);
350 void Console::display_text(const char *buf)
352 m_cursor->movePosition(QTextCursor::End);
353 m_cursor->insertText(buf);
356 /* Position cursor to end of screen */
357 void Console::update_cursor()
359 QApplication::restoreOverrideCursor();
360 m_textEdit->moveCursor(QTextCursor::End);
361 m_textEdit->ensureCursorVisible();
365 * This should be moved into a bSocket class
375 /* Send a command to the Director */
376 void Console::write_dir(const char *msg)
379 mainWin->set_status(_("Processing command ..."));
380 QApplication::setOverrideCursor(Qt::WaitCursor);
383 mainWin->set_status(" Director not connected. Click on connect button.");
384 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
385 QBrush redBrush(Qt::red);
386 m_treeItem->setForeground(0, redBrush);
391 int Console::write(const QString msg)
393 return write(msg.toUtf8().data());
396 int Console::write(const char *msg)
398 m_sock->msglen = strlen(msg);
399 pm_strcpy(&m_sock->msg, msg);
401 if (commDebug) Pmsg1(000, "send: %s\n", msg);
402 return m_sock->send();
406 * Get to main command prompt
408 void Console::beginNewCommand()
422 void Console::displayToPrompt()
425 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
426 while (!m_at_prompt) {
427 if ((stat=read()) > 0) {
431 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
434 void Console::discardToPrompt()
437 if (commDebug) Pmsg0(000, "discardToPrompt\n");
438 while (!m_at_prompt) {
441 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
446 * Blocking read from director
453 stat = bnet_wait_data_intr(m_sock, 1);
457 app->processEvents();
458 if (m_api_set && m_messages_pending) {
459 write_dir(".messages");
460 m_messages_pending = false;
463 stat = m_sock->recv();
469 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
471 switch (m_sock->msglen) {
472 case BNET_SERVER_READY:
473 if (m_api_set && m_messages_pending) {
474 write_dir(".messages");
475 m_messages_pending = false;
479 case BNET_MSGS_PENDING:
480 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
481 m_messages_pending = true;
484 if (commDebug) Pmsg0(000, "CMD OK\n");
488 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
492 if (commDebug) Pmsg0(000, "PROMPT\n");
494 mainWin->set_status(_("At prompt waiting for input ..."));
496 QApplication::restoreOverrideCursor();
498 case BNET_CMD_FAILED:
499 if (commDebug) Pmsg0(000, "CMD FAIL\n");
500 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
502 QApplication::restoreOverrideCursor();
504 /* We should not get this one */
506 if (commDebug) Pmsg0(000, "EOD\n");
507 mainWin->set_status_ready();
509 QApplication::restoreOverrideCursor();
514 case BNET_START_SELECT:
515 new selectDialog(this);
518 new runCmdDialog(this);
521 m_sock->recv(); /* get the message */
523 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
525 case BNET_WARNING_MSG:
526 m_sock->recv(); /* get the message */
528 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
531 m_sock->recv(); /* get the message */
533 mainWin->set_status(msg());
536 if (is_bnet_stop(m_sock)) { /* error or term request */
539 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
540 QBrush redBrush(Qt::red);
541 m_treeItem->setForeground(0, redBrush);
542 m_notifier->setEnabled(false);
545 mainWin->set_status(_("Director disconnected."));
546 QApplication::restoreOverrideCursor();
554 /* Called by signal when the Director has output for us */
555 void Console::read_dir(int fd)
560 if (commDebug) Pmsg0(000, "read_dir\n");
561 while ((stat = read()) >= 0) {
567 * When the notifier is enabled, read_dir() will automatically be
568 * called by the Qt event loop when ever there is any output
569 * from the Directory, and read_dir() will then display it on
572 * When we are in a bat dialog, we want to control *all* output
573 * from the Directory, so we set notify to off.
574 * m_console->notifiy(false);
576 void Console::notify(bool enable)
578 m_notifier->setEnabled(enable);
581 void Console::setDirRes(DIRRES *dir)
586 ******FIXME****** Just Delete me
587 void Console::dosql(QString* sqlcmd, QStringList& strlstret)
590 /* don't effect the string coming in */
591 QString cmd(*sqlcmd);
593 cmd = ".sql \"" + cmd + "\"";
595 write_dir(cmd.toUtf8().data());
596 while ((stat=read()) > 0) {
597 QString line = msg();
598 QRegExp regex("^Using Catalog");
599 if ( regex.indexIn(line) < 0 ){
600 strlstret.append(line);