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