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);
163 * Send a command to the Director, and return the
164 * results in a QStringList.
166 bool Console::dir_cmd(const char *cmd, QStringList &results)
172 while ((stat = read()) > 0) {
173 strip_trailing_junk(msg());
178 return true; /* ***FIXME*** return any command error */
181 bool Console::sql_cmd(QString &query, QStringList &results)
183 return sql_cmd(query.toUtf8().data(), results);
187 * Send an sql query to the Director, and return the
188 * results in a QStringList.
190 bool Console::sql_cmd(const char *query, QStringList &results)
193 POOL_MEM cmd(PM_MESSAGE);
197 pm_strcpy(cmd, ".sql query=\"");
198 pm_strcat(cmd, query);
199 pm_strcat(cmd, "\"");
201 while ((stat = read()) > 0) {
202 strip_trailing_junk(msg());
207 return true; /* ***FIXME*** return any command error */
212 * Send a job name to the director, and read all the resulting
215 bool Console::get_job_defaults(struct job_defaults &job_defs)
223 scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
225 while ((stat = read()) > 0) {
226 def = strchr(msg(), '=');
230 /* Pointer to default value */
232 strip_trailing_junk(def);
234 if (strcmp(msg(), "job") == 0) {
235 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
240 if (strcmp(msg(), "pool") == 0) {
241 job_defs.pool_name = def;
244 if (strcmp(msg(), "messages") == 0) {
245 job_defs.messages_name = def;
248 if (strcmp(msg(), "client") == 0) {
249 job_defs.client_name = def;
252 if (strcmp(msg(), "storage") == 0) {
253 job_defs.store_name = def;
256 if (strcmp(msg(), "where") == 0) {
257 job_defs.where = def;
260 if (strcmp(msg(), "level") == 0) {
261 job_defs.level = def;
264 if (strcmp(msg(), "type") == 0) {
268 if (strcmp(msg(), "fileset") == 0) {
269 job_defs.fileset_name = def;
272 if (strcmp(msg(), "catalog") == 0) {
273 job_defs.catalog_name = def;
276 if (strcmp(msg(), "enabled") == 0) {
277 job_defs.enabled = *def == '1' ? true : false;
283 bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
284 "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
285 job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(),
286 job_defs.client_name.toUtf8().data(),
287 job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(),
288 job_defs.store_name.toUtf8().data(),
289 job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(),
290 job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
291 job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
304 * Save user settings associated with this console
306 void Console::writeSettings()
308 QFont font = get_font();
310 QSettings settings("bacula.org", "bat");
311 /* ***FIXME*** make console name unique */
312 settings.beginGroup("Console");
313 settings.setValue("consoleFont", font.family());
314 settings.setValue("consolePointSize", font.pointSize());
315 settings.setValue("consoleFixedPitch", font.fixedPitch());
320 * Read and restore user settings associated with this console
322 void Console::readSettings()
324 QFont font = get_font();
326 QSettings settings("bacula.org", "bat");
327 settings.beginGroup("Console");
328 font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
329 font.setPointSize(settings.value("consolePointSize", 10).toInt());
330 font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
332 m_textEdit->setFont(font);
336 * Set the console textEdit font
338 void Console::set_font()
341 QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
343 m_textEdit->setFont(font);
348 * Get the console text edit font
350 const QFont Console::get_font()
352 return m_textEdit->font();
356 void Console::status_dir()
358 write_dir("status dir\n");
363 * Put text into the console window
365 void Console::display_textf(const char *fmt, ...)
370 va_start(arg_ptr, fmt);
371 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
376 void Console::display_text(const QString buf)
378 m_cursor->movePosition(QTextCursor::End);
379 m_cursor->insertText(buf);
383 void Console::display_text(const char *buf)
385 m_cursor->movePosition(QTextCursor::End);
386 m_cursor->insertText(buf);
389 /* Position cursor to end of screen */
390 void Console::update_cursor()
392 QApplication::restoreOverrideCursor();
393 m_textEdit->moveCursor(QTextCursor::End);
394 m_textEdit->ensureCursorVisible();
398 * This should be moved into a bSocket class
408 /* Send a command to the Director */
409 void Console::write_dir(const char *msg)
412 mainWin->set_status(_("Processing command ..."));
413 QApplication::setOverrideCursor(Qt::WaitCursor);
416 mainWin->set_status(" Director not connected. Click on connect button.");
417 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
418 QBrush redBrush(Qt::red);
419 m_treeItem->setForeground(0, redBrush);
424 int Console::write(const QString msg)
426 return write(msg.toUtf8().data());
429 int Console::write(const char *msg)
431 m_sock->msglen = pm_strcpy(m_sock->msg, msg);
433 if (commDebug) Pmsg1(000, "send: %s\n", msg);
434 return m_sock->send();
438 * Get to main command prompt
440 void Console::beginNewCommand()
454 void Console::displayToPrompt()
457 if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
458 while (!m_at_prompt) {
459 if ((stat=read()) > 0) {
463 if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
466 void Console::discardToPrompt()
469 if (commDebug) Pmsg0(000, "discardToPrompt\n");
470 while (!m_at_prompt) {
473 if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
478 * Blocking read from director
485 stat = bnet_wait_data_intr(m_sock, 1);
489 app->processEvents();
490 if (m_api_set && m_messages_pending) {
491 write_dir(".messages");
492 m_messages_pending = false;
495 stat = m_sock->recv();
501 if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
503 switch (m_sock->msglen) {
504 case BNET_SERVER_READY:
505 if (m_api_set && m_messages_pending) {
506 write_dir(".messages");
507 m_messages_pending = false;
511 case BNET_MSGS_PENDING:
512 if (commDebug) Pmsg0(000, "MSGS PENDING\n");
513 m_messages_pending = true;
516 if (commDebug) Pmsg0(000, "CMD OK\n");
520 if (commDebug) Pmsg0(000, "CMD BEGIN\n");
524 if (commDebug) Pmsg0(000, "PROMPT\n");
526 mainWin->set_status(_("At prompt waiting for input ..."));
528 QApplication::restoreOverrideCursor();
530 case BNET_CMD_FAILED:
531 if (commDebug) Pmsg0(000, "CMD FAIL\n");
532 mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
534 QApplication::restoreOverrideCursor();
536 /* We should not get this one */
538 if (commDebug) Pmsg0(000, "EOD\n");
539 mainWin->set_status_ready();
541 QApplication::restoreOverrideCursor();
546 case BNET_START_SELECT:
547 new selectDialog(this);
550 new runCmdDialog(this);
553 m_sock->recv(); /* get the message */
555 QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
557 case BNET_WARNING_MSG:
558 m_sock->recv(); /* get the message */
560 QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
563 m_sock->recv(); /* get the message */
565 mainWin->set_status(msg());
568 if (is_bnet_stop(m_sock)) { /* error or term request */
571 mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
572 QBrush redBrush(Qt::red);
573 m_treeItem->setForeground(0, redBrush);
574 m_notifier->setEnabled(false);
577 mainWin->set_status(_("Director disconnected."));
578 QApplication::restoreOverrideCursor();
586 /* Called by signal when the Director has output for us */
587 void Console::read_dir(int fd)
592 if (commDebug) Pmsg0(000, "read_dir\n");
593 while ((stat = read()) >= 0) {
599 * When the notifier is enabled, read_dir() will automatically be
600 * called by the Qt event loop when ever there is any output
601 * from the Directory, and read_dir() will then display it on
604 * When we are in a bat dialog, we want to control *all* output
605 * from the Directory, so we set notify to off.
606 * m_console->notifiy(false);
608 void Console::notify(bool enable)
610 m_notifier->setEnabled(enable);
613 void Console::setDirRes(DIRRES *dir)
618 ******FIXME****** Just Delete me
619 void Console::dosql(QString* sqlcmd, QStringList& strlstret)
622 /* don't effect the string coming in */
623 QString cmd(*sqlcmd);
625 cmd = ".sql \"" + cmd + "\"";
627 write_dir(cmd.toUtf8().data());
628 while ((stat=read()) > 0) {
629 QString line = msg();
630 QRegExp regex("^Using Catalog");
631 if ( regex.indexIn(line) < 0 ){
632 strlstret.append(line);