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