]> git.saurik.com Git - apt.git/blobdiff - cmdline/apt-get.cc
[apt-pkg/sourcelist.cc] only display the warning about missing sources.list
[apt.git] / cmdline / apt-get.cc
index ab069ddc25043cc798f1ef17df598b25cde94392..ab6dca38817f51917b1d519fb57ffa0bb5ae2c44 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: apt-get.cc,v 1.136 2003/08/08 23:48:48 mdz Exp $
+// $Id: apt-get.cc,v 1.156 2004/08/28 01:05:16 mdz Exp $
 /* ######################################################################
    
    apt-get - Cover for dpkg
@@ -38,6 +38,7 @@
 #include <apt-pkg/version.h>
 #include <apt-pkg/cachefile.h>
 #include <apt-pkg/sptr.h>
+#include <apt-pkg/md5.h>
 #include <apt-pkg/versionmatch.h>
     
 #include <config.h>
 
 #include "acqprogress.h"
 
+#include <set>
 #include <locale.h>
+#include <langinfo.h>
 #include <fstream>
 #include <termios.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <sys/statfs.h>
 #include <sys/statvfs.h>
 #include <signal.h>
 #include <unistd.h>
 #include <errno.h>
 #include <regex.h>
 #include <sys/wait.h>
+#include <sstream>
                                                                        /*}}}*/
 
+#define RAMFS_MAGIC     0x858458f6
+
 using namespace std;
 
 ostream c0out(0);
 ostream c1out(0);
 ostream c2out(0);
 ofstream devnull("/dev/null");
-unsigned int ScreenWidth = 80;
+unsigned int ScreenWidth = 80 - 1; /* - 1 for the cursor */
 
 // class CacheFile - Cover class for some dependency cache functions   /*{{{*/
 // ---------------------------------------------------------------------
@@ -104,34 +111,48 @@ class CacheFile : public pkgCacheFile
         return Open(true);
    }
    CacheFile() : List(0) {};
+   ~CacheFile() {
+      delete[] List;
+   }
 };
                                                                        /*}}}*/
 
 // YnPrompt - Yes No Prompt.                                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns true on a Yes.*/
-bool YnPrompt()
+bool YnPrompt(bool Default=true)
 {
-   // This needs to be a capital
-   const char *Yes = _("Y");
-                          
    if (_config->FindB("APT::Get::Assume-Yes",false) == true)
    {
-      c1out << Yes << endl;
+      c1out << _("Y") << endl;
       return true;
    }
-   
-   char C = 0;
-   char Jnk = 0;
-   if (read(STDIN_FILENO,&C,1) != 1)
+
+   char response[1024] = "";
+   cin.getline(response, sizeof(response));
+
+   if (!cin)
       return false;
-   while (C != '\n' && Jnk != '\n') 
-      if (read(STDIN_FILENO,&Jnk,1) != 1)
-        return false;
+
+   if (strlen(response) == 0)
+      return Default;
+
+   regex_t Pattern;
+   int Res;
+
+   Res = regcomp(&Pattern, nl_langinfo(YESEXPR),
+                 REG_EXTENDED|REG_ICASE|REG_NOSUB);
+
+   if (Res != 0) {
+      char Error[300];        
+      regerror(Res,&Pattern,Error,sizeof(Error));
+      return _error->Error(_("Regex compilation error - %s"),Error);
+   }
    
-   if (!(toupper(C) == *Yes || C == '\n' || C == '\r'))
-      return false;
-   return true;
+   Res = regexec(&Pattern, response, 0, NULL, 0);
+   if (Res == 0)
+      return true;
+   return false;
 }
                                                                        /*}}}*/
 // AnalPrompt - Annoying Yes No Prompt.                                        /*{{{*/
@@ -258,7 +279,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
         // Compute a single dependency element (glob or)
         pkgCache::DepIterator Start;
         pkgCache::DepIterator End;
-        D.GlobOr(Start,End);
+        D.GlobOr(Start,End); // advances D
 
         if (Cache->IsImportantDep(End) == false)
            continue;
@@ -345,7 +366,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
 /* */
 void ShowNew(ostream &out,CacheFile &Cache)
 {
-   /* Print out a list of packages that are going to be removed extra
+   /* Print out a list of packages that are going to be installed extra
       to what the user asked */
    string List;
    string VersionsList;
@@ -406,7 +427,7 @@ void ShowKept(ostream &out,CacheFile &Cache)
       List += string(I.Name()) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
-   ShowList(out,_("The following packages have been kept back"),List,VersionsList);
+   ShowList(out,_("The following packages have been kept back:"),List,VersionsList);
 }
                                                                        /*}}}*/
 // ShowUpgraded - Show upgraded packages                               /*{{{*/
@@ -427,7 +448,7 @@ void ShowUpgraded(ostream &out,CacheFile &Cache)
       List += string(I.Name()) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
-   ShowList(out,_("The following packages will be upgraded"),List,VersionsList);
+   ShowList(out,_("The following packages will be upgraded:"),List,VersionsList);
 }
                                                                        /*}}}*/
 // ShowDowngraded - Show downgraded packages                           /*{{{*/
@@ -448,7 +469,7 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache)
       List += string(I.Name()) + " ";
       VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
    }
-   return ShowList(out,_("The following packages will be DOWNGRADED"),List,VersionsList);
+   return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList);
 }
                                                                        /*}}}*/
 // ShowHold - Show held but changed packages                           /*{{{*/
@@ -529,9 +550,10 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
    }
    
    delete [] Added;
-   return ShowList(out,_("WARNING: The following essential packages will be removed\n"
+   return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
                         "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
 }
+
                                                                        /*}}}*/
 // Stats - Show some statistics                                                /*{{{*/
 // ---------------------------------------------------------------------
@@ -559,7 +581,7 @@ void Stats(ostream &out,pkgDepCache &Dep)
         ReInstall++;
    }   
 
-   ioprintf(out,_("%lu packages upgraded, %lu newly installed, "),
+   ioprintf(out,_("%lu upgraded, %lu newly installed, "),
            Upgrade,Install);
    
    if (ReInstall != 0)
@@ -571,11 +593,10 @@ void Stats(ostream &out,pkgDepCache &Dep)
            Dep.DelCount(),Dep.KeepCount());
    
    if (Dep.BadCount() != 0)
-      ioprintf(out,_("%lu packages not fully installed or removed.\n"),
+      ioprintf(out,_("%lu not fully installed or removed.\n"),
               Dep.BadCount());
 }
                                                                        /*}}}*/
-
 // CacheFile::NameComp - QSort compare by name                         /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -613,23 +634,37 @@ void CacheFile::Sort()
    and verifies that the system is OK. */
 bool CacheFile::CheckDeps(bool AllowBroken)
 {
+   bool FixBroken = _config->FindB("APT::Get::Fix-Broken",false);
+
    if (_error->PendingError() == true)
       return false;
 
    // Check that the system is OK
    if (DCache->DelCount() != 0 || DCache->InstCount() != 0)
-      return _error->Error("Internal Error, non-zero counts");
+      return _error->Error("Internal error, non-zero counts");
    
    // Apply corrections for half-installed packages
    if (pkgApplyStatus(*DCache) == false)
       return false;
    
+   if (_config->FindB("APT::Get::Fix-Policy-Broken",false) == true)
+   {
+      FixBroken = true;
+      if ((DCache->PolicyBrokenCount() > 0))
+      {
+        // upgrade all policy-broken packages with ForceImportantDeps=True
+        for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); I++)
+           if ((*DCache)[I].NowPolicyBroken() == true) 
+              DCache->MarkInstall(I,true,0, false, true);
+      }
+   }
+
    // Nothing is broken
    if (DCache->BrokenCount() == 0 || AllowBroken == true)
       return true;
 
    // Attempt to fix broken things
