Otavio Salvador лет назад: 21
Родитель
Сommit
a52f938bcf

+ 29 - 0
apt-pkg/acquire-item.cc

@@ -307,6 +307,35 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
    Mode = decompProg;
    Mode = decompProg;
 }
 }
 
 
+// AcqIndexTrans::pkgAcqIndexTrans - Constructor			/*{{{*/
+// ---------------------------------------------------------------------
+/* The Translation file is added to the queue */
+pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
+			    string URI,string URIDesc,string ShortDesc) :
+                      pkgAcqIndex(Owner, URI, URIDesc, ShortDesc)
+{
+}
+
+									/*}}}*/
+// AcqIndexTrans::Failed - Silence failure messages for missing files	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+   if (Cnf->LocalOnly == true || 
+       StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
+   {      
+      // Ignore this
+      Status = StatDone;
+      Complete = false;
+      Dequeue();
+      return;
+   }
+   
+   Item::Failed(Message,Cnf);
+}
+									/*}}}*/
+
 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
 			     string URI,string URIDesc,string ShortDesc,
 			     string URI,string URIDesc,string ShortDesc,
 			     string MetaIndexURI, string MetaIndexURIDesc,
 			     string MetaIndexURI, string MetaIndexURIDesc,

+ 12 - 2
apt-pkg/acquire-item.h

@@ -9,8 +9,8 @@
    the Owner Acquire class. Derived classes will then call QueueURI to 
    the Owner Acquire class. Derived classes will then call QueueURI to 
    register all the URI's they wish to fetch at the initial moment.   
    register all the URI's they wish to fetch at the initial moment.   
    
    
-   Two item classes are provided to provide functionality for downloading
-   of Index files and downloading of Packages.
+   Tree item classes are provided to provide functionality for
+   downloading of Index, Translation and Packages files.
    
    
    A Archive class is provided for downloading .deb files. It does Md5
    A Archive class is provided for downloading .deb files. It does Md5
    checking and source location as well as a retry algorithm.
    checking and source location as well as a retry algorithm.
@@ -106,6 +106,16 @@ class pkgAcqIndex : public pkgAcquire::Item
 	       string ShortDesct, string ExpectedMD5, string compressExt="");
 	       string ShortDesct, string ExpectedMD5, string compressExt="");
 };
 };
 
 
+// Item class for index files
+class pkgAcqIndexTrans : public pkgAcqIndex
+{
+   public:
+  
+   virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
+   pkgAcqIndexTrans(pkgAcquire *Owner,string URI,string URIDesc,
+		    string ShortDesct);
+};
+
 struct IndexTarget
 struct IndexTarget
 {
 {
    string URI;
    string URI;

+ 81 - 0
apt-pkg/cacheiterators.h

@@ -128,6 +128,7 @@ class pkgCache::VerIterator
    inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
    inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;};
    inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
    inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
    inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
    inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
+   inline DescIterator DescriptionList() const;
    inline DepIterator DependsList() const;
    inline DepIterator DependsList() const;
    inline PrvIterator ProvidesList() const;
    inline PrvIterator ProvidesList() const;
    inline VerFileIterator FileList() const;
    inline VerFileIterator FileList() const;
@@ -148,6 +149,50 @@ class pkgCache::VerIterator
    };
    };
 };
 };
 
 
+// Description Iterator
+class pkgCache::DescIterator
+{
+   Description *Desc;
+   pkgCache *Owner;
+   
+   void _dummy();
+   
+   public:
+
+   // Iteration
+   void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
+   inline void operator ++() {operator ++(0);};
+   inline bool end() const {return Desc == Owner->DescP?true:false;};
+   inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
+   
+   // Comparison
+   inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
+   inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
+   int CompareDesc(const DescIterator &B) const;
+   
+   // Accessors
+   inline Description *operator ->() {return Desc;};
+   inline Description const *operator ->() const {return Desc;};
+   inline Description &operator *() {return *Desc;};
+   inline Description const &operator *() const {return *Desc;};
+   inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
+   inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
+   inline pkgCache *Cache() {return Owner;};
+      
+   inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
+   inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
+   inline DescFileIterator FileList() const;
+   inline unsigned long Index() const {return Desc - Owner->DescP;};
+
+   inline DescIterator() : Desc(0), Owner(0) {};   
+   inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg), 
+              Owner(&Owner) 
+   { 
+      if (Desc == 0)
+	 Desc = Owner.DescP;
+   };
+};
+
 // Dependency iterator
 // Dependency iterator
 class pkgCache::DepIterator
 class pkgCache::DepIterator
 {
 {
@@ -336,6 +381,38 @@ class pkgCache::VerFileIterator
    inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
    inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
 };
 };
 
 
+// Description File 
+class pkgCache::DescFileIterator
+{
+   pkgCache *Owner;
+   DescFile *FileP;
+
+   public:
+
+   // Iteration
+   void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
+   inline void operator ++() {operator ++(0);};
+   inline bool end() const {return FileP == Owner->DescFileP?true:false;};
+
+   // Comparison
+   inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
+   inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
+			   
+   // Accessors
+   inline DescFile *operator ->() {return FileP;};
+   inline DescFile const *operator ->() const {return FileP;};
+   inline DescFile const &operator *() const {return *FileP;};
+   inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
+   inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
+   inline pkgCache *Cache() {return Owner;};
+  
+   inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
+   inline unsigned long Index() const {return FileP - Owner->DescFileP;};
+      
+   inline DescFileIterator() : Owner(0), FileP(0) {};
+   inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {};
+};
+
 // Inlined Begin functions cant be in the class because of order problems
 // Inlined Begin functions cant be in the class because of order problems
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
 inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
        {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
        {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);};
@@ -345,11 +422,15 @@ inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
        {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
        {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);};
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
 inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
        {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
        {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);};
+inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
+       {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
 inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
        {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
        {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);};
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
 inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
        {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
        {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);};
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
 inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
        {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
        {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
+inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
+       {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
 
 
 #endif
 #endif

+ 44 - 1
apt-pkg/contrib/strutl.cc

@@ -32,12 +32,55 @@
 #include <regex.h>
 #include <regex.h>
 #include <errno.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <stdarg.h>
+#include <iconv.h>
 
 
 #include "config.h"
 #include "config.h"
 
 
 using namespace std;
 using namespace std;
 									/*}}}*/
 									/*}}}*/
 
 
+// UTF8ToCodeset - Convert some UTF-8 string for some codeset   	/*{{{*/
+// ---------------------------------------------------------------------
+/* This is handy to use before display some information for enduser  */
+bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest)
+{
+  iconv_t cd;
+  const char *inbuf;
+  char *inptr, *outbuf, *outptr;
+  size_t insize, outsize, nconv;
+  
+  cd = iconv_open(codeset, "UTF-8");
+  if (cd == (iconv_t)(-1)) {
+     // Something went wrong
+     if (errno == EINVAL)
+	_error->Error("conversion from 'UTF-8' to '%s' not available",
+               codeset);
+     else
+	perror("iconv_open");
+     
+     // Clean the destination string
+     *dest = "";
+     
+     return false;
+  }
+
+  insize = outsize = orig.size();
+  inbuf = orig.data();
+  inptr = (char *)inbuf;
+  outbuf = new char[insize+1];
+  outptr = outbuf;
+
+  iconv(cd, &inptr, &insize, &outptr, &outsize);
+  *outptr = '\0';
+
+  *dest = outbuf;
+  delete[] outbuf;
+  
+  iconv_close(cd);
+
+  return true;
+}
+									/*}}}*/
 // strstrip - Remove white space from the front and back of a string	/*{{{*/
 // strstrip - Remove white space from the front and back of a string	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is handy to use when parsing a file. It also removes \n's left 
 /* This is handy to use when parsing a file. It also removes \n's left 
@@ -357,7 +400,7 @@ string URItoFileName(string URI)
    U.Access = "";
    U.Access = "";
    
    
    // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
    // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
-   URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
+   URI = QuoteString(U,"\\|{}[]<>\"^~=!@#$%^&*");
    string::iterator J = URI.begin();
    string::iterator J = URI.begin();
    for (; J != URI.end(); J++)
    for (; J != URI.end(); J++)
       if (*J == '/') 
       if (*J == '/') 

+ 2 - 1
apt-pkg/contrib/strutl.h

@@ -38,7 +38,8 @@ using std::ostream;
 #define APT_FORMAT2
 #define APT_FORMAT2
 #define APT_FORMAT3
 #define APT_FORMAT3
 #endif    
 #endif    
-    
+
+bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
 char *_strstrip(char *String);
 char *_strstrip(char *String);
 char *_strtabexpand(char *String,size_t Len);
 char *_strtabexpand(char *String,size_t Len);
 bool ParseQuoteWord(const char *&String,string &Res);
 bool ParseQuoteWord(const char *&String,string &Res);

+ 138 - 0
apt-pkg/deb/debindexfile.cc

@@ -320,6 +320,140 @@ pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const
 }
 }
 									/*}}}*/
 									/*}}}*/
 
 
+// TranslationsIndex::debTranslationsIndex - Contructor			/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section) : 
+                  URI(URI), Dist(Dist), Section(Section)
+{
+}
+									/*}}}*/
+// TranslationIndex::Trans* - Return the URI to the translation files	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+inline string debTranslationsIndex::IndexFile(const char *Type) const
+{
+   return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+}
+string debTranslationsIndex::IndexURI(const char *Type) const
+{
+   string Res;
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Res = URI + Dist;
+      else 
+	 Res = URI;
+   }
+   else
+      Res = URI + "dists/" + Dist + '/' + Section +
+      "/i18n/Translation-";
+   
+   Res += Type;
+   return Res;
+}
+									/*}}}*/
+// TranslationsIndex::GetIndexes - Fetch the index files		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::GetIndexes(pkgAcquire *Owner) const
+{
+   if (UseTranslation()) {
+     string TranslationFile = "Translation-" + LanguageCode();
+     new pkgAcqIndexTrans(Owner, IndexURI(LanguageCode().c_str()),
+			  Info(TranslationFile.c_str()),
+			  TranslationFile);
+   }
+
+   return true;
+}
+									/*}}}*/
+// TranslationsIndex::Describe - Give a descriptive path to the index	/*{{{*/
+// ---------------------------------------------------------------------
+/* This should help the user find the index in the sources.list and
+   in the filesystem for problem solving */
+string debTranslationsIndex::Describe(bool Short) const
+{   
+   char S[300];
+   if (Short == true)
+      snprintf(S,sizeof(S),"%s",Info(TranslationFile().c_str()).c_str());
+   else
+      snprintf(S,sizeof(S),"%s (%s)",Info(TranslationFile().c_str()).c_str(),
+	       IndexFile(LanguageCode().c_str()).c_str());
+   return S;
+}
+									/*}}}*/
+// TranslationsIndex::Info - One liner describing the index URI		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debTranslationsIndex::Info(const char *Type) const 
+{
+   string Info = ::URI::SiteOnly(URI) + ' ';
+   if (Dist[Dist.size() - 1] == '/')
+   {
+      if (Dist != "/")
+	 Info += Dist;
+   }
+   else
+      Info += Dist + '/' + Section;   
+   Info += " ";
+   Info += Type;
+   return Info;
+}
+									/*}}}*/
+// TranslationsIndex::Exists - Check if the index is available		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::Exists() const
+{
+   return true;
+}
+									/*}}}*/
+// TranslationsIndex::Size - Return the size of the index		/*{{{*/
+// ---------------------------------------------------------------------
+/* This is really only used for progress reporting. */
+unsigned long debTranslationsIndex::Size() const
+{
+   struct stat S;
+   if (stat(IndexFile(LanguageCode().c_str()).c_str(),&S) != 0)
+      return 0;
+   return S.st_size;
+}
+									/*}}}*/
+// TranslationsIndex::Merge - Load the index file into a cache		/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+{
+   // Check the translation file, if in use
+   string TranslationFile = IndexFile(LanguageCode().c_str());
+   if (UseTranslation() && FileExists(TranslationFile))
+   {
+     FileFd Trans(TranslationFile,FileFd::ReadOnly);
+     debListParser TransParser(&Trans);
+     if (_error->PendingError() == true)
+       return false;
+     
+     Prog.SubProgress(0, Info(TranslationFile.c_str()));
+     if (Gen.SelectFile(TranslationFile,string(),*this) == false)
+       return _error->Error("Problem with SelectFile %s",TranslationFile.c_str());
+
+     // Store the IMS information
+     pkgCache::PkgFileIterator TransFile = Gen.GetCurFile();
+     struct stat TransSt;
+     if (fstat(Trans.Fd(),&TransSt) != 0)
+       return _error->Errno("fstat","Failed to stat");
+     TransFile->Size = TransSt.st_size;
+     TransFile->mtime = TransSt.st_mtime;
+   
+     if (Gen.MergeList(TransParser) == false)
+       return _error->Error("Problem with MergeList %s",TranslationFile.c_str());
+   }
+
+   return true;
+}
+									/*}}}*/
+
 // StatusIndex::debStatusIndex - Constructor				/*{{{*/
 // StatusIndex::debStatusIndex - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
@@ -438,6 +572,10 @@ const pkgIndexFile::Type *debPackagesIndex::GetType() const
 {
 {
    return &_apt_Pkg;
    return &_apt_Pkg;
 }
 }
+const pkgIndexFile::Type *debTranslationsIndex::GetType() const
+{
+   return &_apt_Pkg;
+}
 const pkgIndexFile::Type *debStatusIndex::GetType() const
 const pkgIndexFile::Type *debStatusIndex::GetType() const
 {
 {
    return &_apt_Status;
    return &_apt_Status;

+ 29 - 0
apt-pkg/deb/debindexfile.h

@@ -74,6 +74,35 @@ class debPackagesIndex : public pkgIndexFile
    debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
    debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
 };
 };
 
 
+class debTranslationsIndex : public pkgIndexFile
+{
+   string URI;
+   string Dist;
+   string Section;
+   
+   string Info(const char *Type) const;
+   string IndexFile(const char *Type) const;
+   string IndexURI(const char *Type) const;
+
+   inline string TranslationFile() const {return "Translation-" + LanguageCode();};
+
+   public:
+   
+   virtual const Type *GetType() const;
+
+   // Interface for acquire
+   virtual string Describe(bool Short) const;   
+   virtual bool GetIndexes(pkgAcquire *Owner) const;
+   
+   // Interface for the Cache Generator
+   virtual bool Exists() const;
+   virtual bool HasPackages() const {return true;};
+   virtual unsigned long Size() const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+
+   debTranslationsIndex(string URI,string Dist,string Section);
+};
+
 class debSourcesIndex : public pkgIndexFile
 class debSourcesIndex : public pkgIndexFile
 {
 {
    string URI;
    string URI;

+ 41 - 0
apt-pkg/deb/deblistparser.cc

@@ -15,6 +15,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/crc-16.h>
 #include <apt-pkg/crc-16.h>
+#include <apt-pkg/md5.h>
 
 
 #include <ctype.h>
 #include <ctype.h>
 
 
@@ -117,6 +118,46 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// ListParser::Description - Return the description string		/*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the package in debian
+   form. If this returns the blank string then the entry is assumed to
+   only describe package properties */
+string debListParser::Description()
+{
+   if (DescriptionLanguage().empty())
+      return Section.FindS("Description");
+   else
+      return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
+}
+                                                                        /*}}}*/
+// ListParser::DescriptionLanguage - Return the description lang string	/*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the language of
+   description. If this returns the blank string then the entry is
+   assumed to describe original description. */
+string debListParser::DescriptionLanguage()
+{
+   return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
+}
+                                                                        /*}}}*/
+// ListParser::Description - Return the description_md5 MD5SumValue	/*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the md5 string to allow the check if is the right
+   description. If thisreturns a blank string then calculate the md5
+   value. */
+MD5SumValue debListParser::Description_md5()
+{
+   string value = Section.FindS("Description-md5");
+
+   if (value.empty()) {
+      MD5Summation md5;
+      md5.Add((Description() + "\n").c_str());
+      return md5.Result();
+   } else
+      return MD5SumValue(value);
+}
+                                                                        /*}}}*/
 // ListParser::UsePackage - Update a package structure			/*{{{*/
 // ListParser::UsePackage - Update a package structure			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This is called to update the package with any new information 
 /* This is called to update the package with any new information 

+ 4 - 0
apt-pkg/deb/deblistparser.h

@@ -12,6 +12,7 @@
 #define PKGLIB_DEBLISTPARSER_H
 #define PKGLIB_DEBLISTPARSER_H
 
 
 #include <apt-pkg/pkgcachegen.h>
 #include <apt-pkg/pkgcachegen.h>
+#include <apt-pkg/indexfile.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 
 
 class debListParser : public pkgCacheGenerator::ListParser
 class debListParser : public pkgCacheGenerator::ListParser
@@ -47,6 +48,9 @@ class debListParser : public pkgCacheGenerator::ListParser
    virtual string Package();
    virtual string Package();
    virtual string Version();
    virtual string Version();
    virtual bool NewVersion(pkgCache::VerIterator Ver);
    virtual bool NewVersion(pkgCache::VerIterator Ver);
+   virtual string Description();
+   virtual string DescriptionLanguage();
+   virtual MD5SumValue Description_md5();
    virtual unsigned short VersionHash();
    virtual unsigned short VersionHash();
    virtual bool UsePackage(pkgCache::PkgIterator Pkg,
    virtual bool UsePackage(pkgCache::PkgIterator Pkg,
 			   pkgCache::VerIterator Ver);
 			   pkgCache::VerIterator Ver);

+ 1 - 0
apt-pkg/deb/debmetaindex.cc

@@ -227,6 +227,7 @@ class debSLTypeDebian : public pkgSourceList::Type
       debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
       debReleaseIndex *Deb = new debReleaseIndex(URI,Dist);
       Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
       Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc));
       List.push_back(Deb);
       List.push_back(Deb);
+      List.push_back(new debTranslationsIndex(URI,Dist,Section));
       return true;
       return true;
    }
    }
 };
 };

+ 21 - 2
apt-pkg/deb/debrecords.cc

@@ -12,7 +12,9 @@
 #pragma implementation "apt-pkg/debrecords.h"
 #pragma implementation "apt-pkg/debrecords.h"
 #endif
 #endif
 #include <apt-pkg/debrecords.h>
 #include <apt-pkg/debrecords.h>
+#include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
+#include <langinfo.h>
 									/*}}}*/
 									/*}}}*/
 
 
 // RecordParser::debRecordParser - Constructor				/*{{{*/
 // RecordParser::debRecordParser - Constructor				/*{{{*/
@@ -30,6 +32,10 @@ debRecordParser::debRecordParser(string FileName,pkgCache &Cache) :
 bool debRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
 bool debRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
 {
 {
    return Tags.Jump(Section,Ver->Offset);
    return Tags.Jump(Section,Ver->Offset);
+}
+bool debRecordParser::Jump(pkgCache::DescFileIterator const &Desc)
+{
+   return Tags.Jump(Section,Desc->Offset);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // RecordParser::FileName - Return the archive filename on the site	/*{{{*/
 // RecordParser::FileName - Return the archive filename on the site	/*{{{*/
@@ -77,7 +83,7 @@ string debRecordParser::Maintainer()
 /* */
 /* */
 string debRecordParser::ShortDesc()
 string debRecordParser::ShortDesc()
 {
 {
-   string Res = Section.FindS("Description");
+   string Res = LongDesc();
    string::size_type Pos = Res.find('\n');
    string::size_type Pos = Res.find('\n');
    if (Pos == string::npos)
    if (Pos == string::npos)
       return Res;
       return Res;
@@ -89,7 +95,20 @@ string debRecordParser::ShortDesc()
 /* */
 /* */
 string debRecordParser::LongDesc()
 string debRecordParser::LongDesc()
 {
 {
-   return Section.FindS("Description");
+  string orig, dest;
+  char *codeset = nl_langinfo(CODESET);
+
+  if (!Section.FindS("Description").empty())
+     orig = Section.FindS("Description").c_str();
+  else 
+     orig = Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()).c_str();
+
+  if (strcmp(codeset,"UTF-8") != 0) {
+     UTF8ToCodeset(codeset, orig, &dest);
+     orig = dest;
+   }    
+  
+   return orig;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // RecordParser::SourcePkg - Return the source package name if any	/*{{{*/
 // RecordParser::SourcePkg - Return the source package name if any	/*{{{*/

+ 2 - 0
apt-pkg/deb/debrecords.h

@@ -19,6 +19,7 @@
 #endif 
 #endif 
 
 
 #include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/pkgrecords.h>
+#include <apt-pkg/indexfile.h>
 #include <apt-pkg/tagfile.h>
 #include <apt-pkg/tagfile.h>
 
 
 class debRecordParser : public pkgRecords::Parser
 class debRecordParser : public pkgRecords::Parser
@@ -30,6 +31,7 @@ class debRecordParser : public pkgRecords::Parser
    protected:
    protected:
    
    
    virtual bool Jump(pkgCache::VerFileIterator const &Ver);
    virtual bool Jump(pkgCache::VerFileIterator const &Ver);
+   virtual bool Jump(pkgCache::DescFileIterator const &Desc);
    
    
    public:
    public:
 
 

+ 43 - 0
apt-pkg/indexfile.cc

@@ -12,8 +12,11 @@
 #pragma implementation "apt-pkg/indexfile.h"
 #pragma implementation "apt-pkg/indexfile.h"
 #endif
 #endif
 
 
+#include <apt-pkg/configuration.h>
 #include <apt-pkg/indexfile.h>
 #include <apt-pkg/indexfile.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
+
+#include <clocale>
 									/*}}}*/
 									/*}}}*/
 
 
 // Global list of Item supported
 // Global list of Item supported
@@ -67,3 +70,43 @@ string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record,
    return string();
    return string();
 }
 }
 									/*}}}*/
 									/*}}}*/
+// IndexFile::UseTranslation - Check if will use Translation	        /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgIndexFile::UseTranslation()
+{
+  const string Translation = _config->Find("APT::Acquire::Translation");
+  
+  if (Translation.compare("none") != 0)
+    return CheckLanguageCode(LanguageCode().c_str());
+  else
+    return false;
+}
+									/*}}}*/
+// IndexFile::CheckLanguageCode - Check the Language Code   	        /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgIndexFile::CheckLanguageCode(const char *Lang)
+{
+  if (strlen(Lang) == 2 || (strlen(Lang) == 5 && Lang[2] == '_'))
+    return true;
+
+  if (strcmp(Lang,"C") != 0)
+    _error->Warning("Wrong language code %s", Lang);
+
+  return false;
+}
+									/*}}}*/
+// IndexFile::LanguageCode - Return the Language Code            	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string pkgIndexFile::LanguageCode()
+{
+  const string Translation = _config->Find("APT::Acquire::Translation");
+
+  if (Translation.compare("environment") == 0)
+     return std::setlocale(LC_ALL,NULL);
+  else 
+     return Translation;
+}
+									/*}}}*/

+ 6 - 1
apt-pkg/indexfile.h

@@ -5,10 +5,11 @@
 
 
    Index File - Abstraction for an index of archive/source file.
    Index File - Abstraction for an index of archive/source file.
    
    
-   There are 3 primary sorts of index files, all represented by this 
+   There are 4 primary sorts of index files, all represented by this 
    class:
    class:
    
    
    Binary index files 
    Binary index files 
+   Binary translation files 
    Bianry index files decribing the local system
    Bianry index files decribing the local system
    Source index files
    Source index files
    
    
@@ -79,6 +80,10 @@ class pkgIndexFile
    virtual bool MergeFileProvides(pkgCacheGenerator &/*Gen*/,OpProgress &/*Prog*/) const {return true;};
    virtual bool MergeFileProvides(pkgCacheGenerator &/*Gen*/,OpProgress &/*Prog*/) const {return true;};
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
 
+   static bool UseTranslation();
+   static bool CheckLanguageCode(const char *Lang);
+   static string LanguageCode();
+
    bool IsTrusted() const { return Trusted; };
    bool IsTrusted() const { return Trusted; };
    
    
    pkgIndexFile(bool Trusted): Trusted(Trusted) {};
    pkgIndexFile(bool Trusted): Trusted(Trusted) {};

+ 3 - 0
apt-pkg/init.cc

@@ -33,6 +33,9 @@ const char *pkgOS = COMMON_OS;
    is prepended, this allows a fair degree of flexability. */
    is prepended, this allows a fair degree of flexability. */
 bool pkgInitConfig(Configuration &Cnf)
 bool pkgInitConfig(Configuration &Cnf)
 {
 {
+   // Translation
+   Cnf.Set("APT::Acquire::Translation", "environment");
+
    // General APT things
    // General APT things
    if (strcmp(COMMON_OS,"linux") == 0 ||
    if (strcmp(COMMON_OS,"linux") == 0 ||
        strcmp(COMMON_OS,"unknown") == 0)
        strcmp(COMMON_OS,"unknown") == 0)

+ 10 - 1
apt-pkg/pkgcache.cc

@@ -52,7 +52,7 @@ pkgCache::Header::Header()
    
    
    /* Whenever the structures change the major version should be bumped,
    /* Whenever the structures change the major version should be bumped,
       whenever the generator changes the minor version should be bumped. */
       whenever the generator changes the minor version should be bumped. */
-   MajorVersion = 4;
+   MajorVersion = 5;
    MinorVersion = 0;
    MinorVersion = 0;
    Dirty = false;
    Dirty = false;
    
    
@@ -60,17 +60,22 @@ pkgCache::Header::Header()
    PackageSz = sizeof(pkgCache::Package);
    PackageSz = sizeof(pkgCache::Package);
    PackageFileSz = sizeof(pkgCache::PackageFile);
    PackageFileSz = sizeof(pkgCache::PackageFile);
    VersionSz = sizeof(pkgCache::Version);
    VersionSz = sizeof(pkgCache::Version);
+   DescriptionSz = sizeof(pkgCache::Description);
    DependencySz = sizeof(pkgCache::Dependency);
    DependencySz = sizeof(pkgCache::Dependency);
    ProvidesSz = sizeof(pkgCache::Provides);
    ProvidesSz = sizeof(pkgCache::Provides);
    VerFileSz = sizeof(pkgCache::VerFile);
    VerFileSz = sizeof(pkgCache::VerFile);
+   DescFileSz = sizeof(pkgCache::DescFile);
    
    
    PackageCount = 0;
    PackageCount = 0;
    VersionCount = 0;
    VersionCount = 0;
+   DescriptionCount = 0;
    DependsCount = 0;
    DependsCount = 0;
    PackageFileCount = 0;
    PackageFileCount = 0;
    VerFileCount = 0;
    VerFileCount = 0;
+   DescFileCount = 0;
    ProvidesCount = 0;
    ProvidesCount = 0;
    MaxVerFileSize = 0;
    MaxVerFileSize = 0;
+   MaxDescFileSize = 0;
    
    
    FileList = 0;
    FileList = 0;
    StringList = 0;
    StringList = 0;
@@ -89,8 +94,10 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
        PackageSz == Against.PackageSz &&
        PackageSz == Against.PackageSz &&
        PackageFileSz == Against.PackageFileSz &&
        PackageFileSz == Against.PackageFileSz &&
        VersionSz == Against.VersionSz &&
        VersionSz == Against.VersionSz &&
+       DescriptionSz == Against.DescriptionSz &&
        DependencySz == Against.DependencySz &&
        DependencySz == Against.DependencySz &&
        VerFileSz == Against.VerFileSz &&
        VerFileSz == Against.VerFileSz &&
+       DescFileSz == Against.DescFileSz &&
        ProvidesSz == Against.ProvidesSz)
        ProvidesSz == Against.ProvidesSz)
       return true;
       return true;
    return false;
    return false;
@@ -115,8 +122,10 @@ bool pkgCache::ReMap()
    HeaderP = (Header *)Map.Data();
    HeaderP = (Header *)Map.Data();
    PkgP = (Package *)Map.Data();
    PkgP = (Package *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
    VerFileP = (VerFile *)Map.Data();
+   DescFileP = (DescFile *)Map.Data();
    PkgFileP = (PackageFile *)Map.Data();
    PkgFileP = (PackageFile *)Map.Data();
    VerP = (Version *)Map.Data();
    VerP = (Version *)Map.Data();
+   DescP = (Description *)Map.Data();
    ProvideP = (Provides *)Map.Data();
    ProvideP = (Provides *)Map.Data();
    DepP = (Dependency *)Map.Data();
    DepP = (Dependency *)Map.Data();
    StringItemP = (StringItem *)Map.Data();
    StringItemP = (StringItem *)Map.Data();

+ 42 - 2
apt-pkg/pkgcache.h

@@ -38,24 +38,30 @@ class pkgCache
    struct Package;
    struct Package;
    struct PackageFile;
    struct PackageFile;
    struct Version;
    struct Version;
+   struct Description;
    struct Provides;
    struct Provides;
    struct Dependency;
    struct Dependency;
    struct StringItem;
    struct StringItem;
    struct VerFile;
    struct VerFile;
+   struct DescFile;
    
    
    // Iterators
    // Iterators
    class PkgIterator;
    class PkgIterator;
    class VerIterator;
    class VerIterator;
+   class DescIterator;
    class DepIterator;
    class DepIterator;
    class PrvIterator;
    class PrvIterator;
    class PkgFileIterator;
    class PkgFileIterator;
    class VerFileIterator;
    class VerFileIterator;
+   class DescFileIterator;
    friend class PkgIterator;
    friend class PkgIterator;
    friend class VerIterator;
    friend class VerIterator;
+   friend class DescInterator;
    friend class DepIterator;
    friend class DepIterator;
    friend class PrvIterator;
    friend class PrvIterator;
    friend class PkgFileIterator;
    friend class PkgFileIterator;
    friend class VerFileIterator;
    friend class VerFileIterator;
+   friend class DescFileIterator;
    
    
    class Namespace;
    class Namespace;
    
    
@@ -98,8 +104,10 @@ class pkgCache
    Header *HeaderP;
    Header *HeaderP;
    Package *PkgP;
    Package *PkgP;
    VerFile *VerFileP;
    VerFile *VerFileP;
+   DescFile *DescFileP;
    PackageFile *PkgFileP;
    PackageFile *PkgFileP;
    Version *VerP;
    Version *VerP;
+   Description *DescP;
    Provides *ProvideP;
    Provides *ProvideP;
    Dependency *DepP;
    Dependency *DepP;
    StringItem *StringItemP;
    StringItem *StringItemP;
@@ -151,16 +159,20 @@ struct pkgCache::Header
    unsigned short PackageSz;
    unsigned short PackageSz;
    unsigned short PackageFileSz;
    unsigned short PackageFileSz;
    unsigned short VersionSz;
    unsigned short VersionSz;
+   unsigned short DescriptionSz;
    unsigned short DependencySz;
    unsigned short DependencySz;
    unsigned short ProvidesSz;
    unsigned short ProvidesSz;
    unsigned short VerFileSz;
    unsigned short VerFileSz;
+   unsigned short DescFileSz;
    
    
    // Structure counts
    // Structure counts
    unsigned long PackageCount;
    unsigned long PackageCount;
    unsigned long VersionCount;
    unsigned long VersionCount;
+   unsigned long DescriptionCount;
    unsigned long DependsCount;
    unsigned long DependsCount;
    unsigned long PackageFileCount;
    unsigned long PackageFileCount;
    unsigned long VerFileCount;
    unsigned long VerFileCount;
+   unsigned long DescFileCount;
    unsigned long ProvidesCount;
    unsigned long ProvidesCount;
    
    
    // Offsets
    // Offsets
@@ -169,10 +181,11 @@ struct pkgCache::Header
    map_ptrloc VerSysName;            // StringTable
    map_ptrloc VerSysName;            // StringTable
    map_ptrloc Architecture;          // StringTable
    map_ptrloc Architecture;          // StringTable
    unsigned long MaxVerFileSize;
    unsigned long MaxVerFileSize;
+   unsigned long MaxDescFileSize;
 
 
    /* Allocation pools, there should be one of these for each structure
    /* Allocation pools, there should be one of these for each structure
       excluding the header */
       excluding the header */
-   DynamicMMap::Pool Pools[7];
+   DynamicMMap::Pool Pools[8];
    
    
    // Rapid package name lookup
    // Rapid package name lookup
    map_ptrloc HashTable[2*1048];
    map_ptrloc HashTable[2*1048];
@@ -193,7 +206,7 @@ struct pkgCache::Package
    map_ptrloc NextPackage;       // Package
    map_ptrloc NextPackage;       // Package
    map_ptrloc RevDepends;        // Dependency
    map_ptrloc RevDepends;        // Dependency
    map_ptrloc ProvidesList;      // Provides
    map_ptrloc ProvidesList;      // Provides
-   
+
    // Install/Remove/Purge etc
    // Install/Remove/Purge etc
    unsigned char SelectedState;     // What
    unsigned char SelectedState;     // What
    unsigned char InstState;         // Flags
    unsigned char InstState;         // Flags
@@ -232,6 +245,14 @@ struct pkgCache::VerFile
    unsigned short Size;
    unsigned short Size;
 };
 };
 
 
+struct pkgCache::DescFile
+{
+   map_ptrloc File;           // PackageFile
+   map_ptrloc NextFile;       // PkgVerFile
+   map_ptrloc Offset;         // File offset
+   unsigned short Size;
+};
+
 struct pkgCache::Version
 struct pkgCache::Version
 {
 {
    map_ptrloc VerStr;            // Stringtable
    map_ptrloc VerStr;            // Stringtable
@@ -241,6 +262,7 @@ struct pkgCache::Version
    // Lists
    // Lists
    map_ptrloc FileList;          // VerFile
    map_ptrloc FileList;          // VerFile
    map_ptrloc NextVer;           // Version
    map_ptrloc NextVer;           // Version
+   map_ptrloc DescriptionList;   // Description
    map_ptrloc DependsList;       // Dependency
    map_ptrloc DependsList;       // Dependency
    map_ptrloc ParentPkg;         // Package
    map_ptrloc ParentPkg;         // Package
    map_ptrloc ProvidesList;      // Provides
    map_ptrloc ProvidesList;      // Provides
@@ -252,6 +274,22 @@ struct pkgCache::Version
    unsigned char Priority;
    unsigned char Priority;
 };
 };
 
 
+struct pkgCache::Description
+{
+   // Language Code store the description translation language code. If
+   // the value has a 0 lenght then this is readed using the Package
+   // file else the Translation-CODE are used.
+   map_ptrloc language_code;     // StringTable
+   map_ptrloc md5sum;            // StringTable
+
+   // Linked list 
+   map_ptrloc FileList;          // DescFile
+   map_ptrloc NextDesc;          // Description
+   map_ptrloc ParentPkg;         // Package
+
+   unsigned short ID;
+};
+
 struct pkgCache::Dependency
 struct pkgCache::Dependency
 {
 {
    map_ptrloc Version;         // Stringtable
    map_ptrloc Version;         // Stringtable
@@ -299,11 +337,13 @@ class pkgCache::Namespace
 
 
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::PkgIterator PkgIterator;
    typedef pkgCache::VerIterator VerIterator;
    typedef pkgCache::VerIterator VerIterator;
+   typedef pkgCache::DescIterator DescIterator;
    typedef pkgCache::DepIterator DepIterator;
    typedef pkgCache::DepIterator DepIterator;
    typedef pkgCache::PrvIterator PrvIterator;
    typedef pkgCache::PrvIterator PrvIterator;
    typedef pkgCache::PkgFileIterator PkgFileIterator;
    typedef pkgCache::PkgFileIterator PkgFileIterator;
    typedef pkgCache::VerFileIterator VerFileIterator;   
    typedef pkgCache::VerFileIterator VerFileIterator;   
    typedef pkgCache::Version Version;
    typedef pkgCache::Version Version;
+   typedef pkgCache::Description Description;
    typedef pkgCache::Package Package;
    typedef pkgCache::Package Package;
    typedef pkgCache::Header Header;
    typedef pkgCache::Header Header;
    typedef pkgCache::Dep Dep;
    typedef pkgCache::Dep Dep;

+ 102 - 6
apt-pkg/pkgcachegen.cc

@@ -125,6 +125,28 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       string Version = List.Version();
       string Version = List.Version();
       if (Version.empty() == true)
       if (Version.empty() == true)
       {
       {
+ 	 // Find the right version to write the description
+ 	 MD5SumValue CurMd5 = List.Description_md5();
+ 	 pkgCache::VerIterator Ver = Pkg.VersionList();
+ 	 map_ptrloc *LastVer = &Pkg->VersionList;
+ 	 
+  	 for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++) 
+ 	 {
+ 	    pkgCache::DescIterator Desc = Ver.DescriptionList();
+ 	    map_ptrloc *LastDesc = &Ver->DescriptionList;
+       
+ 	    for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++)
+ 	       if (MD5SumValue(Desc.md5()) == CurMd5) {
+ 		  // Add new description
+ 		  *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), CurMd5, *LastDesc);
+ 		  Desc->ParentPkg = Pkg.Index();
+ 
+ 		  if (NewFileDesc(Desc,List) == false)
+ 		     return _error->Error(_("Error occured while processing %s (NewFileDesc1)"),PackageName.c_str());
+ 		  break;
+ 	       }
+ 	 }
+ 
 	 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
 	 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
 	    return _error->Error(_("Error occured while processing %s (UsePackage1)"),
 	    return _error->Error(_("Error occured while processing %s (UsePackage1)"),
 				 PackageName.c_str());
 				 PackageName.c_str());
@@ -132,9 +154,9 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       }
       }
 
 
       pkgCache::VerIterator Ver = Pkg.VersionList();
       pkgCache::VerIterator Ver = Pkg.VersionList();
-      map_ptrloc *Last = &Pkg->VersionList;
+      map_ptrloc *LastVer = &Pkg->VersionList;
       int Res = 1;
       int Res = 1;
-      for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
+      for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
       {
       {
 	 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
 	 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
 	 if (Res >= 0)
 	 if (Res >= 0)
@@ -168,7 +190,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       // Skip to the end of the same version set.
       // Skip to the end of the same version set.
       if (Res == 0)
       if (Res == 0)
       {
       {
-	 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
+	 for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
 	 {
 	 {
 	    Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
 	    Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
 	    if (Res != 0)
 	    if (Res != 0)
@@ -177,9 +199,10 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       }
       }
 
 
       // Add a new version
       // Add a new version
-      *Last = NewVersion(Ver,Version,*Last);
+      *LastVer = NewVersion(Ver,Version,*LastVer);
       Ver->ParentPkg = Pkg.Index();
       Ver->ParentPkg = Pkg.Index();
       Ver->Hash = Hash;
       Ver->Hash = Hash;
+
       if (List.NewVersion(Ver) == false)
       if (List.NewVersion(Ver) == false)
 	 return _error->Error(_("Error occured while processing %s (NewVersion1)"),
 	 return _error->Error(_("Error occured while processing %s (NewVersion1)"),
 			      PackageName.c_str());
 			      PackageName.c_str());
@@ -199,6 +222,21 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
 	 FoundFileDeps |= List.HasFileDeps();
 	 FoundFileDeps |= List.HasFileDeps();
 	 return true;
 	 return true;
       }      
       }      
+
+      /* Record the Description data. Description data always exist in
+	 Packages and Translation-* files. */
+      pkgCache::DescIterator Desc = Ver.DescriptionList();
+      map_ptrloc *LastDesc = &Ver->DescriptionList;
+      
+      // Skip to the end of description set
+      for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++);
+
+      // Add new description
+      *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), List.Description_md5(), *LastDesc);
+      Desc->ParentPkg = Pkg.Index();
+
+      if (NewFileDesc(Desc,List) == false)
+	 return _error->Error(_("Error occured while processing %s (NewFileDesc2)"),PackageName.c_str());
    }
    }
 
 
    FoundFileDeps |= List.HasFileDeps();
    FoundFileDeps |= List.HasFileDeps();
