test/integration/test-ubuntu-bug-346386-apt-get-update-paywall: use downloadfile()
[apt.git] / methods / ftp.cc
index 0d617dd8f83385738b2cd6b381ce7f3aa8d0ea7c..66787a7bea661808f147804ea020426cc2690b5a 100644 (file)
@@ -1,9 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: ftp.cc,v 1.21 2001/02/20 07:03:18 jgg Exp $
+// $Id: ftp.cc,v 1.31.2.1 2004/01/16 18:58:50 mdz Exp $
 /* ######################################################################
 
 /* ######################################################################
 
-   HTTP Aquire Method - This is the FTP aquire method for APT.
+   FTP Acquire Method - This is the FTP acquire method for APT.
 
    This is a very simple implementation that does not try to optimize
    at all. Commands are sent syncronously with the FTP server (as the
 
    This is a very simple implementation that does not try to optimize
    at all. Commands are sent syncronously with the FTP server (as the
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
+#include <config.h>
+
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/acquire-method.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/acquire-method.h>
 #include <apt-pkg/error.h>
-#include <apt-pkg/md5.h>
+#include <apt-pkg/hashes.h>
+#include <apt-pkg/netrc.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/strutl.h>
 
 
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <utime.h>
 #include <unistd.h>
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <unistd.h>
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdarg.h>
+#include <iostream>
 
 // Internet stuff
 #include <netinet/in.h>
 
 // Internet stuff
 #include <netinet/in.h>
 #include "rfc2553emu.h"
 #include "connect.h"
 #include "ftp.h"
 #include "rfc2553emu.h"
 #include "connect.h"
 #include "ftp.h"
+
+#include <apti18n.h>
                                                                        /*}}}*/
 
                                                                        /*}}}*/
 
+using namespace std;
+
 /* This table is for the EPRT and EPSV commands, it maps the OS address
    family to the IETF address families */
 struct AFMap
 /* This table is for the EPRT and EPSV commands, it maps the OS address
    family to the IETF address families */
 struct AFMap
@@ -49,9 +61,9 @@ struct AFMap
 };
 
 #ifndef AF_INET6
 };
 
 #ifndef AF_INET6
-struct AFMap AFMap[] = {{AF_INET,1},{}};
+struct AFMap AFMap[] = {{AF_INET,1},{0, 0}};
 #else
 #else
-struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{}};
+struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{0, 0}};
 #endif
 
 unsigned long TimeOut = 120;
 #endif
 
 unsigned long TimeOut = 120;
@@ -64,10 +76,12 @@ time_t FtpMethod::FailTime = 0;
 // ---------------------------------------------------------------------
 /* */
 FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), 
 // ---------------------------------------------------------------------
 /* */
 FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(-1), DataFd(-1), 
-                            DataListenFd(-1), ServerName(Srv)
+                            DataListenFd(-1), ServerName(Srv),
+                           ForceExtended(false), TryPassive(true)
 {
    Debug = _config->FindB("Debug::Acquire::Ftp",false);
    PasvAddr = 0;
 {
    Debug = _config->FindB("Debug::Acquire::Ftp",false);
    PasvAddr = 0;
+   Buffer[0] = '\0';
 }
                                                                        /*}}}*/
 // FTPConn::~FTPConn - Destructor                                      /*{{{*/
 }
                                                                        /*}}}*/
 // FTPConn::~FTPConn - Destructor                                      /*{{{*/
@@ -108,22 +122,34 @@ bool FTPConn::Open(pkgAcqMethod *Owner)
    Close();
    
    // Determine the proxy setting
    Close();
    
    // Determine the proxy setting
-   if (getenv("ftp_proxy") == 0)
+   string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host);
+   if (!SpecificProxy.empty())
    {
    {
-      string DefProxy = _config->Find("Acquire::ftp::Proxy");
-      string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host);
-      if (SpecificProxy.empty() == false)
-      {
-        if (SpecificProxy == "DIRECT")
-           Proxy = "";
-        else
-           Proxy = SpecificProxy;
-      }   
-      else
-        Proxy = DefProxy;
+          if (SpecificProxy == "DIRECT")
+                  Proxy = "";
+          else
+                  Proxy = SpecificProxy;
    }
    else
    }
    else
