2 Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
4 This file is part of Wget.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
32 #include <sys/types.h>
45 char ftp_last_respline[128];
48 /* Get the response of FTP server and allocate enough room to handle
49 it. <CR> and <LF> characters are stripped from the line, and the
50 line is 0-terminated. All the response lines but the last one are
51 skipped. The last line is determined as described in RFC959. */
53 ftp_response (struct rbuf *rbuf, char **line)
58 *line = (char *)xmalloc (bufsize);
65 *line = (char *)xrealloc (*line, (bufsize <<= 1));
66 res = RBUF_READCHAR (rbuf, *line + i);
67 /* RES is number of bytes read. */
70 if ((*line)[i] == '\n')
74 if (i > 0 && (*line)[i - 1] == '\r')
75 (*line)[i - 1] = '\0';
82 if (opt.server_response)
83 logprintf (LOG_ALWAYS, "%s\n", *line);
85 DEBUGP (("%s\n", *line));
87 while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) &&
88 ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
89 strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline));
90 ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
94 /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
95 it if printing is required. If VALUE is NULL, just use
98 ftp_request (const char *command, const char *value)
100 char *res = (char *)xmalloc (strlen (command)
101 + (value ? (1 + strlen (value)) : 0)
103 sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
104 if (opt.server_response)
106 /* Hack: don't print out password. */
107 if (strncmp (res, "PASS", 4) != 0)
108 logprintf (LOG_ALWAYS, "--> %s\n", res);
110 logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
113 DEBUGP (("\n--> %s\n", res));
118 const char *calculate_skey_response PARAMS ((int, const char *, const char *));
121 /* Sends the USER and PASS commands to the server, to control
122 connection socket csock. */
124 ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
127 char *request, *respline;
131 err = ftp_response (rbuf, &respline);
137 if (*respline != '2')
143 /* Send USER username. */
144 request = ftp_request ("USER", acc);
145 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
152 /* Get appropriate response. */
153 err = ftp_response (rbuf, &respline);
159 /* An unprobable possibility of logging without a password. */
160 if (*respline == '2')
165 /* Else, only response 3 is appropriate. */
166 if (*respline != '3')
169 return FTPLOGREFUSED;
173 static const char *skey_head[] = {
179 for (i = 0; i < ARRAY_SIZE (skey_head); i++)
181 if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
184 if (i < ARRAY_SIZE (skey_head))
187 int skey_sequence = 0;
189 for (cp = respline + strlen (skey_head[i]);
190 '0' <= *cp && *cp <= '9';
193 skey_sequence = skey_sequence * 10 + *cp - '0';
201 return FTPLOGREFUSED;
203 if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
208 #endif /* USE_OPIE */
210 /* Send PASS password. */
211 request = ftp_request ("PASS", pass);
212 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
219 /* Get appropriate response. */
220 err = ftp_response (rbuf, &respline);
226 if (*respline != '2')
236 /* Bind a port and send the appropriate PORT command to the FTP
237 server. Use acceptport after RETR, to get the socket of data
240 ftp_port (struct rbuf *rbuf)
243 char *request, *respline, *bytes;
244 unsigned char *in_addr;
248 /* Setting port to 0 lets the system choose a free port. */
251 err = bindport (&port);
254 /* Get the address of this side of the connection. */
255 if (!(in_addr = conaddr (RBUF_FD (rbuf))))
257 /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
258 bytes = (char *)alloca (6 * 4 + 1);
259 sprintf (bytes, "%d,%d,%d,%d,%d,%d", in_addr[0], in_addr[1],
260 in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8,
262 /* Send PORT request. */
263 request = ftp_request ("PORT", bytes);
264 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
271 /* Get appropriate response. */
272 err = ftp_response (rbuf, &respline);
278 if (*respline != '2')
287 /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
288 transfer. Reads the response from server and parses it. Reads the
289 host and port addresses and returns them. */
291 ftp_pasv (struct rbuf *rbuf, unsigned char *addr)
293 char *request, *respline, *s;
297 /* Form the request. */
298 request = ftp_request ("PASV", NULL);
300 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
307 /* Get the server response. */
308 err = ftp_response (rbuf, &respline);
314 if (*respline != '2')
319 /* Parse the request. */
321 for (s += 4; *s && !ISDIGIT (*s); s++);
324 for (i = 0; i < 6; i++)
327 for (; ISDIGIT (*s); s++)
328 addr[i] = (*s - '0') + 10 * addr[i];
333 /* When on the last number, anything can be a terminator. */
342 /* Sends the TYPE request to the server. */
344 ftp_type (struct rbuf *rbuf, int type)
346 char *request, *respline;
351 /* Construct argument. */
354 /* Send TYPE request. */
355 request = ftp_request ("TYPE", stype);
356 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
363 /* Get appropriate response. */
364 err = ftp_response (rbuf, &respline);
370 if (*respline != '2')
373 return FTPUNKNOWNTYPE;
380 /* Changes the working directory by issuing a CWD command to the
383 ftp_cwd (struct rbuf *rbuf, const char *dir)
385 char *request, *respline;
389 /* Send CWD request. */
390 request = ftp_request ("CWD", dir);
391 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
398 /* Get appropriate response. */
399 err = ftp_response (rbuf, &respline);
405 if (*respline == '5')
410 if (*respline != '2')
420 /* Sends REST command to the FTP server. */
422 ftp_rest (struct rbuf *rbuf, long offset)
424 char *request, *respline;
427 static char numbuf[20]; /* Buffer for the number */
429 long_to_string (numbuf, offset);
430 request = ftp_request ("REST", numbuf);
431 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
438 /* Get appropriate response. */
439 err = ftp_response (rbuf, &respline);
445 if (*respline != '3')
455 /* Sends RETR command to the FTP server. */
457 ftp_retr (struct rbuf *rbuf, const char *file)
459 char *request, *respline;
463 /* Send RETR request. */
464 request = ftp_request ("RETR", file);
465 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
472 /* Get appropriate response. */
473 err = ftp_response (rbuf, &respline);
479 if (*respline == '5')
484 if (*respline != '1')
494 /* Sends the LIST command to the server. If FILE is NULL, send just
495 `LIST' (no space). */
497 ftp_list (struct rbuf *rbuf, const char *file)
499 char *request, *respline;
503 /* Send LIST request. */
504 request = ftp_request ("LIST", file);
505 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
512 /* Get appropriate respone. */
513 err = ftp_response (rbuf, &respline);
519 if (*respline == '5')
524 if (*respline != '1')
534 /* Sends the SYST command to the server. */
536 ftp_syst (struct rbuf *rbuf, enum stype *server_type)
538 char *request, *respline;
542 /* Send SYST request. */
543 request = ftp_request ("SYST", NULL);
544 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
551 /* Get appropriate response. */
552 err = ftp_response (rbuf, &respline);
558 if (*respline == '5')
564 /* Skip the number (215, but 200 (!!!) in case of VMS) */
565 strtok (respline, " ");
567 /* Which system type has been reported (we are interested just in the
568 first word of the server response)? */
569 request = strtok (NULL, " ");
571 if (!strcasecmp (request, "VMS"))
572 *server_type = ST_VMS;
574 if (!strcasecmp (request, "UNIX"))
575 *server_type = ST_UNIX;
577 if (!strcasecmp (request, "WINDOWS_NT"))
578 *server_type = ST_WINNT;
580 if (!strcasecmp (request, "MACOS"))
581 *server_type = ST_MACOS;
583 *server_type = ST_OTHER;
590 /* Sends the PWD command to the server. */
592 ftp_pwd (struct rbuf *rbuf, char **pwd)
594 char *request, *respline;
598 /* Send PWD request. */
599 request = ftp_request ("PWD", NULL);
600 nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
607 /* Get appropriate response. */
608 err = ftp_response (rbuf, &respline);
614 if (*respline == '5')
620 /* Skip the number (257), leading citation mark, trailing citation mark
621 and everything following it. */
622 strtok (respline, "\"");
623 request = strtok (NULL, "\"");
625 /* Has the `pwd' been already allocated? Free! */
628 *pwd = xstrdup (request);