]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/edsp.cc
test: remove SHA1 support testing as unsupported
[apt.git] / apt-pkg / edsp.cc
index 9dbbbaf2646277af27870db1e93b52b5be468cdf..59e8e7ab41b4c7fde674c49edb41c58899a7ab47 100644 (file)
@@ -5,98 +5,99 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#include <apt-pkg/edsp.h>
+#include <config.h>
+
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/version.h>
-#include <apt-pkg/policy.h>
+#include <apt-pkg/cacheset.h>
+#include <apt-pkg/depcache.h>
+#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/cacheiterators.h>
+#include <apt-pkg/progress.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/edsp.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
+#include <apt-pkg/strutl.h>
 
 
-#include <apti18n.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
 #include <limits>
 #include <limits>
+#include <string>
 
 
-#include <stdio.h>
+#include <apti18n.h>
                                                                        /*}}}*/
 
                                                                        /*}}}*/
 
+using std::string;
+
 // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
 // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
-const char * const EDSP::PrioMap[] = {0, "important", "required", "standard",
+const char * const PrioMap[] = {0, "important", "required", "standard",
                                      "optional", "extra"};
                                      "optional", "extra"};
-const char * const EDSP::DepMap[] = {"", "Depends", "PreDepends", "Suggests",
+const char * const DepMap[] = {"", "Depends", "Pre-Depends", "Suggests",
                                     "Recommends" , "Conflicts", "Replaces",
                                     "Obsoletes", "Breaks", "Enhances"};
 
                                     "Recommends" , "Conflicts", "Replaces",
                                     "Obsoletes", "Breaks", "Enhances"};
 
-// EDSP::WriteScenario - to the given file descriptor                  /*{{{*/
-bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output)
-{
-   for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
-      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
-      {
-        WriteScenarioVersion(Cache, output, Pkg, Ver);
-        WriteScenarioDependency(Cache, output, Pkg, Ver);
-        fprintf(output, "\n");
-      }
-   return true;
-}
-                                                                       /*}}}*/
-// EDSP::WriteLimitedScenario - to the given file descriptor           /*{{{*/
-bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
-                               APT::PackageSet const &pkgset)
-{
-   for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
-      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
-      {
-        WriteScenarioVersion(Cache, output, Pkg, Ver);
-        WriteScenarioLimitedDependency(Cache, output, Pkg, Ver, pkgset);
-        fprintf(output, "\n");
-      }
-   return true;
-}
-                                                                       /*}}}*/
-// EDSP::WriteScenarioVersion                                          /*{{{*/
-void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
+
+// WriteScenarioVersion                                                        /*{{{*/
+static void WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
                                pkgCache::VerIterator const &Ver)
 {
    fprintf(output, "Package: %s\n", Pkg.Name());
                                pkgCache::VerIterator const &Ver)
 {
    fprintf(output, "Package: %s\n", Pkg.Name());
+   fprintf(output, "Source: %s\n", Ver.SourcePkgName());
    fprintf(output, "Architecture: %s\n", Ver.Arch());
    fprintf(output, "Version: %s\n", Ver.VerStr());
    fprintf(output, "Architecture: %s\n", Ver.Arch());
    fprintf(output, "Version: %s\n", Ver.VerStr());
+   fprintf(output, "Source-Version: %s\n", Ver.SourceVerStr());
    if (Pkg.CurrentVer() == Ver)
       fprintf(output, "Installed: yes\n");
    if (Pkg.CurrentVer() == Ver)
       fprintf(output, "Installed: yes\n");
-   if (Pkg->SelectedState == pkgCache::State::Hold)
+   if (Pkg->SelectedState == pkgCache::State::Hold ||
+       (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
       fprintf(output, "Hold: yes\n");
    fprintf(output, "APT-ID: %d\n", Ver->ID);
    fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
    if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
       fprintf(output, "Essential: yes\n");
    fprintf(output, "Section: %s\n", Ver.Section());
       fprintf(output, "Hold: yes\n");
    fprintf(output, "APT-ID: %d\n", Ver->ID);
    fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
    if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
       fprintf(output, "Essential: yes\n");
    fprintf(output, "Section: %s\n", Ver.Section());
-   if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
+   if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
       fprintf(output, "Multi-Arch: allowed\n");
       fprintf(output, "Multi-Arch: allowed\n");
-   else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
+   else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
       fprintf(output, "Multi-Arch: foreign\n");
       fprintf(output, "Multi-Arch: foreign\n");
-   else if (Ver->MultiArch == pkgCache::Version::Same)
+   else if ((Ver->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
       fprintf(output, "Multi-Arch: same\n");
    signed short Pin = std::numeric_limits<signed short>::min();
       fprintf(output, "Multi-Arch: same\n");
    signed short Pin = std::numeric_limits<signed short>::min();
-   for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
-      signed short const p = Cache.GetPolicy().GetPriority(File.File());
+   std::set<string> Releases;
+   for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) {
+      pkgCache::PkgFileIterator File = I.File();
+      signed short const p = Cache.GetPolicy().GetPriority(File);
       if (Pin < p)
         Pin = p;
       if (Pin < p)
         Pin = p;
+      if (File.Flagged(pkgCache::Flag::NotSource) == false) {
+        string Release = File.RelStr();
+        if (!Release.empty())
+           Releases.insert(Release);
+      }
+   }
+   if (!Releases.empty()) {
+       fprintf(output, "APT-Release:\n");
+       for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R)
+          fprintf(output, " %s\n", R->c_str());
    }
    fprintf(output, "APT-Pin: %d\n", Pin);
    }
    fprintf(output, "APT-Pin: %d\n", Pin);
-   if (Cache.GetCandidateVer(Pkg) == Ver)
+   if (Cache.GetCandidateVersion(Pkg) == Ver)
       fprintf(output, "APT-Candidate: yes\n");
    if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
       fprintf(output, "APT-Automatic: yes\n");
 }
                                                                        /*}}}*/
       fprintf(output, "APT-Candidate: yes\n");
    if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
       fprintf(output, "APT-Automatic: yes\n");
 }
                                                                        /*}}}*/