-      Proxy = getenv("ftp_proxy");
+   {
+          string DefProxy = _config->Find("Acquire::ftp::Proxy");
+          if (!DefProxy.empty())
+          {
+                  Proxy = DefProxy;
+          }
+          else
+          {
+                  char* result = getenv("ftp_proxy");
+                  Proxy = result ? result : "";
+          }
+   }
+
+   // Parse no_proxy, a , separated list of domains
+   if (getenv("no_proxy") != 0)
+   {
+      if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
+        Proxy = "";
+   }
    
    // Determine what host and port to use based on the proxy settings
    int Port = 0;
    
    // Determine what host and port to use based on the proxy settings
    int Port = 0;
@@ -146,19 +172,22 @@ bool FTPConn::Open(pkgAcqMethod *Owner)
    RotateDNS();
    if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false)
       return false;
    RotateDNS();
    if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false)
       return false;
+
+   // Login must be before getpeername otherwise dante won't work.
+   Owner->Status(_("Logging in"));
+   bool Res = Login();
    
    // Get the remote server's address
    PeerAddrLen = sizeof(PeerAddr);
    if (getpeername(ServerFd,(sockaddr *)&PeerAddr,&PeerAddrLen) != 0)
    
    // Get the remote server's address
    PeerAddrLen = sizeof(PeerAddr);
    if (getpeername(ServerFd,(sockaddr *)&PeerAddr,&PeerAddrLen) != 0)
-      return _error->Errno("getpeername","Unable to determine the peer name");
+      return _error->Errno("getpeername",_("Unable to determine the peer name"));
    
    // Get the local machine's address
    ServerAddrLen = sizeof(ServerAddr);
    if (getsockname(ServerFd,(sockaddr *)&ServerAddr,&ServerAddrLen) != 0)
    
    // Get the local machine's address
    ServerAddrLen = sizeof(ServerAddr);
    if (getsockname(ServerFd,(sockaddr *)&ServerAddr,&ServerAddrLen) != 0)
-      return _error->Errno("getsockname","Unable to determine the local name");
+      return _error->Errno("getsockname",_("Unable to determine the local name"));
    
    
-   Owner->Status("Logging in");
-   return Login();
+   return Res;
 }
                                                                        /*}}}*/
 // FTPConn::Login - Login to the remote server                         /*{{{*/
 }
                                                                        /*}}}*/
 // FTPConn::Login - Login to the remote server                         /*{{{*/
@@ -172,7 +201,7 @@ bool FTPConn::Login()
    
    // Setup the variables needed for authentication
    string User = "anonymous";
    
    // Setup the variables needed for authentication
    string User = "anonymous";
-   string Pass = "apt_get_ftp_2.0@debian.linux.user";
+   string Pass = "apt_get_ftp_2.1@debian.linux.user";
 
    // Fill in the user/pass
    if (ServerName.User.empty() == false)
 
    // Fill in the user/pass
    if (ServerName.User.empty() == false)
@@ -187,19 +216,21 @@ bool FTPConn::Login()
       if (ReadResp(Tag,Msg) == false)
         return false;
       if (Tag >= 400)
       if (ReadResp(Tag,Msg) == false)
         return false;
       if (Tag >= 400)
-        return _error->Error("Server refused our connection and said: %s",Msg.c_str());
+        return _error->Error(_("The server refused the connection and said: %s"),Msg.c_str());
       
       // Send the user
       if (WriteMsg(Tag,Msg,"USER %s",User.c_str()) == false)
         return false;
       if (Tag >= 400)
       
       // Send the user
       if (WriteMsg(Tag,Msg,"USER %s",User.c_str()) == false)
         return false;
       if (Tag >= 400)
-        return _error->Error("USER failed, server said: %s",Msg.c_str());
+        return _error->Error(_("USER failed, server said: %s"),Msg.c_str());
       
       
-      // Send the Password
-      if (WriteMsg(Tag,Msg,"PASS %s",Pass.c_str()) == false)
-        return false;
-      if (Tag >= 400)
-        return _error->Error("PASS failed, server said: %s",Msg.c_str());
+      if (Tag == 331) { // 331 User name okay, need password.
+         // Send the Password
+         if (WriteMsg(Tag,Msg,"PASS %s",Pass.c_str()) == false)
+            return false;
+         if (Tag >= 400)
+            return _error->Error(_("PASS failed, server said: %s"),Msg.c_str());
+      }
       
       // Enter passive mode
       if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
       
       // Enter passive mode
       if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
@@ -213,13 +244,13 @@ bool FTPConn::Login()
       if (ReadResp(Tag,Msg) == false)
         return false;
       if (Tag >= 400)
       if (ReadResp(Tag,Msg) == false)
         return false;
       if (Tag >= 400)