@@ -209,6 +247,9 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
    if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
    if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
       return _error->Error(_("Wow, you exceeded the number of versions "
       return _error->Error(_("Wow, you exceeded the number of versions "
 			     "this APT is capable of."));
 			     "this APT is capable of."));
+   if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1)
+      return _error->Error(_("Wow, you exceeded the number of descriptions "
+			     "this APT is capable of."));
    if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
    if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
       return _error->Error(_("Wow, you exceeded the number of dependencies "
       return _error->Error(_("Wow, you exceeded the number of dependencies "
 			     "this APT is capable of."));
 			     "this APT is capable of."));
@@ -271,7 +312,7 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
    Pkg = Cache.FindPkg(Name);
    Pkg = Cache.FindPkg(Name);
    if (Pkg.end() == false)
    if (Pkg.end() == false)
       return true;
       return true;
-       
+
    // Get a structure
    // Get a structure
    unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
    unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
    if (Package == 0)
    if (Package == 0)
@@ -349,6 +390,61 @@ unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
    return Version;
    return Version;
 }
 }
 									/*}}}*/
 									/*}}}*/
+// CacheGenerator::NewFileDesc - Create a new File<->Desc association	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
+				   ListParser &List)
+{
+   if (CurrentFile == 0)
+      return true;
+   
+   // Get a structure
+   unsigned long DescFile = Map.Allocate(sizeof(pkgCache::DescFile));
+   if (DescFile == 0)
+      return 0;
+   
+   pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
+   DF->File = CurrentFile - Cache.PkgFileP;
+   
+   // Link it to the end of the list
+   map_ptrloc *Last = &Desc->FileList;
+   for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; D++)
+      Last = &D->NextFile;
+   DF->NextFile = *Last;
+   *Last = DF.Index();
+   
+   DF->Offset = List.Offset();
+   DF->Size = List.Size();
+   if (Cache.HeaderP->MaxDescFileSize < DF->Size)
+      Cache.HeaderP->MaxDescFileSize = DF->Size;
+   Cache.HeaderP->DescFileCount++;
+   
+   return true;
+}
+									/*}}}*/
+// CacheGenerator::NewDescription - Create a new Description		/*{{{*/
+// ---------------------------------------------------------------------
+/* This puts a description structure in the linked list */
+map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
+					    const string &Lang, const MD5SumValue &md5sum,
+					    map_ptrloc Next)
+{
+   // Get a structure
+   map_ptrloc Description = Map.Allocate(sizeof(pkgCache::Description));
+   if (Description == 0)
+      return 0;
+
+   // Fill it in
+   Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
+   Desc->NextDesc = Next;
+   Desc->ID = Cache.HeaderP->DescriptionCount++;
+   Desc->language_code = Map.WriteString(Lang);
+   Desc->md5sum = Map.WriteString(md5sum.Value());
+
+   return Description;
+}
+									/*}}}*/
 // ListParser::NewDepends - Create a dependency element			/*{{{*/
 // ListParser::NewDepends - Create a dependency element			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This creates a dependency element in the tree. It is linked to the
 /* This creates a dependency element in the tree. It is linked to the
@@ -580,7 +676,7 @@ static bool CheckValidity(string CacheFile, FileIterator Start,
       pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
       pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
       if (File.end() == true)
       if (File.end() == true)
 	 return false;
 	 return false;
-      
+
       Visited[File->ID] = true;
       Visited[File->ID] = true;
    }
    }
    
    

+ 6 - 0
apt-pkg/pkgcachegen.h

@@ -24,6 +24,7 @@
 #endif 
 #endif 
 
 
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/pkgcache.h>
+#include <apt-pkg/md5.h>
 
 
 class pkgSourceList;
 class pkgSourceList;
 class OpProgress;
 class OpProgress;
@@ -55,7 +56,9 @@ class pkgCacheGenerator
    
    
    bool NewPackage(pkgCache::PkgIterator &Pkg,string Pkg);
    bool NewPackage(pkgCache::PkgIterator &Pkg,string Pkg);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
+   bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next);
    unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next);
+   map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
 
 
    public:
    public:
 
 
@@ -107,6 +110,9 @@ class pkgCacheGenerator::ListParser
    virtual string Package() = 0;
    virtual string Package() = 0;
    virtual string Version() = 0;
    virtual string Version() = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
    virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
+   virtual string Description() = 0;
+   virtual string DescriptionLanguage() = 0;
+   virtual MD5SumValue Description_md5() = 0;
    virtual unsigned short VersionHash() = 0;
    virtual unsigned short VersionHash() = 0;
    virtual bool UsePackage(pkgCache::PkgIterator Pkg,
    virtual bool UsePackage(pkgCache::PkgIterator Pkg,
 			   pkgCache::VerIterator Ver) = 0;
 			   pkgCache::VerIterator Ver) = 0;

+ 9 - 0
apt-pkg/pkgrecords.cc

@@ -63,3 +63,12 @@ pkgRecords::Parser &pkgRecords::Lookup(pkgCache::VerFileIterator const &Ver)
    return *Files[Ver.File()->ID];
    return *Files[Ver.File()->ID];
 }
 }
 									/*}}}*/
 									/*}}}*/