-// EDSP::WriteScenarioDependency                                       /*{{{*/
-void EDSP::WriteScenarioDependency(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
-                               pkgCache::VerIterator const &Ver)
+// WriteScenarioDependency                                             /*{{{*/
+static void WriteScenarioDependency( FILE* output, pkgCache::VerIterator const &Ver)
 {
    std::string dependencies[pkgCache::Dep::Enhances + 1];
    bool orGroup = false;
    for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
    {
 {
    std::string dependencies[pkgCache::Dep::Enhances + 1];
    bool orGroup = false;
    for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
    {
-      // Ignore implicit dependencies for multiarch here
-      if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
+      if (Dep.IsImplicit() == true)
         continue;
       if (orGroup == false)
         dependencies[Dep->Type].append(", ");
         continue;
       if (orGroup == false)
         dependencies[Dep->Type].append(", ");
@@ -117,18 +118,18 @@ void EDSP::WriteScenarioDependency(pkgDepCache &Cache, FILE* output, pkgCache::P
    string provides;
    for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
    {
    string provides;
    for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
    {
-      // Ignore implicit provides for multiarch here
-      if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
+      if (Prv.IsMultiArchImplicit() == true)
         continue;
       provides.append(", ").append(Prv.Name());
         continue;
       provides.append(", ").append(Prv.Name());
+      if (Prv->ProvideVersion != 0)
+        provides.append(" (= ").append(Prv.ProvideVersion()).append(")");
    }
    if (provides.empty() == false)
       fprintf(output, "Provides: %s\n", provides.c_str()+2);
 }
                                                                        /*}}}*/
    }
    if (provides.empty() == false)
       fprintf(output, "Provides: %s\n", provides.c_str()+2);
 }
                                                                        /*}}}*/
-// EDSP::WriteScenarioLimitedDependency                                        /*{{{*/
-void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
-                                         pkgCache::PkgIterator const &Pkg,
+// WriteScenarioLimitedDependency                                      /*{{{*/
+static void WriteScenarioLimitedDependency(FILE* output,
                                          pkgCache::VerIterator const &Ver,
                                          APT::PackageSet const &pkgset)
 {
                                          pkgCache::VerIterator const &Ver,
                                          APT::PackageSet const &pkgset)
 {
@@ -136,8 +137,7 @@ void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
    bool orGroup = false;
    for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
    {
    bool orGroup = false;
    for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
    {
-      // Ignore implicit dependencies for multiarch here
-      if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
+      if (Dep.IsImplicit() == true)
         continue;
       if (orGroup == false)
       {
         continue;
       if (orGroup == false)
       {
@@ -170,8 +170,7 @@ void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
    string provides;
    for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
    {
    string provides;
    for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
    {
-      // Ignore implicit provides for multiarch here
-      if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
+      if (Prv.IsMultiArchImplicit() == true)
         continue;
       if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
         continue;
         continue;
       if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
         continue;
@@ -181,23 +180,86 @@ void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
       fprintf(output, "Provides: %s\n", provides.c_str()+2);
 }
                                                                        /*}}}*/
       fprintf(output, "Provides: %s\n", provides.c_str()+2);
 }
                                                                        /*}}}*/
+// EDSP::WriteScenario - to the given file descriptor                  /*{{{*/
+bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
+{
+   if (Progress != NULL)
+      Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
+   unsigned long p = 0;
+   std::vector<std::string> archs = APT::Configuration::getArchitectures();
+   for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+   {
+      std::string const arch = Pkg.Arch();
+      if (std::find(archs.begin(), archs.end(), arch) == archs.end())
+        continue;
+      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
+      {
+        WriteScenarioVersion(Cache, output, Pkg, Ver);
+        WriteScenarioDependency(output, Ver);
+        fprintf(output, "\n");
+        if (Progress != NULL && p % 100 == 0)
+           Progress->Progress(p);
+      }
+   }
+   return true;
+}
+                                                                       /*}}}*/
+// EDSP::WriteLimitedScenario - to the given file descriptor           /*{{{*/
+bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
+                               APT::PackageSet const &pkgset,
+                               OpProgress *Progress)
+{
+   if (Progress != NULL)
+      Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
+   unsigned long p  = 0;
+   for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
+      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
+      {
+        WriteScenarioVersion(Cache, output, Pkg, Ver);
+        WriteScenarioLimitedDependency(output, Ver, pkgset);
+        fprintf(output, "\n");
+        if (Progress != NULL && p % 100 == 0)
+           Progress->Progress(p);
+      }
+   if (Progress != NULL)
+      Progress->Done();
+   return true;
+}
+                                                                       /*}}}*/
 // EDSP::WriteRequest - to the given file descriptor                   /*{{{*/
 bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
 // EDSP::WriteRequest - to the given file descriptor                   /*{{{*/
 bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
-                       bool const DistUpgrade, bool const AutoRemove)
+                       bool const DistUpgrade, bool const AutoRemove,
+                       OpProgress *Progress)
 {
 {
+   if (Progress != NULL)
+      Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
+   unsigned long p = 0;
    string del, inst;
    string del, inst;
-   for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+   for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
    {
    {
+      if (Progress != NULL && p % 100 == 0)
+         Progress->Progress(p);
       string* req;
       string* req;
-      if (Cache[Pkg].Delete() == true)
+      pkgDepCache::StateCache &P = Cache[Pkg];
+      if (P.Delete() == true)
         req = &del;
         req = &del;
-      else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
+      else if (P.NewInstall() == true || P.Upgrade() == true || P.ReInstall() == true ||
+              (P.Mode == pkgDepCache::ModeKeep && (P.iFlags & pkgDepCache::Protected) == pkgDepCache::Protected))
         req = &inst;
       else
         continue;
       req->append(" ").append(Pkg.FullName());
    }
         req = &inst;
       else
         continue;
       req->append(" ").append(Pkg.FullName());
    }
-   fprintf(output, "Request: EDSP 0.2\n");
+   fprintf(output, "Request: EDSP 0.5\n");
+
+   const char *arch = _config->Find("APT::Architecture").c_str();
+   std::vector<string> archs = APT::Configuration::getArchitectures();
+   fprintf(output, "Architecture: %s\n", arch);
+   fprintf(output, "Architectures:");
+   for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a)
+       fprintf(output, " %s", a->c_str());
+   fprintf(output, "\n");
+
    if (del.empty() == false)
       fprintf(output, "Remove: %s\n", del.c_str()+1);
    if (inst.empty() == false)
    if (del.empty() == false)
       fprintf(output, "Remove: %s\n", del.c_str()+1);
    if (inst.empty() == false)
@@ -211,7 +273,7 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
    if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
       fprintf(output, "Strict-Pinning: no\n");
    string solverpref("APT::Solver::");
    if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
       fprintf(output, "Strict-Pinning: no\n");
    string solverpref("APT::Solver::");
-   solverpref.append(_config->Find("APT::Solver::Name", "internal")).append("::Preferences");
+   solverpref.append(_config->Find("APT::Solver", "internal")).append("::Preferences");
    if (_config->Exists(solverpref) == true)
       fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
    fprintf(output, "\n");
    if (_config->Exists(solverpref) == true)
       fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
    fprintf(output, "\n");
@@ -220,20 +282,23 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
 }
                                                                        /*}}}*/
 // EDSP::ReadResponse - from the given file descriptor                 /*{{{*/
 }
                                                                        /*}}}*/
 // EDSP::ReadResponse - from the given file descriptor                 /*{{{*/
-bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
+bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
        /* We build an map id to mmap offset here
           In theory we could use the offset as ID, but then VersionCount
           couldn't be used to create other versionmappings anymore and it
           would be too easy for a (buggy) solver to segfault APT… */
        unsigned long long const VersionCount = Cache.Head().VersionCount;
        unsigned long VerIdx[VersionCount];
        /* We build an map id to mmap offset here
           In theory we could use the offset as ID, but then VersionCount
           couldn't be used to create other versionmappings anymore and it
           would be too easy for a (buggy) solver to segfault APT… */
        unsigned long long const VersionCount = Cache.Head().VersionCount;
        unsigned long VerIdx[VersionCount];
-       for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P)
+       for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
                for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
                        VerIdx[V->ID] = V.Index();
                for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
                        VerIdx[V->ID] = V.Index();
+               Cache[P].Marked = true;
+               Cache[P].Garbage = false;
+       }
 
        FileFd in;
        in.OpenDescriptor(input, FileFd::ReadOnly);
 
        FileFd in;
        in.OpenDescriptor(input, FileFd::ReadOnly);
-       pkgTagFile response(&in);
+       pkgTagFile response(&in, 100);
        pkgTagSection section;
 
        while (response.Step(section) == true) {
        pkgTagSection section;
 
        while (response.Step(section) == true) {
@@ -243,15 +308,29 @@ bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
                else if (section.Exists("Remove") == true)
                        type = "Remove";
                else if (section.Exists("Progress") == true) {
                else if (section.Exists("Remove") == true)
                        type = "Remove";
                else if (section.Exists("Progress") == true) {
-                       ioprintf(std::clog, "[ %3d%% ] ", section.FindI("Percentage", 0));
-                       std::clog << section.FindS("Progress") << " - ";
-                       string const msg = section.FindS("Message");
-                       if (msg.empty() == true)
-                               std::clog << "Solver is still working on the solution" << std::endl;
-                       else
-                               std::clog << msg << std::endl;
+                       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;
                        continue;
-               } else
+               } 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);
                        continue;
 
                size_t const id = section.FindULL(type.c_str(), VersionCount);
@@ -266,20 +345,28 @@ bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
                pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
                Cache.SetCandidateVersion(Ver);
                if (type == "Install")
                pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
                Cache.SetCandidateVersion(Ver);
                if (type == "Install")
-                       Cache.MarkInstall(Ver.ParentPkg(), false, false);
+               {
+                       pkgCache::PkgIterator const P = Ver.ParentPkg();
+                       if (Cache[P].Mode != pkgDepCache::ModeInstall)
+                               Cache.MarkInstall(P, false, 0, false);
+               }
                else if (type == "Remove")
                        Cache.MarkDelete(Ver.ParentPkg(), 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;
 }
                                                                        /*}}}*/
        }
        return true;
 }
                                                                        /*}}}*/
-// EDSP::ReadLine - first line from the given file descriptor          /*{{{*/
+// 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 */
 // ---------------------------------------------------------------------
 /* 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) {
+static bool ReadLine(int const input, std::string &line) {
        char one;
        ssize_t data = 0;
        line.erase();
        char one;
        ssize_t data = 0;
        line.erase();
@@ -298,11 +385,11 @@ bool EDSP::ReadLine(int const input, std::string &line) {
        return false;
 }
                                                                        /*}}}*/
        return false;
 }
                                                                        /*}}}*/