-        return _error->Error("Server refused our connection and said: %s",Msg.c_str());
+        return _error->Error(_("The server refused the connection and said: %s"),Msg.c_str());
       
       // Perform proxy script execution
       Configuration::Item const *Opts = _config->Tree("Acquire::ftp::ProxyLogin");
       if (Opts == 0 || Opts->Child == 0)
       
       // Perform proxy script execution
       Configuration::Item const *Opts = _config->Tree("Acquire::ftp::ProxyLogin");
       if (Opts == 0 || Opts->Child == 0)
-        return _error->Error("A proxy server was specified but no login "
-                             "script, Acquire::ftp::ProxyLogin is empty.");
+        return _error->Error(_("A proxy server was specified but no login "
+                             "script, Acquire::ftp::ProxyLogin is empty."));
       Opts = Opts->Child;
 
       // Iterate over the entire login script
       Opts = Opts->Child;
 
       // Iterate over the entire login script
@@ -246,7 +277,7 @@ bool FTPConn::Login()
         if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false)
            return false;
         if (Tag >= 400)
         if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false)
            return false;
         if (Tag >= 400)
-           return _error->Error("Login script command '%s' failed, server said: %s",Tmp.c_str(),Msg.c_str());   
+           return _error->Error(_("Login script command '%s' failed, server said: %s"),Tmp.c_str(),Msg.c_str());        
       }
       
       // Enter passive mode
       }
       
       // Enter passive mode
@@ -272,7 +303,7 @@ bool FTPConn::Login()
    if (WriteMsg(Tag,Msg,"TYPE I") == false)
       return false;
    if (Tag >= 400)
    if (WriteMsg(Tag,Msg,"TYPE I") == false)
       return false;
    if (Tag >= 400)
-      return _error->Error("TYPE failed, server said: %s",Msg.c_str());
+      return _error->Error(_("TYPE failed, server said: %s"),Msg.c_str());
    
    return true;
 }
    
    return true;
 }
@@ -310,23 +341,23 @@ bool FTPConn::ReadLine(string &Text)
       if (WaitFd(ServerFd,false,TimeOut) == false)
       {
         Close();
       if (WaitFd(ServerFd,false,TimeOut) == false)
       {
         Close();
-        return _error->Error("Connection timeout");
+        return _error->Error(_("Connection timeout"));
       }
       
       // Suck it back
       int Res = read(ServerFd,Buffer + Len,sizeof(Buffer) - Len);
       if (Res == 0)
       }
       
       // Suck it back
       int Res = read(ServerFd,Buffer + Len,sizeof(Buffer) - Len);
       if (Res == 0)
-        _error->Error("Server closed the connection");
+        _error->Error(_("Server closed the connection"));
       if (Res <= 0)
       {
       if (Res <= 0)
       {
-        _error->Errno("read","Read error");
+        _error->Errno("read",_("Read error"));
         Close();
         return false;
       }      
       Len += Res;
    }
 
         Close();
         return false;
       }      
       Len += Res;
    }
 
-   return _error->Error("A response overflowed the buffer.");
+   return _error->Error(_("A response overflowed the buffer."));
 }
                                                                        /*}}}*/
 // FTPConn::ReadResp - Read a full response from the server            /*{{{*/
 }
                                                                        /*}}}*/
 // FTPConn::ReadResp - Read a full response from the server            /*{{{*/
@@ -343,7 +374,7 @@ bool FTPConn::ReadResp(unsigned int &Ret,string &Text)
    char *End;   
    Ret = strtol(Msg.c_str(),&End,10);
    if (End - Msg.c_str() != 3)
    char *End;   
    Ret = strtol(Msg.c_str(),&End,10);
    if (End - Msg.c_str() != 3)
-      return _error->Error("Protocol corruption");
+      return _error->Error(_("Protocol corruption"));
 
    // All done ?
    Text = Msg.c_str()+4;
 
    // All done ?
    Text = Msg.c_str()+4;
@@ -355,7 +386,7 @@ bool FTPConn::ReadResp(unsigned int &Ret,string &Text)
    }
    
    if (*End != '-')
    }
    
    if (*End != '-')