+// Records::Lookup - Get a parser for the package description file	/*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgRecords::Parser &pkgRecords::Lookup(pkgCache::DescFileIterator const &Desc)
+{
+   Files[Desc.File()->ID]->Jump(Desc);
+   return *Files[Desc.File()->ID];
+}
+									/*}}}*/

+ 2 - 0
apt-pkg/pkgrecords.h

@@ -38,6 +38,7 @@ class pkgRecords
 
 
    // Lookup function
    // Lookup function
    Parser &Lookup(pkgCache::VerFileIterator const &Ver);
    Parser &Lookup(pkgCache::VerFileIterator const &Ver);
+   Parser &Lookup(pkgCache::DescFileIterator const &Desc);
 
 
    // Construct destruct
    // Construct destruct
    pkgRecords(pkgCache &Cache);
    pkgRecords(pkgCache &Cache);
@@ -49,6 +50,7 @@ class pkgRecords::Parser
    protected:
    protected:
    
    
    virtual bool Jump(pkgCache::VerFileIterator const &Ver) = 0;
    virtual bool Jump(pkgCache::VerFileIterator const &Ver) = 0;
+   virtual bool Jump(pkgCache::DescFileIterator const &Desc) = 0;
    
    
    public:
    public:
    friend class pkgRecords;
    friend class pkgRecords;

