From 9b230ebd0d0597b7e8900ad904a81e1da704da2e Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Sat, 24 Apr 2004 20:09:58 +0000 Subject: [PATCH] - wxbMainFrame : the user is now prompted when an unexpected "question" is asked). - wxbRestorePanel : configure is allowed to change fileset - wxbRestorePanel : using dot commands (.clients, .filesets) - console_thread : implemented prompt and heartbeat messages git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1293 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/wx-console/CHANGELOG | 11 ++ bacula/src/wx-console/TODO | 37 +++-- bacula/src/wx-console/wxbmainframe.cpp | 130 +++++++++------ bacula/src/wx-console/wxbmainframe.h | 4 + bacula/src/wx-console/wxbrestorepanel.cpp | 188 ++++++++++++++-------- bacula/src/wx-console/wxbrestorepanel.h | 9 +- bacula/src/wx-console/wxbtableparser.cpp | 12 +- bacula/src/wx-console/wxbtableparser.h | 5 +- bacula/src/wx-console/wxbutils.cpp | 177 +++++++++++++++++++- bacula/src/wx-console/wxbutils.h | 75 ++++++++- 10 files changed, 498 insertions(+), 150 deletions(-) diff --git a/bacula/src/wx-console/CHANGELOG b/bacula/src/wx-console/CHANGELOG index 02b7fadb56..d787d7ba17 100644 --- a/bacula/src/wx-console/CHANGELOG +++ b/bacula/src/wx-console/CHANGELOG @@ -1,3 +1,14 @@ +24-04-2003 : + - wxbMainFrame : the user is now prompted when an + unexpected "question" is asked). + - wxbRestorePanel : configure is allowed to change fileset + - wxbRestorePanel : using dot commands (.clients, .filesets) + - console_thread : implemented prompt and heartbeat messages + +23-04-2003 : + - general : Don't concatenate lines in csprint, but in wxbDataParser + (necessary for dot commands) + 22-04-2003 : - wxbRestorePanel : improved restore appearance - wxbRestorePanel : configure is allowed to change client diff --git a/bacula/src/wx-console/TODO b/bacula/src/wx-console/TODO index 9dd021a762..87e4c5a455 100644 --- a/bacula/src/wx-console/TODO +++ b/bacula/src/wx-console/TODO @@ -7,37 +7,48 @@ console_thread : Show a nice message when config file is not found. wxbRestorePanel : Add buttons to mark/unmark directories/files. -wxbRestorePanel : Add a button to force the refreshing of the whole tree +wxbRestorePanel : Add a button to force to refresh the whole tree wxbRestorePanel : Add a timeout when waiting for commands results -wxbRestorePanel : Check more carefully which job we just have run. +wxbMainFrame : Automatically scroll to the last lines of console control. -wxbRestorePanel : Check if commands run successfully (cd, mark, mods...). +wxbRestorePanel : Check if commands ran successfully (cd, mark, mods...). GTK : Improve look -general : Don't concatenate lines in csprint, but in wxbDataTokenizer - (necessary for dot commands) - -general : use dot commands +wxbRestorePanel : Use ".default job=RestoreFiles" to get defaults parameters + when changing a restore parameter fails. -wxbRestorePanel : Allow configure to change fileset (need dot) +console_thread : Allow the user to choose his config file. -general : Allow the user to be prompted when an unexpected "question" - is asked ("prompt" data message). +wxbRestorePanel : Implement BNET_BREAK to break current command -console_thread : Allow the user to choose his config file. +general : Implement reconnecting + +general : Allow the user to quit however the state is (kill thread if necessary) + +wxbDataParser : Add a boolean in the constructor to avoid storing data is + will not be used. wxblistctrl/wxbtreectrl : Find why events are not forwarded correctly to parent' parent, and correct bad actual implementation. (remove wxbTreeListPanel) - -general : make a good documentation with snapshots + +general : find out why I had to modify string.cpp and string.h + + In include/wx/string.h, replace line 195 by + #if defined(__VISUALC__) // && defined(_MT) && !defined(_DLL) + + In src/common/string.cpp, replace line 167 by + #if defined(__VISUALC__) // && defined(_MT) && !defined(_DLL) mingw : correct findlib stat blocks and block size (Note : nothing to do with wx-console) +wxbRestorePanel : Check more carefully which job we just have run + (needs director modification). + +general : make a good documentation with snapshots + BUGS ---- diff --git a/bacula/src/wx-console/wxbmainframe.cpp b/bacula/src/wx-console/wxbmainframe.cpp index c82dc8fb2b..f2fda1542d 100644 --- a/bacula/src/wx-console/wxbmainframe.cpp +++ b/bacula/src/wx-console/wxbmainframe.cpp @@ -255,6 +255,8 @@ wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSi sizer->SetSizeHints( this ); this->SetSize(size); EnableConsole(false); + + nlines = 0; } /* @@ -265,6 +267,9 @@ void wxbMainFrame::StartConsoleThread() if (ct != NULL) { ct->Delete(); } + else { + promptparser = new wxbPromptParser(); + } ct = new console_thread(); ct->Create(); ct->Run(); @@ -332,20 +337,83 @@ void wxbMainFrame::Print(wxString str, int status) } // CS_DEBUG is often sent by panels, - // and resend it to them would sometimes cause an infinite loop + // and resend it to them would sometimes cause infinite loops + + /* One promptcaught is normal, so we must have two true Print values to be + * sure that the prompt has effectively been caught. + */ + int promptcaught = -1; + if (status != CS_DEBUG) { for (unsigned int i = 0; i < parsers.GetCount(); i++) { - parsers[i]->Print(str, status); - } + promptcaught += parsers[i]->Print(str, status) ? 1 : 0; + } + + if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) { + Print("Unexpected question has been received.\n", CS_DEBUG); +// Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG); + + wxString message; + if (promptparser->getIntroString() != "") { + message << promptparser->getIntroString() << "\n"; + } + message << promptparser->getQuestionString(); + + if (promptparser->getChoices()) { + wxString *choices = new wxString[promptparser->getChoices()->GetCount()]; + int *numbers = new int[promptparser->getChoices()->GetCount()]; + int n = 0; + + for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) { + if ((*promptparser->getChoices())[i] != "") { + choices[n] = (*promptparser->getChoices())[i]; + numbers[n] = i; + n++; + } + } + + int res = ::wxGetSingleChoiceIndex(message, + "wx-console: unexpected director's question.", n, choices, this); + if (res == -1) { + Send("\n"); + } + else { + Send(wxString() << numbers[res] << "\n"); + } + } + else { + Send(::wxGetTextFromUser(message, + "wx-console: unexpected director's question.", "", this) + "\n"); + } + } } - + if (status == CS_END) { str = "#"; } - consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK)); + if (status == CS_DEBUG) { + consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0))); + } + else { + consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK)); + } (*consoleCtrl) << str; - consoleCtrl->SetInsertionPointEnd(); + if (status == CS_PROMPT) { + (*consoleCtrl) << "

"; + } + /*if (status != CS_DEBUG) { + (*consoleCtrl) << "@"; + }*/ + //consoleCtrl->SetInsertionPointEnd(); + +/* if ((consoleCtrl->GetNumberOfLines()-1) > nlines) { + nlines = consoleCtrl->GetNumberOfLines()-1; + } + + if (status == CS_END) { + consoleCtrl->ShowPosition(nlines); + }*/ } /* @@ -357,6 +425,12 @@ void wxbMainFrame::Send(wxString str) typeCtrl->SetValue(""); consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED)); (*consoleCtrl) << str; + +/* if ((consoleCtrl->GetNumberOfLines()-1) > nlines) { + nlines = consoleCtrl->GetNumberOfLines()-1; + } + + consoleCtrl->ShowPosition(nlines);*/ } /* Enable panels */ @@ -405,7 +479,7 @@ void firePrintEvent(wxString str, int status) wxbMainFrame::GetInstance()->AddPendingEvent(evt); } -wxString csBuffer; /* Temporary buffer for receiving data from console thread */ +//wxString csBuffer; /* Temporary buffer for receiving data from console thread */ /* * Called by console thread, this function forwards data line by line and end @@ -414,47 +488,9 @@ wxString csBuffer; /* Temporary buffer for receiving data from console thread */ void csprint(char* str, int status) { if (str != 0) { - int len = strlen(str); - bool allnewline = true; - for (int i = 0; i < len; i++) { - if (!(allnewline = (str[i] == '\n'))) - break; - } - - if (allnewline) { - firePrintEvent(csBuffer << "\n", CS_DATA); - csBuffer = ""; - for (int i = 1; i < len; i++) { - firePrintEvent("\n", status); - } - } - else { - wxStringTokenizer tkz(str, "\n", - wxTOKEN_RET_DELIMS | wxTOKEN_RET_EMPTY | wxTOKEN_RET_EMPTY_ALL); - - while ( tkz.HasMoreTokens() ) { - csBuffer << tkz.GetNextToken(); - if (csBuffer.Length() != 0) { - if ((csBuffer.GetChar(csBuffer.Length()-1) == '\n') || - (csBuffer.GetChar(csBuffer.Length()-1) == '\r')) { - firePrintEvent(csBuffer, status); - csBuffer = ""; - } - } - } - } - - if (csBuffer == "$ ") { // Restore console - firePrintEvent(csBuffer, status); - csBuffer = ""; - } + firePrintEvent(wxString(str), status); } - - if (status != CS_DATA) { - if (csBuffer.Length() != 0) { - firePrintEvent(csBuffer, CS_DATA); - } - csBuffer = ""; + else { firePrintEvent("", status); } } diff --git a/bacula/src/wx-console/wxbmainframe.h b/bacula/src/wx-console/wxbmainframe.h index a8777f6488..9b6c068699 100644 --- a/bacula/src/wx-console/wxbmainframe.h +++ b/bacula/src/wx-console/wxbmainframe.h @@ -137,7 +137,11 @@ private: console_thread* ct; /* thread interacting with the director */ + wxbPromptParser* promptparser; /* prompt parser catching uncatched questions */ + static wxbMainFrame *frame; /* this */ + + int nlines; /* number of lines in the console */ // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() diff --git a/bacula/src/wx-console/wxbrestorepanel.cpp b/bacula/src/wx-console/wxbrestorepanel.cpp index a7eaf9aac6..2b209a47d6 100644 --- a/bacula/src/wx-console/wxbrestorepanel.cpp +++ b/bacula/src/wx-console/wxbrestorepanel.cpp @@ -172,7 +172,8 @@ enum ConfigReplace = 9, ConfigWhen = 10, ConfigPriority = 11, - ConfigClient = 12 + ConfigClient = 12, + ConfigFileset = 13 }; BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel) @@ -192,6 +193,7 @@ BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel) EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated) EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated) EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated) + EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated) EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk) EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply) @@ -292,7 +294,7 @@ wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) { cfgWhere = new wxTextCtrl(restorePanel, ConfigWhere, "", wxDefaultPosition, wxDefaultSize); wxString erlist[] = {"always", "if newer", "if older", "never"}; cfgReplace = new wxChoice(restorePanel, ConfigReplace, wxDefaultPosition, wxDefaultSize, 4, erlist); - cfgFileset = new wxStaticText(restorePanel, -1, " ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + cfgFileset = new wxChoice(restorePanel, ConfigFileset, wxDefaultPosition, wxDefaultSize, 0, elist); cfgClient = new wxChoice(restorePanel, ConfigClient, wxDefaultPosition, wxDefaultSize, 0, elist); cfgStorage = new wxStaticText(restorePanel, -1, " ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); cfgWhen = new wxTextCtrl(restorePanel, ConfigWhen, "0000-00-00 00:00:00", wxDefaultPosition, wxDefaultSize); @@ -307,7 +309,7 @@ wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) { cfgSizer->Add(new wxStaticText(restorePanel, -1, "Replace: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL); cfgSizer->Add(cfgReplace, 1, wxEXPAND); cfgSizer->Add(new wxStaticText(restorePanel, -1, "Fileset: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL); - cfgSizer->Add(cfgFileset, 1, wxEXPAND | wxADJUST_MINSIZE); + cfgSizer->Add(cfgFileset, 1, wxEXPAND); cfgSizer->Add(new wxStaticText(restorePanel, -1, "Client: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL); cfgSizer->Add(cfgClient, 1, wxEXPAND); cfgSizer->Add(new wxStaticText(restorePanel, -1, "Storage: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL); @@ -397,17 +399,30 @@ void wxbRestorePanel::EnablePanel(bool enable) { /* The main button has been clicked */ void wxbRestorePanel::CmdStart() { if (status == activable) { - wxbTableParser* tableparser = CreateAndWaitForParser("list clients\n"); + wxbDataTokenizer* dt = WaitForEnd(".clients\n", true, false); + wxString str; clientChoice->Clear(); - for (unsigned int i = 0; i < tableparser->size(); i++) { - long* j = new long; - (*tableparser)[i][0].ToLong(j); - clientChoice->Append((*tableparser)[i][1], (void*)j); - cfgClient->Append((*tableparser)[i][1]); + cfgClient->Clear(); + for (unsigned int i = 0; i < dt->GetCount(); i++) { + str = (*dt)[i]; + str.RemoveLast(); + clientChoice->Append(str); + cfgClient->Append(str); } - delete tableparser; + delete dt; + + dt = WaitForEnd(".filesets\n", true, false); + + cfgFileset->Clear(); + for (unsigned int i = 0; i < dt->GetCount(); i++) { + str = (*dt)[i]; + str.RemoveLast(); + cfgFileset->Append(str); + } + + delete dt; SetStatus(entered); } @@ -416,10 +431,16 @@ void wxbRestorePanel::CmdStart() { wxbMainFrame::GetInstance()->SetStatusText("Please select a client."); return; } - WaitForEnd("restore\n"); - WaitForEnd("6\n"); - WaitForEnd(wxString() << jobChoice->GetStringSelection() << "\n"); - WaitForEnd(wxString() << *((long*)clientChoice->GetClientData(clientChoice->GetSelection())) << "\n"); + WaitForPrompt("restore\n"); + WaitForPrompt("6\n"); + wxbPromptParser *pp = WaitForPrompt(wxString() << jobChoice->GetStringSelection() << "\n", true); + int client = pp->getChoices()->Index(clientChoice->GetStringSelection()); + if (client == wxNOT_FOUND) { + wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client."); + return; + } + delete pp; + WaitForEnd(wxString() << client << "\n"); WaitForEnd("unmark *\n"); SetStatus(choosing); wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0)); @@ -437,25 +458,11 @@ void wxbRestorePanel::CmdStart() { totfilemessages = 0; wxbDataTokenizer* dt; - - /*dt = WaitForEnd("estimate\n", true); - - int j, k; - - for (unsigned int i = 0; i < dt->GetCount(); i++) {*/ - /* 15847 total files; 1 marked to be restored; 1,034 bytes. */ -/* if ((j = (*dt)[i].Find(" marked to be restored;")) > -1) { - k = (*dt)[i].Find("; "); - (*dt)[i].Mid(k+2, j).ToLong(&totfilemessages); - break; - } - } - - delete dt;*/ - + int j; - dt = WaitForEnd("done\n", true); + dt = new wxbDataTokenizer(true); + WaitForPrompt("done\n"); for (unsigned int i = 0; i < dt->GetCount(); i++) { if ((j = (*dt)[i].Find(" files selected to be restored.")) > -1) { @@ -577,8 +584,8 @@ void wxbRestorePanel::CmdStart() { /* 1: Level (not appropriate) * 2: Storage (automatic ?) * 3: Job (no) - * 4: FileSet (no) - * 5: Client (no) + * 4: FileSet (yes) + * 5: Client (yes) * 6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):") * 7: Priority (yes : "Enter new Priority: (positive integer)") * 8: Bootstrap (?) @@ -594,56 +601,69 @@ void wxbRestorePanel::CmdConfigApply() { EnableConfig(false); wxbDataTokenizer* dt = NULL; + while (cfgUpdated > 0) { wxString def; //String to send if can't use our data if ((cfgUpdated >> ConfigWhere) & 1) { - WaitForEnd("mod\n"); /* TODO: check results */ - WaitForEnd("9\n"); - dt = WaitForEnd(cfgWhere->GetValue() + "\n", true); + WaitForPrompt("mod\n"); /* TODO: check results */ + WaitForPrompt("9\n"); + dt = new wxbDataTokenizer(true); + WaitForPrompt(cfgWhere->GetValue() + "\n"); def = "/tmp"; cfgUpdated = cfgUpdated & (~(1 << ConfigWhere)); } else if ((cfgUpdated >> ConfigReplace) & 1) { - WaitForEnd("mod\n"); /* TODO: check results */ - WaitForEnd("10\n"); - dt = WaitForEnd(wxString() << (cfgReplace->GetSelection()+1) << "\n", true); + WaitForPrompt("mod\n"); /* TODO: check results */ + WaitForPrompt("10\n"); + dt = new wxbDataTokenizer(true); + WaitForPrompt(wxString() << (cfgReplace->GetSelection()+1) << "\n"); def = "1"; cfgUpdated = cfgUpdated & (~(1 << ConfigReplace)); } else if ((cfgUpdated >> ConfigWhen) & 1) { - WaitForEnd("mod\n"); /* TODO: check results */ - WaitForEnd("6\n"); - dt = WaitForEnd(cfgWhen->GetValue() + "\n", true); + WaitForPrompt("mod\n"); /* TODO: check results */ + WaitForPrompt("6\n"); + dt = new wxbDataTokenizer(true); + WaitForPrompt(cfgWhen->GetValue() + "\n"); def = ""; cfgUpdated = cfgUpdated & (~(1 << ConfigWhen)); } else if ((cfgUpdated >> ConfigPriority) & 1) { - WaitForEnd("mod\n"); /* TODO: check results */ - WaitForEnd("7\n"); - dt = WaitForEnd(cfgPriority->GetValue() + "\n", true); + WaitForPrompt("mod\n"); /* TODO: check results */ + WaitForPrompt("7\n"); + dt = new wxbDataTokenizer(true); + WaitForPrompt(cfgPriority->GetValue() + "\n"); def = "10"; cfgUpdated = cfgUpdated & (~(1 << ConfigPriority)); } else if ((cfgUpdated >> ConfigClient) & 1) { - WaitForEnd("mod\n"); /* TODO: check results */ - dt = WaitForEnd("5\n", true); - wxString sel = cfgClient->GetStringSelection(); - wxString sint = "1"; - if (sel != "") { - // "The defined Client resources are:\n 1: velours-fd\n 2: tom-fd\nSelect Client (File daemon) resource (1-2):" - for (unsigned int i = 0; i < dt->GetCount(); i++) { - int j; - if ((j = (*dt)[i].Find(": " + sel + "\n")) > -1) { - sint = (*dt)[i].Mid(0, j).Trim().Trim(false); - break; - } - } + WaitForPrompt("mod\n"); /* TODO: check results */ + wxbPromptParser *pp = WaitForPrompt("5\n", true); + int client = pp->getChoices()->Index(cfgClient->GetStringSelection()); + if (client == wxNOT_FOUND) { + wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client."); + client = 1; } - delete dt; - dt = WaitForEnd(sint + "\n", true); + delete pp; + dt = new wxbDataTokenizer(true); + WaitForPrompt(wxString() << client << "\n"); def = "1"; cfgUpdated = cfgUpdated & (~(1 << ConfigClient)); } + else if ((cfgUpdated >> ConfigFileset) & 1) { + WaitForPrompt("mod\n"); /* TODO: check results */ + wxbPromptParser *pp = WaitForPrompt("4\n", true); + int fileset = pp->getChoices()->Index(cfgFileset->GetStringSelection()); + if (fileset == wxNOT_FOUND) { + wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected fileset."); + fileset = 1; + } + delete pp; + dt = new wxbDataTokenizer(true); + WaitForPrompt(wxString() << fileset << "\n"); + def = "1"; + cfgUpdated = cfgUpdated & (~(1 << ConfigFileset)); + } else { cfgUpdated = 0; break; @@ -680,8 +700,8 @@ void wxbRestorePanel::CmdConfigCancel() { void wxbRestorePanel::CmdListJobs() { if (status == entered) { jobChoice->Clear(); - WaitForEnd("query\n"); - WaitForEnd("6\n"); + WaitForPrompt("query\n"); + WaitForPrompt("6\n"); wxbTableParser* tableparser = CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n"); for (int i = tableparser->size()-1; i > -1; i--) { @@ -818,9 +838,33 @@ wxbTableParser* wxbRestorePanel::CreateAndWaitForParser(wxString cmd) { return tableParser; } +/* Run a command, and waits until prompt result is fully received, + * if keepresults is true, returns a valid pointer to a wxbPromptParser + * containing the data. */ +wxbPromptParser* wxbRestorePanel::WaitForPrompt(wxString cmd, bool keepresults) { + wxbPromptParser* promptParser = new wxbPromptParser(); + + wxbMainFrame::GetInstance()->Send(cmd); + + //time_t base = wxDateTime::Now().GetTicks(); + while (!promptParser->hasFinished()) { + //innerThread->Yield(); + wxTheApp->Yield(); + //if (base+15 < wxDateTime::Now().GetTicks()) break; + } + + if (keepresults) { + return promptParser; + } + else { + delete promptParser; + return NULL; + } +} + /* Run a command, and waits until result is fully received. */ -wxbDataTokenizer* wxbRestorePanel::WaitForEnd(wxString cmd, bool keepresults) { - wxbDataTokenizer* datatokenizer = new wxbDataTokenizer(); +wxbDataTokenizer* wxbRestorePanel::WaitForEnd(wxString cmd, bool keepresults, bool linebyline) { + wxbDataTokenizer* datatokenizer = new wxbDataTokenizer(linebyline); wxbMainFrame::GetInstance()->Send(cmd); @@ -1170,7 +1214,18 @@ bool wxbRestorePanel::UpdateConfig(wxbDataTokenizer* dt) { else cfgReplace->SetSelection(0); if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false; - cfgFileset->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast()); + str = (*dt)[i].Mid(10).Trim(false).RemoveLast(); + for (k = 0; k < cfgFileset->GetCount(); k++) { + if (str == cfgFileset->GetString(k)) { + cfgFileset->SetSelection(k); + break; + } + } + if (k == cfgFileset->GetCount()) { // Should never happen + cfgFileset->Append(str); + cfgFileset->SetSelection(k+1); + } + if ((k = (*dt)[++i].Find("Client:")) != 0) return false; str = (*dt)[i].Mid(10).Trim(false).RemoveLast(); for (k = 0; k < cfgClient->GetCount(); k++) { @@ -1302,6 +1357,7 @@ void wxbRestorePanel::EnableConfig(bool enable) { cfgWhen->Enable(enable); cfgPriority->Enable(enable); cfgClient->Enable(enable); + cfgFileset->Enable(enable); } /*---------------------------------------------------------------------------- @@ -1314,8 +1370,10 @@ void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) { } working = true; clientChoice->Enable(false); + jobChoice->Enable(false); CmdListJobs(); clientChoice->Enable(true); + jobChoice->Enable(true); jobChoice->Refresh(); working = false; } diff --git a/bacula/src/wx-console/wxbrestorepanel.h b/bacula/src/wx-console/wxbrestorepanel.h index 25b75101a7..509db0b405 100644 --- a/bacula/src/wx-console/wxbrestorepanel.h +++ b/bacula/src/wx-console/wxbrestorepanel.h @@ -86,7 +86,12 @@ class wxbRestorePanel : public wxbPanel /* Run a command, and waits until result is fully received, * if keepresults is true, returns a valid pointer to a wxbDataTokenizer * containing the data. */ - wxbDataTokenizer* WaitForEnd(wxString cmd, bool keepresults = false); + wxbDataTokenizer* WaitForEnd(wxString cmd, bool keepresults = false, bool linebyline = true); + + /* Run a command, and waits until prompt result is fully received, + * if keepresults is true, returns a valid pointer to a wxbPromptParser + * containing the data. */ + wxbPromptParser* WaitForPrompt(wxString cmd, bool keepresults = false); /* Run a dir command, and waits until result is fully received. */ void UpdateTreeItem(wxTreeItemId item, bool updatelist); @@ -172,7 +177,7 @@ class wxbRestorePanel : public wxbPanel wxStaticText* cfgBootstrap; wxTextCtrl* cfgWhere; wxChoice* cfgReplace; - wxStaticText* cfgFileset; + wxChoice* cfgFileset; wxChoice* cfgClient; wxStaticText* cfgStorage; wxTextCtrl* cfgWhen; diff --git a/bacula/src/wx-console/wxbtableparser.cpp b/bacula/src/wx-console/wxbtableparser.cpp index 71d354d640..d1413e4a58 100644 --- a/bacula/src/wx-console/wxbtableparser.cpp +++ b/bacula/src/wx-console/wxbtableparser.cpp @@ -41,7 +41,7 @@ /* * wxbTableParser constructor */ -wxbTableParser::wxbTableParser() : wxbTable(5), wxbDataParser() { +wxbTableParser::wxbTableParser() : wxbTable(5), wxbDataParser(true) { separatorNum = 0; tableHeader = wxbTableRow(5); } @@ -61,20 +61,19 @@ wxbTableRow* wxbTableParser::GetHeader() { } /* - * Receives director information, forwarded by the wxbPanel which - * uses this parser. + * Receives data to analyse. */ -void wxbTableParser::Print(wxString str, int status) { +bool wxbTableParser::Analyse(wxString str, int status) { if ((status == CS_END) && (separatorNum > 0)) { separatorNum = 3; } - if (separatorNum == 3) return; + if (separatorNum == 3) return false; if (str.Length() > 4) { if ((str.GetChar(0) == '+') && (str.GetChar(str.Length()-2) == '+') && (str.GetChar(str.Length()-1) == '\n')) { separatorNum++; - return; + return false; } if ((str.GetChar(0) == '|') && (str.GetChar(str.Length()-2) == '|') && (str.GetChar(str.Length()-1) == '\n')) { @@ -97,6 +96,7 @@ void wxbTableParser::Print(wxString str, int status) { } } } + return false; } /* diff --git a/bacula/src/wx-console/wxbtableparser.h b/bacula/src/wx-console/wxbtableparser.h index 0f07aae30c..7310c8b5be 100644 --- a/bacula/src/wx-console/wxbtableparser.h +++ b/bacula/src/wx-console/wxbtableparser.h @@ -67,10 +67,9 @@ class wxbTableParser: public wxbTable, public wxbDataParser virtual ~wxbTableParser(); /* - * Receives director information, forwarded by the wxbPanel which - * uses this parser. + * Receives data to analyse. */ - virtual void Print(wxString str, int status); + virtual bool Analyse(wxString str, int status); /* * Return true table parsing has finished. diff --git a/bacula/src/wx-console/wxbutils.cpp b/bacula/src/wx-console/wxbutils.cpp index 3f2fd4fcc5..0c1c65b16c 100644 --- a/bacula/src/wx-console/wxbutils.cpp +++ b/bacula/src/wx-console/wxbutils.cpp @@ -30,8 +30,10 @@ #include "csprint.h" /* Creates a new wxbDataParser, and register it in wxbMainFrame */ -wxbDataParser::wxbDataParser() { +wxbDataParser::wxbDataParser(bool lineanalysis) { wxbMainFrame::GetInstance()->Register(this); + this->lineanalysis = lineanalysis; +// buffer = ""; } /* Destroy a wxbDataParser, and unregister it in wxbMainFrame */ @@ -39,8 +41,63 @@ wxbDataParser::~wxbDataParser() { wxbMainFrame::GetInstance()->Unregister(this); } +/* + * Receives director information, forwarded by wxbMainFrame, and sends it + * line by line to the virtual function Analyse. + */ +bool wxbDataParser::Print(wxString str, int status) { + bool ret = false; + if (lineanalysis) { + bool allnewline = true; + for (unsigned int i = 0; i < str.Length(); i++) { + if (!(allnewline = (str.GetChar(i) == '\n'))) + break; + } + + if (allnewline) { + ret = Analyse(buffer << "\n", CS_DATA); + buffer = ""; + for (unsigned int i = 1; i < str.Length(); i++) { + ret = Analyse("\n", status); + } + } + else { + wxStringTokenizer tkz(str, "\n", + wxTOKEN_RET_DELIMS | wxTOKEN_RET_EMPTY | wxTOKEN_RET_EMPTY_ALL); + + while ( tkz.HasMoreTokens() ) { + buffer << tkz.GetNextToken(); + if (buffer.Length() != 0) { + if ((buffer.GetChar(buffer.Length()-1) == '\n') || + (buffer.GetChar(buffer.Length()-1) == '\r')) { + ret = Analyse(buffer, status); + buffer = ""; + } + } + } + } + + if (buffer == "$ ") { // Restore console + ret = Analyse(buffer, status); + buffer = ""; + } + + if (status != CS_DATA) { + if (buffer.Length() != 0) { + ret = Analyse(buffer, CS_DATA); + } + buffer = ""; + ret = Analyse("", status); + } + } + else { + ret = Analyse(wxString(str), status); + } + return ret; +} + /* Creates a new wxbDataTokenizer */ -wxbDataTokenizer::wxbDataTokenizer(): wxbDataParser(), wxArrayString() { +wxbDataTokenizer::wxbDataTokenizer(bool linebyline): wxbDataParser(linebyline), wxArrayString() { finished = false; } @@ -52,14 +109,13 @@ wxbDataTokenizer::~wxbDataTokenizer() { /* * Receives director information, forwarded by wxbMainFrame. */ -void wxbDataTokenizer::Print(wxString str, int status) { - finished = ((status == CS_END) || (status == CS_DISCONNECTED)); +bool wxbDataTokenizer::Analyse(wxString str, int status) { + finished = ((status == CS_END) || (status == CS_PROMPT) || (status == CS_DISCONNECTED)); if (str != "") { Add(str); - //wxbMainFrame::GetInstance()->Print("D", CS_DEBUG); } - //wxbMainFrame::GetInstance()->Print(finished ? "F" : "!F", CS_DEBUG); + return false; } /* Returns true if the last signal received was an end signal, @@ -67,3 +123,112 @@ void wxbDataTokenizer::Print(wxString str, int status) { bool wxbDataTokenizer::hasFinished() { return finished; } + +/* Creates a new wxbDataTokenizer */ +wxbPromptParser::wxbPromptParser(): wxbDataParser(false) { + finished = false; + prompt = false; + introStr = ""; + choices = NULL; + questionStr = ""; +} + +/* Destroy a wxbDataTokenizer */ +wxbPromptParser::~wxbPromptParser() { + if (choices) { + delete choices; + } +} + +/* + * Receives director information, forwarded by wxbMainFrame. + */ +bool wxbPromptParser::Analyse(wxString str, int status) { + if (status == CS_DATA) { + if (finished || prompt) { /* New question */ + finished = false; + prompt = false; + if (choices) { + delete choices; + choices = NULL; + } + questionStr = ""; + introStr = ""; + } + int i; + long num; + + if (((i = str.Find(": ")) > 0) && (str.Mid(0, i).Trim(false).ToLong(&num))) { /* List element */ + if (!choices) { + choices = new wxArrayString(); + choices->Add(""); /* index 0 is never used by multiple choice questions */ + } + + if (choices->GetCount() != num) { /* new choice has begun */ + delete choices; + choices = new wxArrayString(num); + choices->Add("", num); /* fill until this number */ + } + + choices->Add(str.Mid(i+2).RemoveLast()); + } + else if (!choices) { /* Introduction, no list received yet */ + introStr << questionStr; + questionStr = wxString(str); + } + else { /* List receveived, get the question now */ + introStr << questionStr; + questionStr = wxString(str); + } + } + else { + finished = ((status == CS_PROMPT) || (status == CS_END) || (status == CS_DISCONNECTED)); + if (prompt = ((status == CS_PROMPT) && (questionStr != "$ "))) { // && (str.Find(": ") == str.Length()) + if ((introStr != "") && (questionStr == "")) { + questionStr = introStr; + introStr = ""; + } + if (introStr.Last() == '\n') { + introStr.RemoveLast(); + } + return true; + } + else { /* ended or (dis)connected */ + if (choices) { + delete choices; + choices = NULL; + } + questionStr = ""; + introStr = ""; + } + } + return false; +} + +/* Returns true if the last signal received was an prompt signal, + * indicating that the answer must be sent */ +bool wxbPromptParser::hasFinished() { + return finished; +} + +/* Returns true if the last message received is a prompt message */ +bool wxbPromptParser::isPrompt() { + return prompt; +} + +/* Returns multiple choice question's introduction */ +wxString wxbPromptParser::getIntroString() { + return introStr; +} + +/* Returns question string */ +wxString wxbPromptParser::getQuestionString() { + return questionStr; +} + +/* Return a wxArrayString containing the indexed choices we have + * to answer the question, or NULL if this question is not a multiple + * choice one. */ +wxArrayString* wxbPromptParser::getChoices() { + return choices; +} diff --git a/bacula/src/wx-console/wxbutils.h b/bacula/src/wx-console/wxbutils.h index b7726a3fa4..d2a0df4946 100644 --- a/bacula/src/wx-console/wxbutils.h +++ b/bacula/src/wx-console/wxbutils.h @@ -39,16 +39,31 @@ class wxbDataParser { public: - /* Creates a new wxbDataParser, and register it in wxbMainFrame */ - wxbDataParser(); + /* Creates a new wxbDataParser, and register it in wxbMainFrame + * lineanalysis : indicate if date is to be analysed line by line (true) + * or packet by packet (false). + */ + wxbDataParser(bool lineanalysis); /* Destroy a wxbDataParser, and unregister it in wxbMainFrame */ virtual ~wxbDataParser(); /* - * Receives director information, forwarded by wxbMainFrame. + * Receives director information, forwarded by wxbMainFrame, and sends it + * line by line to the virtual function Analyse. + * + * Returns true if status == CS_PROMPT and the message has been parsed + * correctly. + */ + bool Print(wxString str, int status); + + /* + * Receives data to analyse. */ - virtual void Print(wxString str, int status) = 0; + virtual bool Analyse(wxString str, int status) = 0; + private: + bool lineanalysis; + wxString buffer; }; /* @@ -79,15 +94,15 @@ class wxbDataTokenizer: public wxbDataParser, public wxArrayString { public: /* Creates a new wxbDataTokenizer */ - wxbDataTokenizer(); + wxbDataTokenizer(bool linebyline); /* Destroy a wxbDataTokenizer */ virtual ~wxbDataTokenizer(); /* - * Receives director information, forwarded by wxbMainFrame. + * Receives data to analyse. */ - virtual void Print(wxString str, int status); + virtual bool Analyse(wxString str, int status); /* Returns true if the last signal received was an end signal, * indicating that no more data is available */ @@ -95,7 +110,51 @@ class wxbDataTokenizer: public wxbDataParser, public wxArrayString private: bool finished; - wxString buffer; +}; + +/* + * Receives director information, and check if the last messages are questions. + */ +class wxbPromptParser: public wxbDataParser +{ + public: + /* Creates a new wxbDataTokenizer */ + wxbPromptParser(); + + /* Destroy a wxbDataTokenizer */ + virtual ~wxbPromptParser(); + + /* + * Receives data to analyse. + */ + virtual bool Analyse(wxString str, int status); + + /* Returns true if the last signal received was an prompt signal, + * or an end signal */ + bool hasFinished(); + + /* Returns true if the last message received is a prompt message */ + bool isPrompt(); + + /* Returns multiple choice question's introduction */ + wxString getIntroString(); + + /* Returns question string */ + wxString getQuestionString(); + + /* Return a wxArrayString containing the indexed choices we have + * to answer the question, or NULL if this question is not a multiple + * choice one. */ + wxArrayString* getChoices(); + + + + private: + bool finished; + bool prompt; + wxString introStr; + wxArrayString* choices; + wxString questionStr; }; #endif // WXBPANEL_H -- 2.39.5