-      return _error->Error("Protocol corruption");
+      return _error->Error(_("Protocol corruption"));
    
    /* Okay, here we do the continued message trick. This is foolish, but
       proftpd follows the protocol as specified and wu-ftpd doesn't, so 
    
    /* Okay, here we do the continued message trick. This is foolish, but
       proftpd follows the protocol as specified and wu-ftpd doesn't, so 
@@ -409,6 +440,7 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...)
    char S[400];
    vsnprintf(S,sizeof(S) - 4,Fmt,args);
    strcat(S,"\r\n");
    char S[400];
    vsnprintf(S,sizeof(S) - 4,Fmt,args);
    strcat(S,"\r\n");
+   va_end(args);
  
    if (Debug == true)
       cerr << "-> '" << QuoteString(S,"") << "'" << endl;
  
    if (Debug == true)
       cerr << "-> '" << QuoteString(S,"") << "'" << endl;
@@ -421,13 +453,13 @@ bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...)
       if (WaitFd(ServerFd,true,TimeOut) == false)
       {
         Close();
       if (WaitFd(ServerFd,true,TimeOut) == false)
       {
         Close();
-        return _error->Error("Connection timeout");
+        return _error->Error(_("Connection timeout"));
       }
       
       int Res = write(ServerFd,S + Start,Len);
       if (Res <= 0)
       {
       }
       
       int Res = write(ServerFd,S + Start,Len);
       if (Res <= 0)
       {
-        _error->Errno("write","Write Error");
+        _error->Errno("write",_("Write error"));
         Close();
         return false;
       }
         Close();
         return false;
       }
@@ -537,7 +569,7 @@ bool FTPConn::ExtGoPasv()
    string::const_iterator List[4];
    unsigned Count = 0;
    Pos++;
    string::const_iterator List[4];
    unsigned Count = 0;
    Pos++;
-   for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); I++)
+   for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); ++I)
    {
       if (*I != Msg[Pos])
         continue;
    {
       if (*I != Msg[Pos])
         continue;
@@ -595,8 +627,7 @@ bool FTPConn::ExtGoPasv()
    }
    
    // Get a new passive address.
    }
    
    // Get a new passive address.
-   int Res;
-   if ((Res = getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr)) != 0)
+   if (getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr) != 0)
       return true;
    
    return true;
       return true;
    
    return true;
@@ -605,7 +636,7 @@ bool FTPConn::ExtGoPasv()
 // FTPConn::Size - Return the size of a file                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Grab the file size from the server, 0 means no size or empty file */
 // FTPConn::Size - Return the size of a file                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Grab the file size from the server, 0 means no size or empty file */
-bool FTPConn::Size(const char *Path,unsigned long &Size)
+bool FTPConn::Size(const char *Path,unsigned long long &Size)
 {
    // Query the size
    unsigned int Tag;
 {
    // Query the size
    unsigned int Tag;
@@ -615,7 +646,7 @@ bool FTPConn::Size(const char *Path,unsigned long &Size)
       return false;
    
    char *End;
       return false;
    
    char *End;
-   Size = strtol(Msg.c_str(),&End,10);
+   Size = strtoull(Msg.c_str(),&End,10);
    if (Tag >= 400 || End == Msg.c_str())
       Size = 0;
    return true;
    if (Tag >= 400 || End == Msg.c_str())
       Size = 0;
    return true;
@@ -639,8 +670,7 @@ bool FTPConn::ModTime(const char *Path, time_t &Time)
       return true;
    
    // Parse it
       return true;
    
    // Parse it
-   StrToTime(Msg,Time);
-   return true;
+   return FTPMDTMStrToTime(Msg.c_str(), Time);
 }
                                                                        /*}}}*/
 // FTPConn::CreateDataFd - Get a data connection                       /*{{{*/
 }
                                                                        /*}}}*/
 // FTPConn::CreateDataFd - Get a data connection                       /*{{{*/
@@ -668,24 +698,24 @@ bool FTPConn::CreateDataFd()
       // Get a socket
       if ((DataFd = socket(PasvAddr->ai_family,PasvAddr->ai_socktype,
                           PasvAddr->ai_protocol)) < 0)
       // Get a socket
       if ((DataFd = socket(PasvAddr->ai_family,PasvAddr->ai_socktype,
                           PasvAddr->ai_protocol)) < 0)
-        return _error->Errno("socket","Could not create a socket");
+        return _error->Errno("socket",_("Could not create a socket"));
       
       // Connect to the server
       SetNonBlock(DataFd,true);
       if (connect(DataFd,PasvAddr->ai_addr,PasvAddr->ai_addrlen) < 0 &&
          errno != EINPROGRESS)
       
       // Connect to the server
       SetNonBlock(DataFd,true);
       if (connect(DataFd,PasvAddr->ai_addr,PasvAddr->ai_addrlen) < 0 &&
          errno != EINPROGRESS)