+ 81 - 22
cmdline/apt-cache.cc

@@ -71,6 +71,12 @@ void LocalitySort(pkgCache::VerFile **begin,
 {   
 {   
    qsort(begin,Count,Size,LocalityCompare);
    qsort(begin,Count,Size,LocalityCompare);
 }
 }
+
+void LocalitySort(pkgCache::DescFile **begin,
+		  unsigned long Count,size_t Size)
+{   
+   qsort(begin,Count,Size,LocalityCompare);
+}
 									/*}}}*/
 									/*}}}*/
 // UnMet - Show unmet dependencies					/*{{{*/
 // UnMet - Show unmet dependencies					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
@@ -182,7 +188,14 @@ bool DumpPackage(CommandLine &CmdL)
       {
       {
 	 cout << Cur.VerStr();
 	 cout << Cur.VerStr();
 	 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
 	 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
-	    cout << "(" << Vf.File().FileName() << ")";
+	    cout << " (" << Vf.File().FileName() << ")";
+	 cout << endl;
+	 for (pkgCache::DescIterator D = Cur.DescriptionList(); D.end() == false; D++)
+	 {
+	    cout << " Description Language: " << D.LanguageCode() << endl
+		 << "                 File: " << D.FileList().File().FileName() << endl
+		 << "                  MD5: " << D.md5() << endl;
+	 }
 	 cout << endl;
 	 cout << endl;
       }
       }
       
       
@@ -277,11 +290,15 @@ bool Stats(CommandLine &Cmd)
    
    
    cout << _("Total Distinct Versions: ") << Cache.Head().VersionCount << " (" <<
    cout << _("Total Distinct Versions: ") << Cache.Head().VersionCount << " (" <<
       SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
       SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
+   cout << _("Total Distinct Descriptions: ") << Cache.Head().DescriptionCount << " (" <<
+      SizeToStr(Cache.Head().DescriptionCount*Cache.Head().DescriptionSz) << ')' << endl;
    cout << _("Total Dependencies: ") << Cache.Head().DependsCount << " (" << 
    cout << _("Total Dependencies: ") << Cache.Head().DependsCount << " (" << 
       SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
       SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
    
    
    cout << _("Total Ver/File relations: ") << Cache.Head().VerFileCount << " (" <<
    cout << _("Total Ver/File relations: ") << Cache.Head().VerFileCount << " (" <<
       SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
       SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
+   cout << _("Total Desc/File relations: ") << Cache.Head().DescFileCount << " (" <<
+      SizeToStr(Cache.Head().DescFileCount*Cache.Head().DescFileSz) << ')' << endl;
    cout << _("Total Provides Mappings: ") << Cache.Head().ProvidesCount << " (" <<
    cout << _("Total Provides Mappings: ") << Cache.Head().ProvidesCount << " (" <<
       SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
       SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
    
    
@@ -344,6 +361,12 @@ bool Dump(CommandLine &Cmd)
 	 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
 	 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
 	    cout << "  Depends: " << D.TargetPkg().Name() << ' ' << 
 	    cout << "  Depends: " << D.TargetPkg().Name() << ' ' << 
 	                     DeNull(D.TargetVer()) << endl;
 	                     DeNull(D.TargetVer()) << endl;
+	 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; D++)
+	 {
+	    cout << " Description Language: " << D.LanguageCode() << endl
+		 << "                 File: " << D.FileList().File().FileName() << endl
+		 << "                  MD5: " << D.md5() << endl;
+	 } 
       }      
       }      
    }
    }
 
 
