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