]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
kes The bgnome-console (gnome-console) and bwx-console (wx-console) are
[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 plus additions
19    that are listed 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 started. JobId="))) > -1) {
811             jobid = (*dt)[i].Mid(j+19);
812             wxbMainFrame::GetInstance()->SetStatusText(_("Restore started, 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    if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1892    restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1893    cfgUpdated = 0;
1894    
1895    restorePanel->Layout();
1896    
1897    return true;
1898 }
1899
1900 /*----------------------------------------------------------------------------
1901    Status function
1902   ----------------------------------------------------------------------------*/
1903
1904 /* Set current status by enabling/disabling components */
1905 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1906    switch (newstatus) {
1907    case disabled:
1908       centerSizer->Remove(configPanel);
1909       centerSizer->Remove(restorePanel);
1910       centerSizer->Remove(treelistPanel);
1911       treelistPanel->Show(false);
1912       restorePanel->Show(false);
1913       centerSizer->Add(configPanel, 1, wxEXPAND);
1914       configPanel->Show(true);
1915       configPanel->Layout();
1916       centerSizer->Layout();
1917       this->Layout();
1918       start->SetLabel(_("Enter restore mode"));
1919       start->Enable(false);
1920       configPanel->Enable(false);
1921       tree->Enable(false);
1922       list->Enable(false);
1923       gauge->Enable(false);
1924       cancel->Enable(false);
1925       cfgUpdated = 0;
1926       cancelled = 0;
1927       break;
1928    case finished:
1929       centerSizer->Remove(configPanel);
1930       centerSizer->Remove(restorePanel);
1931       centerSizer->Remove(treelistPanel);
1932       treelistPanel->Show(false);
1933       restorePanel->Show(false);
1934       centerSizer->Add(configPanel, 1, wxEXPAND);
1935       configPanel->Show(true);
1936       configPanel->Layout();
1937       centerSizer->Layout();
1938       this->Layout();
1939       tree->DeleteAllItems();
1940       list->DeleteAllItems();
1941       configPanel->ClearRowChoices(_("Client"));
1942       configPanel->ClearRowChoices(_("Before"));
1943       wxbMainFrame::GetInstance()->EnablePanels();
1944       newstatus = activable;
1945    case activable:
1946       cancelled = 0;
1947       start->SetLabel(_("Enter restore mode"));
1948       start->Enable(true);
1949       configPanel->Enable(false);
1950       tree->Enable(false);
1951       list->Enable(false);
1952       gauge->Enable(false);
1953       cancel->Enable(false);
1954       cfgUpdated = 0;
1955       break;
1956    case entered:
1957       wxbMainFrame::GetInstance()->DisablePanels(this);
1958       gauge->SetValue(0);
1959       start->Enable(false);
1960       //start->SetLabel(_("Choose files to restore"));
1961       configPanel->Enable(true);
1962       tree->Enable(false);
1963       list->Enable(false);
1964       cancel->Enable(true);
1965       cfgUpdated = 0;
1966       break;
1967    case listing:
1968       
1969       break;
1970    case choosing:
1971       start->Enable(true);
1972       start->SetLabel(_("Restore"));
1973       centerSizer->Remove(configPanel);
1974       configPanel->Show(false);
1975       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1976       treelistPanel->Show(true);
1977       treelistPanel->Layout();
1978       centerSizer->Layout();
1979       this->Layout();
1980       tree->Enable(true);
1981       list->Enable(true);
1982       SetWorking(false);
1983       break;
1984    case configuring:
1985       start->Enable(false);
1986       configPanel->Enable(false);
1987       tree->Enable(false);
1988       list->Enable(false);
1989       centerSizer->Remove(treelistPanel);
1990       treelistPanel->Show(false);
1991       centerSizer->Add(restorePanel, 1, wxEXPAND);
1992       restorePanel->Show(true);
1993       restorePanel->Layout();
1994       centerSizer->Layout();
1995       this->Layout();
1996       restorePanel->EnableApply(false);
1997       break;
1998    case restoring:
1999       start->SetLabel(_("Restoring..."));
2000       gauge->Enable(true);
2001       gauge->SetValue(0);
2002       start->Enable(false);
2003       configPanel->Enable(false);
2004       tree->Enable(false);
2005       list->Enable(false);
2006       SetWorking(true);
2007       break;
2008    }
2009    status = newstatus;
2010 }
2011
2012 /*----------------------------------------------------------------------------
2013    UI related
2014   ----------------------------------------------------------------------------*/
2015
2016 void wxbRestorePanel::SetWorking(bool working) {
2017    this->working = working;
2018    if (working) {
2019       SetCursor(*wxHOURGLASS_CURSOR);
2020 //      SetEvtHandlerEnabled(false); //EVTQUEUE
2021    }
2022 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
2023    else {
2024 //      processing = true; //EVTQUEUE
2025       SetCursor(*wxSTANDARD_CURSOR);
2026 //      SetEvtHandlerEnabled(true); //EVTQUEUE
2027 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
2028       while ( node ) {
2029          wxEvent *event = (wxEvent *)node->Data();
2030          delete node;
2031    
2032          wxEvtHandler::ProcessEvent(*event);
2033          delete event;
2034    
2035          node = pendingEvents->First();
2036       }
2037       processing = false;*/
2038    }
2039 }
2040
2041 bool wxbRestorePanel::IsWorking() {
2042    return this->working;
2043 }
2044
2045 void wxbRestorePanel::EnableConfig(bool enable) {
2046    restorePanel->Enable(enable);
2047 }
2048
2049 /*----------------------------------------------------------------------------
2050    Event handling
2051   ----------------------------------------------------------------------------*/
2052
2053
2054 //EVTQUEUE
2055 /*
2056 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2057    if (IsWorking() || processing) {
2058       wxEvent *eventCopy = event.Clone();
2059       
2060       pendingEvents->Append(eventCopy);
2061       return TRUE;
2062    }
2063    else {
2064       return wxEvtHandler::ProcessEvent(event);
2065    }
2066 }
2067 */
2068
2069 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2070    cancel->Enable(false);
2071    SetCursor(*wxHOURGLASS_CURSOR);
2072    CmdCancel();
2073    SetCursor(*wxSTANDARD_CURSOR);
2074 }
2075
2076 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2077    if (IsWorking()) {
2078       return;
2079    }
2080    SetWorking(true);
2081    CmdStart();
2082    SetWorking(false);
2083 }
2084
2085 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2086    if (IsWorking()) {
2087       event.Veto();
2088    }
2089 }
2090
2091 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2092    if (IsWorking()) {
2093       event.Veto();
2094       return;
2095    }
2096    //working = true;
2097    //CmdList(event.GetItem());
2098    if (tree->GetSelection() != event.GetItem()) {
2099       tree->SelectItem(event.GetItem());
2100    }
2101    //working = false;
2102 }
2103
2104 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2105    if (IsWorking()) {
2106       return;
2107    }
2108    if (currentTreeItem == event.GetItem()) {
2109       return;
2110    }
2111    treeadd->Enable(false);
2112    treeremove->Enable(false);
2113    treerefresh->Enable(false);
2114    markWhenCommandDone = false;
2115    SetWorking(true);
2116    currentTreeItem = event.GetItem();
2117    CmdList(event.GetItem());
2118    if (markWhenCommandDone) {
2119       CmdMark(event.GetItem(), NULL, 0);
2120       tree->Refresh();
2121    }
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    treerefresh->Enable(true);
2129 }
2130
2131 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2132    if (IsWorking()) {
2133       if (tree->GetSelection() == event.GetItem()) {
2134          markWhenCommandDone = !markWhenCommandDone;
2135       }
2136       return;
2137    }
2138    SetWorking(true);
2139    markWhenCommandDone = false;
2140    CmdMark(event.GetItem(), NULL, 0);
2141    if (markWhenCommandDone) {
2142       CmdMark(event.GetItem(), NULL, 0);
2143       tree->Refresh();
2144    }
2145    tree->Refresh();
2146    SetWorking(false);
2147    if (event.GetItem().IsOk()) {
2148       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2149       treeadd->Enable(status != 1);
2150       treeremove->Enable(status != 0);
2151    }
2152 }
2153
2154 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2155    if (IsWorking()) {
2156       return;
2157    }
2158    
2159    if (currentTreeItem.IsOk()) {
2160       SetWorking(true);
2161       CmdMark(currentTreeItem, NULL, 0, 1);
2162       tree->Refresh();
2163       treeadd->Enable(0);
2164       treeremove->Enable(1);
2165       SetWorking(false);
2166    }
2167 }
2168
2169 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2170    if (IsWorking()) {
2171       return;
2172    }
2173    
2174    if (currentTreeItem.IsOk()) {
2175       SetWorking(true);
2176       CmdMark(currentTreeItem, NULL, 0, 0);
2177       tree->Refresh();
2178       treeadd->Enable(1);
2179       treeremove->Enable(0);
2180       SetWorking(false);
2181    }
2182 }
2183
2184 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2185    if (IsWorking()) {
2186       return;
2187    }
2188    
2189    SetWorking(true);
2190    RefreshTree();
2191    SetWorking(false);
2192 }
2193
2194 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2195    if (IsWorking()) {
2196       return;
2197    }
2198    
2199    if (list->GetSelectedItemCount() == 0) {
2200       return;
2201    }
2202    
2203    SetWorking(true);  
2204    
2205    long* items = new long[list->GetSelectedItemCount()];
2206    
2207    int num = 0;
2208    
2209    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2210    while (item != -1) {
2211       items[num] = item;
2212       num++;
2213       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2214    }
2215    
2216    CmdMark(wxTreeItemId(), items, num);
2217    
2218    delete[] items;
2219    
2220    wxListEvent listevt;
2221    
2222    OnListChanged(listevt);
2223    
2224    event.Skip();
2225    tree->Refresh();
2226    SetWorking(false);
2227 }
2228
2229 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2230    if (IsWorking()) {
2231       return;
2232    }
2233    SetWorking(true);
2234    long item = event.GetIndex();
2235 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2236    if (item > -1) {
2237       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2238       wxString name = itemdata->GetName();
2239       event.Skip();
2240
2241       wxString itemStr;
2242
2243 #if wxCHECK_VERSION(2, 6, 0)
2244       wxTreeItemIdValue cookie;
2245 #else
2246       long cookie;
2247 #endif
2248
2249       if (IsPathSeparator(name.GetChar(name.Length()-1))) {
2250          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2251
2252          while (currentChild.IsOk()) {
2253             wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2254             if (name2 == name) {
2255                //tree->UnselectAll();
2256                SetWorking(false);
2257                tree->Expand(currentTreeItem);
2258                tree->SelectItem(currentChild);
2259                //tree->Refresh();
2260                return;
2261             }
2262             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2263          }
2264       }
2265    }
2266    SetWorking(false);
2267 }
2268
2269 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2270    if (IsWorking()) {
2271       return;
2272    }
2273  
2274    listadd->Enable(false);
2275    listremove->Enable(false);
2276    
2277    bool marked = false;
2278    bool unmarked = false;
2279    
2280    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2281    while (item != -1) {
2282       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2283       case 0:
2284          unmarked = true;
2285          break;
2286       case 1:
2287          marked = true;
2288          break;
2289       case 2:
2290          marked = true;
2291          unmarked = true;
2292          break;
2293       default:
2294          break;
2295          // Should never happen
2296       }
2297       if (marked && unmarked) break;
2298       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2299    }
2300    
2301    listadd->Enable(unmarked);
2302    listremove->Enable(marked);
2303 }
2304
2305 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2306    if (IsWorking()) {
2307       return;
2308    }
2309    
2310    SetWorking(true);
2311    
2312    long* items = new long[list->GetSelectedItemCount()];
2313    
2314    int num = 0;
2315    
2316    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2317    while (item != -1) {
2318       items[num] = item;
2319       num++;
2320       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2321    }
2322      
2323    CmdMark(wxTreeItemId(), items, num, 1);
2324    
2325    delete[] items;
2326    
2327    tree->Refresh();
2328    SetWorking(false);
2329    
2330    listadd->Enable(false);
2331    listremove->Enable(true);
2332 }
2333
2334 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2335    if (IsWorking()) {
2336       return;
2337    }
2338    
2339    SetWorking(true);
2340    
2341    long* items = new long[list->GetSelectedItemCount()];
2342    
2343    int num = 0;
2344    
2345    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2346    while (item != -1) {
2347       items[num] = item;
2348       num++;
2349       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2350    }
2351      
2352    CmdMark(wxTreeItemId(), items, num, 0);
2353    
2354    delete[] items;
2355    
2356    tree->Refresh();
2357    SetWorking(false);
2358    
2359    listadd->Enable(true);
2360    listremove->Enable(false);
2361 }
2362
2363 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2364    if (IsWorking()) {
2365       return;
2366    }
2367    
2368    SetWorking(true);
2369    RefreshList();
2370    SetWorking(false);
2371 }
2372
2373 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2374    if (status == entered) {
2375       if (event.GetId() == ConfigJobName) {
2376          if (IsWorking()) {
2377             return;
2378          }
2379          SetWorking(true);
2380          UpdateFirstConfig();
2381          SetWorking(false);
2382       }
2383       else if ((event.GetId() == ConfigClient) || (event.GetId() == ConfigFileset)) {
2384          if (IsWorking()) {
2385             return;
2386          }
2387          SetWorking(true);
2388          configPanel->Enable(false);
2389          CmdListJobs();
2390          configPanel->Enable(true);
2391          SetWorking(false);
2392       }
2393       cfgUpdated = cfgUpdated | (1 << event.GetId());
2394    }
2395    else if (status == configuring) {
2396       restorePanel->EnableApply(true);
2397       cfgUpdated = cfgUpdated | (1 << event.GetId());
2398    }
2399 }
2400
2401 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2402    if (status != configuring) return;
2403    if (IsWorking()) {
2404       return;
2405    }
2406    SetWorking(true);
2407    CmdStart();
2408    SetWorking(false);
2409 }
2410
2411 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2412    if (status != configuring) return;
2413    if (IsWorking()) {
2414       return;
2415    }
2416    SetWorking(true);
2417    CmdConfigApply();
2418    if (cfgUpdated == 0) {
2419       restorePanel->EnableApply(false);
2420    }
2421    SetWorking(false);  
2422 }
2423
2424 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2425    if (status != configuring) return;
2426    if (IsWorking()) {
2427       return;
2428    }
2429    SetWorking(true);
2430    CmdConfigCancel();
2431    SetWorking(false);
2432 }