@@ -1192,28 +1215,51 @@ bool DisplayRecord(pkgCache::VerIterator V)
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
    
    
-   // Read the record and then write it out again.
+   // Read the record
    unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
    unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
    Buffer[V.FileList()->Size] = '\n';
    Buffer[V.FileList()->Size] = '\n';
    if (PkgF.Seek(V.FileList()->Offset) == false ||
    if (PkgF.Seek(V.FileList()->Offset) == false ||
-       PkgF.Read(Buffer,V.FileList()->Size) == false ||
-       fwrite(Buffer,1,V.FileList()->Size+1,stdout) < (size_t)(V.FileList()->Size+1))
+       PkgF.Read(Buffer,V.FileList()->Size) == false)
    {
    {
       delete [] Buffer;
       delete [] Buffer;
       return false;
       return false;
    }
    }
-   
+
+   // Strip the Description
+   unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:");
+   *DescP='\0';
+
+   // Write all the rest
+   if (fwrite(Buffer,1,V.FileList()->Size+1,stdout) < V.FileList()->Size+1))
+   {
+      delete [] Buffer;
+      return false;
+   }
+
    delete [] Buffer;
    delete [] Buffer;
 
 
+   // Show the right description
+   pkgRecords Recs(*GCache);
+   pkgCache::DescIterator DescDefault = V.DescriptionList();
+   pkgCache::DescIterator Desc = DescDefault;
+   for (; Desc.end() == false; Desc++)
+      if (pkgIndexFile::LanguageCode() == Desc.LanguageCode())
+	 break;
+   if (Desc.end() == true) Desc = DescDefault;
+
+   pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
+   cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc() << endl;
+
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // Search - Perform a search						/*{{{*/
 // Search - Perform a search						/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* This searches the package names and pacakge descriptions for a pattern */
 /* This searches the package names and pacakge descriptions for a pattern */