-        return _error->Errno("socket","Could not create a socket");
+        return _error->Errno("socket",_("Could not create a socket"));
    
       /* This implements a timeout for connect by opening the connection
          nonblocking */
       if (WaitFd(DataFd,true,TimeOut) == false)
    
       /* This implements a timeout for connect by opening the connection
          nonblocking */
       if (WaitFd(DataFd,true,TimeOut) == false)
-        return _error->Error("Could not connect data socket, connection timed out");
+        return _error->Error(_("Could not connect data socket, connection timed out"));
       unsigned int Err;
       unsigned int Len = sizeof(Err);
       if (getsockopt(DataFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0)
       unsigned int Err;
       unsigned int Len = sizeof(Err);
       if (getsockopt(DataFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0)
-        return _error->Errno("getsockopt","Failed");
+        return _error->Errno("getsockopt",_("Failed"));
       if (Err != 0)
       if (Err != 0)
-        return _error->Error("Could not connect passive socket.");
+        return _error->Error(_("Could not connect passive socket."));
 
       return true;
    }
 
       return true;
    }
@@ -695,40 +725,40 @@ bool FTPConn::CreateDataFd()
    DataListenFd = -1;
 
    // Get the information for a listening socket.
    DataListenFd = -1;
 
    // Get the information for a listening socket.
-   struct addrinfo *BindAddr = 0;
+   struct addrinfo *BindAddr = NULL;
    struct addrinfo Hints;
    memset(&Hints,0,sizeof(Hints));
    Hints.ai_socktype = SOCK_STREAM;
    Hints.ai_flags |= AI_PASSIVE;
    Hints.ai_family = ((struct sockaddr *)&ServerAddr)->sa_family;
    struct addrinfo Hints;
    memset(&Hints,0,sizeof(Hints));
    Hints.ai_socktype = SOCK_STREAM;
    Hints.ai_flags |= AI_PASSIVE;
    Hints.ai_family = ((struct sockaddr *)&ServerAddr)->sa_family;
-   int Res;
-   if ((Res = getaddrinfo(0,"0",&Hints,&BindAddr)) != 0)
-      return _error->Error("getaddrinfo was unable to get a listening socket");
+   if (getaddrinfo(0,"0",&Hints,&BindAddr) != 0 || BindAddr == NULL)
+      return _error->Error(_("getaddrinfo was unable to get a listening socket"));
    
    // Construct the socket
    if ((DataListenFd = socket(BindAddr->ai_family,BindAddr->ai_socktype,
                              BindAddr->ai_protocol)) < 0)
    {
       freeaddrinfo(BindAddr);
    
    // Construct the socket
    if ((DataListenFd = socket(BindAddr->ai_family,BindAddr->ai_socktype,
                              BindAddr->ai_protocol)) < 0)
    {
       freeaddrinfo(BindAddr);
-      return _error->Errno("socket","Could not create a socket");
+      return _error->Errno("socket",_("Could not create a socket"));
    }
    
    // Bind and listen
    if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0)
    {
       freeaddrinfo(BindAddr);
    }
    
    // Bind and listen
    if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0)
    {
       freeaddrinfo(BindAddr);
-      return _error->Errno("bind","Could not bind a socket");
+      return _error->Errno("bind",_("Could not bind a socket"));
    }
    freeaddrinfo(BindAddr);   
    if (listen(DataListenFd,1) < 0)
    }
    freeaddrinfo(BindAddr);   
    if (listen(DataListenFd,1) < 0)
-      return _error->Errno("listen","Could not listen on the socket");
+      return _error->Errno("listen",_("Could not listen on the socket"));
    SetNonBlock(DataListenFd,true);
    
    // Determine the name to send to the remote
    struct sockaddr_storage Addr;
    socklen_t AddrLen = sizeof(Addr);
    if (getsockname(DataListenFd,(sockaddr *)&Addr,&AddrLen) < 0)
    SetNonBlock(DataListenFd,true);
    
    // Determine the name to send to the remote
    struct sockaddr_storage Addr;
    socklen_t AddrLen = sizeof(Addr);
    if (getsockname(DataListenFd,(sockaddr *)&Addr,&AddrLen) < 0)
