// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: ftp.cc,v 1.24 2001/03/06 07:15:29 jgg Exp $
+// $Id: ftp.cc,v 1.31.2.1 2004/01/16 18:58:50 mdz Exp $
/* ######################################################################
FTP Aquire Method - This is the FTP aquire method for APT.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#include <config.h>
+
#include <apt-pkg/fileutl.h>
#include <apt-pkg/acquire-method.h>
#include <apt-pkg/error.h>
#include <apt-pkg/hashes.h>
+#include <apt-pkg/netrc.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
+#include <iostream>
// Internet stuff
#include <netinet/in.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
// ---------------------------------------------------------------------
/* */
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;
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
- 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)
{
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)
- 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)
- 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 /*{{{*/
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)
- 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)
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)
- 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
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
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;
}
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)
- _error->Error("Server closed the connection");
+ _error->Error(_("Server closed the connection"));
if (Res <= 0)
{
- _error->Errno("read","Read error");
+ _error->Errno("read",_("Read error"));
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 /*{{{*/
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;
}
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
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)
{
- _error->Errno("write","Write Error");
+ _error->Errno("write",_("Write error"));
Close();
return false;
}
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;
// 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;
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;
return true;
// Parse it
- StrToTime(Msg,Time);
- return true;
+ return FTPMDTMStrToTime(Msg.c_str(), Time);
}
/*}}}*/
// FTPConn::CreateDataFd - Get a data connection /*{{{*/
// 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)
- 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)
- 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)
- return _error->Errno("getsockopt","Failed");
+ return _error->Errno("getsockopt",_("Failed"));
if (Err != 0)
- return _error->Error("Could not connect passive socket.");
+ return _error->Error(_("Could not connect passive socket."));
return true;
}
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");
+ 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);
- 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);
- 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)
- 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)
- 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];
(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;
}
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
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;
}
/*}}}*/
// 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)
- return _error->Errno("accept","Unable to accept connection");
+ return _error->Errno("accept",_("Unable to accept connection"));
close(DataListenFd);
DataListenFd = -1;
// ---------------------------------------------------------------------
/* 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,
+bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume,
Hashes &Hash,bool &Missing)
{
Missing = false;
{
if (Hash.AddFD(To.Fd(),Resume) == false)
{
- _error->Errno("read","Problem hashing file");
+ _error->Errno("read",_("Problem hashing file"));
return false;
}
}
{
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
if (WaitFd(DataFd,false,TimeOut) == false)
{
Close();
- return _error->Error("Data socket timed out");
+ return _error->Error(_("Data socket timed out"));
}
// Read the data..
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;
}
/*}}}*/
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)
{
}
// 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)
{
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;
}
// 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;
}
UBuf.modtime = FailTime;
utime(FailFile.c_str(),&UBuf);
- // If the file is missing we hard fail otherwise transient fail
- if (Missing == true)
+ // If the file is missing we hard fail and delete the destfile
+ // otherwise transient fail
+ if (Missing == true) {
+ unlink(FailFile.c_str());
return false;
+ }
Fail(true);
return true;
}
}
Res.LastModified = FailTime;
- Res.MD5Sum = Hash.MD5.Result();
+ Res.TakeHashes(Hash);
// Timestamp
struct utimbuf UBuf;
int main(int argc,const 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"));
- // Parse no_proxy, a , separated list of domains
- if (getenv("no_proxy") != 0)
- {
- if (CheckDomainList(Proxy.Host,getenv("no_proxy")) == true)
- Proxy.Access = "";
- }
-
// Run the HTTP method
if (Proxy.Access == "http")
{
char S[300];
snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy"));
putenv(S);
+ putenv((char *)"no_proxy=");
// 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);
}
}