]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
Tweak fix MySQL quoting again :-(
[bacula/bacula] / bacula / src / wx-console / wxbrestorepanel.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2008 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 three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    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 Affero 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 Kern Sibbald.
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  *   wxbPanel for restoring files
31  *
32  *    Nicolas Boichat, April-July 2004
33  *
34  *    Version $Id$
35  */
36
37 /* Note concerning "done" output (modifiable marked with +)
38 Run Restore job
39 +JobName:    RestoreFiles
40 Bootstrap:  /var/lib/bacula/restore.bsr
41 +Where:      /tmp/bacula-restores
42 +Replace:    always
43 +FileSet:    Full Set
44 +Client:     tom-fd
45 +Storage:    File
46 +When:       2004-04-18 01:18:56
47 +Priority:   10
48 OK to run? (yes/mod/no):mod
49 Parameters to modify:
50      1: Level (not appropriate)
51      2: Storage (automatic ?)
52      3: Job (no)
53      4: FileSet (yes)
54      5: Client (yes : "The defined Client resources are:\n\t1: velours-fd\n\t2: tom-fd\nSelect Client (File daemon) resource (1-2):")
55      6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
56      7: Priority (yes : "Enter new Priority: (positive integer)")
57      8: Bootstrap (?)
58      9: Where (yes : "Please enter path prefix for restore (/ for none):")
59     10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
60           Select replace option (1-4):")
61     11: JobId (no)
62 Select parameter to modify (1-11):
63        */
64
65 /*  Windows debug builds set _DEBUG which is used by wxWidgets to select their
66  *  debug memory allocator.  Unfortunately it conflicts with Bacula's SmartAlloc.
67  * So we turn _DEBUG off since we aren't interested in things it enables.
68  */
69
70 #undef _DEBUG
71
72 #include "bacula.h"
73
74 #include "wxbrestorepanel.h"
75 #include "wxbmainframe.h"
76 #include "csprint.h"
77 #include <wx/choice.h>
78 #include <wx/datetime.h>
79 #include <wx/timer.h>
80 #include "unmarked.xpm"
81 #include "marked.xpm"
82 #include "partmarked.xpm"
83 #include <wx/imaglist.h>
84 #include <wx/listimpl.cpp>
85
86 /* A macro named Yield is defined under MinGW */
87 #undef Yield
88
89 WX_DEFINE_LIST(wxbEventList);
90
91 /*
92  *  Class which is stored in the tree and in the list to keep informations
93  *  about the element.
94  */
95 class wxbTreeItemData : public wxTreeItemData {
96    public:
97       wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
98       ~wxbTreeItemData();
99       wxString GetPath();
100       wxString GetName();
101       
102       int GetMarked();
103       void SetMarked(int marked);
104       
105       long GetListId();
106    private:
107       wxString* path; /* Full path */
108       wxString* name; /* File name */
109       int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
110       long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
111 };
112
113 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
114    this->path = new wxString(path);
115    this->name = new wxString(name);
116    this->marked = marked;
117    this->listid = listid;
118 }
119
120 wxbTreeItemData::~wxbTreeItemData() {
121    delete path;
122    delete name;
123 }
124
125 int wxbTreeItemData::GetMarked() {
126    return marked;
127 }
128
129 void wxbTreeItemData::SetMarked(int marked) {
130    this->marked = marked;
131 }
132
133 long wxbTreeItemData::GetListId() {
134    return listid;
135 }
136
137 wxString wxbTreeItemData::GetPath() {
138    return *path;
139 }
140
141 wxString wxbTreeItemData::GetName() {
142    return *name;
143 }
144
145 // ----------------------------------------------------------------------------
146 // event tables and other macros for wxWindows
147 // ----------------------------------------------------------------------------
148
149 enum
150 {
151    RestoreStart = 1,
152    RestoreCancel = 2,
153    TreeCtrl = 3,
154    ListCtrl = 4,
155    ConfigOk = 5,
156    ConfigApply = 6,
157    ConfigCancel = 7,
158    ConfigWhere = 8,
159    ConfigReplace = 9,
160    ConfigWhen = 10,
161    ConfigPriority = 11,
162    ConfigClient = 12,
163    ConfigFileset = 13,
164    ConfigStorage = 14,
165    ConfigJobName = 15,
166    ConfigPool = 16,
167    TreeAdd = 17,
168    TreeRemove = 18,
169    TreeRefresh = 19,
170    ListAdd = 20,
171    ListRemove = 21,
172    ListRefresh = 22
173 };
174
175 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
176    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
177    EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
178    
179    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
180    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
181    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
182    EVT_TREE_MARKED_EVENT(TreeCtrl, wxbRestorePanel::OnTreeMarked)
183    EVT_BUTTON(TreeAdd, wxbRestorePanel::OnTreeAdd)
184    EVT_BUTTON(TreeRemove, wxbRestorePanel::OnTreeRemove)
185    EVT_BUTTON(TreeRefresh, wxbRestorePanel::OnTreeRefresh)
186
187    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
188    EVT_LIST_MARKED_EVENT(ListCtrl, wxbRestorePanel::OnListMarked)
189    EVT_LIST_ITEM_SELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
190    EVT_LIST_ITEM_DESELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
191    EVT_BUTTON(ListAdd, wxbRestorePanel::OnListAdd)
192    EVT_BUTTON(ListRemove, wxbRestorePanel::OnListRemove)
193    EVT_BUTTON(ListRefresh, wxbRestorePanel::OnListRefresh)
194   
195    EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
196    EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
197    EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
198    EVT_CHOICE(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
199    EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
200    EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
201    EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
202    EVT_CHOICE(ConfigStorage, wxbRestorePanel::OnConfigUpdated)
203    EVT_CHOICE(ConfigJobName, wxbRestorePanel::OnConfigUpdated)
204    EVT_CHOICE(ConfigPool, wxbRestorePanel::OnConfigUpdated)
205    
206    EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
207    EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
208    EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
209 END_EVENT_TABLE()
210
211 /*
212  *  wxbRestorePanel constructor
213  */
214 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) 
215 {
216    //pendingEvents = new wxbEventList(); //EVTQUEUE
217    //processing = false; //EVTQUEUE
218    SetWorking(false);
219    
220    imagelist = new wxImageList(16, 16, TRUE, 3);
221    imagelist->Add(wxIcon(unmarked_xpm));
222    imagelist->Add(wxIcon(marked_xpm));
223    imagelist->Add(wxIcon(partmarked_xpm));
224
225    wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
226    mainSizer->AddGrowableCol(0);
227    mainSizer->AddGrowableRow(1);
228
229    wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
230
231    firstSizer->AddGrowableCol(0);
232    firstSizer->AddGrowableRow(0);
233
234    start = new wxButton(this, RestoreStart, _("Enter restore mode"), wxDefaultPosition, wxSize(150, 30));
235    firstSizer->Add(start, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
236
237    cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
238    firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
239
240    wxString elist[1];
241
242 /*   clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
243    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
244
245    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
246    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
247
248    mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
249
250    treelistPanel = new wxSplitterWindow(this);
251
252    wxPanel* treePanel = new wxPanel(treelistPanel);
253    wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
254    treeSizer->AddGrowableCol(0);
255    treeSizer->AddGrowableRow(0);
256
257    tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));  
258    tree->SetImageList(imagelist);
259    
260    treeSizer->Add(tree, 1, wxEXPAND, 0);
261    
262    wxBoxSizer *treeCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
263    treeadd = new wxButton(treePanel, TreeAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
264    treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
265    treeremove = new wxButton(treePanel, TreeRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
266    treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
267    treerefresh = new wxButton(treePanel, TreeRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
268    treeCtrlSizer->Add(treerefresh, 0, wxLEFT | wxRIGHT, 3);
269    
270    treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
271    
272    treePanel->SetSizer(treeSizer);
273    
274    wxPanel* listPanel = new wxPanel(treelistPanel);
275    wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
276    listSizer->AddGrowableCol(0);
277    listSizer->AddGrowableRow(0);
278    
279    list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
280    //treelistSizer->Add(list, 1, wxEXPAND, 10);
281
282    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
283
284    wxListItem info;
285    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
286    info.SetText(_("M"));
287    info.SetAlign(wxLIST_FORMAT_CENTER);
288    list->InsertColumn(0, info);
289    
290    info.SetText(_("Filename"));
291    info.SetAlign(wxLIST_FORMAT_LEFT);
292    list->InsertColumn(1, info);
293
294    info.SetText(_("Size"));
295    info.SetAlign(wxLIST_FORMAT_RIGHT);   
296    list->InsertColumn(2, info);
297
298    info.SetText(_("Date"));
299    info.SetAlign(wxLIST_FORMAT_LEFT);
300    list->InsertColumn(3, info);
301
302    info.SetText(_("Perm."));
303    info.SetAlign(wxLIST_FORMAT_LEFT);
304    list->InsertColumn(4, info);
305    
306    info.SetText(_("User"));
307    info.SetAlign(wxLIST_FORMAT_RIGHT);
308    list->InsertColumn(5, info);
309    
310    info.SetText(_("Group"));
311    info.SetAlign(wxLIST_FORMAT_RIGHT);
312    list->InsertColumn(6, info);
313     
314    listSizer->Add(list, 1, wxEXPAND, 0);
315    
316    wxBoxSizer *listCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
317    listadd = new wxButton(listPanel, ListAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
318    listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
319    listremove = new wxButton(listPanel, ListRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
320    listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
321    listrefresh = new wxButton(listPanel, ListRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
322    listCtrlSizer->Add(listrefresh, 0, wxLEFT | wxRIGHT, 5);
323    
324    listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
325    
326    listPanel->SetSizer(listSizer);
327    
328    treelistPanel->SplitVertically(treePanel, listPanel, 210);
329    
330    treelistPanel->SetMinimumPaneSize(210);
331      
332    treelistPanel->Show(false);
333    
334    wxbConfig* config = new wxbConfig();
335    config->Add(new wxbConfigParam(_("Job Name"), ConfigJobName, choice, 0, elist));
336    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, elist));
337    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, elist));
338    config->Add(new wxbConfigParam(_("Pool"), ConfigPool, choice, 0, elist));
339    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, elist));
340    config->Add(new wxbConfigParam(_("Before"), ConfigWhen, choice, 0, elist));
341    
342    configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
343    
344    configPanel->Show(true);
345    configPanel->Enable(false);
346    
347    config = new wxbConfig();
348    config->Add(new wxbConfigParam(_("Job Name"), -1, text, wxT("")));
349    config->Add(new wxbConfigParam(_("Bootstrap"), -1, text, wxT("")));
350    config->Add(new wxbConfigParam(_("Where"), ConfigWhere, modifiableText, wxT("")));
351    wxString erlist[] = {_("always"), _("if newer"), _("if older"), _("never")};
352    config->Add(new wxbConfigParam(_("Replace"), ConfigReplace, choice, 4, erlist));
353    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, erlist));
354    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, erlist));
355    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, erlist));
356    config->Add(new wxbConfigParam(_("When"), ConfigWhen, modifiableText, wxT("")));
357    config->Add(new wxbConfigParam(_("Priority"), ConfigPriority, modifiableText, wxT("")));
358    
359    restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
360     
361    restorePanel->Show(false);
362    
363    centerSizer = new wxBoxSizer(wxHORIZONTAL);
364    //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
365       
366    mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
367
368    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
369
370    mainSizer->Add(gauge, 1, wxEXPAND, 5);
371    gauge->SetValue(0);
372    gauge->Enable(false);
373
374    SetSizer(mainSizer);
375    mainSizer->SetSizeHints(this);
376
377    SetStatus(disabled);
378
379    for (int i = 0; i < 7; i++) {
380       list->SetColumnWidth(i, 70);
381    }
382
383    SetCursor(*wxSTANDARD_CURSOR);
384
385    markWhenCommandDone = false;
386    
387    cancelled = 0;
388 }
389
390 /*
391  *  wxbRestorePanel destructor
392  */
393 wxbRestorePanel::~wxbRestorePanel() 
394 {
395    delete imagelist;
396 }
397
398 /*----------------------------------------------------------------------------
399    wxbPanel overloadings
400   ----------------------------------------------------------------------------*/
401
402 wxString wxbRestorePanel::GetTitle() 
403 {
404    return _("Restore");
405 }
406
407 void wxbRestorePanel::EnablePanel(bool enable) 
408 {
409    if (enable) {
410       if (status == disabled) {
411          SetStatus(activable);
412       }
413    } else {
414       SetStatus(disabled);
415    }
416 }
417
418 /*----------------------------------------------------------------------------
419    Commands called by events handler
420   ----------------------------------------------------------------------------*/
421
422 /* The main button has been clicked */
423 void wxbRestorePanel::CmdStart() 
424 {
425    unsigned int i;
426    if (status == activable) {
427       wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
428       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
429       wxString str;
430
431       configPanel->ClearRowChoices(_("Client"));
432       restorePanel->ClearRowChoices(_("Client"));
433       
434       if (dt->GetCount() == 0) {
435          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
436          return;
437       }
438       
439       for (i = 0; i < dt->GetCount(); i++) {
440          str = (*dt)[i];
441          str.RemoveLast();
442          configPanel->AddRowChoice(_("Client"), str);
443          restorePanel->AddRowChoice(_("Client"), str);
444       }
445           
446       delete dt;
447       
448       if (cancelled) {
449          cancelled = 2;
450          return;
451       }
452       
453       dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
454       
455       configPanel->ClearRowChoices(_("Fileset"));
456       restorePanel->ClearRowChoices(_("Fileset"));
457     
458       if (dt->GetCount() == 0) {
459          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
460          return;
461       }
462       
463       for (i = 0; i < dt->GetCount(); i++) {
464          str = (*dt)[i];
465          str.RemoveLast();
466          configPanel->AddRowChoice(_("Fileset"), str);
467          restorePanel->AddRowChoice(_("Fileset"), str);
468       }
469       
470       delete dt;
471       
472       if (cancelled) {
473          cancelled = 2;
474          return;
475       }
476       
477       dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
478     
479       configPanel->ClearRowChoices(_("Storage"));
480       restorePanel->ClearRowChoices(_("Storage"));
481     
482       if (dt->GetCount() == 0) {
483          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
484          return;
485       }
486       
487       for (i = 0; i < dt->GetCount(); i++) {
488          str = (*dt)[i];
489          str.RemoveLast();
490          configPanel->AddRowChoice(_("Storage"), str);
491          restorePanel->AddRowChoice(_("Storage"), str);
492       }
493       
494       delete dt;
495       
496       if (cancelled) {
497          cancelled = 2;
498          return;
499       }
500       
501       dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
502     
503       configPanel->ClearRowChoices(_("Job Name"));
504     
505       if (dt->GetCount() == 0) {
506          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
507          return;
508       }
509       
510       for (i = 0; i < dt->GetCount(); i++) {
511          str = (*dt)[i];
512          str.RemoveLast();
513          configPanel->AddRowChoice(_("Job Name"), str);
514       }
515       
516       configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
517       
518       delete dt;
519       
520       if (cancelled) {
521          cancelled = 2;
522          return;
523       }
524       
525       dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
526     
527       configPanel->ClearRowChoices(_("Pool"));
528     
529       if (dt->GetCount() == 0) {
530          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
531          return;
532       }
533       
534       for (i = 0; i < dt->GetCount(); i++) {
535          str = (*dt)[i];
536          str.RemoveLast();
537          configPanel->AddRowChoice(_("Pool"), str);
538       }
539          
540       delete dt; 
541       
542       if (cancelled) {
543          cancelled = 2;
544          return;
545       }
546
547       SetStatus(entered);
548
549       UpdateFirstConfig();
550            
551       wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
552    }
553    else if (status == entered) {
554 #ifdef xxx
555       if (clientChoice->GetStringSelection().Length() < 1) {
556          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
557          return;
558       }
559       if (jobChoice->GetStringSelection().Length() < 1) {
560          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
561          return;
562       }
563 #endif
564
565       wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
566       
567       SetStatus(choosing);
568       
569       wxbTableParser* tableparser = new wxbTableParser();
570       wxbDataTokenizer* dt = new wxbDataTokenizer(false);
571       
572 /*
573  * The following line was removed from  ::GetInstance below because
574  *  it does not work with multiple pools -- KES 5Oct05 see bug #433  
575  *       wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
576  */
577       wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
578          wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
579          wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
580          wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
581          wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
582          wxT("\" select\n"));
583
584 #ifdef xxx
585       wxbUtils::WaitForPrompt("6\n");
586       WaitForEnd();
587
588       wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
589
590       int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
591       if (client == wxNOT_FOUND) {
592          wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
593          return;
594       }
595       delete pp;
596       
597       wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
598 #endif
599    
600       while (!tableparser->hasFinished() && !dt->hasFinished()) {
601          wxTheApp->Yield(true);
602          wxbUtils::MilliSleep(100);
603       }
604       
605       wxString str;
606
607       if (dt->hasFinished() && !tableparser->hasFinished()) {
608          str = wxT("");
609          if (dt->GetCount() > 1) {
610             str = (*dt)[dt->GetCount()-2];
611             str.RemoveLast();
612          }
613          wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
614          delete dt;
615          delete tableparser;
616          SetStatus(finished);
617          return;
618       }
619            
620       int tot = 0;
621       long l;
622       
623       for (i = 0; i < tableparser->GetCount(); i++) {
624          str = (*tableparser)[i][2];
625          str.Replace(wxT(","), wxT(""));
626          if (str.ToLong(&l)) {
627             tot += l;
628          }
629       }
630            
631       gauge->SetValue(0);
632       gauge->SetRange(tot);
633       
634 #ifdef xxx
635       wxbMainFrame::GetInstance()->Print(
636                wxString("[") << tot << "]", CS_DEBUG);
637 #endif
638       
639       wxDateTime base = wxDateTime::Now();
640       wxDateTime newdate;
641       int done = 0;
642       int willdo = 0;
643       unsigned int lastindex = 0;
644       
645       int var = 0;
646       
647       int i1, i2;
648       
649       while (true) {
650          newdate = wxDateTime::Now();
651          if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
652             base = newdate;
653             for (; lastindex < dt->GetCount(); lastindex++) {
654                if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) && 
655                      ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
656                   str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
657                   for (i = 0; i < tableparser->GetCount(); i++) {
658                      if (str == (*tableparser)[i][0]) {
659                         str = (*tableparser)[i][2];
660                         str.Replace(wxT(","), wxT(""));
661                         if (str.ToLong(&l)) {
662                            done += willdo;
663                            willdo += l;
664                            var = (willdo-done)/50;
665                            gauge->SetValue(done);
666                            wxTheApp->Yield(true);
667                         }
668                         break;
669                      }
670                   }
671                }
672                else if ((*dt)[lastindex] == wxT("+")) {
673                   gauge->SetValue(gauge->GetValue()+var);
674                   wxTheApp->Yield(true);
675                }
676             }
677             
678                        
679             if (dt->hasFinished()) {
680                break;
681             }
682          }
683          wxTheApp->Yield(true);
684          wxbUtils::MilliSleep(1);
685       }
686
687       gauge->SetValue(tot);
688       wxTheApp->Yield(true);
689       gauge->SetValue(0);
690       
691       delete dt;
692       delete tableparser;
693
694       if (cancelled) {
695          cancelled = 2;
696          return;
697       }
698
699       wxbUtils::WaitForEnd(wxT("unmark *\n"));
700       wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
701       currentTreeItem = root;
702       tree->Refresh();
703       tree->SelectItem(root);
704       CmdList(root);
705       wxbMainFrame::GetInstance()->SetStatusText(_("Right click on a file or on a directory, or double-click on its mark to add it to the restore list."));
706       tree->Expand(root);
707    }
708    else if (status == choosing) {
709       EnableConfig(false);
710       
711       totfilemessages = 0;
712       wxbDataTokenizer* dt;
713            
714       int j;
715       
716       dt = new wxbDataTokenizer(true);
717       wxbPromptParser* promptparser = wxbUtils::WaitForPrompt(wxT("done\n"), true);
718
719       while (!promptparser->getChoices() || (promptparser->getChoices()->Index(wxT("mod")) < 0)) {
720          wxbMainFrame::GetInstance()->Print(_("Unexpected question has been received.\n"), CS_DEBUG);
721          
722          wxString message;
723          if (promptparser->getIntroString() != wxT("")) {
724             message << promptparser->getIntroString() << wxT("\n");
725          }
726          message << promptparser->getQuestionString();
727          
728          if (promptparser->getChoices()) {
729             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
730             int *numbers = new int[promptparser->getChoices()->GetCount()];
731             int n = 0;
732             
733             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
734                if ((*promptparser->getChoices())[i] != wxT("")) {
735                   choices[n] = (*promptparser->getChoices())[i];
736                   numbers[n] = i;
737                   n++;
738                }
739             }
740             
741             int res = ::wxGetSingleChoiceIndex(message,
742                _("bwx-console: unexpected restore question."), n, choices, this);
743             if (res == -1) {
744                delete promptparser;
745                promptparser = wxbUtils::WaitForPrompt(wxT(".\n"), true);
746             }
747             else {
748                if (promptparser->isNumericalChoice()) {
749                   delete promptparser;
750                   promptparser = wxbUtils::WaitForPrompt(wxString() << numbers[res] << wxT("\n"), true);
751                }
752                else {
753                   delete promptparser;
754                   promptparser = wxbUtils::WaitForPrompt(wxString() << choices[res] << wxT("\n"), true);
755                }
756             }
757             delete[] choices;
758             delete[] numbers;
759          }
760          else {
761             delete promptparser;
762             
763             promptparser = wxbUtils::WaitForPrompt(::wxGetTextFromUser(message,
764                _("bwx-console: unexpected restore question."),
765                wxT(""), this) + wxT("\n"));
766          }
767       }
768       printf("promptparser->getChoices()=%ld", (long)promptparser->getChoices());
769       
770       delete promptparser;
771
772       SetStatus(configuring);
773
774       for (i = 0; i < dt->GetCount(); i++) {
775          if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
776             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
777             break;
778          }
779
780          if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
781             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
782             break;
783          }
784       }
785       
786       wxbMainFrame::GetInstance()->SetStatusText(
787          wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
788       
789       UpdateSecondConfig(dt);
790       
791       delete dt;
792       
793       EnableConfig(true);
794       restorePanel->EnableApply(false);
795
796       if (totfilemessages == 0) {
797          wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
798          wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
799          SetStatus(finished);
800          return;
801       }
802    }
803    else if (status == configuring) {
804       cancel->Enable(false);
805       jobid = wxT("");
806       EnableConfig(false);
807     
808       wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
809     
810       wxbDataTokenizer* dt;
811     
812       SetStatus(restoring);
813       dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
814
815       gauge->SetValue(0);
816       gauge->SetRange(totfilemessages);
817
818       int j;
819             
820       for (i = 0; i < dt->GetCount(); i++) {
821          if ((j = (*dt)[i].Find(_("Job queued. JobId="))) > -1) {
822             jobid = (*dt)[i].Mid(j+19);
823             wxbMainFrame::GetInstance()->SetStatusText(_("Restore queued, jobid=") + jobid);
824             break;
825          }
826
827          if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
828             wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
829             wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
830             return;
831          }
832       }
833       
834       if (jobid == wxT("")) {
835          wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
836          wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
837          return;         
838       }
839
840       wxDateTime currenttime;
841       
842       dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
843       wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
844       if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
845            (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
846          currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
847       }
848       else {
849          currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
850       }
851       delete dt;
852     
853       wxDateTime scheduledtime;
854       wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
855       
856       if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
857            (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
858          scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
859       }
860
861       if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
862          wxbMainFrame::GetInstance()->Print(_("Restore is scheduled to run. bwx-console will not wait for its completion.\n"), CS_DEBUG);
863          wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled to run. bwx-console will not wait for its completion."));
864          SetStatus(finished);
865          return;
866       }
867
868       wxString cmd = wxString(wxT("list jobid=")) + jobid;
869
870       wxbTableParser* tableparser;
871       
872       long filemessages = 0;
873       
874       bool ended = false;
875       bool waitforever = false;
876       
877       char status = '?';
878
879       wxStopWatch sw;
880       
881       wxbUtils::WaitForEnd(wxT("autodisplay off\n"));
882       wxbUtils::WaitForEnd(wxT("gui on\n"));
883       while (true) {
884          tableparser = wxbUtils::CreateAndWaitForParser(cmd);
885          ended = false;
886          status = (*tableparser)[0][7].GetChar(0);
887          switch (status) {
888          case JS_Created:
889             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
890             waitforever = false;
891             break;
892          case JS_Running:
893             wxbMainFrame::GetInstance()->SetStatusText(
894                wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
895             waitforever = true;
896             break;
897          case JS_Terminated:
898             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
899             wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
900             waitforever = false;
901             ended = true;
902             break;
903          case JS_ErrorTerminated:
904             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
905             wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
906             waitforever = false;
907             ended = true;
908             break;
909          case JS_Error:
910             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
911             waitforever = false;
912             break;
913          case JS_FatalError:
914             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
915             waitforever = false;
916             ended = true;
917             break;
918          case JS_Canceled:
919             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
920             wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
921             waitforever = false;
922             ended = true;
923             break;
924          case JS_WaitFD:
925             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
926             waitforever = false;
927             break;
928          case JS_WaitMedia:
929             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
930             waitforever = false;
931             break;
932          case JS_WaitStoreRes:
933             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
934             waitforever = false;
935             break;
936          case JS_WaitJobRes:
937             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
938             waitforever = false;
939             break;
940          case JS_WaitClientRes:
941             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
942             waitforever = false;
943             break;
944          case JS_WaitMaxJobs:
945             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
946             waitforever = false;
947             break;
948          case JS_WaitStartTime:
949             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
950             waitforever = false;
951             break;
952          case JS_WaitPriority:
953             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
954             waitforever = false;
955             break;
956          }
957          delete tableparser;
958          
959          dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
960                   
961          for (unsigned int i = 0; i < dt->GetCount(); i++) {
962             wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
963    
964             wxDateTime datetime;
965    
966             //   Date    Time   name:   perm      ?   user   grp      size    date     time
967             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
968    
969             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
970                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
971                   if (tkz.GetNextToken().Last() == ':') { // name:
972                   tkz.GetNextToken(); // perm
973                   tkz.GetNextToken(); // ?
974                   tkz.GetNextToken(); // user
975                   tkz.GetNextToken(); // grp
976                   tkz.GetNextToken(); // size
977                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
978                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
979                            filemessages++;
980                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
981                            gauge->SetValue(filemessages);
982                         }
983                      }
984                   }
985                }
986             }
987          }
988          
989          delete dt;
990          
991          wxStopWatch sw2;
992          while (sw2.Time() < 10000) {  
993             wxTheApp->Yield(true);
994             wxbUtils::MilliSleep(100);
995          }
996          
997          if (ended) {
998             break;
999          }
1000          
1001          if ((!waitforever) && (sw.Time() > 60000)) {
1002             wxbMainFrame::GetInstance()->Print(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore.\n"), CS_DEBUG);
1003             wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore."));
1004             break;
1005          }
1006       }
1007       wxbUtils::WaitForEnd(wxT("autodisplay on\n"));
1008       wxbUtils::WaitForEnd(wxT(".messages\n"));
1009
1010       gauge->SetValue(totfilemessages);
1011
1012       if (status == JS_Terminated) {
1013          wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
1014          wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
1015       }
1016       SetStatus(finished);
1017    }
1018 }
1019
1020 /* The cancel button has been clicked */
1021 void wxbRestorePanel::CmdCancel() {
1022    cancelled = 1;
1023    
1024    if (status == restoring) {
1025       if (jobid != wxT("")) {
1026          wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
1027       }
1028       cancel->Enable(true);
1029       return;
1030    }
1031    
1032    wxStopWatch sw;
1033    while ((IsWorking()) && (cancelled != 2)) {
1034       wxTheApp->Yield(true);
1035       wxbUtils::MilliSleep(100);
1036       if (sw.Time() > 30000) { /* 30 seconds timeout */
1037          if (status == choosing) {
1038             wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1039          }
1040          else if (status == configuring) {
1041             wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1042          }
1043          else if (status == restoring) {
1044             
1045          }
1046          SetStatus(finished);
1047          wxbUtils::MilliSleep(1000);
1048          return;
1049       }
1050    }
1051    
1052    switch (status) {
1053    case choosing:
1054       wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1055       break;
1056    case configuring:
1057       wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1058       break;
1059    default:
1060       break;
1061    }
1062    wxbUtils::MilliSleep(1000);
1063    SetStatus(finished);
1064 }
1065
1066 /* Apply configuration changes */
1067
1068 /*   1: Level (not appropriate)
1069  *   2: Storage (yes)
1070  *   3: Job (no)
1071  *   4: FileSet (yes)
1072  *   5: Client (yes)
1073  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1074  *   7: Priority (yes : "Enter new Priority: (positive integer)")
1075  *   8: Bootstrap (?)
1076  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
1077  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
1078  *         Select replace option (1-4):")
1079  *  11: JobId (no)
1080  */
1081
1082 void wxbRestorePanel::CmdConfigApply() 
1083 {
1084    if (cfgUpdated == 0) return;
1085    
1086    wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1087    
1088    EnableConfig(false);
1089    
1090    wxbDataTokenizer* dt = NULL;
1091    
1092    bool failed = false;
1093    
1094    while (cfgUpdated > 0) {
1095       if (cancelled) {
1096          cancelled = 2;
1097          return;
1098       }
1099       wxString def; //String to send if can't use our data
1100       if ((cfgUpdated >> ConfigWhere) & 1) {
1101          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1102          wxbUtils::WaitForPrompt(wxT("9\n"));
1103          dt = new wxbDataTokenizer(true);
1104          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1105          def = wxT("/tmp");
1106          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1107       }
1108       else if ((cfgUpdated >> ConfigReplace) & 1) {
1109          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1110          wxbUtils::WaitForPrompt(wxT("11\n"));
1111          dt = new wxbDataTokenizer(true);
1112          wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1113          def = wxT("1");
1114          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1115       }
1116       else if ((cfgUpdated >> ConfigWhen) & 1) {
1117          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1118          wxbUtils::WaitForPrompt(wxT("6\n"));
1119          dt = new wxbDataTokenizer(true);
1120          wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1121          def = wxT("");
1122          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1123       }
1124       else if ((cfgUpdated >> ConfigPriority) & 1) {
1125          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1126          wxbUtils::WaitForPrompt(wxT("7\n"));
1127          dt = new wxbDataTokenizer(true);
1128          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1129          def = wxT("10");
1130          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1131       }
1132       else if ((cfgUpdated >> ConfigClient) & 1) {
1133          if (restorePanel->GetRowCount(_("Client")) > 1) {
1134             wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1135             wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1136             int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1137             if (client == wxNOT_FOUND) {
1138                wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1139                failed = true;
1140                client = 1;
1141             }
1142             delete pp;
1143             dt = new wxbDataTokenizer(true);
1144             wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1145             def = wxT("1");
1146             cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1147          } else {
1148             cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1149             continue;
1150          }
1151       }
1152       else if ((cfgUpdated >> ConfigFileset) & 1) {
1153          if (restorePanel->GetRowCount(_("Fileset")) > 1) {
1154             wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1155             wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1156             int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1157             if (fileset == wxNOT_FOUND) {
1158                wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1159                failed = true;
1160                fileset = 1;
1161             }
1162             delete pp;
1163             dt = new wxbDataTokenizer(true);
1164             wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1165             def = wxT("1");
1166             cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1167          } else {
1168             cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1169             continue;
1170          }
1171       }
1172       else if ((cfgUpdated >> ConfigStorage) & 1) {
1173          if (restorePanel->GetRowCount(_("Storage")) > 1) {
1174             wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1175             wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1176             int storage = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1177             if (storage == wxNOT_FOUND) {
1178                wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1179                failed = true;
1180                storage = 1;
1181             }
1182             delete pp;
1183             dt = new wxbDataTokenizer(true);
1184             wxbUtils::WaitForPrompt(wxString() << storage << wxT("\n"));
1185             def = wxT("1");
1186             cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1187          } else {
1188             cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1189             continue;
1190          }
1191       }
1192       else {
1193          cfgUpdated = 0;
1194          break;
1195       }
1196                  
1197       unsigned int i;
1198       for (i = 0; i < dt->GetCount(); i++) {
1199          if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1200             break;
1201          }
1202       }
1203       
1204       if (i != 0 && i == dt->GetCount()) {
1205          delete dt;   
1206          dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1207          failed = true;
1208       }
1209    }
1210    UpdateSecondConfig(dt); /* TODO: Check result */
1211    
1212    EnableConfig(true);
1213    restorePanel->EnableApply(false);
1214
1215    if (!failed) {
1216       wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1217    }
1218
1219    delete dt;
1220 }
1221
1222 /* Cancel restore */
1223 void wxbRestorePanel::CmdConfigCancel() {
1224    wxbUtils::WaitForEnd(wxT("no\n"));
1225    wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1226    wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1227    SetStatus(finished);
1228 }
1229
1230 /* List jobs for a specified client and fileset */
1231 void wxbRestorePanel::CmdListJobs() {
1232    if (status == entered) {
1233       configPanel->ClearRowChoices(_("Before"));
1234       /*wxbUtils::WaitForPrompt("query\n");
1235       wxbUtils::WaitForPrompt("6\n");*/
1236       wxbTableParser* tableparser = new wxbTableParser(false);
1237       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1238          wxString(wxT(".backups client=\"")) + configPanel->GetRowString(_("Client")) + 
1239                   wxT("\" fileset=\"") + configPanel->GetRowString(_("Fileset")) + wxT("\"\n"), true);
1240
1241       while (!tableparser->hasFinished()) {
1242          wxTheApp->Yield(true);
1243          wxbUtils::MilliSleep(100);
1244       }
1245          
1246       if (!tableparser->GetCount() == 0) {
1247          for (unsigned int i = 0; i < dt->Count(); i++) {
1248             if ((*dt)[i].Find(_("No results to list.")) == 0) {
1249                configPanel->AddRowChoice(_("Before"),
1250                   _("No backup found for this client."));
1251                configPanel->SetRowSelection(_("Before"), 0);
1252                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1253                delete tableparser;
1254                delete dt;
1255                return;
1256             }
1257             else if (((*dt)[i].Find(_("ERROR")) > -1) || 
1258                   ((*dt)[i].Find(_("Query failed")) > -1)) {
1259                configPanel->AddRowChoice(_("Before"),
1260                   _("Cannot get previous backups list, see console."));
1261                configPanel->SetRowSelection(_("Before"), 0);
1262                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1263                delete tableparser;
1264                delete dt;
1265                return;
1266             }
1267          }
1268       }
1269       
1270       delete dt;
1271
1272       wxDateTime lastdatetime = (time_t) 0;
1273       for (int i = tableparser->GetCount()-1; i > -1; i--) {
1274          wxString str = (*tableparser)[i][3];
1275          wxDateTime datetime;
1276          const wxChar* chr;
1277          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) && ! lastdatetime.IsEqualTo(datetime) ) {
1278             lastdatetime = datetime;
1279             datetime += wxTimeSpan::Seconds(1);
1280             configPanel->AddRowChoice(_("Before"),
1281                datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1282          }
1283       }
1284            
1285       delete tableparser;
1286
1287       configPanel->SetRowSelection(_("Before"), 0);
1288       configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1289    }
1290 }
1291
1292 /* List files and directories for a specified tree item */
1293 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1294    if (status == choosing) {
1295       list->DeleteAllItems();
1296
1297       if (!item.IsOk()) {
1298          return;
1299       }
1300       UpdateTreeItem(item, true, false);
1301     
1302       if (list->GetItemCount() >= 1) {
1303          int firstwidth = list->GetSize().GetWidth(); 
1304          for (int i = 2; i < 7; i++) {
1305             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1306             firstwidth -= list->GetColumnWidth(i);
1307          }
1308        
1309          list->SetColumnWidth(0, 18);
1310          firstwidth -= 18;
1311          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1312          if (list->GetColumnWidth(1) < firstwidth) {
1313             list->SetColumnWidth(1, firstwidth-25);
1314          }
1315       }
1316    }
1317 }
1318
1319 /* Mark a treeitem (directory) or a listitem (file or directory) */
1320 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1321    if (status == choosing) {
1322       wxbTreeItemData** itemdata;
1323       int itemdatasize = 0;
1324       if (listsize == 0) {
1325          itemdata = new wxbTreeItemData*[1];
1326          itemdatasize = 1;
1327       }
1328       else {
1329          itemdata = new wxbTreeItemData*[listsize];
1330          itemdatasize = listsize;
1331       }
1332       
1333       if (listitems != NULL) {
1334          for (int i = 0; i < itemdatasize; i++) {
1335             itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1336          }
1337       }
1338       else if (treeitem.IsOk()) {
1339          itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1340       }
1341       else {
1342          delete[] itemdata;
1343          return;
1344       }
1345
1346       if (itemdata[0] == NULL) { //Should never happen
1347          delete[] itemdata;
1348          return;
1349       }
1350
1351       wxString dir = itemdata[0]->GetPath();
1352       wxString file;
1353
1354       if (dir != wxT("/")) {
1355          if (IsPathSeparator(dir.GetChar(dir.Length()-1))) {
1356             dir.RemoveLast();
1357          }
1358
1359          int i = dir.Find('/', TRUE);
1360          if (i == -1) {
1361             file = dir;
1362             dir = wxT("/");
1363          }
1364          else { /* first dir below root */
1365             file = dir.Mid(i+1);
1366             dir = dir.Mid(0, i+1);
1367          }
1368       }
1369       else {
1370          dir = wxT("/");
1371          file = wxT("*");
1372       }
1373
1374       if (state == -1) {
1375          bool marked = false;
1376          bool unmarked = false;
1377          state = 0;
1378          for (int i = 0; i < itemdatasize; i++) {
1379             switch(itemdata[i]->GetMarked()) {
1380             case 0:
1381                unmarked = true;
1382                break;
1383             case 1:
1384                marked = true;
1385                break;
1386             case 2:
1387                marked = true;
1388                unmarked = true;
1389                break;
1390             default:
1391                break;
1392             }
1393             if (marked && unmarked)
1394                break;
1395          }
1396          if (marked) {
1397             if (unmarked) {
1398                state = 1;
1399             }
1400             else {
1401                state = 0;
1402             }
1403          }
1404          else {
1405             state = 1;
1406          }
1407       }
1408
1409       wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1410       wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1411
1412       /* TODO: Check commands results */
1413
1414       /*if ((dir == "/") && (file == "*")) {
1415             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1416       }*/
1417
1418       if (listitems == NULL) { /* tree item state changed */
1419          SetTreeItemState(treeitem, state);
1420          /*treeitem = tree->GetSelection();
1421          UpdateTree(treeitem, true);
1422          treeitem = tree->GetItemParent(treeitem);*/
1423       }
1424       else {
1425          for (int i = 0; i < itemdatasize; i++) {
1426             SetListItemState(listitems[i], state);
1427          }
1428          listadd->Enable(state == 0);
1429          listremove->Enable(state == 1);
1430          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1431          treeitem = tree->GetItemParent(treeitem);*/
1432       }
1433
1434       /*while (treeitem.IsOk()) {
1435          WaitForList(treeitem, false);
1436          treeitem = tree->GetItemParent(treeitem);
1437       }*/
1438       
1439       delete[] itemdata;
1440    }
1441 }
1442
1443 /*----------------------------------------------------------------------------
1444    General functions
1445   ----------------------------------------------------------------------------*/
1446
1447 /* Run a dir command, and waits until result is fully received. */
1448 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse)
1449 {
1450 //   this->updatelist = updatelist;
1451    wxbDataTokenizer* dt;
1452
1453    dt = wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << 
1454       static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1455          ->GetPath() << wxT("\"\n"), false);
1456
1457    /* TODO: check command result */
1458    
1459    //delete dt;
1460
1461    status = listing;
1462
1463    if (updatelist)
1464       list->DeleteAllItems();
1465    dt = wxbUtils::WaitForEnd(wxT(".dir\n"), true);
1466    
1467    wxString str;
1468    
1469    for (unsigned int i = 0; i < dt->GetCount(); i++) {
1470       str = (*dt)[i];
1471       
1472       if (str.Find(wxT("cwd is:")) == 0) { // Sometimes cd command result "infiltrate" into listings.
1473          break;
1474       }
1475
1476       str.RemoveLast();
1477
1478       wxbDirEntry entry;
1479       
1480       if (!ParseList(str, &entry))
1481             break;
1482
1483       wxTreeItemId treeid;
1484
1485       if (IsPathSeparator(entry.fullname.GetChar(entry.fullname.Length()-1))) {
1486          wxString itemStr;
1487
1488 #if wxCHECK_VERSION(2, 6, 0)
1489          wxTreeItemIdValue cookie;
1490 #else
1491          long cookie;
1492 #endif
1493          
1494          treeid = tree->GetFirstChild(item, cookie);
1495
1496          bool updated = false;
1497
1498          while (treeid.IsOk()) {
1499             itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1500             if (entry.filename == itemStr) {
1501                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != entry.marked) {
1502                   tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Normal);
1503                   tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Selected);
1504                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(entry.marked);
1505                }
1506                if ((recurse) && (tree->IsExpanded(treeid))) {
1507                   UpdateTreeItem(treeid, false, true);
1508                }
1509                updated = true;
1510                break;
1511             }
1512             treeid = tree->GetNextChild(item, cookie);
1513          }
1514
1515          if (!updated) {
1516             treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(entry.filename), entry.marked, entry.marked, new wxbTreeItemData(entry.fullname, entry.filename, entry.marked));
1517          }
1518       }
1519
1520       if (updatelist) {
1521          long ind = list->InsertItem(list->GetItemCount(), entry.marked);
1522          wxbTreeItemData* data = new wxbTreeItemData(entry.fullname, entry.filename, entry.marked, ind);
1523          data->SetId(treeid);
1524          list->SetItemData(ind, (long)data);
1525          list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(entry.filename));
1526          list->SetItem(ind, 2, entry.size);
1527          list->SetItem(ind, 3, entry.date);
1528          list->SetItem(ind, 4, entry.perm);
1529          list->SetItem(ind, 5, entry.user);
1530          list->SetItem(ind, 6, entry.group);
1531       }
1532    }
1533    
1534    delete dt;
1535    
1536    tree->Refresh();
1537    status = choosing;
1538 }
1539
1540 /* Parse .dir command results, returns true if the result has been stored in entry, false otherwise. */
1541 int wxbRestorePanel::ParseList(wxString line, wxbDirEntry* entry) 
1542 {
1543    /* See ls_output in dird/ua_tree.c */
1544    //-rw-r-----,1,root,root,41575,2005-10-18 18:21:36, ,/usr/var/bacula/working/bacula.sql
1545
1546    wxStringTokenizer tkz(line, wxT(","));
1547    
1548    if (!tkz.HasMoreTokens())
1549       return false;
1550    entry->perm = tkz.GetNextToken();
1551    
1552    if (!tkz.HasMoreTokens())
1553       return false;
1554    entry->nlink = tkz.GetNextToken();
1555    
1556    if (!tkz.HasMoreTokens())
1557       return false;
1558    entry->user = tkz.GetNextToken();
1559    
1560    if (!tkz.HasMoreTokens())
1561       return false;
1562    entry->group = tkz.GetNextToken();
1563    
1564    if (!tkz.HasMoreTokens())
1565       return false;
1566    entry->size = tkz.GetNextToken();
1567    
1568    if (!tkz.HasMoreTokens())
1569       return false;
1570    entry->date = tkz.GetNextToken();
1571    
1572    if (!tkz.HasMoreTokens())
1573       return false;
1574    wxString marked = tkz.GetNextToken();
1575    if (marked == wxT("*")) {
1576       entry->marked = 1;
1577    }
1578    else if (marked == wxT("+")) {
1579       entry->marked = 2;
1580    }
1581    else {
1582       entry->marked = 0;
1583    }
1584    
1585    if (!tkz.HasMoreTokens())
1586       return false;
1587    entry->fullname = tkz.GetString();
1588    
1589    /* Get only the filename (cut path by finding the last '/') */
1590    if (IsPathSeparator(entry->fullname.GetChar(entry->fullname.Length()-1))) {
1591       wxString tmp = entry->fullname;
1592       tmp.RemoveLast();
1593       entry->filename = entry->fullname.Mid(tmp.Find('/', true)+1);
1594    }
1595    else {
1596       entry->filename = entry->fullname.Mid(entry->fullname.Find('/', true)+1);
1597    }
1598
1599    return true;
1600 }
1601
1602 /* Sets a list item state, and update its parents and children if it is a directory */
1603 void wxbRestorePanel::SetListItemState(long listitem, int newstate) 
1604 {
1605    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1606    
1607    wxTreeItemId treeitem;
1608    
1609    itemdata->SetMarked(newstate);
1610    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1611    list->SetItemImage(listitem, newstate, 1);
1612       
1613    if ((treeitem = itemdata->GetId()).IsOk()) {
1614       SetTreeItemState(treeitem, newstate);
1615    }
1616    else {
1617       UpdateTreeItemState(tree->GetSelection());
1618    }
1619 }
1620
1621 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1622 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1623 #if wxCHECK_VERSION(2, 6, 0)
1624    wxTreeItemIdValue cookie;
1625 #else
1626    long cookie;
1627 #endif
1628    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1629
1630    wxbTreeItemData* itemdata;
1631
1632    while (currentChild.IsOk()) {
1633       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1634       int state = itemdata->GetMarked();
1635       
1636       if (state != newstate) {
1637          itemdata->SetMarked(newstate);
1638          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1639          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1640       }
1641       
1642       currentChild = tree->GetNextChild(item, cookie);
1643    }
1644      
1645    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1646    itemdata->SetMarked(newstate);
1647    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1648    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1649    tree->Refresh();
1650    
1651    if (tree->GetSelection() == item) {
1652       for (long i = 0; i < list->GetItemCount(); i++) {
1653          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1654          list->SetItemImage(i, newstate, 1);
1655       }
1656    }
1657    
1658    UpdateTreeItemState(tree->GetItemParent(item));
1659 }
1660
1661 /* Update a tree item state, and its parents' state */
1662 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1663    if (!item.IsOk()) {
1664       return;
1665    }
1666    
1667    int state = 0;
1668        
1669 #if wxCHECK_VERSION(2, 6, 0)
1670    wxTreeItemIdValue cookie;
1671 #else
1672    long cookie;
1673 #endif
1674    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1675
1676    bool onechildmarked = false;
1677    bool onechildunmarked = false;
1678
1679    while (currentChild.IsOk()) {
1680       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1681       switch (state) {
1682       case 0:
1683          onechildunmarked = true;
1684          break;
1685       case 1:
1686          onechildmarked = true;
1687          break;
1688       case 2:
1689          onechildmarked = true;
1690          onechildunmarked = true;
1691          break;
1692       }
1693       
1694       if (onechildmarked && onechildunmarked) {
1695          break;
1696       }
1697       
1698       currentChild = tree->GetNextChild(item, cookie);
1699    }
1700    
1701    if (tree->GetSelection() == item) {
1702       for (long i = 0; i < list->GetItemCount(); i++) {
1703          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1704          
1705          switch (state) {
1706          case 0:
1707             onechildunmarked = true;
1708             break;
1709          case 1:
1710             onechildmarked = true;
1711             break;
1712          case 2:
1713             onechildmarked = true;
1714             onechildunmarked = true;
1715             break;
1716          }
1717          
1718          if (onechildmarked && onechildunmarked) {
1719             break;
1720          }
1721       }
1722    }
1723    
1724    state = 0;
1725    
1726    if (onechildmarked && onechildunmarked) {
1727       state = 2;
1728    }
1729    else if (onechildmarked) {
1730       state = 1;
1731    }
1732    else if (onechildunmarked) {
1733       state = 0;
1734    }
1735    else { // no child, don't change anything
1736       UpdateTreeItemState(tree->GetItemParent(item));
1737       return;
1738    }
1739    
1740    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1741       
1742    itemdata->SetMarked(state);
1743    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1744    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1745    
1746    UpdateTreeItemState(tree->GetItemParent(item));
1747 }
1748
1749 /* Refresh the whole tree. */
1750 void wxbRestorePanel::RefreshTree() {
1751    /* Save current selection */
1752    wxArrayString current;
1753    
1754    wxTreeItemId item = currentTreeItem;
1755    
1756    while ((item.IsOk()) && (item != tree->GetRootItem())) {
1757       current.Add(tree->GetItemText(item));
1758       item = tree->GetItemParent(item);
1759    }
1760
1761    /* Update the tree */
1762    UpdateTreeItem(tree->GetRootItem(), false, true);
1763
1764    /* Reselect the former selected item */   
1765    item = tree->GetRootItem();
1766    
1767    if (current.Count() == 0) {
1768       tree->SelectItem(item);
1769       return;
1770    }
1771    
1772    bool match;
1773    
1774    for (int i = current.Count()-1; i >= 0; i--) {
1775 #if wxCHECK_VERSION(2, 6, 0)
1776       wxTreeItemIdValue cookie;
1777 #else
1778       long cookie;
1779 #endif
1780       wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1781       
1782       match = false;
1783       
1784       while (currentChild.IsOk()) {
1785          if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1786             item = currentChild;
1787             match = true;
1788             break;
1789          }
1790    
1791          currentChild = tree->GetNextChild(item, cookie);
1792       }
1793       
1794       if (!match) break;
1795    }
1796    
1797    UpdateTreeItem(item, true, false); /* Update the list */
1798    
1799    tree->SelectItem(item);
1800 }
1801
1802 void wxbRestorePanel::RefreshList() {
1803    if (currentTreeItem.IsOk()) {
1804       UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1805    }
1806 }
1807
1808 /* Update first config, adapting settings to the job name selected */
1809 void wxbRestorePanel::UpdateFirstConfig() {
1810    configPanel->Enable(false);
1811    wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(wxT(".defaults job=")) + configPanel->GetRowString(_("Job Name")) + wxT("\n"), true, false);
1812    /* job=RestoreFiles
1813     * pool=Default
1814     * messages=Standard
1815     * client=***
1816     * storage=File
1817     * where=/tmp/bacula-restores
1818     * level=0
1819     * type=Restore
1820     * fileset=***
1821     */
1822    
1823    wxString name, str;
1824    unsigned int i;
1825    int j;
1826    wxString client;
1827    bool dolistjobs = false;
1828    
1829    for (i = 0; i < dt->GetCount(); i++) {
1830       str = (*dt)[i];
1831       if ((j = str.Find('=')) > -1) {
1832          name = str.Mid(0, j);
1833          if (name == wxT("pool")) {
1834             configPanel->SetRowString(_("Pool"), str.Mid(j+1));
1835          }
1836          else if (name == wxT("client")) {
1837             str = str.Mid(j+1);
1838             if ((str != configPanel->GetRowString(_("Client"))) ||
1839                   (configPanel->GetRowString(_("Before"))) == wxT("")) {
1840                configPanel->SetRowString(_("Client"), str);
1841                dolistjobs = true;
1842             }
1843          }
1844          else if (name == wxT("storage")) {
1845             configPanel->SetRowString(_("Storage"), str.Mid(j+1));
1846          }
1847          else if (name == wxT("fileset")) {
1848             str = str.Mid(j+1);
1849             if ((str != configPanel->GetRowString(_("Fileset"))) ||
1850                   (configPanel->GetRowString(_("Before"))) == wxT("")) {
1851                configPanel->SetRowString(_("Fileset"), str);
1852                dolistjobs = true;
1853             }
1854          }
1855       }
1856    }
1857       
1858    delete dt;
1859    
1860    if (dolistjobs) {
1861       //wxTheApp->Yield(false);
1862       CmdListJobs();
1863    }
1864    configPanel->Enable(true);
1865 }
1866
1867 /* 
1868  * Update second config.
1869  * 
1870  * Run Restore job
1871  * JobName:    RestoreFiles
1872  * Bootstrap:  /var/lib/bacula/restore.bsr
1873  * Where:      /tmp/bacula-restores
1874  * Replace:    always
1875  * FileSet:    Full Set
1876  * Client:     tom-fd
1877  * Storage:    File
1878  * When:       2004-04-18 01:18:56
1879  * Priority:   10
1880  * OK to run? (yes/mod/no):
1881  * 
1882  */
1883 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1884    unsigned int i;
1885    for (i = 0; i < dt->GetCount(); i++) {
1886       if ((*dt)[i].Find(_("Run Restore job")) == 0)
1887          break;
1888    }
1889    
1890    if ((i + 10) > dt->GetCount()) {
1891       return false;
1892    }
1893    
1894    int k;
1895    
1896    if ((k = (*dt)[++i].Find(_("JobName:"))) != 0) return false;
1897    restorePanel->SetRowString(_("Job Name"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1898    if ((k = (*dt)[++i].Find(_("Bootstrap:"))) != 0) return false;
1899    restorePanel->SetRowString(_("Bootstrap"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1900    if ((k = (*dt)[++i].Find(_("Where:"))) != 0) return false;
1901    restorePanel->SetRowString(_("Where"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1902    
1903    if ((k = (*dt)[++i].Find(_("Replace:"))) != 0) return false;
1904    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1905    if (str == _("always")) restorePanel->SetRowSelection(_("Replace"), 0);
1906    else if (str == _("ifnewer")) restorePanel->SetRowSelection(_("Replace"), 1);
1907    else if (str == _("ifolder")) restorePanel->SetRowSelection(_("Replace"), 2);
1908    else if (str == _("never")) restorePanel->SetRowSelection(_("Replace"), 3);
1909    else restorePanel->SetRowSelection(_("Replace"), 0);
1910
1911    if ((k = (*dt)[++i].Find(_("FileSet:"))) != 0) return false;
1912    restorePanel->SetRowString(_("Fileset"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1913    if ((k = (*dt)[++i].Find(_("Client:"))) != 0) return false;
1914    restorePanel->SetRowString(_("Client"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1915    if ((k = (*dt)[++i].Find(_("Storage:"))) != 0) return false;
1916    restorePanel->SetRowString(_("Storage"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1917    if ((k = (*dt)[++i].Find(_("When:"))) != 0) return false;
1918    restorePanel->SetRowString(_("When"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1919    i++;        /* Skip catalog field */
1920    if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1921    restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1922    cfgUpdated = 0;
1923    
1924    restorePanel->Layout();
1925    
1926    return true;
1927 }
1928
1929 /*----------------------------------------------------------------------------
1930    Status function
1931   ----------------------------------------------------------------------------*/
1932
1933 /* Set current status by enabling/disabling components */
1934 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1935    switch (newstatus) {
1936    case disabled:
1937       centerSizer->Remove(configPanel);
1938       centerSizer->Remove(restorePanel);
1939       centerSizer->Remove(treelistPanel);
1940       treelistPanel->Show(false);
1941       restorePanel->Show(false);
1942       centerSizer->Add(configPanel, 1, wxEXPAND);
1943       configPanel->Show(true);
1944       configPanel->Layout();
1945       centerSizer->Layout();
1946       this->Layout();
1947       start->SetLabel(_("Enter restore mode"));
1948       start->Enable(false);
1949       configPanel->Enable(false);
1950       tree->Enable(false);
1951       list->Enable(false);
1952       gauge->Enable(false);
1953       cancel->Enable(false);
1954       cfgUpdated = 0;
1955       cancelled = 0;
1956       break;
1957    case finished:
1958       centerSizer->Remove(configPanel);
1959       centerSizer->Remove(restorePanel);
1960       centerSizer->Remove(treelistPanel);
1961       treelistPanel->Show(false);
1962       restorePanel->Show(false);
1963       centerSizer->Add(configPanel, 1, wxEXPAND);
1964       configPanel->Show(true);
1965       configPanel->Layout();
1966       centerSizer->Layout();
1967       this->Layout();
1968       tree->DeleteAllItems();
1969       list->DeleteAllItems();
1970       configPanel->ClearRowChoices(_("Client"));
1971       configPanel->ClearRowChoices(_("Before"));
1972       wxbMainFrame::GetInstance()->EnablePanels();
1973       newstatus = activable;
1974    case activable:
1975       cancelled = 0;
1976       start->SetLabel(_("Enter restore mode"));
1977       start->Enable(true);
1978       configPanel->Enable(false);
1979       tree->Enable(false);
1980       list->Enable(false);
1981       gauge->Enable(false);
1982       cancel->Enable(false);
1983       cfgUpdated = 0;
1984       break;
1985    case entered:
1986       wxbMainFrame::GetInstance()->DisablePanels(this);
1987       gauge->SetValue(0);
1988       start->Enable(false);
1989       //start->SetLabel(_("Choose files to restore"));
1990       configPanel->Enable(true);
1991       tree->Enable(false);
1992       list->Enable(false);
1993       cancel->Enable(true);
1994       cfgUpdated = 0;
1995       break;
1996    case listing:
1997       break;
1998    case choosing:
1999       start->Enable(true);
2000       start->SetLabel(_("Restore"));
2001       centerSizer->Remove(configPanel);
2002       configPanel->Show(false);
2003       centerSizer->Add(treelistPanel, 1, wxEXPAND);
2004       treelistPanel->Show(true);
2005       treelistPanel->Layout();
2006       centerSizer->Layout();
2007       this->Layout();
2008       tree->Enable(true);
2009       list->Enable(true);
2010       SetWorking(false);
2011       break;
2012    case configuring:
2013       start->Enable(false);
2014       configPanel->Enable(false);
2015       tree->Enable(false);
2016       list->Enable(false);
2017       centerSizer->Remove(treelistPanel);
2018       treelistPanel->Show(false);
2019       centerSizer->Add(restorePanel, 1, wxEXPAND);
2020       restorePanel->Show(true);
2021       restorePanel->Layout();
2022       centerSizer->Layout();
2023       this->Layout();
2024       restorePanel->EnableApply(false);
2025       cancel->Enable(true);
2026       break;
2027    case restoring:
2028       start->SetLabel(_("Restoring..."));
2029       gauge->Enable(true);
2030       gauge->SetValue(0);
2031       start->Enable(false);
2032       configPanel->Enable(false);
2033       tree->Enable(false);
2034       list->Enable(false);
2035       SetWorking(true);
2036       break;
2037    }
2038    status = newstatus;
2039 }
2040
2041 /*----------------------------------------------------------------------------
2042    UI related
2043   ----------------------------------------------------------------------------*/
2044
2045 void wxbRestorePanel::SetWorking(bool working) {
2046    this->working = working;
2047    if (working) {
2048       SetCursor(*wxHOURGLASS_CURSOR);
2049 //      SetEvtHandlerEnabled(false); //EVTQUEUE
2050    }
2051 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
2052    else {
2053 //      processing = true; //EVTQUEUE
2054       SetCursor(*wxSTANDARD_CURSOR);
2055 //      SetEvtHandlerEnabled(true); //EVTQUEUE
2056 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
2057       while ( node ) {
2058          wxEvent *event = (wxEvent *)node->Data();
2059          delete node;
2060    
2061          wxEvtHandler::ProcessEvent(*event);
2062          delete event;
2063    
2064          node = pendingEvents->First();
2065       }
2066       processing = false;*/
2067    }
2068 }
2069
2070 bool wxbRestorePanel::IsWorking() {
2071    return this->working;
2072 }
2073
2074 void wxbRestorePanel::EnableConfig(bool enable) {
2075    restorePanel->Enable(enable);
2076 }
2077
2078 /*----------------------------------------------------------------------------
2079    Event handling
2080   ----------------------------------------------------------------------------*/
2081
2082
2083 //EVTQUEUE
2084 /*
2085 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2086    if (IsWorking() || processing) {
2087       wxEvent *eventCopy = event.Clone();
2088       
2089       pendingEvents->Append(eventCopy);
2090       return TRUE;
2091    }
2092    else {
2093       return wxEvtHandler::ProcessEvent(event);
2094    }
2095 }
2096 */
2097
2098 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2099    cancel->Enable(false);
2100    SetCursor(*wxHOURGLASS_CURSOR);
2101    CmdCancel();
2102    SetCursor(*wxSTANDARD_CURSOR);
2103 }
2104
2105 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2106    if (IsWorking()) {
2107       return;
2108    }
2109    SetWorking(true);
2110    CmdStart();
2111    SetWorking(false);
2112 }
2113
2114 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2115    if (IsWorking()) {
2116       event.Veto();
2117    }
2118 }
2119
2120 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2121    if (IsWorking()) {
2122       event.Veto();
2123       return;
2124    }
2125    //working = true;
2126    //CmdList(event.GetItem());
2127    if (tree->GetSelection() != event.GetItem()) {
2128       tree->SelectItem(event.GetItem());
2129    }
2130    //working = false;
2131 }
2132
2133 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2134    if (IsWorking()) {
2135       return;
2136    }
2137    if (currentTreeItem == event.GetItem()) {
2138       return;
2139    }
2140    treeadd->Enable(false);
2141    treeremove->Enable(false);
2142    treerefresh->Enable(false);
2143    markWhenCommandDone = false;
2144    SetWorking(true);
2145    currentTreeItem = event.GetItem();
2146    CmdList(event.GetItem());
2147    if (markWhenCommandDone) {
2148       CmdMark(event.GetItem(), NULL, 0);
2149       tree->Refresh();
2150    }
2151    SetWorking(false);
2152    if (event.GetItem().IsOk()) {
2153       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2154       treeadd->Enable(status != 1);
2155       treeremove->Enable(status != 0);
2156    }
2157    treerefresh->Enable(true);
2158 }
2159
2160 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2161    if (IsWorking()) {
2162       if (tree->GetSelection() == event.GetItem()) {
2163          markWhenCommandDone = !markWhenCommandDone;
2164       }
2165       return;
2166    }
2167    SetWorking(true);
2168    markWhenCommandDone = false;
2169    CmdMark(event.GetItem(), NULL, 0);
2170    if (markWhenCommandDone) {
2171       CmdMark(event.GetItem(), NULL, 0);
2172       tree->Refresh();
2173    }
2174    tree->Refresh();
2175    SetWorking(false);
2176    if (event.GetItem().IsOk()) {
2177       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2178       treeadd->Enable(status != 1);
2179       treeremove->Enable(status != 0);
2180    }
2181 }
2182
2183 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2184    if (IsWorking()) {
2185       return;
2186    }
2187    
2188    if (currentTreeItem.IsOk()) {
2189       SetWorking(true);
2190       CmdMark(currentTreeItem, NULL, 0, 1);
2191       tree->Refresh();
2192       treeadd->Enable(0);
2193       treeremove->Enable(1);
2194       SetWorking(false);
2195    }
2196 }
2197
2198 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2199    if (IsWorking()) {
2200       return;
2201    }
2202    
2203    if (currentTreeItem.IsOk()) {
2204       SetWorking(true);
2205       CmdMark(currentTreeItem, NULL, 0, 0);
2206       tree->Refresh();
2207       treeadd->Enable(1);
2208       treeremove->Enable(0);
2209       SetWorking(false);
2210    }
2211 }
2212
2213 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2214    if (IsWorking()) {
2215       return;
2216    }
2217    
2218    SetWorking(true);
2219    RefreshTree();
2220    SetWorking(false);
2221 }
2222
2223 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2224    if (IsWorking()) {
2225       return;
2226    }
2227    
2228    if (list->GetSelectedItemCount() == 0) {
2229       return;
2230    }
2231    
2232    SetWorking(true);  
2233    
2234    long* items = new long[list->GetSelectedItemCount()];
2235    
2236    int num = 0;
2237    
2238    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2239    while (item != -1) {
2240       items[num] = item;
2241       num++;
2242       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2243    }
2244    
2245    CmdMark(wxTreeItemId(), items, num);
2246    
2247    delete[] items;
2248    
2249    wxListEvent listevt;
2250    
2251    OnListChanged(listevt);
2252    
2253    event.Skip();
2254    tree->Refresh();
2255    SetWorking(false);
2256 }
2257
2258 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2259    if (IsWorking()) {
2260       return;
2261    }
2262    SetWorking(true);
2263    long item = event.GetIndex();
2264 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2265    if (item > -1) {
2266       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2267       wxString name = itemdata->GetName();
2268       event.Skip();
2269
2270       wxString itemStr;
2271
2272 #if wxCHECK_VERSION(2, 6, 0)
2273       wxTreeItemIdValue cookie;
2274 #else
2275       long cookie;
2276 #endif
2277
2278       if (IsPathSeparator(name.GetChar(name.Length()-1))) {
2279          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2280
2281          while (currentChild.IsOk()) {
2282             wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2283             if (name2 == name) {
2284                //tree->UnselectAll();
2285                SetWorking(false);
2286                tree->Expand(currentTreeItem);
2287                tree->SelectItem(currentChild);
2288                //tree->Refresh();
2289                return;
2290             }
2291             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2292          }
2293       }
2294    }
2295    SetWorking(false);
2296 }
2297
2298 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2299    if (IsWorking()) {
2300       return;
2301    }
2302  
2303    listadd->Enable(false);
2304    listremove->Enable(false);
2305    
2306    bool marked = false;
2307    bool unmarked = false;
2308    
2309    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2310    while (item != -1) {
2311       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2312       case 0:
2313          unmarked = true;
2314          break;
2315       case 1:
2316          marked = true;
2317          break;
2318       case 2:
2319          marked = true;
2320          unmarked = true;
2321          break;
2322       default:
2323          break;
2324          // Should never happen
2325       }
2326       if (marked && unmarked) break;
2327       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2328    }
2329    
2330    listadd->Enable(unmarked);
2331    listremove->Enable(marked);
2332 }
2333
2334 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2335    if (IsWorking()) {
2336       return;
2337    }
2338    
2339    SetWorking(true);
2340    
2341    long* items = new long[list->GetSelectedItemCount()];
2342    
2343    int num = 0;
2344    
2345    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2346    while (item != -1) {
2347       items[num] = item;
2348       num++;
2349       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2350    }
2351      
2352    CmdMark(wxTreeItemId(), items, num, 1);
2353    
2354    delete[] items;
2355    
2356    tree->Refresh();
2357    SetWorking(false);
2358    
2359    listadd->Enable(false);
2360    listremove->Enable(true);
2361 }
2362
2363 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2364    if (IsWorking()) {
2365       return;
2366    }
2367    
2368    SetWorking(true);
2369    
2370    long* items = new long[list->GetSelectedItemCount()];
2371    
2372    int num = 0;
2373    
2374    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2375    while (item != -1) {
2376       items[num] = item;
2377       num++;
2378       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2379    }
2380      
2381    CmdMark(wxTreeItemId(), items, num, 0);
2382    
2383    delete[] items;
2384    
2385    tree->Refresh();
2386    SetWorking(false);
2387    
2388    listadd->Enable(true);
2389    listremove->Enable(false);
2390 }
2391
2392 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) 
2393 {
2394    if (IsWorking()) {
2395       return;
2396    }
2397    
2398    SetWorking(true);
2399    RefreshList();
2400    SetWorking(false);
2401 }
2402
2403 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) 
2404 {
2405    if (status == entered) {
2406       if (event.GetId() == ConfigJobName) {
2407          if (IsWorking()) {
2408             return;
2409          }
2410          SetWorking(true);
2411          UpdateFirstConfig();
2412          SetWorking(false);
2413       }
2414       else if ((event.GetId() == ConfigClient) || (event.GetId() == ConfigFileset)) {
2415          if (IsWorking()) {
2416             return;
2417          }
2418          SetWorking(true);
2419          configPanel->Enable(false);
2420          CmdListJobs();
2421          configPanel->Enable(true);
2422          SetWorking(false);
2423       }
2424       cfgUpdated = cfgUpdated | (1 << event.GetId());
2425    }
2426    else if (status == configuring) {
2427       restorePanel->EnableApply(true);
2428       cfgUpdated = cfgUpdated | (1 << event.GetId());
2429    }
2430 }
2431
2432 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2433    if (status != configuring) return;
2434    if (IsWorking()) {
2435       return;
2436    }
2437    SetWorking(true);
2438    CmdStart();
2439    SetWorking(false);
2440 }
2441
2442 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2443    if (status != configuring) return;
2444    if (IsWorking()) {
2445       return;
2446    }
2447    SetWorking(true);
2448    CmdConfigApply();
2449    if (cfgUpdated == 0) {
2450       restorePanel->EnableApply(false);
2451    }
2452    SetWorking(false);  
2453 }
2454
2455 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2456    if (status != configuring) return;
2457    if (IsWorking()) {
2458       return;
2459    }
2460    SetWorking(true);
2461    CmdConfigCancel();
2462    SetWorking(false);
2463 }