-struct ExVerFile
+struct ExDescFile
 {
 {
-   pkgCache::VerFile *Vf;
+   pkgCache::DescFile *Df;
    bool NameMatch;
    bool NameMatch;
 };
 };
 
 
@@ -1253,35 +1299,35 @@ bool Search(CommandLine &CmdL)
       return false;
       return false;
    }
    }
    
    
-   ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
-   memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
+   ExDescFile *DFList = new ExDescFile[Cache.HeaderP->PackageCount+1];
+   memset(DFList,0,sizeof(*DFList)*Cache.HeaderP->PackageCount+1);
 
 
    // Map versions that we want to write out onto the VerList array.
    // Map versions that we want to write out onto the VerList array.
    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
    {
    {
-      VFList[P->ID].NameMatch = NumPatterns != 0;
+      DFList[P->ID].NameMatch = NumPatterns != 0;
       for (unsigned I = 0; I != NumPatterns; I++)
       for (unsigned I = 0; I != NumPatterns; I++)
       {
       {
 	 if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
 	 if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
-	    VFList[P->ID].NameMatch &= true;
+	    DFList[P->ID].NameMatch &= true;
 	 else
 	 else
-	    VFList[P->ID].NameMatch = false;
+	    DFList[P->ID].NameMatch = false;
       }
       }
         
         
       // Doing names only, drop any that dont match..
       // Doing names only, drop any that dont match..
-      if (NamesOnly == true && VFList[P->ID].NameMatch == false)
+      if (NamesOnly == true && DFList[P->ID].NameMatch == false)
 	 continue;
 	 continue;
 	 
 	 
       // Find the proper version to use. 
       // Find the proper version to use. 
       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
       pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
       if (V.end() == false)
       if (V.end() == false)
-	 VFList[P->ID].Vf = V.FileList();
+	 DFList[P->ID].Df = V.DescriptionList().FileList();
    }
    }
       
       
    // Include all the packages that provide matching names too
    // Include all the packages that provide matching names too
    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
    for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
    {
    {
-      if (VFList[P->ID].NameMatch == false)
+      if (DFList[P->ID].NameMatch == false)
 	 continue;
 	 continue;
 
 
       for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
       for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
@@ -1289,18 +1335,18 @@ bool Search(CommandLine &CmdL)
 	 pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
 	 pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
 	 if (V.end() == false)
 	 if (V.end() == false)
 	 {
 	 {
-	    VFList[Prv.OwnerPkg()->ID].Vf = V.FileList();
-	    VFList[Prv.OwnerPkg()->ID].NameMatch = true;
+	    DFList[Prv.OwnerPkg()->ID].Df = V.DescriptionList().FileList();
+	    DFList[Prv.OwnerPkg()->ID].NameMatch = true;
 	 }
 	 }
       }
       }
    }
    }
