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