-// EDSP::StringToBool - convert yes/no to bool                         /*{{{*/
+// 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 */
 // ---------------------------------------------------------------------
 /* 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) {
+static bool StringToBool(char const *answer, bool const defValue) {
    for (; isspace(*answer) != 0; ++answer);
    if (strncasecmp(answer, "yes", 3) == 0)
       return true;
    for (; isspace(*answer) != 0; ++answer);
    if (strncasecmp(answer, "yes", 3) == 0)
       return true;
@@ -351,11 +438,18 @@ bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
            request = &remove;
         }
         else if (line.compare(0, 8, "Upgrade:") == 0)
            request = &remove;
         }
         else if (line.compare(0, 8, "Upgrade:") == 0)
-           upgrade = EDSP::StringToBool(line.c_str() + 9, false);
+           upgrade = StringToBool(line.c_str() + 9, false);
         else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
         else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
-           distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
+           distUpgrade = StringToBool(line.c_str() + 14, false);
         else if (line.compare(0, 11, "Autoremove:") == 0)
         else if (line.compare(0, 11, "Autoremove:") == 0)
-           autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
+           autoRemove = StringToBool(line.c_str() + 12, false);
+        else if (line.compare(0, 13, "Architecture:") == 0)
+           _config->Set("APT::Architecture", line.c_str() + 14);
+        else if (line.compare(0, 14, "Architectures:") == 0)
+        {
+           std::string const archs = line.c_str() + 15;
+           _config->Set("APT::Architectures", SubstVar(archs, " ", ","));
+        }
         else
            _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
 
         else
            _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
 
@@ -418,9 +512,16 @@ bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
       }
       else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
       {
       }
       else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
       {
-        fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
+        pkgCache::VerIterator const CandVer = Cache.GetCandidateVersion(Pkg);
+        fprintf(output, "Install: %d\n", CandVer->ID);
+        if (Debug == true)
+           fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), CandVer.VerStr());
+      }
+      else if (Cache[Pkg].Garbage == true)
+      {
+        fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
         if (Debug == true)
         if (Debug == true)
-           fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
+           fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
       }
       else
         continue;
       }
       else
         continue;
@@ -439,4 +540,93 @@ bool EDSP::WriteProgress(unsigned short const percent, const char* const message
        return true;
 }
                                                                        /*}}}*/
        return true;
 }
                                                                        /*}}}*/
