]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/console/console.cpp
Add updated nagios plugin supplied by Christian Masopust.
[bacula/bacula] / bacula / src / qt-console / console / console.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
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.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *   Version $Id$
30  *
31  *  Console Class
32  *
33  *   Kern Sibbald, January MMVII
34  *
35  */ 
36
37 #include <QAbstractEventDispatcher>
38 #include "bat.h"
39 #include "console.h"
40
41 Console::Console(QStackedWidget *parent)
42 {
43    QFont font;
44    QTreeWidgetItem *item, *topItem;
45    QTreeWidget *treeWidget = mainWin->treeWidget;
46
47    setupUi(this);
48    parent->addWidget(this);
49    m_sock = NULL;
50    m_at_prompt = false;
51    m_textEdit = textEdit;   /* our console screen */
52    m_cursor = new QTextCursor(m_textEdit->document());
53    mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
54
55    bRestore *brestore = new bRestore(parent);
56    brestore->setupUi(brestore);
57    parent->addWidget(brestore);
58
59    /* Just take the first Director */
60    LockRes();
61    m_dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
62    UnlockRes();
63
64    /* ***FIXME*** Dummy setup of treeWidget */
65    treeWidget->clear();
66    treeWidget->setColumnCount(1);
67    treeWidget->setHeaderLabel("Selection");
68    topItem = new QTreeWidgetItem(treeWidget);
69    topItem->setText(0, m_dir->name());
70    topItem->setIcon(0, QIcon(QString::fromUtf8("images/server.png")));
71    item = new QTreeWidgetItem(topItem);
72    m_consoleItem = item;
73    item->setText(0, "Console");
74    item->setText(1, "0");
75    QBrush redBrush(Qt::red);
76    item->setForeground(0, redBrush);
77    item = new QTreeWidgetItem(topItem);
78    item->setText(0, "brestore");
79    item->setText(1, "1");
80    treeWidget->expandItem(topItem);
81
82    readSettings();
83    /* Check for messages every 5 seconds */
84 // m_timer = new QTimer(this);
85 // QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
86 // m_timer->start(5000);
87
88 }
89
90 void Console::poll_messages()
91 {
92    m_messages_pending = true;
93 }
94
95 /* Terminate any open socket */
96 void Console::terminate()
97 {
98    if (m_sock) {
99       m_sock->close();
100       m_sock = NULL;
101    }
102 // m_timer->stop();
103 }
104
105 /*
106  * Connect to Director. If there are more than one, put up
107  * a modal dialog so that the user chooses one.
108  */
109 void Console::connect()
110 {
111    JCR jcr;
112
113    m_textEdit = textEdit;   /* our console screen */
114
115    if (!m_dir) {          
116       mainWin->set_status("No Director found.");
117       return;
118    }
119    if (m_sock) {
120       mainWin->set_status("Already connected.");
121       return;
122    }
123
124    memset(&jcr, 0, sizeof(jcr));
125
126    mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
127    display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
128
129    /* Give GUI a chance */
130    app->processEvents();
131    
132    LockRes();
133    /* If cons==NULL, default console will be used */
134    CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
135    UnlockRes();
136
137    m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address,
138                           NULL, m_dir->DIRport, 0);
139    if (m_sock == NULL) {
140       mainWin->set_status("Connection failed");
141       return;
142    } else {
143       /* Update page selector to green to indicate that Console is connected */
144       mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png")));
145       QBrush greenBrush(Qt::green);
146       m_consoleItem->setForeground(0, greenBrush);
147    }
148
149    jcr.dir_bsock = m_sock;
150
151    if (!authenticate_director(&jcr, m_dir, cons)) {
152       display_text(m_sock->msg);
153       return;
154    }
155
156    /* Give GUI a chance */
157    app->processEvents();
158
159    mainWin->set_status(_("Initializing ..."));
160
161    /* Set up input notifier */
162    m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0);
163    QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
164
165    write(".api");
166    discardToPrompt();
167
168    beginNewCommand();
169    job_list = get_list(".jobs");
170    client_list = get_list(".clients");
171    fileset_list = get_list(".filesets");
172    messages_list = get_list(".messages");
173    pool_list = get_list(".pools");
174    storage_list = get_list(".storage");
175    type_list = get_list(".types");
176    level_list = get_list(".levels");
177
178    mainWin->set_status(_("Connected"));
179    return;
180 }
181
182
183 /*  
184  * Send a command to the director, and read all the resulting
185  *  output into a list.
186  */
187 QStringList Console::get_list(char *cmd)
188 {
189    QStringList list;
190    int stat;
191
192    setEnabled(false);
193    write(cmd);
194    while ((stat = read()) > 0) {
195       strip_trailing_junk(msg());
196       list << msg();
197    }
198    setEnabled(true);
199 // list.sort();
200    return list;
201 }
202
203 /*  
204  * Send a job name to the director, and read all the resulting
205  *  defaults. 
206  */
207 bool Console::get_job_defaults(struct job_defaults &job_defs)
208 {
209    QString scmd;
210    char cmd[1000];
211    int stat;
212    char *def;
213
214    setEnabled(false);
215    beginNewCommand();
216    scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
217    write(scmd);
218    while ((stat = read()) > 0) {
219       def = strchr(msg(), '=');
220       if (!def) {
221          continue;
222       }
223       /* Pointer to default value */
224       *def++ = 0;
225       strip_trailing_junk(def);
226
227       if (strcmp(msg(), "job") == 0) {
228          if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) {
229             goto bail_out;
230          }
231          continue;
232       }
233       if (strcmp(msg(), "pool") == 0) {
234          job_defs.pool_name = def;
235          continue;
236       }
237       if (strcmp(msg(), "messages") == 0) {
238          job_defs.messages_name = def;
239          continue;
240       }
241       if (strcmp(msg(), "client") == 0) {
242          job_defs.client_name = def;
243          continue;
244       }
245       if (strcmp(msg(), "storage") == 0) {
246          job_defs.store_name = def;
247          continue;
248       }
249       if (strcmp(msg(), "where") == 0) {
250          job_defs.where = def;
251          continue;
252       }
253       if (strcmp(msg(), "level") == 0) {
254          job_defs.level = def;
255          continue;
256       }
257       if (strcmp(msg(), "type") == 0) {
258          job_defs.type = def;
259          continue;
260       }
261       if (strcmp(msg(), "fileset") == 0) {
262          job_defs.fileset_name = def;
263          continue;
264       }
265       if (strcmp(msg(), "catalog") == 0) {
266          job_defs.catalog_name = def;
267          continue;
268       }
269       if (strcmp(msg(), "enabled") == 0) {
270          job_defs.enabled = *def == '1' ? true : false;
271          continue;
272       }
273    }
274    bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n"
275       "level=%s type=%s fileset=%s catalog=%s enabled=%d\n",
276       job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(), 
277       job_defs.client_name.toUtf8().data(), 
278       job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(), 
279       job_defs.store_name.toUtf8().data(),
280       job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(), 
281       job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(),
282       job_defs.catalog_name.toUtf8().data(), job_defs.enabled);
283
284    setEnabled(true);
285    return true;
286
287 bail_out:
288    setEnabled(true);
289    return false;
290 }
291
292
293 /*
294  * Save user settings associated with this console
295  */
296 void Console::writeSettings()
297 {
298    QFont font = get_font();
299
300    QSettings settings("bacula.org", "bat");
301    /* ***FIXME*** make console name unique */
302    settings.beginGroup("Console");
303    settings.setValue("consoleFont", font.family());
304    settings.setValue("consolePointSize", font.pointSize());
305    settings.setValue("consoleFixedPitch", font.fixedPitch());
306    settings.endGroup();
307 }
308
309 /*
310  * Read and restore user settings associated with this console
311  */
312 void Console::readSettings()
313
314    QFont font = get_font();
315
316    QSettings settings("bacula.org", "bat");
317    settings.beginGroup("Console");
318    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
319    font.setPointSize(settings.value("consolePointSize", 10).toInt());
320    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
321    settings.endGroup();
322    m_textEdit->setFont(font);
323 }
324
325 /*
326  * Set the console textEdit font
327  */
328 void Console::set_font()
329 {
330    bool ok;
331    QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this);
332    if (ok) {
333       m_textEdit->setFont(font);
334    }
335 }
336
337 /*
338  * Get the console text edit font
339  */
340 const QFont Console::get_font()
341 {
342    return m_textEdit->font();
343 }
344
345
346 void Console::status_dir()
347 {
348    write_dir("status dir\n");
349    displayToPrompt();
350 }
351
352 /*
353  * Put text into the console window
354  */
355 void Console::display_textf(const char *fmt, ...)
356 {
357    va_list arg_ptr;
358    char buf[1000];
359    int len;
360    va_start(arg_ptr, fmt);
361    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
362    va_end(arg_ptr);
363    display_text(buf);
364 }
365
366 void Console::display_text(const QString buf)
367 {
368    m_cursor->movePosition(QTextCursor::End);
369    m_cursor->insertText(buf);
370 }
371
372
373 void Console::display_text(const char *buf)
374 {
375    m_cursor->movePosition(QTextCursor::End);
376    m_cursor->insertText(buf);
377 }
378
379 /* Position cursor to end of screen */
380 void Console::update_cursor()
381 {
382    QApplication::restoreOverrideCursor();
383    m_textEdit->moveCursor(QTextCursor::End);
384    m_textEdit->ensureCursorVisible();
385 }
386
387 /* 
388  * This should be moved into a bSocket class 
389  */
390 char *Console::msg()
391 {
392    if (m_sock) {
393       return m_sock->msg;
394    }
395    return NULL;
396 }
397
398 /* Send a command to the Director */
399 void Console::write_dir(const char *msg)
400 {
401    if (m_sock) {
402       mainWin->set_status(_("Processing command ..."));
403       QApplication::setOverrideCursor(Qt::WaitCursor);
404       write(msg);
405    } else {
406       mainWin->set_status(" Director not connected. Click on connect button.");
407       mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
408       QBrush redBrush(Qt::red);
409       m_consoleItem->setForeground(0, redBrush);
410    }
411 }
412
413 int Console::write(const QString msg)
414 {
415    return write(msg.toUtf8().data());
416 }
417
418 int Console::write(const char *msg)
419 {
420    m_sock->msglen = strlen(msg);
421    pm_strcpy(&m_sock->msg, msg);
422    m_at_prompt = false;
423    if (commDebug) Pmsg1(000, "send: %s\n", msg);
424    return m_sock->send();
425 }
426
427 /*
428  * Get to main command prompt 
429  */
430 void Console::beginNewCommand()
431 {
432    write(".\n");
433    while (read() > 0) {
434    }
435    write(".\n");
436    while (read() > 0) {
437    }
438    write(".\n");
439    while (read() > 0) {
440    }
441    display_text("\n");
442 }
443
444 void Console::displayToPrompt()
445
446    int stat;
447    if (commDebug) Pmsg0(000, "DisplaytoPrompt\n");
448    m_notifier->setEnabled(false);
449    while ((stat = read()) > 0) {
450       display_text(msg());
451    }
452    if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
453    m_notifier->setEnabled(true);
454 }
455
456 void Console::discardToPrompt()
457
458    int stat;
459    if (commDebug) Pmsg0(000, "discardToPrompt\n");
460    m_notifier->setEnabled(false);
461    while ((stat = read()) > 0) {
462    }
463    if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
464    m_notifier->setEnabled(true);
465 }
466
467
468 /* 
469  * Blocking read from director
470  */
471 int Console::read()
472 {
473    int stat = BNET_HARDEOF;
474    while (m_sock) {
475       for (;;) {
476          stat = bnet_wait_data_intr(m_sock, 1);
477          if (stat > 0) {
478             break;
479          } 
480          app->processEvents();
481 //       if (m_api_set && m_messages_pending) {
482 //          write_dir(".messages");
483 //          m_messages_pending = false;
484 //       }
485       }
486       stat = m_sock->recv();
487       if (stat >= 0) {
488          if (m_at_prompt) {
489             display_text("\n");
490             m_at_prompt = false;
491          }
492          if (commDebug) Pmsg1(000, "got: %s", m_sock->msg);
493
494       }
495       switch (m_sock->msglen) {
496       case BNET_SERVER_READY:
497 //       if (m_api_set && m_messages_pending) {
498 //          write_dir(".messages");
499 //          m_messages_pending = false;
500 //       }
501          m_at_prompt = true;
502          continue;
503       case BNET_MESSAGES_PENDING:
504          m_messages_pending = true;
505          continue;
506       case BNET_CMD_BEGIN:
507          m_at_prompt = false;
508          continue;
509       case BNET_PROMPT:
510       case BNET_CMD_OK:
511          if (commDebug) Pmsg0(000, "CMD OK/PROMPT\n");
512          m_at_prompt = true;
513          mainWin->set_status(_("At prompt waiting for input ..."));
514          update_cursor();
515          QApplication::restoreOverrideCursor();
516          break;
517       case BNET_CMD_FAILED:
518          if (commDebug) Pmsg0(000, "CMD FAIL\n");
519          m_at_prompt = true;
520          mainWin->set_status(_("Command failed. At prompt waiting for input ..."));
521          update_cursor();
522          QApplication::restoreOverrideCursor();
523          break;
524       case BNET_EOD:
525          if (commDebug) Pmsg0(000, "EOD\n");
526          mainWin->set_status_ready();
527          update_cursor();
528          QApplication::restoreOverrideCursor();
529          if (!m_api_set) {
530             break;
531          }
532          continue;
533       }
534       if (is_bnet_stop(m_sock)) {         /* error or term request */
535          m_sock->close();
536          m_sock = NULL;
537          mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png")));
538          QBrush redBrush(Qt::red);
539          m_consoleItem->setForeground(0, redBrush);
540          m_notifier->setEnabled(false);
541          delete m_notifier;
542          m_notifier = NULL;
543          mainWin->set_status(_("Director disconnected."));
544          QApplication::restoreOverrideCursor();
545       }
546       break;
547    } 
548    return stat;
549 }
550
551 /* Called by signal when the Director has output for us */
552 void Console::read_dir(int fd)
553 {
554    int stat;
555    (void)fd;
556
557    if (commDebug) Pmsg0(000, "read_dir\n");
558    while ((stat = read()) >= 0) {
559       display_text(msg());
560    }
561 }