-      return _error->Errno("getsockname","Could not determine the socket's name");
+      return _error->Errno("getsockname",_("Could not determine the socket's name"));
+
 
    // Reverse the address. We need the server address and the data port.
    char Name[NI_MAXHOST];
 
    // Reverse the address. We need the server address and the data port.
    char Name[NI_MAXHOST];
@@ -759,7 +789,7 @@ bool FTPConn::CreateDataFd()
                   (int)(Port >> 8) & 0xff, (int)(Port & 0xff)) == false)
         return false;
       if (Tag >= 400)
                   (int)(Port >> 8) & 0xff, (int)(Port & 0xff)) == false)
         return false;
       if (Tag >= 400)
-        return _error->Error("Unable to send PORT command");
+        return _error->Error(_("Unable to send PORT command"));
       return true;
    }
 
       return true;
    }
 
@@ -769,7 +799,7 @@ bool FTPConn::CreateDataFd()
       if (AFMap[J].Family == ((struct sockaddr *)&Addr)->sa_family)
         Proto = AFMap[J].IETFFamily;
    if (Proto == 0)
       if (AFMap[J].Family == ((struct sockaddr *)&Addr)->sa_family)
         Proto = AFMap[J].IETFFamily;
    if (Proto == 0)
-      return _error->Error("Unkonwn address family %u (AF_*)",
+      return _error->Error(_("Unknown address family %u (AF_*)"),
                           ((struct sockaddr *)&Addr)->sa_family);
    
    // Send the EPRT command
                           ((struct sockaddr *)&Addr)->sa_family);
    
    // Send the EPRT command
@@ -778,7 +808,7 @@ bool FTPConn::CreateDataFd()
    if (WriteMsg(Tag,Msg,"EPRT |%u|%s|%s|",Proto,Name,Service) == false)
       return false;
    if (Tag >= 400)
    if (WriteMsg(Tag,Msg,"EPRT |%u|%s|%s|",Proto,Name,Service) == false)
       return false;
    if (Tag >= 400)
-      return _error->Error("EPRT failed, server said: %s",Msg.c_str());
+      return _error->Error(_("EPRT failed, server said: %s"),Msg.c_str());
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
@@ -798,14 +828,14 @@ bool FTPConn::Finalize()
    
    // Wait for someone to connect..
    if (WaitFd(DataListenFd,false,TimeOut) == false)
    
    // Wait for someone to connect..
    if (WaitFd(DataListenFd,false,TimeOut) == false)
-      return _error->Error("Data socket connect timed out");
+      return _error->Error(_("Data socket connect timed out"));
       
    // Accept the connection
    struct sockaddr_in Addr;
    socklen_t Len = sizeof(Addr);
    DataFd = accept(DataListenFd,(struct sockaddr *)&Addr,&Len);
    if (DataFd < 0)
       
    // Accept the connection
    struct sockaddr_in Addr;
    socklen_t Len = sizeof(Addr);
    DataFd = accept(DataListenFd,(struct sockaddr *)&Addr,&Len);
    if (DataFd < 0)
-      return _error->Errno("accept","Unable to accept connection");
+      return _error->Errno("accept",_("Unable to accept connection"));
 
    close(DataListenFd);
    DataListenFd = -1;
 
    close(DataListenFd);
    DataListenFd = -1;
@@ -817,8 +847,8 @@ bool FTPConn::Finalize()
 // ---------------------------------------------------------------------
 /* This opens a data connection, sends REST and RETR and then
    transfers the file over. */
 // ---------------------------------------------------------------------
 /* This opens a data connection, sends REST and RETR and then
    transfers the file over. */
-bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
-                 MD5Summation &MD5,bool &Missing)
+bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume,
+                 Hashes &Hash,bool &Missing)
 {
    Missing = false;
    if (CreateDataFd() == false)
 {
    Missing = false;
    if (CreateDataFd() == false)
@@ -842,9 +872,9 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
    
    if (Resume != 0)
    {
    
    if (Resume != 0)
    {
-      if (MD5.AddFD(To.Fd(),Resume) == false)
+      if (Hash.AddFD(To,Resume) == false)
       {
       {
-        _error->Errno("read","Problem hashing file");
+        _error->Errno("read",_("Problem hashing file"));
         return false;
       }
    }
         return false;
       }
    }
@@ -857,7 +887,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
    {
       if (Tag == 550)
         Missing = true;
    {
       if (Tag == 550)
         Missing = true;
-      return _error->Error("Unable to fetch file, server said '%s'",Msg.c_str());
+      return _error->Error(_("Unable to fetch file, server said '%s'"),Msg.c_str());
    }
    
    // Finish off the data connection
    }
    
    // Finish off the data connection
@@ -872,7 +902,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
       if (WaitFd(DataFd,false,TimeOut) == false)
       {
         Close();
       if (WaitFd(DataFd,false,TimeOut) == false)
       {
         Close();
-        return _error->Error("Data socket timed out");
+        return _error->Error(_("Data socket timed out"));
       }
       
       // Read the data..
       }
       
       // Read the data..
@@ -886,7 +916,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
         break;
       }
    
         break;
       }
    