-   if (_config->FindB("APT::Get::Fix-Broken",false) == true)
+   if (FixBroken == true)
    {
       c1out << _("Correcting dependencies...") << flush;
       if (pkgFixBroken(*DCache) == false || DCache->BrokenCount() != 0)
@@ -655,13 +690,56 @@ bool CacheFile::CheckDeps(bool AllowBroken)
    return true;
 }
                                                                        /*}}}*/
+// CheckAuth - check if each download comes form a trusted source      /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+static bool CheckAuth(pkgAcquire& Fetcher)
+{
+   string UntrustedList;
+   for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd(); ++I)
+   {
+      if (!(*I)->IsTrusted())
+      {
+         UntrustedList += string((*I)->ShortDesc()) + " ";
+      }
+   }
 
+   if (UntrustedList == "")
+   {
+      return true;
+   }
+        
+   ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"),UntrustedList,"");
+
+   if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
+   {
+      c2out << _("Authentication warning overridden.\n");
+      return true;
+   }
+
+   if (_config->FindI("quiet",0) < 2
+       && _config->FindB("APT::Get::Assume-Yes",false) == false)
+   {
+      c2out << _("Install these packages without verification [y/N]? ") << flush;
+      if (!YnPrompt(false))
+         return _error->Error(_("Some packages could not be authenticated"));
+
+      return true;
+   }
+   else if (_config->FindB("APT::Get::Force-Yes",false) == true)
+   {
+      return true;
+   }
+
+   return _error->Error(_("There are problems and -y was used without --force-yes"));
+}
+                                                                       /*}}}*/
 // InstallPackages - Actually download and install the packages                /*{{{*/
 // ---------------------------------------------------------------------
 /* This displays the informative messages describing what is going to 
    happen and then calls the download routines */
 bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
-                    bool Saftey = true)
+                    bool Safety = true)
 {
    if (_config->FindB("APT::Get::Purge",false) == true)
    {
@@ -682,19 +760,19 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
    if (ShwKept == true)
       ShowKept(c1out,Cache);
    Fail |= !ShowHold(c1out,Cache);
-   if (_config->FindB("APT::Get::Show-Upgraded",false) == true)
+   if (_config->FindB("APT::Get::Show-Upgraded",true) == true)
       ShowUpgraded(c1out,Cache);
    Fail |= !ShowDowngraded(c1out,Cache);
    if (_config->FindB("APT::Get::Download-Only",false) == false)
         Essential = !ShowEssential(c1out,Cache);
    Fail |= Essential;
    Stats(c1out,Cache);
-   
+
    // Sanity check
    if (Cache->BrokenCount() != 0)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error("Internal Error, InstallPackages was called with broken packages!");
+      return _error->Error(_("Internal error, InstallPackages was called with broken packages!"));
    }
 
    if (Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
@@ -703,17 +781,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
 
    // No remove flag
    if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false)
-      return _error->Error(_("Packages need to be removed but Remove is disabled."));
+      return _error->Error(_("Packages need to be removed but remove is disabled."));
        
    // Run the simulator ..
    if (_config->FindB("APT::Get::Simulate") == true)
    {
       pkgSimulate PM(Cache);
-      pkgPackageManager::OrderResult Res = PM.DoInstall();
+      int status_fd = _config->FindI("APT::Status-Fd",-1);
+      pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd);
       if (Res == pkgPackageManager::Failed)
         return false;
       if (Res != pkgPackageManager::Completed)
-        return _error->Error("Internal Error, Ordering didn't finish");
+        return _error->Error(_("Internal error, Ordering didn't finish"));
       return true;
    }
    
@@ -754,23 +833,23 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
    if (DebBytes != Cache->DebSize())
    {
       c0out << DebBytes << ',' << Cache->DebSize() << endl;
-      c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl;
+      c0out << _("How odd.. The sizes didn't match, email apt@packages.debian.org") << endl;
    }
    
    // Number of bytes
    if (DebBytes != FetchBytes)
       ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"),
               SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
-   else
+   else if (DebBytes != 0)
       ioprintf(c1out,_("Need to get %sB of archives.\n"),
               SizeToStr(DebBytes).c_str());
 
    // Size delta
    if (Cache->UsrSize() >= 0)
-      ioprintf(c1out,_("After unpacking %sB of additional disk space will be used.\n"),
+      ioprintf(c1out,_("After this operation, %sB of additional disk space will be used.\n"),
               SizeToStr(Cache->UsrSize()).c_str());
    else
-      ioprintf(c1out,_("After unpacking %sB disk space will be freed.\n"),
+      ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"),
               SizeToStr(-1*Cache->UsrSize()).c_str());
 
    if (_error->PendingError() == true)
@@ -784,11 +863,16 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       struct statvfs Buf;
       string OutputDir = _config->FindDir("Dir::Cache::Archives");
       if (statvfs(OutputDir.c_str(),&Buf) != 0)
-        return _error->Errno("statvfs","Couldn't determine free space in %s",
+        return _error->Errno("statvfs",_("Couldn't determine free space in %s"),
                              OutputDir.c_str());
       if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
-        return _error->Error(_("You don't have enough free space in %s."),
-                             OutputDir.c_str());
+      {
+         struct statfs Stat;
+         if (statfs(OutputDir.c_str(),&Stat) != 0 ||
+                        unsigned(Stat.f_type) != RAMFS_MAGIC)
+            return _error->Error(_("You don't have enough free space in %s."),
+                OutputDir.c_str());
+      }
    }
    
    // Fail safe check
@@ -799,14 +883,14 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
         return _error->Error(_("There are problems and -y was used without --force-yes"));
    }         
 
