]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Add intelegence to prerestore. Radio buttons for select or all files. Radio
[bacula/bacula] / bacula / src / qt-console / restore / restore.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 /*
30  *   Version $Id$
31  *
32  *  Restore Class 
33  *
34  *   Kern Sibbald, February MMVII
35  *
36  */ 
37
38 #include "bat.h"
39 #include "restore.h"
40
41 restorePage::restorePage()
42 {
43    QStringList titles;
44
45    setupUi(this);
46    m_name = "Restore Select";
47    pgInitialize();
48    m_console->notify(false);          /* this should already be off */
49    m_closeable = true;
50
51    connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), 
52            this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
53    connect(directoryWidget, SIGNAL(
54            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
55            this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
56    connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
57    connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
58    connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
59    connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
60    connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
61    setFont(m_console->get_font());
62    m_console->displayToPrompt();
63
64    titles << "Mark" << "File" << "Mode" << "User" << "Group" << "Size" << "Date";
65    fileWidget->setHeaderLabels(titles);
66
67    get_cwd();
68
69    fillDirectory();
70    dockPage();
71    setCurrent();
72    this->show();
73 }
74
75 /*
76  * Fill the fileWidget box with the contents of the current directory
77  */
78 void restorePage::fillDirectory()
79 {
80    char modes[20], user[20], group[20], size[20], date[30];
81    char marked[10];
82    int pnl, fnl;
83    POOLMEM *file = get_pool_memory(PM_FNAME);
84    POOLMEM *path = get_pool_memory(PM_FNAME);
85
86    fileWidget->clear();
87    m_console->write_dir("dir");
88    QList<QTreeWidgetItem *> treeItemList;
89    QStringList item;
90    while (m_console->read() > 0) {
91       char *p = m_console->msg();
92       char *l;
93       strip_trailing_junk(p);
94       if (*p == '$' || !*p) {
95          continue;
96       }
97       l = p;
98       skip_nonspaces(&p);             /* permissions */
99       *p++ = 0;
100       bstrncpy(modes, l, sizeof(modes));
101       skip_spaces(&p);
102       skip_nonspaces(&p);             /* link count */
103       *p++ = 0;
104       skip_spaces(&p);
105       l = p;
106       skip_nonspaces(&p);             /* user */
107       *p++ = 0;
108       skip_spaces(&p);
109       bstrncpy(user, l, sizeof(user));
110       l = p;
111       skip_nonspaces(&p);             /* group */
112       *p++ = 0;
113       bstrncpy(group, l, sizeof(group));
114       skip_spaces(&p);
115       l = p;
116       skip_nonspaces(&p);             /* size */
117       *p++ = 0;
118       bstrncpy(size, l, sizeof(size));
119       skip_spaces(&p);
120       l = p;
121       skip_nonspaces(&p);             /* date/time */
122       skip_spaces(&p);
123       skip_nonspaces(&p);
124       *p++ = 0;
125       bstrncpy(date, l, sizeof(date));
126       skip_spaces(&p);
127       if (*p == '*') {
128          bstrncpy(marked, "*", sizeof(marked));
129          p++;
130       } else {
131          bstrncpy(marked, " ", sizeof(marked));
132       }
133       split_path_and_filename(p, &path, &pnl, &file, &fnl);
134       item.clear();
135       item << marked << file << modes << user << group << size << date;
136       if (item[1].endsWith("/")) {
137          addDirectory(item[1]);
138        }
139       QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
140       ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
141       treeItemList.append(ti);
142    }
143    fileWidget->clear();
144    fileWidget->insertTopLevelItems(0, treeItemList);
145    for (int i=0; i<7; i++) {
146       fileWidget->resizeColumnToContents(i);
147    }
148
149    free_pool_memory(file);
150    free_pool_memory(path);
151 }
152
153 /*
154  * Function called from fill directory when a directory is found to see if this
155  * directory exists in the directory pane and then add it to the directory pane
156  */
157 void restorePage::addDirectory(QString &newdirr)
158 {
159    QString newdir = newdirr;
160    QString fullpath = m_cwd + newdirr;
161    QRegExp regex("^/[a-z]:/$");
162    bool ok=true;
163
164    //printf("In addDirectory cwd \"%s\" newdir \"%s\"\n", m_cwd.toUtf8().data(),
165         //newdir.toUtf8().data());
166
167    /* add unix '/' directory first */
168    if (m_dirPaths.empty() && (regex.indexIn(fullpath,0) == -1)) {
169       QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
170       QString text("/");
171       item->setText(0, text.toUtf8().data());
172       //printf("Pre Inserting %s\n",text.toUtf8().data());
173       m_dirPaths.insert(text, item);
174       m_dirTreeItems.insert(item, text);
175    }
176
177    if (regex.indexIn(fullpath,0) == 0) {
178       /* this is a windows drive */
179       //printf("Need to do windows c:/\n");
180       fullpath.replace(0,1,"");
181    }
182  
183    /* is it already existent ?? */
184    if (!m_dirPaths.contains(fullpath)) {
185       QTreeWidgetItem *item = NULL;
186       if (m_dirPaths.empty()) {
187          /* this is the base widget */
188          item = new QTreeWidgetItem(directoryWidget);
189          item->setText(0, fullpath.toUtf8().data());
190       } else {
191          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
192          if (parent) {
193             /* new directories to add */
194             item = new QTreeWidgetItem(parent);
195             item->setText(0, newdir.toUtf8().data());
196             directoryWidget->expandItem(parent);
197          } else {
198             ok=false;
199             //printf("In else of if parent cwd \"%s\" newdir \"%s\"\n", 
200                //m_cwd.toUtf8().data() ,newdir.toUtf8().data());
201          }
202       }
203       /* insert into both forward and reverse hash */
204       if (ok) {
205          //printf("Inserting %s\n",fullpath.toUtf8().data());
206          m_dirPaths.insert(fullpath, item);
207          m_dirTreeItems.insert(item, fullpath);
208       }
209    }
210 }
211
212 /*
213  * Executed when the tree item in the directory pane is changed.  This will
214  * allow us to populate the file pane and make this the cwd.
215  */
216 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
217                                          QTreeWidgetItem * /*previousitem*/)
218 {
219    QString fullpath = m_dirTreeItems.value(currentitem);
220    if (fullpath != ""){
221       cwd(fullpath.toUtf8().data());
222       fillDirectory();
223    }
224 }
225
226 void restorePage::okButtonPushed()
227 {
228    this->hide();
229    m_console->write("done");
230    m_console->notify(true);
231    closeStackPage();
232    mainWin->resetFocus();
233 }
234
235
236 void restorePage::cancelButtonPushed()
237 {
238    this->hide();
239    m_console->write("quit");
240    m_console->displayToPrompt();
241    mainWin->set_status("Canceled");
242    closeStackPage();
243    m_console->notify(true);
244    mainWin->resetFocus();
245 }
246
247 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
248 {
249    char cmd[1000];
250    if (column == 0) {                 /* mark/unmark */
251       if (item->text(0) == "*") {
252          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
253          item->setText(0, " ");
254       } else {
255          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
256          item->setText(0, "*");
257       }
258       m_console->write_dir(cmd);
259       if (m_console->read() > 0) {
260          strip_trailing_junk(m_console->msg());
261          statusLine->setText(m_console->msg());
262       }
263       m_console->displayToPrompt();
264       return;
265    }    
266    /* 
267     * Double clicking other than column 0 means to decend into
268     *  the directory -- or nothing if it is not a directory.
269     */
270    if (item->text(1).endsWith("/")) {
271       QString fullpath = m_cwd + item->text(1);
272       /* check for fullpath = "/c:/" */
273       QRegExp regex("^/[a-z]:/");
274       if (regex.indexIn(fullpath,0) == 0)  /* remove leading '/' */
275          fullpath.replace(0,1,"");
276       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
277       if (item) {
278          directoryWidget->setCurrentItem(item);
279       } else {
280          /* FIXME ***** Create an error log */
281          //printf("DoubleClick else of item column %i fullpath %s\n", column, fullpath.toUtf8().data());
282       }
283    }
284 }
285
286 /*
287  * If up button pushed, making the parent tree widget current will call fill
288  * directory.
289  */
290 void restorePage::upButtonPushed()
291 {
292    cwd("..");
293    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
294    if (item) {
295       directoryWidget->setCurrentItem(item);
296    }
297 }
298
299 /*
300  * Mark selected items
301  */
302 void restorePage::markButtonPushed()
303 {
304    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
305    QTreeWidgetItem *item;
306    char cmd[1000];
307    foreach (item, treeItemList) {
308       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
309       item->setText(0, "*");
310       m_console->write_dir(cmd);
311       if (m_console->read() > 0) {
312          strip_trailing_junk(m_console->msg());
313          statusLine->setText(m_console->msg());
314       }
315       Dmsg1(100, "cmd=%s\n", cmd);
316       m_console->discardToPrompt();
317    }
318 }
319
320 /*
321  * Unmark selected items
322  */
323 void restorePage::unmarkButtonPushed()
324 {
325    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
326    QTreeWidgetItem *item;
327    char cmd[1000];
328    foreach (item, treeItemList) {
329       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
330       item->setText(0, " ");
331       m_console->write_dir(cmd);
332       if (m_console->read() > 0) {
333          strip_trailing_junk(m_console->msg());
334          statusLine->setText(m_console->msg());
335       }
336       Dmsg1(100, "cmd=%s\n", cmd);
337       m_console->discardToPrompt();
338    }
339 }
340
341 /*
342  * Change current working directory 
343  */
344 bool restorePage::cwd(const char *dir)
345 {
346    int stat;
347    char cd_cmd[MAXSTRING];
348
349    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
350    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
351    m_console->write_dir(cd_cmd);
352    lineEdit->clear();
353    if ((stat = m_console->read()) > 0) {
354       m_cwd = m_console->msg();
355       lineEdit->insert(m_cwd);
356       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
357    } else {
358       Dmsg1(000, "stat=%d\n", stat);
359       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
360    }
361    m_console->discardToPrompt();
362    return true;  /* ***FIXME*** return real status */
363 }
364
365 /*
366  * Return cwd when in tree restore mode 
367  */
368 char *restorePage::get_cwd()
369 {
370    int stat;
371    m_console->write_dir(".pwd");
372    Dmsg0(100, "send: .pwd\n");
373    if ((stat = m_console->read()) > 0) {
374       m_cwd = m_console->msg();
375       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
376    } else {
377       Dmsg1(000, "stat=%d\n", stat);
378       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
379       Dmsg1(000, "stat=%d\n", stat);
380    }
381    m_console->discardToPrompt(); 
382    return m_cwd.toUtf8().data();
383 }