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