-   if (Essential == true && Saftey == true)
+   if (Essential == true && Safety == true)
    {
       if (_config->FindB("APT::Get::Trivial-Only",false) == true)
         return _error->Error(_("Trivial Only specified but this is not a trivial operation."));
       
       const char *Prompt = _("Yes, do as I say!");
       ioprintf(c2out,
-              _("You are about to do something potentially harmful\n"
+              _("You are about to do something potentially harmful.\n"
                 "To continue type in the phrase '%s'\n"
                 " ?] "),Prompt);
       c2out << flush;
@@ -827,7 +911,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
         if (_config->FindI("quiet",0) < 2 &&
             _config->FindB("APT::Get::Assume-Yes",false) == false)
         {
-           c2out << _("Do you want to continue? [Y/n] ") << flush;
+           c2out << _("Do you want to continue [Y/n]? ") << flush;
         
            if (YnPrompt() == false)
            {
@@ -844,10 +928,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       pkgAcquire::UriIterator I = Fetcher.UriBegin();
       for (; I != Fetcher.UriEnd(); I++)
         cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
-              I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl;
+              I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl;
       return true;
    }
 
+   if (!CheckAuth(Fetcher))
+      return false;
+
    /* Unlock the dpkg lock if we are not going to be doing an install
       after. */
    if (_config->FindB("APT::Get::Download-Only",false) == true)
@@ -931,11 +1018,12 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       if (Failed == true && PM->FixMissing() == false)
       {
         cerr << _("Unable to correct missing packages.") << endl;
-        return _error->Error(_("Aborting Install."));
+        return _error->Error(_("Aborting install."));
       }
-                
+
       _system->UnLock();
-      pkgPackageManager::OrderResult Res = PM->DoInstall();
+      int status_fd = _config->FindI("APT::Status-Fd",-1);
+      pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd);
       if (Res == pkgPackageManager::Failed || _error->PendingError() == true)
         return false;
       if (Res == pkgPackageManager::Completed)
@@ -1025,10 +1113,9 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       else
       {
         ioprintf(c1out,
-        _("Package %s has no available version, but exists in the database.\n"
-          "This typically means that the package was mentioned in a dependency and\n"
-          "never uploaded, has been obsoleted or is not available with the contents\n"
-          "of sources.list\n"),Pkg.Name());
+        _("Package %s is not available, but is referred to by another package.\n"
+          "This may mean that the package is missing, has been obsoleted, or\n"
+           "is only available from another source\n"),Pkg.Name());
         
         string List;
         string VersionsList;
@@ -1083,9 +1170,11 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    else
       ExpectedInst++;
    
-   // Install it with autoinstalling enabled.
-   if (State.InstBroken() == true && BrokenFix == false)
+   // Install it with autoinstalling enabled (if we not respect the minial
+   // required deps or the policy)
+   if ((State.InstBroken() == true || State.InstPolicyBroken() == true) && BrokenFix == false)
       Cache.MarkInstall(Pkg,true);
+
    return true;
 }
                                                                        /*}}}*/
@@ -1130,24 +1219,55 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
    string VerTag;
    string TmpSrc = Name;
    string::size_type Slash = TmpSrc.rfind('=');
+
+   // honor default release
+   string DefRel = _config->Find("APT::Default-Release");
+   pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc);
+
    if (Slash != string::npos)
    {
       VerTag = string(TmpSrc.begin() + Slash + 1,TmpSrc.end());
       TmpSrc = string(TmpSrc.begin(),TmpSrc.begin() + Slash);
+   } 
+   else  if(!Pkg.end() && DefRel.empty() == false)
+   {
+      // we have a default release, try to locate the pkg. we do it like
+      // this because GetCandidateVer() will not "downgrade", that means
+      // "apt-get source -t stable apt" won't work on a unstable system
+      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; 
+          Ver++)
+      {
+        for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false;
+             VF++)
+        {
+           /* If this is the status file, and the current version is not the
+              version in the status file (ie it is not installed, or somesuch)
+              then it is not a candidate for installation, ever. This weeds
+              out bogus entries that may be due to config-file states, or
+              other. */
+           if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 
+               pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver)
+           continue;
+           
+           //std::cout << VF.File().Archive() << std::endl;
+           if(VF.File().Archive() && (VF.File().Archive() == DefRel)) 
+           {
+              VerTag = Ver.VerStr();
+              break;
+           }
+        }
+      }
    }
-   
+
    /* Lookup the version of the package we would install if we were to
       install a version and determine the source package name, then look
-      in the archive for a source package of the same name. In theory
-      we could stash the version string as well and match that too but
-      today there aren't multi source versions in the archive. */
-   if (_config->FindB("APT::Get::Only-Source") == false && 
-       VerTag.empty() == true)
+      in the archive for a source package of the same name. */
+   bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source");
+   if (MatchSrcOnly == false)
    {
-      pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc);
       if (Pkg.end() == false)
       {
-        pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);      
+        pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);
         if (Ver.end() == false)
         {
            pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
@@ -1155,16 +1275,22 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
         }
       }   
    }
-   
-   // No source package name..
-   if (Src.empty() == true)
-      Src = TmpSrc;
-   
+
    // The best hit
    pkgSrcRecords::Parser *Last = 0;
    unsigned long Offset = 0;
    string Version;
    bool IsMatch = false;
+
+   // No source package name..
+   if (Src.empty() == true)
+      Src = TmpSrc;
+   else 
+      // if we have a source pkg name, make sure to only search
+      // for srcpkg names, otherwise apt gets confused if there
+      // is a binary package "pkg1" and a source package "pkg1"
+      // with the same name but that comes from different packages
+      MatchSrcOnly = true;
    
    // If we are matching by version then we need exact matches to be happy
    if (VerTag.empty() == false)
@@ -1174,13 +1300,13 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
       binary packages in the search */
    pkgSrcRecords::Parser *Parse;
    SrcRecs.Restart();
-   while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0)
+   while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0)
    {
       string Ver = Parse->Version();
-      
-      // Skip name mismatches
-      if (IsMatch == true && Parse->Package() != Src)
-        continue;
+
+      // show name mismatches
+      if (IsMatch == true && Parse->Package() != Src)       
+        ioprintf(c1out,  _("No source package '%s' picking '%s' instead\n"), Parse->Package().c_str(), Src.c_str());
       
       if (VerTag.empty() == false)
       {
@@ -1205,16 +1331,12 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
       }      
    }
    
-   if (Last == 0)
-      return 0;
-   
-   if (Last->Jump(Offset) == false)
+   if (Last == 0 || Last->Jump(Offset) == false)
       return 0;
    
    return Last;
 }
                                                                        /*}}}*/
-
 // DoUpdate - Update the package lists                                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -1237,57 +1359,103 @@ bool DoUpdate(CommandLine &CmdL)
         return _error->Error(_("Unable to lock the list directory"));
    }
    
-   // Create the download object
+   // Create the progress
    AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
-   pkgAcquire Fetcher(&Stat);
-
-   // Populate it with the source selection
-   if (List.GetIndexes(&Fetcher) == false)
-        return false;
-   
+      
    // Just print out the uris an exit if the --print-uris flag was used
    if (_config->FindB("APT::Get::Print-URIs") == true)
    {
+      // get a fetcher
+      pkgAcquire Fetcher(&Stat);
+
+      // Populate it with the source selection and get all Indexes 
+      // (GetAll=true)
+      if (List.GetIndexes(&Fetcher,true) == false)
+        return false;
+
       pkgAcquire::UriIterator I = Fetcher.UriBegin();
       for (; I != Fetcher.UriEnd(); I++)
         cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
-              I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl;
+              I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl;
       return true;
    }
-   
-   // Run it
-   if (Fetcher.Run() == pkgAcquire::Failed)
+
+   // do the work
+   CacheFile Cache;
+   if (_config->FindB("APT::Get::Download",true) == true)
+       ListUpdate(Stat, List);
+
+   // Rebuild the cache.   
+   if (Cache.BuildCaches() == false)
       return false;
+   
+   return true;
+}
+                                                                       /*}}}*/
+// DoAutomaticRemove - Remove all automatic unused packages            /*{{{*/
+// ---------------------------------------------------------------------
+/* Remove unused automatic packages */
+bool DoAutomaticRemove(CacheFile &Cache)
+{
+   bool Debug = _config->FindI("Debug::pkgAutoRemove",false);
+   bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false);
+   bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove");
+   pkgDepCache::ActionGroup group(*Cache);
 