-
-   LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
+   
+   LocalitySort(&DFList->Df,Cache.HeaderP->PackageCount,sizeof(*DFList));
 
 
    // Iterate over all the version records and check them
    // Iterate over all the version records and check them
-   for (ExVerFile *J = VFList; J->Vf != 0; J++)
+   for (ExDescFile *J = DFList; J->Df != 0; J++)
    {
    {
-      pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
+      pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(Cache,J->Df));
 
 
       bool Match = true;
       bool Match = true;
       if (J->NameMatch == false)
       if (J->NameMatch == false)
@@ -1331,7 +1377,7 @@ bool Search(CommandLine &CmdL)
       }
       }
    }
    }
    
    
-   delete [] VFList;
+   delete [] DFList;
    for (unsigned I = 0; I != NumPatterns; I++)
    for (unsigned I = 0; I != NumPatterns; I++)
       regfree(&Patterns[I]);
       regfree(&Patterns[I]);
    if (ferror(stdout))
    if (ferror(stdout))
@@ -1360,6 +1406,19 @@ bool ShowPackage(CommandLine &CmdL)
 
 
       ++found;
       ++found;
 
 
+      // Show virtual packages
+      if (Pkg->ProvidesList != 0)
+      {
+	 ioprintf(std::cout,_("Package %s is a virtual package provided by:\n"),
+		  Pkg.Name());
+	 
+	 pkgCache::PrvIterator I = Pkg.ProvidesList();
+	 for (; I.end() == false; I++)
+	    cout << "  " << I.OwnerPkg().Name() << endl;
+	 cout << _("You should explicitly select one to show.") << endl;
+	 continue;
+      }
+
       // Find the proper version to use.
       // Find the proper version to use.
       if (_config->FindB("APT::Cache::AllVersions","true") == true)
       if (_config->FindB("APT::Cache::AllVersions","true") == true)
       {
       {

+ 11 - 2
cmdline/apt-get.cc

@@ -1380,6 +1380,15 @@ bool DoUpgrade(CommandLine &CmdL)
 /* Install named packages */
 /* Install named packages */
 bool DoInstall(CommandLine &CmdL)
 bool DoInstall(CommandLine &CmdL)
 {
 {
+   // Lock the list directory
+   FileFd Lock;
+   if (_config->FindB("Debug::NoLocking",false) == false)
+   {
+      Lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
+      if (_error->PendingError() == true)
+        return _error->Error(_("Unable to lock the list directory"));
+   }
+   
    CacheFile Cache;
    CacheFile Cache;
    if (Cache.OpenForInstall() == false || 
    if (Cache.OpenForInstall() == false || 
        Cache.CheckDeps(CmdL.FileSize() != 1) == false)
        Cache.CheckDeps(CmdL.FileSize() != 1) == false)
@@ -1580,8 +1589,8 @@ bool DoInstall(CommandLine &CmdL)
       {
       {
 	 pkgCache::PkgIterator I(Cache,Cache.List[J]);
 	 pkgCache::PkgIterator I(Cache,Cache.List[J]);
 
 
-	 /* Just look at the ones we want to install */
-	 if ((*Cache)[I].Install() == false)
+	 /* Just look at the ones we want to install but skip all already selected */
+	 if ((*Cache)[I].Install() == false || (*Cache)[I].NewInstall() == true)
 	   continue;
 	   continue;
 
 
 	 for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)
 	 for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)

+ 8 - 0
debian/changelog

@@ -1,3 +1,11 @@
+apt (0.6.35os1) unstable; urgency=low
+
+   * Resync with apt--main--0--patch-71.
+     [ This include the DDTP support for testing propose, report bugs
+     directly to me ]
+
+ -- Otavio Salvador <otavio@debian.org>  Wed, 23 Mar 2005 17:19:28 -0300
+
 apt (0.6.35) hoary; urgency=low
 apt (0.6.35) hoary; urgency=low
 
 
   * Merge apt--mvo--0:
   * Merge apt--mvo--0: