+ FileFd in;
+ in.OpenDescriptor(input, FileFd::ReadOnly);
+ pkgTagFile response(&in, 100);
+ pkgTagSection section;
+
+ while (response.Step(section) == true) {
+ std::string type;
+ if (section.Exists("Install") == true)
+ type = "Install";
+ else if (section.Exists("Remove") == true)
+ type = "Remove";
+ else if (section.Exists("Progress") == true) {
+ if (Progress != NULL) {
+ string msg = section.FindS("Message");
+ if (msg.empty() == true)
+ msg = _("Prepare for receiving solution");
+ Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
+ }
+ continue;
+ } else if (section.Exists("Error") == true) {
+ std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
+ if (msg.empty() == true) {
+ msg = _("External solver failed without a proper error message");
+ _error->Error("%s", msg.c_str());
+ } else
+ _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
+ if (Progress != NULL)
+ Progress->Done();
+ std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
+ std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
+ std::cerr << msg << std::endl << std::endl;
+ return false;
+ } else if (section.Exists("Autoremove") == true)
+ type = "Autoremove";
+ else
+ continue;
+
+ size_t const id = section.FindULL(type.c_str(), VersionCount);
+ if (id == VersionCount) {
+ _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
+ continue;
+ } else if (id > Cache.Head().VersionCount) {
+ _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type.c_str()).c_str(), type.c_str());
+ continue;
+ }
+
+ pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
+ Cache.SetCandidateVersion(Ver);
+ if (type == "Install")
+ Cache.MarkInstall(Ver.ParentPkg(), false, 0, false);
+ else if (type == "Remove")
+ Cache.MarkDelete(Ver.ParentPkg(), false);
+ else if (type == "Autoremove") {
+ Cache[Ver.ParentPkg()].Marked = false;
+ Cache[Ver.ParentPkg()].Garbage = true;
+ }
+ }
+ return true;
+}
+ /*}}}*/
+// EDSP::ReadLine - first line from the given file descriptor /*{{{*/
+// ---------------------------------------------------------------------
+/* Little helper method to read a complete line into a string. Similar to
+ fgets but we need to use the low-level read() here as otherwise the
+ listparser will be confused later on as mixing of fgets and read isn't
+ a supported action according to the manpages and results are undefined */
+bool EDSP::ReadLine(int const input, std::string &line) {
+ char one;
+ ssize_t data = 0;
+ line.erase();
+ line.reserve(100);
+ while ((data = read(input, &one, sizeof(one))) != -1) {
+ if (data != 1)
+ continue;
+ if (one == '\n')
+ return true;
+ if (one == '\r')
+ continue;
+ if (line.empty() == true && isblank(one) != 0)
+ continue;
+ line += one;
+ }
+ return false;
+}
+ /*}}}*/
+// EDSP::StringToBool - convert yes/no to bool /*{{{*/
+// ---------------------------------------------------------------------
+/* we are not as lazy as we are in the global StringToBool as we really
+ only accept yes/no here - but we will ignore leading spaces */
+bool EDSP::StringToBool(char const *answer, bool const defValue) {
+ for (; isspace(*answer) != 0; ++answer);
+ if (strncasecmp(answer, "yes", 3) == 0)
+ return true;
+ else if (strncasecmp(answer, "no", 2) == 0)
+ return false;
+ else
+ _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
+ return defValue;
+}
+ /*}}}*/
+// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
+bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
+ std::list<std::string> &remove, bool &upgrade,
+ bool &distUpgrade, bool &autoRemove)
+{
+ install.clear();
+ remove.clear();
+ upgrade = false;
+ distUpgrade = false;
+ autoRemove = false;
+ std::string line;
+ while (ReadLine(input, line) == true)
+ {
+ // Skip empty lines before request
+ if (line.empty() == true)
+ continue;
+ // The first Tag must be a request, so search for it
+ if (line.compare(0, 8, "Request:") != 0)
+ continue;
+
+ while (ReadLine(input, line) == true)
+ {
+ // empty lines are the end of the request
+ if (line.empty() == true)
+ return true;
+
+ std::list<std::string> *request = NULL;
+ if (line.compare(0, 8, "Install:") == 0)
+ {
+ line.erase(0, 8);
+ request = &install;
+ }
+ else if (line.compare(0, 7, "Remove:") == 0)
+ {
+ line.erase(0, 7);
+ request = &remove;
+ }
+ else if (line.compare(0, 8, "Upgrade:") == 0)
+ upgrade = EDSP::StringToBool(line.c_str() + 9, false);
+ else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
+ distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
+ else if (line.compare(0, 11, "Autoremove:") == 0)
+ autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
+ else
+ _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
+
+ if (request == NULL)
+ continue;
+ size_t end = line.length();
+ do {
+ size_t begin = line.rfind(' ');
+ if (begin == std::string::npos)
+ {
+ request->push_back(line.substr(0, end));
+ break;
+ }
+ else if (begin < end)
+ request->push_back(line.substr(begin + 1, end));
+ line.erase(begin);
+ end = line.find_last_not_of(' ');
+ } while (end != std::string::npos);
+ }
+ }
+ return false;
+}
+ /*}}}*/
+// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/