-   bool Failed = false;
-   for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+   if(Debug)
+      std::cout << "DoAutomaticRemove()" << std::endl;
+
+   if (_config->FindB("APT::Get::Remove",true) == false &&
+       doAutoRemove == true)
    {
-      if ((*I)->Status == pkgAcquire::Item::StatDone)
-        continue;
+      c1out << _("We are not supposed to delete stuff, can't start "
+                "AutoRemover") << std::endl;
+      doAutoRemove = false;
+   }
 
-      (*I)->Finished();
-      
-      fprintf(stderr,_("Failed to fetch %s  %s\n"),(*I)->DescURI().c_str(),
-             (*I)->ErrorText.c_str());
-      Failed = true;
+   string autoremovelist, autoremoveversions;
+   // look over the cache to see what can be removed
+   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg)
+   {
+      if (Cache[Pkg].Garbage)
+      {
+        if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
+           if(Debug)
+              std::cout << "We could delete %s" <<  Pkg.Name() << std::endl;
+         
+        // only show stuff in the list that is not yet marked for removal
+        if(Cache[Pkg].Delete() == false) 
+        {
+           autoremovelist += string(Pkg.Name()) + " ";
+           autoremoveversions += string(Cache[Pkg].CandVersion) + "\n";
+        }
+        if (doAutoRemove)
+        {
+           if(Pkg.CurrentVer() != 0 && 
+              Pkg->CurrentState != pkgCache::State::ConfigFiles)
+              Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false));
+           else
+              Cache->MarkKeep(Pkg, false, false);
+        }
+      }
    }
-   
-   // Clean out any old list files
-   if (_config->FindB("APT::Get::List-Cleanup",true) == true)
+   if (!hideAutoRemove) 
+      ShowList(c1out, _("The following packages were automatically installed and are no longer required:"), autoremovelist, autoremoveversions);
+   if (!doAutoRemove && !hideAutoRemove && autoremovelist.size() > 0)
+      c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl;
+
+   // Now see if we destroyed anything
+   if (Cache->BrokenCount() != 0)
    {
-      if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
-         Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
-        return false;
+      c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n"
+                "shouldn't happen. Please file a bug report against apt.") << endl;
+      c1out << endl;
+      c1out << _("The following information may help to resolve the situation:") << endl;
+      c1out << endl;
+      ShowBroken(c1out,Cache,false);
+
+      return _error->Error(_("Internal Error, AutoRemover broke stuff"));
    }
-   
-   // Prepare the cache.   
-   CacheFile Cache;
-   if (Cache.BuildCaches() == false)
-      return false;
-   
-   if (Failed == true)
-      return _error->Error(_("Some index files failed to download, they have been ignored, or old ones used instead."));
-   
    return true;
 }
                                                                        /*}}}*/
@@ -1305,12 +1473,67 @@ bool DoUpgrade(CommandLine &CmdL)
    if (pkgAllUpgrade(Cache) == false)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error(_("Internal Error, AllUpgrade broke stuff"));
+      return _error->Error(_("Internal error, AllUpgrade broke stuff"));
    }
    
    return InstallPackages(Cache,true);
 }
                                                                        /*}}}*/
+// DoInstallTask - Install task from the command line                  /*{{{*/
+// ---------------------------------------------------------------------
+/* Install named task */
+bool TryInstallTask(pkgDepCache &Cache, pkgProblemResolver &Fix, 
+                   bool BrokenFix,
+                   unsigned int& ExpectedInst, 
+                   const char *taskname,
+                   bool Remove)
+{
+   const char *start, *end;
+   pkgCache::PkgIterator Pkg;
+   char buf[64*1024];
+   regex_t Pattern;
+
+   // get the records
+   pkgRecords Recs(Cache);
+
+   // build regexp for the task
+   char S[300];
+   snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", taskname);
+   if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0)
+      return _error->Error("Failed to compile task regexp");
+   
+   bool found = false;
+   bool res = true;
+
+   // two runs, first ignore dependencies, second install any missing
+   for(int IgnoreBroken=1; IgnoreBroken >= 0; IgnoreBroken--)
+   {
+      for (Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
+      {
+        pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache);
+        if(ver.end())
+           continue;
+        pkgRecords::Parser &parser = Recs.Lookup(ver.FileList());
+        parser.GetRec(start,end);
+        strncpy(buf, start, end-start);
+        buf[end-start] = 0x0;
+        if (regexec(&Pattern,buf,0,0,0) != 0)
+           continue;
+        res &= TryToInstall(Pkg,Cache,Fix,Remove,IgnoreBroken,ExpectedInst);
+        found = true;
+      }
+   }
+   
+   // now let the problem resolver deal with any issues
+   Fix.Resolve(true);
+
+   if(!found)
+      _error->Error(_("Couldn't find task %s"),taskname);
+
+   regfree(&Pattern);
+   return res;
+}
+                                                                       /*}}}*/
 // DoInstall - Install packages from the command line                  /*{{{*/
 // ---------------------------------------------------------------------
 /* Install named packages */
@@ -1326,6 +1549,7 @@ bool DoInstall(CommandLine &CmdL)
    if (Cache->BrokenCount() != 0)
       BrokenFix = true;
    
+   unsigned int AutoMarkChanged = 0;
    unsigned int ExpectedInst = 0;
    unsigned int Packages = 0;
    pkgProblemResolver Fix(Cache);
@@ -1333,155 +1557,198 @@ bool DoInstall(CommandLine &CmdL)
    bool DefRemove = false;
    if (strcasecmp(CmdL.FileList[0],"remove") == 0)
       DefRemove = true;
