]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Fix filesest was offset by 1. Weird, I had changed it earlier the other
[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    bool windrive = false;
164
165    //printf("In addDirectory cwd \"%s\" newdir \"%s\"\n", m_cwd.toUtf8().data(),
166         //newdir.toUtf8().data());
167
168    /* add unix '/' directory first */
169    if (m_dirPaths.empty() && (regex.indexIn(fullpath,0) == -1)) {
170       QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
171       QString text("/");
172       item->setText(0, text.toUtf8().data());
173       //printf("Pre Inserting %s\n",text.toUtf8().data());
174       m_dirPaths.insert(text, item);
175       m_dirTreeItems.insert(item, text);
176    }
177
178    if (regex.indexIn(fullpath,0) == 0) {
179       /* this is a windows drive */
180       //printf("Need to do windows \"letter\":/\n");
181       fullpath.replace(0,1,"");
182       windrive = true;
183    }
184  
185    /* is it already existent ?? */
186    if (!m_dirPaths.contains(fullpath)) {
187       QTreeWidgetItem *item = NULL;
188       if (windrive) {
189          /* this is the base widget */
190          item = new QTreeWidgetItem(directoryWidget);
191          item->setText(0, fullpath.toUtf8().data());
192       } else {
193          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
194          if (parent) {
195             /* new directories to add */
196             item = new QTreeWidgetItem(parent);
197             item->setText(0, newdir.toUtf8().data());
198             directoryWidget->expandItem(parent);
199          } else {
200             ok = false;
201             //printf("In else of if parent cwd \"%s\" newdir \"%s\"\n", 
202                //m_cwd.toUtf8().data() ,newdir.toUtf8().data());
203          }
204       }
205       /* insert into both forward and reverse hash */
206       if (ok) {
207          //printf("Inserting %s\n",fullpath.toUtf8().data());
208          m_dirPaths.insert(fullpath, item);
209          m_dirTreeItems.insert(item, fullpath);
210       }
211    }
212 }
213
214 /*
215  * Executed when the tree item in the directory pane is changed.  This will
216  * allow us to populate the file pane and make this the cwd.
217  */
218 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
219                                          QTreeWidgetItem * /*previousitem*/)
220 {
221    QString fullpath = m_dirTreeItems.value(currentitem);
222    if (fullpath != ""){
223       cwd(fullpath.toUtf8().data());
224       fillDirectory();
225    }
226 }
227
228 void restorePage::okButtonPushed()
229 {
230    this->hide();
231    m_console->write("done");
232    m_console->notify(true);
233    setConsoleCurrent();
234    closeStackPage();
235    mainWin->resetFocus();
236 }
237
238
239 void restorePage::cancelButtonPushed()
240 {
241    this->hide();
242    m_console->write("quit");
243    m_console->displayToPrompt();
244    mainWin->set_status("Canceled");
245    closeStackPage();
246    m_console->notify(true);
247    mainWin->resetFocus();
248 }
249
250 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
251 {
252    char cmd[1000];
253    if (column == 0) {                 /* mark/unmark */
254       if (item->text(0) == "*") {
255          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
256          item->setText(0, " ");
257       } else {
258          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
259          item->setText(0, "*");
260       }
261       m_console->write_dir(cmd);
262       if (m_console->read() > 0) {
263          strip_trailing_junk(m_console->msg());
264          statusLine->setText(m_console->msg());
265       }
266       m_console->displayToPrompt();
267       return;
268    }    
269    /* 
270     * Double clicking other than column 0 means to decend into
271     *  the directory -- or nothing if it is not a directory.
272     */
273    if (item->text(1).endsWith("/")) {
274       QString fullpath = m_cwd + item->text(1);
275       /* check for fullpath = "/c:/" */
276       QRegExp regex("^/[a-z]:/");
277       if (regex.indexIn(fullpath,0) == 0)  /* remove leading '/' */
278          fullpath.replace(0,1,"");
279       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
280       if (item) {
281          directoryWidget->setCurrentItem(item);
282       } else {
283          /* FIXME ***** Create an error log */
284          //printf("DoubleClick else of item column %i fullpath %s\n", column, fullpath.toUtf8().data());
285       }
286    }
287 }
288
289 /*
290  * If up button pushed, making the parent tree widget current will call fill
291  * directory.
292  */
293 void restorePage::upButtonPushed()
294 {
295    cwd("..");
296    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
297    if (item) {
298       directoryWidget->setCurrentItem(item);
299    }
300 }
301
302 /*
303  * Mark selected items
304  */
305 void restorePage::markButtonPushed()
306 {
307    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
308    QTreeWidgetItem *item;
309    char cmd[1000];
310    foreach (item, treeItemList) {
311       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
312       item->setText(0, "*");
313       m_console->write_dir(cmd);
314       if (m_console->read() > 0) {
315          strip_trailing_junk(m_console->msg());
316          statusLine->setText(m_console->msg());
317       }
318       Dmsg1(100, "cmd=%s\n", cmd);
319       m_console->discardToPrompt();
320    }
321 }
322
323 /*
324  * Unmark selected items
325  */
326 void restorePage::unmarkButtonPushed()
327 {
328    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
329    QTreeWidgetItem *item;
330    char cmd[1000];
331    foreach (item, treeItemList) {
332       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
333       item->setText(0, " ");
334       m_console->write_dir(cmd);
335       if (m_console->read() > 0) {
336          strip_trailing_junk(m_console->msg());
337          statusLine->setText(m_console->msg());
338       }
339       Dmsg1(100, "cmd=%s\n", cmd);
340       m_console->discardToPrompt();
341    }
342 }
343
344 /*
345  * Change current working directory 
346  */
347 bool restorePage::cwd(const char *dir)
348 {
349    int stat;
350    char cd_cmd[MAXSTRING];
351
352    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
353    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
354    m_console->write_dir(cd_cmd);
355    lineEdit->clear();
356    if ((stat = m_console->read()) > 0) {
357       m_cwd = m_console->msg();
358       lineEdit->insert(m_cwd);
359       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
360    } else {
361       Dmsg1(000, "stat=%d\n", stat);
362       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
363    }
364    m_console->discardToPrompt();
365    return true;  /* ***FIXME*** return real status */
366 }
367
368 /*
369  * Return cwd when in tree restore mode 
370  */
371 char *restorePage::get_cwd()
372 {
373    int stat;
374    m_console->write_dir(".pwd");
375    Dmsg0(100, "send: .pwd\n");
376    if ((stat = m_console->read()) > 0) {
377       m_cwd = m_console->msg();
378       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
379    } else {
380       Dmsg1(000, "Something went wrong read stat=%d\n", stat);
381       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
382    }
383    m_console->discardToPrompt(); 
384    return m_cwd.toUtf8().data();
385 }