2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * wxbPanel for restoring files
32 * Nicolas Boichat, April-July 2004
37 /* Note concerning "done" output (modifiable marked with +)
39 +JobName: RestoreFiles
40 Bootstrap: /var/lib/bacula/restore.bsr
41 +Where: /tmp/bacula-restores
46 +When: 2004-04-18 01:18:56
48 OK to run? (yes/mod/no):mod
50 1: Level (not appropriate)
51 2: Storage (automatic ?)
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)")
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):")
62 Select parameter to modify (1-11):
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.
74 #include "wxbrestorepanel.h"
75 #include "wxbmainframe.h"
77 #include <wx/choice.h>
78 #include <wx/datetime.h>
80 #include "unmarked.xpm"
82 #include "partmarked.xpm"
83 #include <wx/imaglist.h>
84 #include <wx/listimpl.cpp>
86 /* A macro named Yield is defined under MinGW */
89 WX_DEFINE_LIST(wxbEventList);
92 * Class which is stored in the tree and in the list to keep informations
95 class wxbTreeItemData : public wxTreeItemData {
97 wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
103 void SetMarked(int marked);
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) */
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;
120 wxbTreeItemData::~wxbTreeItemData() {
125 int wxbTreeItemData::GetMarked() {
129 void wxbTreeItemData::SetMarked(int marked) {
130 this->marked = marked;
133 long wxbTreeItemData::GetListId() {
137 wxString wxbTreeItemData::GetPath() {
141 wxString wxbTreeItemData::GetName() {
145 // ----------------------------------------------------------------------------
146 // event tables and other macros for wxWindows
147 // ----------------------------------------------------------------------------
175 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
176 EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
177 EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
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)
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)
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)
206 EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
207 EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
208 EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
212 * wxbRestorePanel constructor
214 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent)
216 //pendingEvents = new wxbEventList(); //EVTQUEUE
217 //processing = false; //EVTQUEUE
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));
225 wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
226 mainSizer->AddGrowableCol(0);
227 mainSizer->AddGrowableRow(1);
229 wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
231 firstSizer->AddGrowableCol(0);
232 firstSizer->AddGrowableRow(0);
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);
237 cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
238 firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
242 /* clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
243 firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
245 jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
246 firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
248 mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
250 treelistPanel = new wxSplitterWindow(this);
252 wxPanel* treePanel = new wxPanel(treelistPanel);
253 wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
254 treeSizer->AddGrowableCol(0);
255 treeSizer->AddGrowableRow(0);
257 tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));
258 tree->SetImageList(imagelist);
260 treeSizer->Add(tree, 1, wxEXPAND, 0);
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);
270 treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
272 treePanel->SetSizer(treeSizer);
274 wxPanel* listPanel = new wxPanel(treelistPanel);
275 wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
276 listSizer->AddGrowableCol(0);
277 listSizer->AddGrowableRow(0);
279 list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
280 //treelistSizer->Add(list, 1, wxEXPAND, 10);
282 list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
285 info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
286 info.SetText(_("M"));
287 info.SetAlign(wxLIST_FORMAT_CENTER);
288 list->InsertColumn(0, info);
290 info.SetText(_("Filename"));
291 info.SetAlign(wxLIST_FORMAT_LEFT);
292 list->InsertColumn(1, info);
294 info.SetText(_("Size"));
295 info.SetAlign(wxLIST_FORMAT_RIGHT);
296 list->InsertColumn(2, info);
298 info.SetText(_("Date"));
299 info.SetAlign(wxLIST_FORMAT_LEFT);
300 list->InsertColumn(3, info);
302 info.SetText(_("Perm."));
303 info.SetAlign(wxLIST_FORMAT_LEFT);
304 list->InsertColumn(4, info);
306 info.SetText(_("User"));
307 info.SetAlign(wxLIST_FORMAT_RIGHT);
308 list->InsertColumn(5, info);
310 info.SetText(_("Group"));
311 info.SetAlign(wxLIST_FORMAT_RIGHT);
312 list->InsertColumn(6, info);
314 listSizer->Add(list, 1, wxEXPAND, 0);
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);
324 listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
326 listPanel->SetSizer(listSizer);
328 treelistPanel->SplitVertically(treePanel, listPanel, 210);
330 treelistPanel->SetMinimumPaneSize(210);
332 treelistPanel->Show(false);
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));
342 configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
344 configPanel->Show(true);
345 configPanel->Enable(false);
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("")));
359 restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
361 restorePanel->Show(false);
363 centerSizer = new wxBoxSizer(wxHORIZONTAL);
364 //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
366 mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
368 gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
370 mainSizer->Add(gauge, 1, wxEXPAND, 5);
372 gauge->Enable(false);
375 mainSizer->SetSizeHints(this);
379 for (int i = 0; i < 7; i++) {
380 list->SetColumnWidth(i, 70);
383 SetCursor(*wxSTANDARD_CURSOR);
385 markWhenCommandDone = false;
391 * wxbRestorePanel destructor
393 wxbRestorePanel::~wxbRestorePanel()
398 /*----------------------------------------------------------------------------
399 wxbPanel overloadings
400 ----------------------------------------------------------------------------*/
402 wxString wxbRestorePanel::GetTitle()
407 void wxbRestorePanel::EnablePanel(bool enable)
410 if (status == disabled) {
411 SetStatus(activable);
418 /*----------------------------------------------------------------------------
419 Commands called by events handler
420 ----------------------------------------------------------------------------*/
422 /* The main button has been clicked */
423 void wxbRestorePanel::CmdStart()
426 if (status == activable) {
427 wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
428 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
431 configPanel->ClearRowChoices(_("Client"));
432 restorePanel->ClearRowChoices(_("Client"));
434 if (dt->GetCount() == 0) {
435 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
439 for (i = 0; i < dt->GetCount(); i++) {
442 configPanel->AddRowChoice(_("Client"), str);
443 restorePanel->AddRowChoice(_("Client"), str);
453 dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
455 configPanel->ClearRowChoices(_("Fileset"));
456 restorePanel->ClearRowChoices(_("Fileset"));
458 if (dt->GetCount() == 0) {
459 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
463 for (i = 0; i < dt->GetCount(); i++) {
466 configPanel->AddRowChoice(_("Fileset"), str);
467 restorePanel->AddRowChoice(_("Fileset"), str);
477 dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
479 configPanel->ClearRowChoices(_("Storage"));
480 restorePanel->ClearRowChoices(_("Storage"));
482 if (dt->GetCount() == 0) {
483 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
487 for (i = 0; i < dt->GetCount(); i++) {
490 configPanel->AddRowChoice(_("Storage"), str);
491 restorePanel->AddRowChoice(_("Storage"), str);
501 dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
503 configPanel->ClearRowChoices(_("Job Name"));
505 if (dt->GetCount() == 0) {
506 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
510 for (i = 0; i < dt->GetCount(); i++) {
513 configPanel->AddRowChoice(_("Job Name"), str);
516 configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
525 dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
527 configPanel->ClearRowChoices(_("Pool"));
529 if (dt->GetCount() == 0) {
530 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
534 for (i = 0; i < dt->GetCount(); i++) {
537 configPanel->AddRowChoice(_("Pool"), str);
551 wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
553 else if (status == entered) {
555 if (clientChoice->GetStringSelection().Length() < 1) {
556 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
559 if (jobChoice->GetStringSelection().Length() < 1) {
560 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
565 wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
569 wxbTableParser* tableparser = new wxbTableParser();
570 wxbDataTokenizer* dt = new wxbDataTokenizer(false);
573 * The following line was removed from ::GetInstance below because
574 * it does not work with multiple pools -- KES 5Oct05 see bug #433
575 * wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
577 wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
578 wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
579 wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
580 wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
581 wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
585 wxbUtils::WaitForPrompt("6\n");
588 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
590 int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
591 if (client == wxNOT_FOUND) {
592 wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
597 wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
600 while (!tableparser->hasFinished() && !dt->hasFinished()) {
601 wxTheApp->Yield(true);
602 wxbUtils::MilliSleep(100);
607 if (dt->hasFinished() && !tableparser->hasFinished()) {
609 if (dt->GetCount() > 1) {
610 str = (*dt)[dt->GetCount()-2];
613 wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
623 for (i = 0; i < tableparser->GetCount(); i++) {
624 str = (*tableparser)[i][2];
625 str.Replace(wxT(","), wxT(""));
626 if (str.ToLong(&l)) {
632 gauge->SetRange(tot);
635 wxbMainFrame::GetInstance()->Print(
636 wxString("[") << tot << "]", CS_DEBUG);
639 wxDateTime base = wxDateTime::Now();
643 unsigned int lastindex = 0;
650 newdate = wxDateTime::Now();
651 if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
653 for (; lastindex < dt->GetCount(); lastindex++) {
654 if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) &&
655 ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
656 str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
657 for (i = 0; i < tableparser->GetCount(); i++) {
658 if (str == (*tableparser)[i][0]) {
659 str = (*tableparser)[i][2];
660 str.Replace(wxT(","), wxT(""));
661 if (str.ToLong(&l)) {
664 var = (willdo-done)/50;
665 gauge->SetValue(done);
666 wxTheApp->Yield(true);
672 else if ((*dt)[lastindex] == wxT("+")) {
673 gauge->SetValue(gauge->GetValue()+var);
674 wxTheApp->Yield(true);
679 if (dt->hasFinished()) {
683 wxTheApp->Yield(true);
684 wxbUtils::MilliSleep(1);
687 gauge->SetValue(tot);
688 wxTheApp->Yield(true);
699 wxbUtils::WaitForEnd(wxT("unmark *\n"));
700 wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
701 currentTreeItem = root;
703 tree->SelectItem(root);
705 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."));
708 else if (status == choosing) {
712 wxbDataTokenizer* dt;
716 dt = new wxbDataTokenizer(true);
717 wxbPromptParser* promptparser = wxbUtils::WaitForPrompt(wxT("done\n"), true);
719 while (!promptparser->getChoices() || (promptparser->getChoices()->Index(wxT("mod")) < 0)) {
720 wxbMainFrame::GetInstance()->Print(_("Unexpected question has been received.\n"), CS_DEBUG);
723 if (promptparser->getIntroString() != wxT("")) {
724 message << promptparser->getIntroString() << wxT("\n");
726 message << promptparser->getQuestionString();
728 if (promptparser->getChoices()) {
729 wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
730 int *numbers = new int[promptparser->getChoices()->GetCount()];
733 for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
734 if ((*promptparser->getChoices())[i] != wxT("")) {
735 choices[n] = (*promptparser->getChoices())[i];
741 int res = ::wxGetSingleChoiceIndex(message,
742 _("bwx-console: unexpected restore question."), n, choices, this);
745 promptparser = wxbUtils::WaitForPrompt(wxT(".\n"), true);
748 if (promptparser->isNumericalChoice()) {
750 promptparser = wxbUtils::WaitForPrompt(wxString() << numbers[res] << wxT("\n"), true);
754 promptparser = wxbUtils::WaitForPrompt(wxString() << choices[res] << wxT("\n"), true);
763 promptparser = wxbUtils::WaitForPrompt(::wxGetTextFromUser(message,
764 _("bwx-console: unexpected restore question."),
765 wxT(""), this) + wxT("\n"));
768 printf("promptparser->getChoices()=%ld", (long)promptparser->getChoices());
772 SetStatus(configuring);
774 for (i = 0; i < dt->GetCount(); i++) {
775 if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
776 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
780 if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
781 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
786 wxbMainFrame::GetInstance()->SetStatusText(
787 wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
789 UpdateSecondConfig(dt);
794 restorePanel->EnableApply(false);
796 if (totfilemessages == 0) {
797 wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
798 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
803 else if (status == configuring) {
804 cancel->Enable(false);
808 wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
810 wxbDataTokenizer* dt;
812 SetStatus(restoring);
813 dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
816 gauge->SetRange(totfilemessages);
820 for (i = 0; i < dt->GetCount(); i++) {
821 if ((j = (*dt)[i].Find(_("Job queued. JobId="))) > -1) {
822 jobid = (*dt)[i].Mid(j+19);
823 wxbMainFrame::GetInstance()->SetStatusText(_("Restore queued, jobid=") + jobid);
827 if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
828 wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
829 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
834 if (jobid == wxT("")) {
835 wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
836 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
840 wxDateTime currenttime;
842 dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
843 wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
844 if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
845 (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
846 currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
849 currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
853 wxDateTime scheduledtime;
854 wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
856 if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
857 (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
858 scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
861 if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
862 wxbMainFrame::GetInstance()->Print(_("Restore is scheduled to run. bwx-console will not wait for its completion.\n"), CS_DEBUG);
863 wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled to run. bwx-console will not wait for its completion."));
868 wxString cmd = wxString(wxT("list jobid=")) + jobid;
870 wxbTableParser* tableparser;
872 long filemessages = 0;
875 bool waitforever = false;
881 wxbUtils::WaitForEnd(wxT("autodisplay off\n"));
882 wxbUtils::WaitForEnd(wxT("gui on\n"));
884 tableparser = wxbUtils::CreateAndWaitForParser(cmd);
886 status = (*tableparser)[0][7].GetChar(0);
889 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
893 wxbMainFrame::GetInstance()->SetStatusText(
894 wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
898 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
899 wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
903 case JS_ErrorTerminated:
904 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
905 wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
910 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
914 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
919 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
920 wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
925 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
929 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
932 case JS_WaitStoreRes:
933 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
937 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
940 case JS_WaitClientRes:
941 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
945 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
948 case JS_WaitStartTime:
949 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
952 case JS_WaitPriority:
953 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
959 dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
961 for (unsigned int i = 0; i < dt->GetCount(); i++) {
962 wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
966 // Date Time name: perm ? user grp size date time
967 //04-Apr-2004 17:19 Tom-fd: -rwx------ 1 nicolas None 514967 2004-03-20 20:03:42 filename
969 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
970 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
971 if (tkz.GetNextToken().Last() == ':') { // name:
972 tkz.GetNextToken(); // perm
973 tkz.GetNextToken(); // ?
974 tkz.GetNextToken(); // user
975 tkz.GetNextToken(); // grp
976 tkz.GetNextToken(); // size
977 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
978 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
980 //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
981 gauge->SetValue(filemessages);
992 while (sw2.Time() < 10000) {
993 wxTheApp->Yield(true);
994 wxbUtils::MilliSleep(100);
1001 if ((!waitforever) && (sw.Time() > 60000)) {
1002 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);
1003 wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore."));
1007 wxbUtils::WaitForEnd(wxT("autodisplay on\n"));
1008 wxbUtils::WaitForEnd(wxT(".messages\n"));
1010 gauge->SetValue(totfilemessages);
1012 if (status == JS_Terminated) {
1013 wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
1014 wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
1016 SetStatus(finished);
1020 /* The cancel button has been clicked */
1021 void wxbRestorePanel::CmdCancel() {
1024 if (status == restoring) {
1025 if (jobid != wxT("")) {
1026 wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
1028 cancel->Enable(true);
1033 while ((IsWorking()) && (cancelled != 2)) {
1034 wxTheApp->Yield(true);
1035 wxbUtils::MilliSleep(100);
1036 if (sw.Time() > 30000) { /* 30 seconds timeout */
1037 if (status == choosing) {
1038 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1040 else if (status == configuring) {
1041 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1043 else if (status == restoring) {
1046 SetStatus(finished);
1047 wxbUtils::MilliSleep(1000);
1054 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1057 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1062 wxbUtils::MilliSleep(1000);
1063 SetStatus(finished);
1066 /* Apply configuration changes */
1068 /* 1: Level (not appropriate)
1073 * 6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1074 * 7: Priority (yes : "Enter new Priority: (positive integer)")
1076 * 9: Where (yes : "Please enter path prefix for restore (/ for none):")
1077 * 10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n
1078 * Select replace option (1-4):")
1082 void wxbRestorePanel::CmdConfigApply()
1084 if (cfgUpdated == 0) return;
1086 wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1088 EnableConfig(false);
1090 wxbDataTokenizer* dt = NULL;
1092 bool failed = false;
1094 while (cfgUpdated > 0) {
1099 wxString def; //String to send if can't use our data
1100 if ((cfgUpdated >> ConfigWhere) & 1) {
1101 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1102 wxbUtils::WaitForPrompt(wxT("9\n"));
1103 dt = new wxbDataTokenizer(true);
1104 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1106 cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1108 else if ((cfgUpdated >> ConfigReplace) & 1) {
1109 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1110 wxbUtils::WaitForPrompt(wxT("11\n"));
1111 dt = new wxbDataTokenizer(true);
1112 wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1114 cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1116 else if ((cfgUpdated >> ConfigWhen) & 1) {
1117 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1118 wxbUtils::WaitForPrompt(wxT("6\n"));
1119 dt = new wxbDataTokenizer(true);
1120 wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1122 cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1124 else if ((cfgUpdated >> ConfigPriority) & 1) {
1125 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1126 wxbUtils::WaitForPrompt(wxT("7\n"));
1127 dt = new wxbDataTokenizer(true);
1128 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1130 cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1132 else if ((cfgUpdated >> ConfigClient) & 1) {
1133 if (restorePanel->GetRowCount(_("Client")) > 1) {
1134 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1135 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1136 int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1137 if (client == wxNOT_FOUND) {
1138 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1143 dt = new wxbDataTokenizer(true);
1144 wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1146 cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1148 cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1152 else if ((cfgUpdated >> ConfigFileset) & 1) {
1153 if (restorePanel->GetRowCount(_("Fileset")) > 1) {
1154 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1155 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1156 int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1157 if (fileset == wxNOT_FOUND) {
1158 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1163 dt = new wxbDataTokenizer(true);
1164 wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1166 cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1168 cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1172 else if ((cfgUpdated >> ConfigStorage) & 1) {
1173 if (restorePanel->GetRowCount(_("Storage")) > 1) {
1174 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1175 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1176 int storage = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1177 if (storage == wxNOT_FOUND) {
1178 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1183 dt = new wxbDataTokenizer(true);
1184 wxbUtils::WaitForPrompt(wxString() << storage << wxT("\n"));
1186 cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1188 cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1198 for (i = 0; i < dt->GetCount(); i++) {
1199 if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1204 if (i != 0 && i == dt->GetCount()) {
1206 dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1210 UpdateSecondConfig(dt); /* TODO: Check result */
1213 restorePanel->EnableApply(false);
1216 wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1222 /* Cancel restore */
1223 void wxbRestorePanel::CmdConfigCancel() {
1224 wxbUtils::WaitForEnd(wxT("no\n"));
1225 wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1226 wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1227 SetStatus(finished);
1230 /* List jobs for a specified client and fileset */
1231 void wxbRestorePanel::CmdListJobs() {
1232 if (status == entered) {
1233 configPanel->ClearRowChoices(_("Before"));
1234 /*wxbUtils::WaitForPrompt("query\n");
1235 wxbUtils::WaitForPrompt("6\n");*/
1236 wxbTableParser* tableparser = new wxbTableParser(false);
1237 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1238 wxString(wxT(".backups client=\"")) + configPanel->GetRowString(_("Client")) +
1239 wxT("\" fileset=\"") + configPanel->GetRowString(_("Fileset")) + wxT("\"\n"), true);
1241 while (!tableparser->hasFinished()) {
1242 wxTheApp->Yield(true);
1243 wxbUtils::MilliSleep(100);
1246 if (!tableparser->GetCount() == 0) {
1247 for (unsigned int i = 0; i < dt->Count(); i++) {
1248 if ((*dt)[i].Find(_("No results to list.")) == 0) {
1249 configPanel->AddRowChoice(_("Before"),
1250 _("No backup found for this client."));
1251 configPanel->SetRowSelection(_("Before"), 0);
1252 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1257 else if (((*dt)[i].Find(_("ERROR")) > -1) ||
1258 ((*dt)[i].Find(_("Query failed")) > -1)) {
1259 configPanel->AddRowChoice(_("Before"),
1260 _("Cannot get previous backups list, see console."));
1261 configPanel->SetRowSelection(_("Before"), 0);
1262 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1272 wxDateTime lastdatetime = (time_t) 0;
1273 for (int i = tableparser->GetCount()-1; i > -1; i--) {
1274 wxString str = (*tableparser)[i][3];
1275 wxDateTime datetime;
1277 if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) && ! lastdatetime.IsEqualTo(datetime) ) {
1278 lastdatetime = datetime;
1279 datetime += wxTimeSpan::Seconds(1);
1280 configPanel->AddRowChoice(_("Before"),
1281 datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1287 configPanel->SetRowSelection(_("Before"), 0);
1288 configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1292 /* List files and directories for a specified tree item */
1293 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1294 if (status == choosing) {
1295 list->DeleteAllItems();
1300 UpdateTreeItem(item, true, false);
1302 if (list->GetItemCount() >= 1) {
1303 int firstwidth = list->GetSize().GetWidth();
1304 for (int i = 2; i < 7; i++) {
1305 list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1306 firstwidth -= list->GetColumnWidth(i);
1309 list->SetColumnWidth(0, 18);
1311 list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1312 if (list->GetColumnWidth(1) < firstwidth) {
1313 list->SetColumnWidth(1, firstwidth-25);
1319 /* Mark a treeitem (directory) or a listitem (file or directory) */
1320 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1321 if (status == choosing) {
1322 wxbTreeItemData** itemdata;
1323 int itemdatasize = 0;
1324 if (listsize == 0) {
1325 itemdata = new wxbTreeItemData*[1];
1329 itemdata = new wxbTreeItemData*[listsize];
1330 itemdatasize = listsize;
1333 if (listitems != NULL) {
1334 for (int i = 0; i < itemdatasize; i++) {
1335 itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1338 else if (treeitem.IsOk()) {
1339 itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1346 if (itemdata[0] == NULL) { //Should never happen
1351 wxString dir = itemdata[0]->GetPath();
1354 if (dir != wxT("/")) {
1355 if (IsPathSeparator(dir.GetChar(dir.Length()-1))) {
1359 int i = dir.Find('/', TRUE);
1364 else { /* first dir below root */
1365 file = dir.Mid(i+1);
1366 dir = dir.Mid(0, i+1);
1375 bool marked = false;
1376 bool unmarked = false;
1378 for (int i = 0; i < itemdatasize; i++) {
1379 switch(itemdata[i]->GetMarked()) {
1393 if (marked && unmarked)
1409 wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1410 wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1412 /* TODO: Check commands results */
1414 /*if ((dir == "/") && (file == "*")) {
1415 itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1418 if (listitems == NULL) { /* tree item state changed */
1419 SetTreeItemState(treeitem, state);
1420 /*treeitem = tree->GetSelection();
1421 UpdateTree(treeitem, true);
1422 treeitem = tree->GetItemParent(treeitem);*/
1425 for (int i = 0; i < itemdatasize; i++) {
1426 SetListItemState(listitems[i], state);
1428 listadd->Enable(state == 0);
1429 listremove->Enable(state == 1);
1430 /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1431 treeitem = tree->GetItemParent(treeitem);*/
1434 /*while (treeitem.IsOk()) {
1435 WaitForList(treeitem, false);
1436 treeitem = tree->GetItemParent(treeitem);
1443 /*----------------------------------------------------------------------------
1445 ----------------------------------------------------------------------------*/
1447 /* Run a dir command, and waits until result is fully received. */
1448 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse)
1450 // this->updatelist = updatelist;
1451 wxbDataTokenizer* dt;
1453 dt = wxbUtils::WaitForEnd(wxString(wxT("cd \"")) <<
1454 static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1455 ->GetPath() << wxT("\"\n"), false);
1457 /* TODO: check command result */
1464 list->DeleteAllItems();
1465 dt = wxbUtils::WaitForEnd(wxT(".dir\n"), true);
1469 for (unsigned int i = 0; i < dt->GetCount(); i++) {
1472 if (str.Find(wxT("cwd is:")) == 0) { // Sometimes cd command result "infiltrate" into listings.
1480 if (!ParseList(str, &entry))
1483 wxTreeItemId treeid;
1485 if (IsPathSeparator(entry.fullname.GetChar(entry.fullname.Length()-1))) {
1488 #if wxCHECK_VERSION(2, 6, 0)
1489 wxTreeItemIdValue cookie;
1494 treeid = tree->GetFirstChild(item, cookie);
1496 bool updated = false;
1498 while (treeid.IsOk()) {
1499 itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1500 if (entry.filename == itemStr) {
1501 if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != entry.marked) {
1502 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Normal);
1503 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Selected);
1504 static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(entry.marked);
1506 if ((recurse) && (tree->IsExpanded(treeid))) {
1507 UpdateTreeItem(treeid, false, true);
1512 treeid = tree->GetNextChild(item, cookie);
1516 treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(entry.filename), entry.marked, entry.marked, new wxbTreeItemData(entry.fullname, entry.filename, entry.marked));
1521 long ind = list->InsertItem(list->GetItemCount(), entry.marked);
1522 wxbTreeItemData* data = new wxbTreeItemData(entry.fullname, entry.filename, entry.marked, ind);
1523 data->SetId(treeid);
1524 list->SetItemData(ind, (long)data);
1525 list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(entry.filename));
1526 list->SetItem(ind, 2, entry.size);
1527 list->SetItem(ind, 3, entry.date);
1528 list->SetItem(ind, 4, entry.perm);
1529 list->SetItem(ind, 5, entry.user);
1530 list->SetItem(ind, 6, entry.group);
1540 /* Parse .dir command results, returns true if the result has been stored in entry, false otherwise. */
1541 int wxbRestorePanel::ParseList(wxString line, wxbDirEntry* entry)
1543 /* See ls_output in dird/ua_tree.c */
1544 //-rw-r-----,1,root,root,41575,2005-10-18 18:21:36, ,/usr/var/bacula/working/bacula.sql
1546 wxStringTokenizer tkz(line, wxT(","));
1548 if (!tkz.HasMoreTokens())
1550 entry->perm = tkz.GetNextToken();
1552 if (!tkz.HasMoreTokens())
1554 entry->nlink = tkz.GetNextToken();
1556 if (!tkz.HasMoreTokens())
1558 entry->user = tkz.GetNextToken();
1560 if (!tkz.HasMoreTokens())
1562 entry->group = tkz.GetNextToken();
1564 if (!tkz.HasMoreTokens())
1566 entry->size = tkz.GetNextToken();
1568 if (!tkz.HasMoreTokens())
1570 entry->date = tkz.GetNextToken();
1572 if (!tkz.HasMoreTokens())
1574 wxString marked = tkz.GetNextToken();
1575 if (marked == wxT("*")) {
1578 else if (marked == wxT("+")) {
1585 if (!tkz.HasMoreTokens())
1587 entry->fullname = tkz.GetString();
1589 /* Get only the filename (cut path by finding the last '/') */
1590 if (IsPathSeparator(entry->fullname.GetChar(entry->fullname.Length()-1))) {
1591 wxString tmp = entry->fullname;
1593 entry->filename = entry->fullname.Mid(tmp.Find('/', true)+1);
1596 entry->filename = entry->fullname.Mid(entry->fullname.Find('/', true)+1);
1602 /* Sets a list item state, and update its parents and children if it is a directory */
1603 void wxbRestorePanel::SetListItemState(long listitem, int newstate)
1605 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1607 wxTreeItemId treeitem;
1609 itemdata->SetMarked(newstate);
1610 list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1611 list->SetItemImage(listitem, newstate, 1);
1613 if ((treeitem = itemdata->GetId()).IsOk()) {
1614 SetTreeItemState(treeitem, newstate);
1617 UpdateTreeItemState(tree->GetSelection());
1621 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1622 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1623 #if wxCHECK_VERSION(2, 6, 0)
1624 wxTreeItemIdValue cookie;
1628 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1630 wxbTreeItemData* itemdata;
1632 while (currentChild.IsOk()) {
1633 itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1634 int state = itemdata->GetMarked();
1636 if (state != newstate) {
1637 itemdata->SetMarked(newstate);
1638 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1639 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1642 currentChild = tree->GetNextChild(item, cookie);
1645 itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1646 itemdata->SetMarked(newstate);
1647 tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1648 tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1651 if (tree->GetSelection() == item) {
1652 for (long i = 0; i < list->GetItemCount(); i++) {
1653 list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1654 list->SetItemImage(i, newstate, 1);
1658 UpdateTreeItemState(tree->GetItemParent(item));
1661 /* Update a tree item state, and its parents' state */
1662 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {
1669 #if wxCHECK_VERSION(2, 6, 0)
1670 wxTreeItemIdValue cookie;
1674 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1676 bool onechildmarked = false;
1677 bool onechildunmarked = false;
1679 while (currentChild.IsOk()) {
1680 state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1683 onechildunmarked = true;
1686 onechildmarked = true;
1689 onechildmarked = true;
1690 onechildunmarked = true;
1694 if (onechildmarked && onechildunmarked) {
1698 currentChild = tree->GetNextChild(item, cookie);
1701 if (tree->GetSelection() == item) {
1702 for (long i = 0; i < list->GetItemCount(); i++) {
1703 state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1707 onechildunmarked = true;
1710 onechildmarked = true;
1713 onechildmarked = true;
1714 onechildunmarked = true;
1718 if (onechildmarked && onechildunmarked) {
1726 if (onechildmarked && onechildunmarked) {
1729 else if (onechildmarked) {
1732 else if (onechildunmarked) {
1735 else { // no child, don't change anything
1736 UpdateTreeItemState(tree->GetItemParent(item));
1740 wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1742 itemdata->SetMarked(state);
1743 tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1744 tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1746 UpdateTreeItemState(tree->GetItemParent(item));
1749 /* Refresh the whole tree. */
1750 void wxbRestorePanel::RefreshTree() {
1751 /* Save current selection */
1752 wxArrayString current;
1754 wxTreeItemId item = currentTreeItem;
1756 while ((item.IsOk()) && (item != tree->GetRootItem())) {
1757 current.Add(tree->GetItemText(item));
1758 item = tree->GetItemParent(item);
1761 /* Update the tree */
1762 UpdateTreeItem(tree->GetRootItem(), false, true);
1764 /* Reselect the former selected item */
1765 item = tree->GetRootItem();
1767 if (current.Count() == 0) {
1768 tree->SelectItem(item);
1774 for (int i = current.Count()-1; i >= 0; i--) {
1775 #if wxCHECK_VERSION(2, 6, 0)
1776 wxTreeItemIdValue cookie;
1780 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1784 while (currentChild.IsOk()) {
1785 if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1786 item = currentChild;
1791 currentChild = tree->GetNextChild(item, cookie);
1797 UpdateTreeItem(item, true, false); /* Update the list */
1799 tree->SelectItem(item);
1802 void wxbRestorePanel::RefreshList() {
1803 if (currentTreeItem.IsOk()) {
1804 UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1808 /* Update first config, adapting settings to the job name selected */
1809 void wxbRestorePanel::UpdateFirstConfig() {
1810 configPanel->Enable(false);
1811 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(wxT(".defaults job=")) + configPanel->GetRowString(_("Job Name")) + wxT("\n"), true, false);
1817 * where=/tmp/bacula-restores
1827 bool dolistjobs = false;
1829 for (i = 0; i < dt->GetCount(); i++) {
1831 if ((j = str.Find('=')) > -1) {
1832 name = str.Mid(0, j);
1833 if (name == wxT("pool")) {
1834 configPanel->SetRowString(_("Pool"), str.Mid(j+1));
1836 else if (name == wxT("client")) {
1838 if ((str != configPanel->GetRowString(_("Client"))) ||
1839 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1840 configPanel->SetRowString(_("Client"), str);
1844 else if (name == wxT("storage")) {
1845 configPanel->SetRowString(_("Storage"), str.Mid(j+1));
1847 else if (name == wxT("fileset")) {
1849 if ((str != configPanel->GetRowString(_("Fileset"))) ||
1850 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1851 configPanel->SetRowString(_("Fileset"), str);
1861 //wxTheApp->Yield(false);
1864 configPanel->Enable(true);
1868 * Update second config.
1871 * JobName: RestoreFiles
1872 * Bootstrap: /var/lib/bacula/restore.bsr
1873 * Where: /tmp/bacula-restores
1878 * When: 2004-04-18 01:18:56
1880 * OK to run? (yes/mod/no):
1883 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1885 for (i = 0; i < dt->GetCount(); i++) {
1886 if ((*dt)[i].Find(_("Run Restore job")) == 0)
1890 if ((i + 10) > dt->GetCount()) {
1896 if ((k = (*dt)[++i].Find(_("JobName:"))) != 0) return false;
1897 restorePanel->SetRowString(_("Job Name"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1898 if ((k = (*dt)[++i].Find(_("Bootstrap:"))) != 0) return false;
1899 restorePanel->SetRowString(_("Bootstrap"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1900 if ((k = (*dt)[++i].Find(_("Where:"))) != 0) return false;
1901 restorePanel->SetRowString(_("Where"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1903 if ((k = (*dt)[++i].Find(_("Replace:"))) != 0) return false;
1904 wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1905 if (str == _("always")) restorePanel->SetRowSelection(_("Replace"), 0);
1906 else if (str == _("ifnewer")) restorePanel->SetRowSelection(_("Replace"), 1);
1907 else if (str == _("ifolder")) restorePanel->SetRowSelection(_("Replace"), 2);
1908 else if (str == _("never")) restorePanel->SetRowSelection(_("Replace"), 3);
1909 else restorePanel->SetRowSelection(_("Replace"), 0);
1911 if ((k = (*dt)[++i].Find(_("FileSet:"))) != 0) return false;
1912 restorePanel->SetRowString(_("Fileset"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1913 if ((k = (*dt)[++i].Find(_("Client:"))) != 0) return false;
1914 restorePanel->SetRowString(_("Client"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1915 if ((k = (*dt)[++i].Find(_("Storage:"))) != 0) return false;
1916 restorePanel->SetRowString(_("Storage"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1917 if ((k = (*dt)[++i].Find(_("When:"))) != 0) return false;
1918 restorePanel->SetRowString(_("When"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1919 i++; /* Skip catalog field */
1920 if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1921 restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1924 restorePanel->Layout();
1929 /*----------------------------------------------------------------------------
1931 ----------------------------------------------------------------------------*/
1933 /* Set current status by enabling/disabling components */
1934 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1935 switch (newstatus) {
1937 centerSizer->Remove(configPanel);
1938 centerSizer->Remove(restorePanel);
1939 centerSizer->Remove(treelistPanel);
1940 treelistPanel->Show(false);
1941 restorePanel->Show(false);
1942 centerSizer->Add(configPanel, 1, wxEXPAND);
1943 configPanel->Show(true);
1944 configPanel->Layout();
1945 centerSizer->Layout();
1947 start->SetLabel(_("Enter restore mode"));
1948 start->Enable(false);
1949 configPanel->Enable(false);
1950 tree->Enable(false);
1951 list->Enable(false);
1952 gauge->Enable(false);
1953 cancel->Enable(false);
1958 centerSizer->Remove(configPanel);
1959 centerSizer->Remove(restorePanel);
1960 centerSizer->Remove(treelistPanel);
1961 treelistPanel->Show(false);
1962 restorePanel->Show(false);
1963 centerSizer->Add(configPanel, 1, wxEXPAND);
1964 configPanel->Show(true);
1965 configPanel->Layout();
1966 centerSizer->Layout();
1968 tree->DeleteAllItems();
1969 list->DeleteAllItems();
1970 configPanel->ClearRowChoices(_("Client"));
1971 configPanel->ClearRowChoices(_("Before"));
1972 wxbMainFrame::GetInstance()->EnablePanels();
1973 newstatus = activable;
1976 start->SetLabel(_("Enter restore mode"));
1977 start->Enable(true);
1978 configPanel->Enable(false);
1979 tree->Enable(false);
1980 list->Enable(false);
1981 gauge->Enable(false);
1982 cancel->Enable(false);
1986 wxbMainFrame::GetInstance()->DisablePanels(this);
1988 start->Enable(false);
1989 //start->SetLabel(_("Choose files to restore"));
1990 configPanel->Enable(true);
1991 tree->Enable(false);
1992 list->Enable(false);
1993 cancel->Enable(true);
1999 start->Enable(true);
2000 start->SetLabel(_("Restore"));
2001 centerSizer->Remove(configPanel);
2002 configPanel->Show(false);
2003 centerSizer->Add(treelistPanel, 1, wxEXPAND);
2004 treelistPanel->Show(true);
2005 treelistPanel->Layout();
2006 centerSizer->Layout();
2013 start->Enable(false);
2014 configPanel->Enable(false);
2015 tree->Enable(false);
2016 list->Enable(false);
2017 centerSizer->Remove(treelistPanel);
2018 treelistPanel->Show(false);
2019 centerSizer->Add(restorePanel, 1, wxEXPAND);
2020 restorePanel->Show(true);
2021 restorePanel->Layout();
2022 centerSizer->Layout();
2024 restorePanel->EnableApply(false);
2025 cancel->Enable(true);
2028 start->SetLabel(_("Restoring..."));
2029 gauge->Enable(true);
2031 start->Enable(false);
2032 configPanel->Enable(false);
2033 tree->Enable(false);
2034 list->Enable(false);
2041 /*----------------------------------------------------------------------------
2043 ----------------------------------------------------------------------------*/
2045 void wxbRestorePanel::SetWorking(bool working) {
2046 this->working = working;
2048 SetCursor(*wxHOURGLASS_CURSOR);
2049 // SetEvtHandlerEnabled(false); //EVTQUEUE
2051 // else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
2053 // processing = true; //EVTQUEUE
2054 SetCursor(*wxSTANDARD_CURSOR);
2055 // SetEvtHandlerEnabled(true); //EVTQUEUE
2056 /* wxNode *node = pendingEvents->First(); //EVTQUEUE
2058 wxEvent *event = (wxEvent *)node->Data();
2061 wxEvtHandler::ProcessEvent(*event);
2064 node = pendingEvents->First();
2066 processing = false;*/
2070 bool wxbRestorePanel::IsWorking() {
2071 return this->working;
2074 void wxbRestorePanel::EnableConfig(bool enable) {
2075 restorePanel->Enable(enable);
2078 /*----------------------------------------------------------------------------
2080 ----------------------------------------------------------------------------*/
2085 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2086 if (IsWorking() || processing) {
2087 wxEvent *eventCopy = event.Clone();
2089 pendingEvents->Append(eventCopy);
2093 return wxEvtHandler::ProcessEvent(event);
2098 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2099 cancel->Enable(false);
2100 SetCursor(*wxHOURGLASS_CURSOR);
2102 SetCursor(*wxSTANDARD_CURSOR);
2105 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2114 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2120 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2126 //CmdList(event.GetItem());
2127 if (tree->GetSelection() != event.GetItem()) {
2128 tree->SelectItem(event.GetItem());
2133 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2137 if (currentTreeItem == event.GetItem()) {
2140 treeadd->Enable(false);
2141 treeremove->Enable(false);
2142 treerefresh->Enable(false);
2143 markWhenCommandDone = false;
2145 currentTreeItem = event.GetItem();
2146 CmdList(event.GetItem());
2147 if (markWhenCommandDone) {
2148 CmdMark(event.GetItem(), NULL, 0);
2152 if (event.GetItem().IsOk()) {
2153 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2154 treeadd->Enable(status != 1);
2155 treeremove->Enable(status != 0);
2157 treerefresh->Enable(true);
2160 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2162 if (tree->GetSelection() == event.GetItem()) {
2163 markWhenCommandDone = !markWhenCommandDone;
2168 markWhenCommandDone = false;
2169 CmdMark(event.GetItem(), NULL, 0);
2170 if (markWhenCommandDone) {
2171 CmdMark(event.GetItem(), NULL, 0);
2176 if (event.GetItem().IsOk()) {
2177 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2178 treeadd->Enable(status != 1);
2179 treeremove->Enable(status != 0);
2183 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2188 if (currentTreeItem.IsOk()) {
2190 CmdMark(currentTreeItem, NULL, 0, 1);
2193 treeremove->Enable(1);
2198 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2203 if (currentTreeItem.IsOk()) {
2205 CmdMark(currentTreeItem, NULL, 0, 0);
2208 treeremove->Enable(0);
2213 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2223 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2228 if (list->GetSelectedItemCount() == 0) {
2234 long* items = new long[list->GetSelectedItemCount()];
2238 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2239 while (item != -1) {
2242 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2245 CmdMark(wxTreeItemId(), items, num);
2249 wxListEvent listevt;
2251 OnListChanged(listevt);
2258 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2263 long item = event.GetIndex();
2264 // long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2266 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2267 wxString name = itemdata->GetName();
2272 #if wxCHECK_VERSION(2, 6, 0)
2273 wxTreeItemIdValue cookie;
2278 if (IsPathSeparator(name.GetChar(name.Length()-1))) {
2279 wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2281 while (currentChild.IsOk()) {
2282 wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2283 if (name2 == name) {
2284 //tree->UnselectAll();
2286 tree->Expand(currentTreeItem);
2287 tree->SelectItem(currentChild);
2291 currentChild = tree->GetNextChild(currentTreeItem, cookie);
2298 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2303 listadd->Enable(false);
2304 listremove->Enable(false);
2306 bool marked = false;
2307 bool unmarked = false;
2309 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2310 while (item != -1) {
2311 switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2324 // Should never happen
2326 if (marked && unmarked) break;
2327 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2330 listadd->Enable(unmarked);
2331 listremove->Enable(marked);
2334 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2341 long* items = new long[list->GetSelectedItemCount()];
2345 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2346 while (item != -1) {
2349 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2352 CmdMark(wxTreeItemId(), items, num, 1);
2359 listadd->Enable(false);
2360 listremove->Enable(true);
2363 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2370 long* items = new long[list->GetSelectedItemCount()];
2374 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2375 while (item != -1) {
2378 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2381 CmdMark(wxTreeItemId(), items, num, 0);
2388 listadd->Enable(true);
2389 listremove->Enable(false);
2392 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event)
2403 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event)
2405 if (status == entered) {
2406 if (event.GetId() == ConfigJobName) {
2411 UpdateFirstConfig();
2414 else if ((event.GetId() == ConfigClient) || (event.GetId() == ConfigFileset)) {
2419 configPanel->Enable(false);
2421 configPanel->Enable(true);
2424 cfgUpdated = cfgUpdated | (1 << event.GetId());
2426 else if (status == configuring) {
2427 restorePanel->EnableApply(true);
2428 cfgUpdated = cfgUpdated | (1 << event.GetId());
2432 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2433 if (status != configuring) return;
2442 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2443 if (status != configuring) return;
2449 if (cfgUpdated == 0) {
2450 restorePanel->EnableApply(false);
2455 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2456 if (status != configuring) return;