-      MD5.Add(Buffer,Res);
+      Hash.Add(Buffer,Res);
       if (To.Write(Buffer,Res) == false)
       {
         Close();
       if (To.Write(Buffer,Res) == false)
       {
         Close();
@@ -902,7 +932,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long Resume,
    if (ReadResp(Tag,Msg) == false)
       return false;
    if (Tag >= 400)
    if (ReadResp(Tag,Msg) == false)
       return false;
    if (Tag >= 400)
-      return _error->Error("Data transfer failed, server said '%s'",Msg.c_str());
+      return _error->Error(_("Data transfer failed, server said '%s'"),Msg.c_str());
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
@@ -921,20 +951,22 @@ FtpMethod::FtpMethod() : pkgAcqMethod("1.0",SendConfig)
                                                                        /*}}}*/
 // FtpMethod::SigTerm - Handle a fatal signal                          /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // FtpMethod::SigTerm - Handle a fatal signal                          /*{{{*/
 // ---------------------------------------------------------------------
-/* This closes and timestamps the open file. This is neccessary to get 
+/* This closes and timestamps the open file. This is necessary to get
    resume behavoir on user abort */
 void FtpMethod::SigTerm(int)
 {
    if (FailFd == -1)
       _exit(100);
    resume behavoir on user abort */
 void FtpMethod::SigTerm(int)
 {
    if (FailFd == -1)
       _exit(100);
-   close(FailFd);
-   
+
    // Timestamp
    // Timestamp
-   struct utimbuf UBuf;
-   UBuf.actime = FailTime;
-   UBuf.modtime = FailTime;
-   utime(FailFile.c_str(),&UBuf);
-   
+   struct timeval times[2];
+   times[0].tv_sec = FailTime;
+   times[1].tv_sec = FailTime;
+   times[0].tv_usec = times[1].tv_usec = 0;
+   utimes(FailFile.c_str(), times);
+
+   close(FailFd);
+
    _exit(100);
 }
                                                                        /*}}}*/
    _exit(100);
 }
                                                                        /*}}}*/
@@ -960,7 +992,9 @@ bool FtpMethod::Fetch(FetchItem *Itm)
    FetchResult Res;
    Res.Filename = Itm->DestFile;
    Res.IMSHit = false;
    FetchResult Res;
    Res.Filename = Itm->DestFile;
    Res.IMSHit = false;
-   
+
+   maybe_add_auth (Get, _config->FindFile("Dir::Etc::netrc"));
+
    // Connect to the server
    if (Server == 0 || Server->Comp(Get) == false)
    {
    // Connect to the server
    if (Server == 0 || Server->Comp(Get) == false)
    {
@@ -977,8 +1011,8 @@ bool FtpMethod::Fetch(FetchItem *Itm)
    }
    
    // Get the files information
    }
    
    // Get the files information
-   Status("Query");
-   unsigned long Size;
+   Status(_("Query"));
+   unsigned long long Size;
    if (Server->Size(File,Size) == false ||
        Server->ModTime(File,FailTime) == false)
    {
    if (Server->Size(File,Size) == false ||
        Server->ModTime(File,FailTime) == false)
    {
@@ -1000,7 +1034,7 @@ bool FtpMethod::Fetch(FetchItem *Itm)
    struct stat Buf;
    if (stat(Itm->DestFile.c_str(),&Buf) == 0)
    {
    struct stat Buf;
    if (stat(Itm->DestFile.c_str(),&Buf) == 0)
    {
-      if (Size == (unsigned)Buf.st_size && FailTime == Buf.st_mtime)
+      if (Size == (unsigned long long)Buf.st_size && FailTime == Buf.st_mtime)
       {
         Res.Size = Buf.st_size;
         Res.LastModified = Buf.st_mtime;
       {
         Res.Size = Buf.st_size;
         Res.LastModified = Buf.st_mtime;
@@ -1010,12 +1044,12 @@ bool FtpMethod::Fetch(FetchItem *Itm)
       }
       
       // Resume?
       }
       
       // Resume?
-      if (FailTime == Buf.st_mtime && Size > (unsigned)Buf.st_size)
+      if (FailTime == Buf.st_mtime && Size > (unsigned long long)Buf.st_size)
         Res.ResumePoint = Buf.st_size;
    }
    
    // Open the file
         Res.ResumePoint = Buf.st_size;
    }
    
    // Open the file
-   MD5Summation MD5;
+   Hashes Hash;
    {
       FileFd Fd(Itm->DestFile,FileFd::WriteAny);
       if (_error->PendingError() == true)
    {
       FileFd Fd(Itm->DestFile,FileFd::WriteAny);
       if (_error->PendingError() == true)
@@ -1028,60 +1062,70 @@ bool FtpMethod::Fetch(FetchItem *Itm)
       FailFd = Fd.Fd();
       
       bool Missing;
       FailFd = Fd.Fd();
       
       bool Missing;
-      if (Server->Get(File,Fd,Res.ResumePoint,MD5,Missing) == false)
+      if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing) == false)
       {
         Fd.Close();
       {
         Fd.Close();
-        
+
         // Timestamp
         // Timestamp
-        struct utimbuf UBuf;
-        UBuf.actime = FailTime;
-        UBuf.modtime = FailTime;
-        utime(FailFile.c_str(),&UBuf);
-        
-        // If the file is missing we hard fail otherwise transient fail
-        if (Missing == true)
+        struct timeval times[2];
+        times[0].tv_sec = FailTime;
+        times[1].tv_sec = FailTime;
+        times[0].tv_usec = times[1].tv_usec = 0;
+        utimes(FailFile.c_str(), times);
+
+        // If the file is missing we hard fail and delete the destfile
+        // otherwise transient fail
+        if (Missing == true) {
+           unlink(FailFile.c_str());
            return false;
            return false;
+        }
         Fail(true);
         return true;
       }
 
       Res.Size = Fd.Size();
         Fail(true);
         return true;
       }
 
       Res.Size = Fd.Size();
+
+      // Timestamp
+      struct timeval times[2];
+      times[0].tv_sec = FailTime;
+      times[1].tv_sec = FailTime;
+      times[0].tv_usec = times[1].tv_usec = 0;
+      utimes(Fd.Name().c_str(), times);
+      FailFd = -1;
    }
    }
-   
+
    Res.LastModified = FailTime;
    Res.LastModified = FailTime;
-   Res.MD5Sum = MD5.Result();
-   
-   // Timestamp
-   struct utimbuf UBuf;
-   UBuf.actime = FailTime;
-   UBuf.modtime = FailTime;
-   utime(Queue->DestFile.c_str(),&UBuf);
-   FailFd = -1;
+   Res.TakeHashes(Hash);
 
    URIDone(Res);
 
    URIDone(Res);
-   
+
    return true;
 }
                                                                        /*}}}*/
 
    return true;
 }
                                                                        /*}}}*/
 