-
-   for (const char **I = CmdL.FileList + 1; *I != 0; I++)
+   else if (strcasecmp(CmdL.FileList[0], "purge") == 0)
    {
-      // Duplicate the string
-      unsigned int Length = strlen(*I);
-      char S[300];
-      if (Length >= sizeof(S))
-        continue;
-      strcpy(S,*I);
-      
-      // See if we are removing and special indicators..
-      bool Remove = DefRemove;
-      char *VerTag = 0;
-      bool VerIsRel = false;
-      while (Cache->FindPkg(S).end() == true)
+      _config->Set("APT::Get::Purge", true);
+      DefRemove = true;
+   }
+   else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0)
+   {
+      _config->Set("APT::Get::AutomaticRemove", "true");
+      DefRemove = true;
+   }
+   // new scope for the ActionGroup
+   {
+      pkgDepCache::ActionGroup group(Cache);
+      for (const char **I = CmdL.FileList + 1; *I != 0; I++)
       {
-        // Handle an optional end tag indicating what to do
-        if (Length >= 1 && S[Length - 1] == '-')
-        {
-           Remove = true;
-           S[--Length] = 0;
+        // Duplicate the string
+        unsigned int Length = strlen(*I);
+        char S[300];
+        if (Length >= sizeof(S))
            continue;
-        }
-        
-        if (Length >= 1 && S[Length - 1] == '+')
+        strcpy(S,*I);
+      
+        // See if we are removing and special indicators..
+        bool Remove = DefRemove;
+        char *VerTag = 0;
+        bool VerIsRel = false;
+
+         // this is a task!
+         if (Length >= 1 && S[Length - 1] == '^')
+         {
+            S[--Length] = 0;
+            // tasks must always be confirmed
+            ExpectedInst += 1000;
+            // see if we can install it
+            TryInstallTask(Cache, Fix, BrokenFix, ExpectedInst, S, Remove);
+            continue;
+         }
+
+        while (Cache->FindPkg(S).end() == true)
         {
-           Remove = false;
-           S[--Length] = 0;
-           continue;
-        }
+           // Handle an optional end tag indicating what to do
+           if (Length >= 1 && S[Length - 1] == '-')
+           {
+              Remove = true;
+              S[--Length] = 0;
+              continue;
+           }
         
-        char *Slash = strchr(S,'=');
-        if (Slash != 0)
-        {
-           VerIsRel = false;
-           *Slash = 0;
-           VerTag = Slash + 1;
-        }
+           if (Length >= 1 && S[Length - 1] == '+')
+           {
+              Remove = false;
+              S[--Length] = 0;
+              continue;
+           }
         
-        Slash = strchr(S,'/');
-        if (Slash != 0)
-        {
-           VerIsRel = true;
-           *Slash = 0;
-           VerTag = Slash + 1;
-        }
+           char *Slash = strchr(S,'=');
+           if (Slash != 0)
+           {
+              VerIsRel = false;
+              *Slash = 0;
+              VerTag = Slash + 1;
+           }
         
-        break;
-      }
-      
-      // Locate the package
-      pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
-      Packages++;
-      if (Pkg.end() == true)
-      {
-        // Check if the name is a regex
-        const char *I;
-        for (I = S; *I != 0; I++)
-           if (*I == '?' || *I == '*' || *I == '|' ||
-               *I == '[' || *I == '^' || *I == '$')
-              break;
-        if (*I == 0)
-           return _error->Error(_("Couldn't find package %s"),S);
-
-        // Regexs must always be confirmed
-        ExpectedInst += 1000;
+           Slash = strchr(S,'/');
+           if (Slash != 0)
+           {
+              VerIsRel = true;
+              *Slash = 0;
+              VerTag = Slash + 1;
+           }
         
-        // Compile the regex pattern
-        regex_t Pattern;
-        int Res;
-        if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
-                    REG_NOSUB)) != 0)
-        {
-           char Error[300];        
-           regerror(Res,&Pattern,Error,sizeof(Error));
-           return _error->Error(_("Regex compilation error - %s"),Error);
+           break;
         }
-        
-        // Run over the matches
-        bool Hit = false;
-        for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+      
+        // Locate the package
+        pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
+        Packages++;
+        if (Pkg.end() == true)
         {
-           if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
-              continue;
+           // Check if the name is a regex
+           const char *I;
+           for (I = S; *I != 0; I++)
+              if (*I == '?' || *I == '*' || *I == '|' ||
+                  *I == '[' || *I == '^' || *I == '$')
+                 break;
+           if (*I == 0)
+              return _error->Error(_("Couldn't find package %s"),S);
+
+           // Regexs must always be confirmed
+           ExpectedInst += 1000;
+        
+           // Compile the regex pattern
+           regex_t Pattern;
+           int Res;
+           if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
+                              REG_NOSUB)) != 0)
+           {
+              char Error[300];     
+              regerror(Res,&Pattern,Error,sizeof(Error));
+              return _error->Error(_("Regex compilation error - %s"),Error);
+           }
+        
+           // Run over the matches
+           bool Hit = false;
+           for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+           {
+              if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
+                 continue;
+           
+              ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
+                       Pkg.Name(),S);
            
-           ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
-                    Pkg.Name(),S);
+              if (VerTag != 0)
+                 if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
+                    return false;
            
+              Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
+                                  ExpectedInst,false);
+           }
+           regfree(&Pattern);
+        
+           if (Hit == false)
+              return _error->Error(_("Couldn't find package %s"),S);
+        }
+        else
+        {
            if (VerTag != 0)
               if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
                  return false;
-           
-           Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
-                               ExpectedInst,false);
-        }
-        regfree(&Pattern);
-        
-        if (Hit == false)
-           return _error->Error(_("Couldn't find package %s"),S);
-      }
-      else
-      {
-        if (VerTag != 0)
-           if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
+           if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
               return false;
-        if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
-           return false;
-      }      
-   }
 
-   /* If we are in the Broken fixing mode we do not attempt to fix the
-      problems. This is if the user invoked install without -f and gave
-      packages */
-   if (BrokenFix == true && Cache->BrokenCount() != 0)
-   {
-      c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
-      ShowBroken(c1out,Cache,false);
+           // see if we need to fix the auto-mark flag 
+           // e.g. apt-get install foo 
+           // where foo is marked automatic
+           if(!Remove && 
+              Cache[Pkg].Install() == false && 
+              (Cache[Pkg].Flags & pkgCache::Flag::Auto) &&
+              _config->FindB("APT::Get::ReInstall",false) == false)
+           {
+              ioprintf(c1out,_("%s set to manually installed.\n"),
+                       Pkg.Name());
+              Cache->MarkAuto(Pkg,false);
+              AutoMarkChanged++;
+           }
+        }      
+      }
 
-      return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
-   }
+      /* If we are in the Broken fixing mode we do not attempt to fix the
+        problems. This is if the user invoked install without -f and gave
+        packages */
+      if (BrokenFix == true && Cache->BrokenCount() != 0)
+      {
+        c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
+        ShowBroken(c1out,Cache,false);
+
+        return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
+      }
    
-   // Call the scored problem resolver
-   Fix.InstallProtect();
-   if (Fix.Resolve(true) == false)
-      _error->Discard();
+      // Call the scored problem resolver
+      Fix.InstallProtect();
+      if (Fix.Resolve(true) == false)
+        _error->Discard();
 
-   // Now we check the state of the packages,
-   if (Cache->BrokenCount() != 0)
-   {
-      c1out << 
-       _("Some packages could not be installed. This may mean that you have\n" 
-        "requested an impossible situation or if you are using the unstable\n" 
-        "distribution that some required packages have not yet been created\n"
-        "or been moved out of Incoming.") << endl;
-      if (Packages == 1)
+      // Now we check the state of the packages,
+      if (Cache->BrokenCount() != 0)
       {
-        c1out << endl;
         c1out << 
-         _("Since you only requested a single operation it is extremely likely that\n"
-           "the package is simply not installable and a bug report against\n" 
-           "that package should be filed.") << endl;
-      }
+           _("Some packages could not be installed. This may mean that you have\n" 
+             "requested an impossible situation or if you are using the unstable\n" 
+             "distribution that some required packages have not yet been created\n"
+             "or been moved out of Incoming.") << endl;
+        /*
+        if (Packages == 1)
+        {
+           c1out << endl;
+           c1out << 
+              _("Since you only requested a single operation it is extremely likely that\n"
+                "the package is simply not installable and a bug report against\n" 
+                "that package should be filed.") << endl;
+        }
+        */
+
+        c1out << _("The following information may help to resolve the situation:") << endl;
+        c1out << endl;
+        ShowBroken(c1out,Cache,false);
+        return _error->Error(_("Broken packages"));
+      }   
+   }
+   if (!DoAutomaticRemove(Cache)) 
+      return false;
 
-      c1out << _("The following information may help to resolve the situation:") << endl;
-      c1out << endl;
-      ShowBroken(c1out,Cache,false);
-      return _error->Error(_("Broken packages"));
-   }   
-   
    /* Print out a list of packages that are going to be installed extra
       to what the user asked */
    if (Cache->InstCount() != ExpectedInst)