-bool EDSP::WriteError(std::string const &message, FILE* output) { return false; }
+// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
+bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
+       fprintf(output, "Error: %s\n", uuid);
+       fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
+       return true;
+}
+                                                                       /*}}}*/
+// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes     {{{*/
+pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) {
+       std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
+       std::string file;
+       for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
+            dir != solverDirs.end(); ++dir) {
+               file = flCombine(*dir, solver);
+               if (RealFileExists(file.c_str()) == true)
+                       break;
+               file.clear();
+       }
+
+       if (file.empty() == true)
+       {
+               _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
+               return 0;
+       }
+       int external[4] = {-1, -1, -1, -1};
+       if (pipe(external) != 0 || pipe(external + 2) != 0)
+       {
+               _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
+               return 0;
+       }
+       for (int i = 0; i < 4; ++i)
+               SetCloseExec(external[i], true);
+
+       pid_t Solver = ExecFork();
+       if (Solver == 0) {
+               dup2(external[0], STDIN_FILENO);
+               dup2(external[3], STDOUT_FILENO);
+               const char* calling[2] = { file.c_str(), 0 };
+               execv(calling[0], (char**) calling);
+               std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
+               _exit(100);
+       }
+       close(external[0]);
+       close(external[3]);
+
+       if (WaitFd(external[1], true, 5) == false)
+       {
+               _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
+               return 0;
+       }
+
+       *solver_in = external[1];
+       *solver_out = external[2];
+       return Solver;
+}
+bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
+   if (ExecuteSolver(solver, solver_in, solver_out, true) == 0)
+      return false;
+   return true;
+}
+                                                                       /*}}}*/
+// EDSP::ResolveExternal - resolve problems by asking external for help        {{{*/
+bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
+                        bool const upgrade, bool const distUpgrade,
+                        bool const autoRemove, OpProgress *Progress) {
+       int solver_in, solver_out;
+       pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true);
+       if (solver_pid == 0)
+               return false;
+
+       FILE* output = fdopen(solver_in, "w");
+       if (output == NULL)
+               return _error->Errno("Resolve", "fdopen on solver stdin failed");
+
+       if (Progress != NULL)
+               Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
+       EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
+       if (Progress != NULL)
+               Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
+       EDSP::WriteScenario(Cache, output, Progress);
+       fclose(output);
+
+       if (Progress != NULL)
+               Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
+       if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
+               return false;
+
+       return ExecWait(solver_pid, solver);
+}
+                                                                       /*}}}*/