-int main(int argc,const char *argv[])
+int main(intconst char *argv[])
 { 
 { 
+   setlocale(LC_ALL, "");
+
    /* See if we should be come the http client - we do this for http
       proxy urls */
    if (getenv("ftp_proxy") != 0)
    {
       URI Proxy = string(getenv("ftp_proxy"));
    /* See if we should be come the http client - we do this for http
       proxy urls */
    if (getenv("ftp_proxy") != 0)
    {
       URI Proxy = string(getenv("ftp_proxy"));
+      
+      // Run the HTTP method
       if (Proxy.Access == "http")
       {
         // Copy over the environment setting
         char S[300];
         snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy"));
         putenv(S);
       if (Proxy.Access == "http")
       {
         // Copy over the environment setting
         char S[300];
         snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy"));
         putenv(S);
+        putenv((char *)"no_proxy=");
         
         // Run the http method
         
         // Run the http method
-        string Path = flNotFile(argv[0]) + "/http";
-        execl(Path.c_str(),Path.c_str(),0);
-        cerr << "Unable to invoke " << Path << endl;
+        string Path = flNotFile(argv[0]) + "http";
+        execl(Path.c_str(),Path.c_str(),(char *)NULL);
+        cerr << _("Unable to invoke ") << Path << endl;
         exit(100);
       }      
    }
         exit(100);
       }      
    }