@@ -1501,8 +1768,8 @@ bool DoInstall(CommandLine &CmdL)
         
         if (*J == 0) {
            List += string(I.Name()) + " ";
-        VersionsList += string(Cache[I].CandVersion) + "\n";
-     }
+           VersionsList += string(Cache[I].CandVersion) + "\n";
+        }
       }
       
       ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList);
@@ -1514,86 +1781,104 @@ bool DoInstall(CommandLine &CmdL)
       string SuggestsVersions, RecommendsVersions;
       for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
       {
-        pkgCache::PkgIterator I(Cache,Cache.List[J]);
+        pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
 
         /* Just look at the ones we want to install */
-        if ((*Cache)[I].Install() == false)
+        if ((*Cache)[Pkg].Install() == false)
           continue;
 
-        for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)
-          {
-            for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
+        // get the recommends/suggests for the candidate ver
+        pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+        for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; )
+        {
+           pkgCache::DepIterator Start;
+           pkgCache::DepIterator End;
+           D.GlobOr(Start,End); // advances D
+
+           // FIXME: we really should display a or-group as a or-group to the user
+           //        the problem is that ShowList is incapable of doing this
+           string RecommendsOrList,RecommendsOrVersions;
+           string SuggestsOrList,SuggestsOrVersions;
+           bool foundInstalledInOrGroup = false;
+           for(;;)
+           {
+              /* Skip if package is  installed already, or is about to be */
+              string target = string(Start.TargetPkg().Name()) + " ";
+              
+              if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
+                  || Cache[Start.TargetPkg()].Install())
               {
-                pkgCache::DepIterator Start;
-                pkgCache::DepIterator End;
-                D.GlobOr(Start,End);
-
-                /* 
-                 * If this is a virtual package, we need to check the list of
-                 * packages that provide it and see if any of those are
-                 * installed
-                 */
-                pkgCache::PrvIterator Prv = Start.TargetPkg().ProvidesList();
-                bool providedBySomething = false;
-                for (; Prv.end() != true; Prv++)
-                   if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) {
-                      providedBySomething = true;
-                      break;
-                   }
-
-                if (providedBySomething) continue;
-            
-                do
-                  {
-                    if (Start->Type == pkgCache::Dep::Suggests) {
-
-                      /* A suggests relations, let's see if we have it 
-                         installed already */
-
-                      string target = string(Start.TargetPkg().Name()) + " ";
-                      if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install || Cache[Start.TargetPkg()].Install())
-                        break;
-                      /* Does another package suggest it as well?  If so,
-                         don't print it twice */
-                      if (int(SuggestsList.find(target)) > -1)
-                        break; 
-                      SuggestsList += target;
-                      SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
-                    }
-                    
-                    if (Start->Type == pkgCache::Dep::Recommends) {
-
-                      /* A recommends relation, let's see if we have it
-                         installed already */
-
-                      string target = string(Start.TargetPkg().Name()) + " ";
-                      if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install || Cache[Start.TargetPkg()].Install())
-                        break;
-                      
-                      /* Does another package recommend it as well?  If so,
-                         don't print it twice */
-
-                      if (int(RecommendsList.find(target)) > -1)
-                        break;
-                      RecommendsList += target;
-                      SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
-                    }
-             if (Start == End)
-               break;
-             Start++;
-           } while (1);
+                 foundInstalledInOrGroup=true;
+                 break;
+              }
+
+              /* Skip if we already saw it */
+              if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
+              {
+                 foundInstalledInOrGroup=true;
+                 break; 
+              }
+
+              // this is a dep on a virtual pkg, check if any package that provides it
+              // should be installed
+              if(Start.TargetPkg().ProvidesList() != 0)
+              {
+                 pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList();
+                 for (; I.end() == false; I++)
+                 {
+                    pkgCache::PkgIterator Pkg = I.OwnerPkg();
+                    if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && 
+                        Pkg.CurrentVer() != 0)
+                       foundInstalledInOrGroup=true;
+                 }
+              }
+
+              if (Start->Type == pkgCache::Dep::Suggests) 
+              {
+                 SuggestsOrList += target;
+                 SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+              }
+              
+              if (Start->Type == pkgCache::Dep::Recommends) 
+              {
+                 RecommendsOrList += target;
+                 RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
               }
-          }
+
+              if (Start >= End)
+                 break;
+              Start++;
+           }
+           
+           if(foundInstalledInOrGroup == false)
+           {
+              RecommendsList += RecommendsOrList;
+              RecommendsVersions += RecommendsOrVersions;
+              SuggestsList += SuggestsOrList;
+              SuggestsVersions += SuggestsOrVersions;
+           }
+              
+        }
       }
+
       ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions);
       ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions);
 
    }
 
+   // if nothing changed in the cache, but only the automark information
+   // we write the StateFile here, otherwise it will be written in 
+   // cache.commit()
+   if (AutoMarkChanged > 0 &&
+       Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
+       Cache->BadCount() == 0 &&
+       _config->FindB("APT::Get::Simulate",false) == false)
+      Cache->writeStateFile(NULL);
+
    // See if we need to prompt
    if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0)
       return InstallPackages(Cache,false,false);
-   
+
    return InstallPackages(Cache,false);   
 }
                                                                        /*}}}*/
@@ -1606,7 +1891,7 @@ bool DoDistUpgrade(CommandLine &CmdL)
    if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
       return false;
 
-   c0out << _("Calculating Upgrade... ") << flush;
+   c0out << _("Calculating upgrade... ") << flush;
    if (pkgDistUpgrade(*Cache) == false)
    {
       c0out << _("Failed") << endl;
@@ -1628,6 +1913,8 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
       return false;
    
+   pkgDepCache::ActionGroup group(Cache);
+
    // Install everything with the install flag set
    pkgCache::PkgIterator I = Cache->PkgBegin();
    for (;I.end() != true; I++)
@@ -1679,7 +1966,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
       if (Fix.Resolve() == false)
       {
         ShowBroken(c1out,Cache,false);
-        return _error->Error("Internal Error, problem resolver broke stuff");
+        return _error->Error(_("Internal error, problem resolver broke stuff"));
       }
    }
 
@@ -1687,7 +1974,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    if (pkgAllUpgrade(Cache) == false)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error("Internal Error, problem resolver broke stuff");
+      return _error->Error(_("Internal error, problem resolver broke stuff"));
    }
    
    return InstallPackages(Cache,false);
@@ -1806,6 +2093,9 @@ bool DoSource(CommandLine &CmdL)
 
    DscFile *Dsc = new DscFile[CmdL.FileSize()];
    
+   // insert all downloaded uris into this set to avoid downloading them
+   // twice
+   set<string> queued;
    // Load the requestd sources into the fetcher
    unsigned J = 0;
    for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
@@ -1842,7 +2132,33 @@ bool DoSource(CommandLine &CmdL)
         if (_config->FindB("APT::Get::Tar-Only",false) == true &&
             I->Type != "tar")
            continue;
