X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fftp-basic.c;h=7d36bf267c6f4f3f1ae2a12972dd5a861a10bc4b;hp=8d433a69fe0d79fdfc5bfdc22a3920ce2f836fa0;hb=d5be8ecca466601bda9b81c28a79077fbda6ccde;hpb=eef4a668b754cf3a7bbee58a65c654df5d414ec6 diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 8d433a69..7d36bf26 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -1,32 +1,33 @@ /* Basic FTP routines. Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc. -This file is part of Wget. +This file is part of GNU Wget. -This program is free software; you can redistribute it and/or modify +GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, +GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software +along with Wget; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include +#include + #ifdef HAVE_STRING_H # include #else # include #endif -#include #ifdef HAVE_UNISTD_H # include #endif @@ -41,13 +42,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "rbuf.h" #include "connect.h" #include "host.h" - -#ifndef errno -extern int errno; -#endif -#ifndef h_errno -extern int h_errno; -#endif +#include "ftp.h" char ftp_last_respline[128]; @@ -66,33 +61,33 @@ ftp_response (struct rbuf *rbuf, char **line) do { for (i = 0; 1; i++) - { - int res; - if (i > bufsize - 1) - *line = (char *)xrealloc (*line, (bufsize <<= 1)); - res = RBUF_READCHAR (rbuf, *line + i); - /* RES is number of bytes read. */ - if (res == 1) - { - if ((*line)[i] == '\n') - { - (*line)[i] = '\0'; - /* Get rid of \r. */ - if (i > 0 && (*line)[i - 1] == '\r') - (*line)[i - 1] = '\0'; - break; - } - } - else - return FTPRERR; - } + { + int res; + if (i > bufsize - 1) + *line = (char *)xrealloc (*line, (bufsize <<= 1)); + res = RBUF_READCHAR (rbuf, *line + i); + /* RES is number of bytes read. */ + if (res == 1) + { + if ((*line)[i] == '\n') + { + (*line)[i] = '\0'; + /* Get rid of \r. */ + if (i > 0 && (*line)[i - 1] == '\r') + (*line)[i - 1] = '\0'; + break; + } + } + else + return FTPRERR; + } if (opt.server_response) - logprintf (LOG_ALWAYS, "%s\n", *line); + logprintf (LOG_ALWAYS, "%s\n", *line); else - DEBUGP (("%s\n", *line)); + DEBUGP (("%s\n", *line)); } while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) && - ISDIGIT ((*line)[2]) && (*line)[3] == ' ')); + ISDIGIT ((*line)[2]) && (*line)[3] == ' ')); strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline)); ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0'; return FTPOK; @@ -105,16 +100,16 @@ static char * ftp_request (const char *command, const char *value) { char *res = (char *)xmalloc (strlen (command) - + (value ? (1 + strlen (value)) : 0) - + 2 + 1); + + (value ? (1 + strlen (value)) : 0) + + 2 + 1); sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : ""); if (opt.server_response) { /* Hack: don't print out password. */ if (strncmp (res, "PASS", 4) != 0) - logprintf (LOG_ALWAYS, "--> %s\n", res); + logprintf (LOG_ALWAYS, "--> %s\n", res); else - logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n"); + logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n"); } else DEBUGP (("\n--> %s\n", res)); @@ -138,41 +133,41 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPSRVERR; } - free (respline); + xfree (respline); /* Send USER username. */ request = ftp_request ("USER", acc); nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } /* An unprobable possibility of logging without a password. */ if (*respline == '2') { - free (respline); + xfree (respline); return FTPOK; } /* Else, only response 3 is appropriate. */ if (*respline != '3') { - free (respline); + xfree (respline); return FTPLOGREFUSED; } #ifdef USE_OPIE @@ -185,57 +180,57 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) for (i = 0; i < ARRAY_SIZE (skey_head); i++) { - if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0) - break; + if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0) + break; } if (i < ARRAY_SIZE (skey_head)) { - const char *cp; - int skey_sequence = 0; - - for (cp = respline + strlen (skey_head[i]); - '0' <= *cp && *cp <= '9'; - cp++) - { - skey_sequence = skey_sequence * 10 + *cp - '0'; - } - if (*cp == ' ') - cp++; - else - { - bad: - free (respline); - return FTPLOGREFUSED; - } - if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0) - goto bad; - pass = cp; + const char *cp; + int skey_sequence = 0; + + for (cp = respline + strlen (skey_head[i]); + '0' <= *cp && *cp <= '9'; + cp++) + { + skey_sequence = skey_sequence * 10 + *cp - '0'; + } + if (*cp == ' ') + cp++; + else + { + bad: + xfree (respline); + return FTPLOGREFUSED; + } + if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0) + goto bad; + pass = cp; } } #endif /* USE_OPIE */ - free (respline); + xfree (respline); /* Send PASS password. */ request = ftp_request ("PASS", pass); nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPLOGINC; } - free (respline); + xfree (respline); /* All OK. */ return FTPOK; } @@ -264,30 +259,30 @@ ftp_port (struct rbuf *rbuf) /* Construct the argument of PORT (of the form a,b,c,d,e,f). */ bytes = (char *)alloca (6 * 4 + 1); sprintf (bytes, "%d,%d,%d,%d,%d,%d", in_addr[0], in_addr[1], - in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8, - port & 0xff); + in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8, + port & 0xff); /* Send PORT request. */ request = ftp_request ("PORT", bytes); nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPPORTERR; } - free (respline); + xfree (respline); return FTPOK; } @@ -307,20 +302,20 @@ ftp_pasv (struct rbuf *rbuf, unsigned char *addr) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get the server response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPNOPASV; } /* Parse the request. */ @@ -332,17 +327,17 @@ ftp_pasv (struct rbuf *rbuf, unsigned char *addr) { addr[i] = 0; for (; ISDIGIT (*s); s++) - addr[i] = (*s - '0') + 10 * addr[i]; + addr[i] = (*s - '0') + 10 * addr[i]; if (*s == ',') - s++; + s++; else if (i < 5) - { - /* When on the last number, anything can be a terminator. */ - free (respline); - return FTPINVPASV; - } + { + /* When on the last number, anything can be a terminator. */ + xfree (respline); + return FTPINVPASV; + } } - free (respline); + xfree (respline); return FTPOK; } @@ -363,23 +358,23 @@ ftp_type (struct rbuf *rbuf, int type) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPUNKNOWNTYPE; } - free (respline); + xfree (respline); /* All OK. */ return FTPOK; } @@ -398,28 +393,28 @@ ftp_cwd (struct rbuf *rbuf, const char *dir) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline == '5') { - free (respline); + xfree (respline); return FTPNSFOD; } if (*respline != '2') { - free (respline); + xfree (respline); return FTPRERR; } - free (respline); + xfree (respline); /* All OK. */ return FTPOK; } @@ -438,23 +433,23 @@ ftp_rest (struct rbuf *rbuf, long offset) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline != '3') { - free (respline); + xfree (respline); return FTPRESTFAIL; } - free (respline); + xfree (respline); /* All OK. */ return FTPOK; } @@ -472,28 +467,28 @@ ftp_retr (struct rbuf *rbuf, const char *file) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate response. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline == '5') { - free (respline); + xfree (respline); return FTPNSFOD; } if (*respline != '1') { - free (respline); + xfree (respline); return FTPRERR; } - free (respline); + xfree (respline); /* All OK. */ return FTPOK; } @@ -512,28 +507,200 @@ ftp_list (struct rbuf *rbuf, const char *file) nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); if (nwritten < 0) { - free (request); + xfree (request); return WRITEFAILED; } - free (request); + xfree (request); /* Get appropriate respone. */ err = ftp_response (rbuf, &respline); if (err != FTPOK) { - free (respline); + xfree (respline); return err; } if (*respline == '5') { - free (respline); + xfree (respline); return FTPNSFOD; } if (*respline != '1') { - free (respline); + xfree (respline); return FTPRERR; } - free (respline); + xfree (respline); + /* All OK. */ + return FTPOK; +} + +/* Sends the SYST command to the server. */ +uerr_t +ftp_syst (struct rbuf *rbuf, enum stype *server_type) +{ + char *request, *respline; + int nwritten; + uerr_t err; + + /* Send SYST request. */ + request = ftp_request ("SYST", NULL); + nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); + if (nwritten < 0) + { + xfree (request); + return WRITEFAILED; + } + xfree (request); + /* Get appropriate response. */ + err = ftp_response (rbuf, &respline); + if (err != FTPOK) + { + xfree (respline); + return err; + } + if (*respline == '5') + { + xfree (respline); + return FTPSRVERR; + } + + /* Skip the number (215, but 200 (!!!) in case of VMS) */ + strtok (respline, " "); + + /* Which system type has been reported (we are interested just in the + first word of the server response)? */ + request = strtok (NULL, " "); + + if (!strcasecmp (request, "VMS")) + *server_type = ST_VMS; + else + if (!strcasecmp (request, "UNIX")) + *server_type = ST_UNIX; + else + if (!strcasecmp (request, "WINDOWS_NT")) + *server_type = ST_WINNT; + else + if (!strcasecmp (request, "MACOS")) + *server_type = ST_MACOS; + else + *server_type = ST_OTHER; + + xfree (respline); + /* All OK. */ + return FTPOK; +} + +/* Sends the PWD command to the server. */ +uerr_t +ftp_pwd (struct rbuf *rbuf, char **pwd) +{ + char *request, *respline; + int nwritten; + uerr_t err; + + /* Send PWD request. */ + request = ftp_request ("PWD", NULL); + nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); + if (nwritten < 0) + { + xfree (request); + return WRITEFAILED; + } + xfree (request); + /* Get appropriate response. */ + err = ftp_response (rbuf, &respline); + if (err != FTPOK) + { + xfree (respline); + return err; + } + if (*respline == '5') + { + xfree (respline); + return FTPSRVERR; + } + + /* Skip the number (257), leading citation mark, trailing citation mark + and everything following it. */ + strtok (respline, "\""); + request = strtok (NULL, "\""); + + /* Has the `pwd' been already allocated? Free! */ + FREE_MAYBE (*pwd); + + *pwd = xstrdup (request); + + xfree (respline); + /* All OK. */ + return FTPOK; +} + +/* Sends the SIZE command to the server, and returns the value in 'size'. + * If an error occurs, size is set to zero. */ +uerr_t +ftp_size (struct rbuf *rbuf, const char *file, long int *size) +{ + char *request, *respline; + int nwritten; + uerr_t err; + + /* Send PWD request. */ + request = ftp_request ("SIZE", file); + nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); + if (nwritten < 0) + { + xfree (request); + *size = 0; + return WRITEFAILED; + } + xfree (request); + /* Get appropriate response. */ + err = ftp_response (rbuf, &respline); + if (err != FTPOK) + { + xfree (respline); + *size = 0; + return err; + } + if (*respline == '5') + { + /* + * Probably means SIZE isn't supported on this server. + * Error is nonfatal since SIZE isn't in RFC 959 + */ + xfree (respline); + *size = 0; + return FTPOK; + } + + errno = 0; + *size = strtol (respline + 4, NULL, 0); + if (errno) + { + /* + * Couldn't parse the response for some reason. On the (few) + * tests I've done, the response is 213 with nothing else - + * maybe something a bit more resilient is necessary. It's not a + * fatal error, however. + */ + xfree (respline); + *size = 0; + return FTPOK; + } + + xfree (respline); /* All OK. */ return FTPOK; } + +/* If URL's params are of the form "type=X", return character X. + Otherwise, return 'I' (the default type). */ +char +ftp_process_type (const char *params) +{ + if (params + && 0 == strncasecmp (params, "type=", 5) + && params[5] != '\0') + return TOUPPER (params[5]); + else + return 'I'; +}