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