-        
+
+        // Dsc only mode only fetches .dsc files
+        if (_config->FindB("APT::Get::Dsc-Only",false) == true &&
+            I->Type != "dsc")
+           continue;
+
+        // don't download the same uri twice (should this be moved to
+        // the fetcher interface itself?)
+        if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
+           continue;
+        queued.insert(Last->Index().ArchiveURI(I->Path));
+           
+        // check if we have a file with that md5 sum already localy
+        if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path)))  
+        {
+           FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly);
+           MD5Summation sum;
+           sum.AddFD(Fd.Fd(), Fd.Size());
+           Fd.Close();
+           if((string)sum.Result() == I->MD5Hash) 
+           {
+              ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
+                       flNotDir(I->Path).c_str());
+              continue;
+           }
+        }
+
         new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
                        I->MD5Hash,I->Size,
                        Last->Index().SourceInfo(*Last,*I),Src);
@@ -1858,11 +2174,16 @@ bool DoSource(CommandLine &CmdL)
    struct statvfs Buf;
    string OutputDir = ".";
    if (statvfs(OutputDir.c_str(),&Buf) != 0)
-      return _error->Errno("statvfs","Couldn't determine free space in %s",
+      return _error->Errno("statvfs",_("Couldn't determine free space in %s"),
                           OutputDir.c_str());
    if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
-      return _error->Error(_("You don't have enough free space in %s"),
-                          OutputDir.c_str());
+     {
+       struct statfs Stat;
+       if (statfs(OutputDir.c_str(),&Stat) != 0 || 
+           unsigned(Stat.f_type) != RAMFS_MAGIC) 
+          return _error->Error(_("You don't have enough free space in %s"),
+              OutputDir.c_str());
+      }
    
    // Number of bytes
    if (DebBytes != FetchBytes)
@@ -1875,7 +2196,7 @@ bool DoSource(CommandLine &CmdL)
    if (_config->FindB("APT::Get::Simulate",false) == true)
    {
       for (unsigned I = 0; I != J; I++)
-        ioprintf(cout,_("Fetch Source %s\n"),Dsc[I].Package.c_str());
+        ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
       return true;
    }
    
@@ -1885,7 +2206,7 @@ bool DoSource(CommandLine &CmdL)
       pkgAcquire::UriIterator I = Fetcher.UriBegin();
       for (; I != Fetcher.UriEnd(); I++)
         cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
-              I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl;
+              I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl;
       return true;
    }
    
@@ -1947,6 +2268,7 @@ bool DoSource(CommandLine &CmdL)
            if (system(S) != 0)
            {
               fprintf(stderr,_("Unpack command '%s' failed.\n"),S);
+              fprintf(stderr,_("Check if the 'dpkg-dev' package is installed.\n"));
               _exit(1);
            }       
         }
@@ -2041,7 +2363,7 @@ bool DoBuildDep(CommandLine &CmdL)
         rec.Package = Opts->Value;
         rec.Type = pkgSrcRecords::Parser::BuildDependIndep;
         rec.Op = 0;
-        BuildDeps.insert(BuildDeps.begin(), rec);
+        BuildDeps.push_back(rec);
       }
 
       if (BuildDeps.size() == 0)
@@ -2054,8 +2376,18 @@ bool DoBuildDep(CommandLine &CmdL)
       unsigned int ExpectedInst = 0;
       vector <pkgSrcRecords::Parser::BuildDepRec>::iterator D;
       pkgProblemResolver Fix(Cache);
+      bool skipAlternatives = false; // skip remaining alternatives in an or group
       for (D = BuildDeps.begin(); D != BuildDeps.end(); D++)
       {
+         bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or);
+
+         if (skipAlternatives == true)
+         {
+            if (!hasAlternatives)
+               skipAlternatives = false; // end of or group
+            continue;
+         }
+
          if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
             (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
          {
@@ -2077,16 +2409,21 @@ bool DoBuildDep(CommandLine &CmdL)
         else // BuildDep || BuildDepIndep
          {
            pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+            if (_config->FindB("Debug::BuildDeps",false) == true)
+                 cout << "Looking for " << (*D).Package << "...\n";
+
            if (Pkg.end() == true)
             {
-               // Check if there are any alternatives
-               if (((*D).Op & pkgCache::Dep::Or) != pkgCache::Dep::Or)
-                 return _error->Error(_("%s dependency for %s cannot be satisfied "
-                                         "because the package %s cannot be found"),
-                                        Last->BuildDepType((*D).Type),Src.c_str(),
-                                         (*D).Package.c_str());
-               // Try the next alternative
-               continue;
+               if (_config->FindB("Debug::BuildDeps",false) == true)
+                    cout << " (not found)" << (*D).Package << endl;
+
+               if (hasAlternatives)
+                  continue;
+
+               return _error->Error(_("%s dependency for %s cannot be satisfied "
+                                      "because the package %s cannot be found"),
+                                    Last->BuildDepType((*D).Type),Src.c_str(),
+                                    (*D).Package.c_str());
             }
 
             /*
@@ -2099,9 +2436,6 @@ bool DoBuildDep(CommandLine &CmdL)
              * this would require we do a Resolve cycle for each package we 
              * add to the install list. Ugh
              */
-            while (D != BuildDeps.end() && 
-                   (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or))
-               D++;
                        
            /* 
             * If this is a virtual package, we need to check the list of
@@ -2109,9 +2443,11 @@ bool DoBuildDep(CommandLine &CmdL)
             * installed
             */
             pkgCache::PrvIterator Prv = Pkg.ProvidesList();
-           bool providedBySomething = !Prv.end();
             for (; Prv.end() != true; Prv++)
            {
+               if (_config->FindB("Debug::BuildDeps",false) == true)
+                    cout << "  Checking provider " << Prv.OwnerPkg().Name() << endl;
+
               if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
                  break;
             }
@@ -2119,9 +2455,8 @@ bool DoBuildDep(CommandLine &CmdL)
             // Get installed version and version we are going to install
            pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
 
-            if (!providedBySomething || (*D).Version[0] != '\0') {
-                 /* We either have a versioned dependency (so a provides won't do)
-                    or nothing is providing this package */
+            if ((*D).Version[0] != '\0') {
+                 // Versioned dependency
 
                  pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
 
@@ -2131,25 +2466,81 @@ bool DoBuildDep(CommandLine &CmdL)
                            break;
                  }
                  if (CV.end() == true)
+                {
+                  if (hasAlternatives)
+                  {
+                     continue;
+                  }
+                  else
+                  {
                       return _error->Error(_("%s dependency for %s cannot be satisfied "
                                              "because no available versions of package %s "
                                              "can satisfy version requirements"),
                                            Last->BuildDepType((*D).Type),Src.c_str(),
                                            (*D).Package.c_str());
+                  }
+                }
+            }
+            else
+            {
+               // Only consider virtual packages if there is no versioned dependency
+               if (Prv.end() == false)
+               {
+                  if (_config->FindB("Debug::BuildDeps",false) == true)
+                     cout << "  Is provided by installed package " << Prv.OwnerPkg().Name() << endl;
+                  skipAlternatives = hasAlternatives;
+                  continue;
+               }
             }
 
-            /*
-            * TODO: if we depend on a version lower than what we already have 
-            * installed it is not clear what should be done; in practice
-            * this case should be rare, and right now nothing is 
-             * done about it :-( 
-            */
-           if (Prv.end() == true && // Nothing provides it; and
-                (IV.end() == true || //  It is not installed, or
-                Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false))
-                                     //  the version installed doesn't 
-                                     //  satisfy constraints 
-              TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst);
+            if (IV.end() == false)
+            {
+               if (_config->FindB("Debug::BuildDeps",false) == true)
+                  cout << "  Is installed\n";
+
+               if (Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+               {
+                  skipAlternatives = hasAlternatives;
+                  continue;
+               }
+
+               if (_config->FindB("Debug::BuildDeps",false) == true)
+                  cout << "    ...but the installed version doesn't meet the version requirement\n";
+
+               if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
+               {
+                  return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
+                                       Last->BuildDepType((*D).Type),
+                                       Src.c_str(),
+                                       Pkg.Name());
+               }
+            }
+
+
+            if (_config->FindB("Debug::BuildDeps",false) == true)
+               cout << "  Trying to install " << (*D).Package << endl;
+
+            if (TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst) == true)
+            {
+               // We successfully installed something; skip remaining alternatives
+               skipAlternatives = hasAlternatives;
+              if(_config->FindB("APT::Get::Build-Dep-Automatic", false) == true)
+                 Cache->MarkAuto(Pkg, true);
+               continue;
+            }
+            else if (hasAlternatives)
+            {
+               if (_config->FindB("Debug::BuildDeps",false) == true)
+                  cout << "  Unsatisfiable, trying alternatives\n";
+               continue;
+            }
+            else
+            {
+               return _error->Error(_("Failed to satisfy %s dependency for %s: %s"),
+                                    Last->BuildDepType((*D).Type),
+                                    Src.c_str(),
+                                    (*D).Package.c_str());
+            }
         }             
       }
       
