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