@@ -2159,8 +2550,7 @@ bool DoBuildDep(CommandLine &CmdL)
       
       // Now we check the state of the packages,
       if (Cache->BrokenCount() != 0)
-        return _error->Error(_("Some broken packages were found while trying to process build-dependencies.\n"
-                               "You might want to run `apt-get -f install' to correct these."));
+         return _error->Error(_("Build-dependencies for %s could not be satisfied."),*I);
    }
   
    if (InstallPackages(Cache, false, true) == false)
@@ -2191,12 +2581,12 @@ bool DoMoo(CommandLine &CmdL)
 /* */
 bool ShowHelp(CommandLine &CmdL)
 {
-   ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
-           COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
+   ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,VERSION,
+           COMMON_ARCH,__DATE__,__TIME__);
            
    if (_config->FindB("version") == true)
    {
-      cout << _("Supported Modules:") << endl;
+      cout << _("Supported modules:") << endl;
       
       for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++)
       {
@@ -2250,6 +2640,8 @@ bool ShowHelp(CommandLine &CmdL)
       "   upgrade - Perform an upgrade\n"
       "   install - Install new packages (pkg is libc6 not libc6.deb)\n"
       "   remove - Remove packages\n"
+      "   autoremove - Remove automatically all unused packages\n"
+      "   purge - Remove packages and config files\n"
       "   source - Download source archives\n"
       "   build-dep - Configure build-dependencies for source packages\n"
       "   dist-upgrade - Distribution upgrade, see apt-get(8)\n"
@@ -2265,13 +2657,13 @@ bool ShowHelp(CommandLine &CmdL)
       "  -d  Download only - do NOT install or unpack archives\n"
       "  -s  No-act. Perform ordering simulation\n"
       "  -y  Assume Yes to all queries and do not prompt\n"
-      "  -f  Attempt to continue if the integrity check fails\n"
+      "  -f  Attempt to correct a system with broken dependencies in place\n"
       "  -m  Attempt to continue if archives are unlocatable\n"
       "  -u  Show a list of upgraded packages as well\n"
       "  -b  Build the source package after fetching it\n"
       "  -V  Show verbose version numbers\n"
       "  -c=? Read this configuration file\n"
-      "  -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
+      "  -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
       "See the apt-get(8), sources.list(5) and apt.conf(5) manual\n"
       "pages for more information and options.\n"
       "                       This APT has Super Cow Powers.\n");
@@ -2290,7 +2682,8 @@ void GetInitialize()
    _config->Set("APT::Get::Assume-Yes",false);
    _config->Set("APT::Get::Fix-Broken",false);
    _config->Set("APT::Get::Force-Yes",false);
-   _config->Set("APT::Get::APT::Get::No-List-Cleanup",true);
+   _config->Set("APT::Get::List-Cleanup",true);
+   _config->Set("APT::Get::AutomaticRemove",false);
 }
                                                                        /*}}}*/
 // SigWinch - Window size change signal handler                                /*{{{*/
@@ -2307,8 +2700,7 @@ void SigWinch(int)
 #endif
 }
                                                                        /*}}}*/
-
-int main(int argc,const char *argv[])
+int main(int argc,const char *argv[])                                  /*{{{*/
 {
    CommandLine::Args Args[] = {
       {'h',"help","help",0},
@@ -2338,7 +2730,8 @@ int main(int argc,const char *argv[])
       {0,"force-yes","APT::Get::force-yes",0},
       {0,"print-uris","APT::Get::Print-URIs",0},
       {0,"diff-only","APT::Get::Diff-Only",0},
-      {0,"tar-only","APT::Get::tar-Only",0},
+      {0,"tar-only","APT::Get::Tar-Only",0},
+      {0,"dsc-only","APT::Get::Dsc-Only",0},
       {0,"purge","APT::Get::Purge",0},
       {0,"list-cleanup","APT::Get::List-Cleanup",0},
       {0,"reinstall","APT::Get::ReInstall",0},
@@ -2346,6 +2739,10 @@ int main(int argc,const char *argv[])
       {0,"remove","APT::Get::Remove",0},
       {0,"only-source","APT::Get::Only-Source",0},
       {0,"arch-only","APT::Get::Arch-Only",0},
+      {0,"auto-remove","APT::Get::AutomaticRemove",0},
+      {0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0},
+      {0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean},
+      {0,"fix-policy","APT::Get::Fix-Policy-Broken",0},
       {'c',"config-file",0,CommandLine::ConfigFile},
       {'o',"option",0,CommandLine::ArbItem},
       {0,0,0,0}};
@@ -2353,6 +2750,9 @@ int main(int argc,const char *argv[])
                                    {"upgrade",&DoUpgrade},
                                    {"install",&DoInstall},
                                    {"remove",&DoInstall},
+                                   {"purge",&DoInstall},
+                                  {"autoremove",&DoInstall},
+                                  {"purge",&DoInstall},
                                    {"dist-upgrade",&DoDistUpgrade},
                                    {"dselect-upgrade",&DoDSelectUpgrade},
                                   {"build-dep",&DoBuildDep},
@@ -2389,9 +2789,21 @@ int main(int argc,const char *argv[])
       ShowHelp(CmdL);
       return 0;
    }
-   
+
+   // simulate user-friendly if apt-get has no root privileges
+   if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true)
+   {
+      if (_config->FindB("APT::Get::Show-User-Simulation-Note",true) == true)
+        cout << _("NOTE: This is only a simulation!\n"
+           "      apt-get needs root privileges for real execution.\n"
+           "      Keep also in mind that locking is deactivated,\n"
+           "      so don't depend on the relevance to the real current situation!"
+        ) << std::endl;
+      _config->Set("Debug::NoLocking",true);
+   }
+
    // Deal with stdout not being a tty
-   if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
+   if (!isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1)
       _config->Set("quiet","1");
 
    // Setup the output streams
@@ -2421,3 +2833,4 @@ int main(int argc,const char *argv[])
    
    return 0;   
 }
+                                                                       /*}}}*/