1 /***************************************************************************/
2 /*    This code is part of WWW grabber called pavuk                        */
3 /*    Copyright (c) 1997 - 2001 Stefan Ondrejicka                          */
4 /*    Distributed under GPL 2 or later                                     */
5 /***************************************************************************/
6 
7 #include "config.h"
8 
9 #include <ctype.h>
10 #include <errno.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <netdb.h>
14 #include <netinet/in.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <unistd.h>
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
26 #endif
27 
28 #include "absio.h"
29 #include "abstract.h"
30 #include "dns.h"
31 #include "doc.h"
32 #include "errcode.h"
33 #include "ftp.h"
34 #include "http.h"
35 #include "mode.h"
36 #include "myssl.h"
37 #include "net.h"
38 #include "times.h"
39 #include "tools.h"
40 #include "uexit.h"
41 #include "url.h"
42 
43 static ftp_handshake_info *ftp_handshake_info_data_find(char *, int);
44 static int ftp_do_login_handshake_cust(ftp_handshake_info *, doc *, char *,
45   char *);
46 
ftp_control_write(doc * docp,char * buf,size_t bufsize)47 static int ftp_control_write(doc * docp, char *buf, size_t bufsize)
48 {
49   return bufio_write(docp->ftp_control, buf, bufsize);
50 }
51 
ftp_control_readln(doc * docp,char * buf,int bufsize)52 static int ftp_control_readln(doc * docp, char *buf, int bufsize)
53 {
54   return bufio_readln(docp->ftp_control, buf, bufsize);
55 }
56 
57 /********************************************************/
58 /* zistenie navratoveho kodu z FTP servera              */
59 /* FIXME: Translate me!                                 */
60 /********************************************************/
ftp_get_response(doc * docp,char ** mbuf,int setrc)61 int ftp_get_response(doc * docp, char **mbuf, int setrc)
62 {
63   char buf[1024];
64   bool_t end = FALSE;
65   int alen, tlen = 0;
66   char *sresp = NULL;
67 
68   while(!end)
69   {
70     if((alen = ftp_control_readln(docp, buf, sizeof(buf))) > 0)
71     {
72       DEBUG_PROTOS("%s", buf);
73       if(mbuf)
74       {
75         tlen += alen;
76         sresp = _realloc(sresp, tlen + 1);
77         memcpy(sresp + tlen - alen, buf, alen + 1);
78       }
79 
80       if(strlen(buf) > 3)
81       {
82         if(tl_ascii_isdigit(*(buf)) &&
83           tl_ascii_isdigit(*(buf + 1)) &&
84           tl_ascii_isdigit(*(buf + 2)) && tl_ascii_isspace(*(buf + 3)))
85           end = TRUE;
86       }
87     }
88     else
89     {
90       if(alen)
91         xperror("ftp_get_response");
92       else
93         xprintf(1,
94           gettext
95           ("ftp_get_response: ftp control connection closed before any response\n"));
96       if(setrc)
97         docp->ftp_respc = 600;
98       return 600;
99     }
100   }
101 
102   if(mbuf)
103     *mbuf = sresp;
104 
105   if(setrc)
106     docp->ftp_respc = _atoi(buf);
107 
108   return _atoi(buf);
109 }
110 
ftp_open_data_finish(doc * docp)111 static bufio *ftp_open_data_finish(doc * docp)
112 {
113   if(docp->ftp_data_con_finished)
114     return docp->datasock;
115 
116   if(!cfg.ftp_activec || (priv_cfg.ftp_proxy && cfg.ftp_dirtyp))
117   {
118     if(priv_cfg.ftp_proxy && cfg.ftp_dirtyp)
119     {
120       if(!(docp->datasock =
121           bufio_sock_fdopen(net_connect(priv_cfg.ftp_proxy,
122               cfg.ftp_proxy_port, docp))))
123       {
124         if(_h_errno_ != 0)
125           xherror(priv_cfg.ftp_proxy);
126         else
127           xperror("net_connect");
128 
129         docp->errcode = ERR_PROXY_CONNECT;
130         return NULL;
131       }
132       if(http_dumy_proxy_connect(docp, docp->ftp_pasv_host,
133           docp->ftp_pasv_port, priv_cfg.ftp_proxy, cfg.ftp_proxy_port))
134       {
135         docp->errcode = ERR_PROXY_CONNECT;
136         bufio_close(docp->datasock);
137         docp->datasock = NULL;
138         return NULL;
139       }
140     }
141     else
142     {
143       if(!(docp->datasock =
144           bufio_sock_fdopen(net_connect(docp->ftp_pasv_host,
145               docp->ftp_pasv_port, docp))))
146       {
147         if(_h_errno_ != 0)
148           xherror(priv_cfg.ftp_proxy);
149         else
150           xperror("net_connect");
151 
152         docp->errcode = ERR_FTP_DATACON;
153         return NULL;
154       }
155     }
156   }
157   else
158   {
159     bufio *dsock = bufio_sock_fdopen(net_accept(bufio_getfd(docp->datasock)));
160     bufio_close(docp->datasock);
161     docp->datasock = dsock;
162   }
163 
164 #ifdef IP_TOS
165 #ifdef IPTOS_THROUGHPUT
166   if(docp->datasock)
167   {
168     int v = IPTOS_THROUGHPUT;
169 
170     if(setsockopt(bufio_getfd(docp->datasock),
171         IPPROTO_IP, IP_TOS, (char *) &v, sizeof(v)))
172     {
173       xperror(gettext("ftp: setsockopt TOS - THROUGHPUT failed"));
174     }
175   }
176 #endif
177 #endif
178 
179 #ifdef USE_SSL
180   if(docp->doc_url->type == URLT_FTPS)
181   {
182     bufio *ssl_sock;
183 
184     ssl_sock = my_ssl_do_connect(docp, docp->datasock,
185       bufio_get_ssl_hook_data(docp->ftp_control));
186 
187     if(!ssl_sock)
188     {
189       if(!docp->errcode)
190         docp->errcode = ERR_FTPS_DATASSLCONNECT;
191       bufio_close(docp->datasock);
192       docp->datasock = NULL;
193     }
194     else
195       docp->datasock = ssl_sock;
196   }
197 #endif
198 
199   if(docp->datasock)
200     docp->ftp_data_con_finished = TRUE;
201 
202   return docp->datasock;
203 }
204 
ftp_open_data_init(doc * docp)205 static int ftp_open_data_init(doc * docp)
206 {
207   char buf[256];
208   char *mbuf;
209   struct sockaddr_storage scaddr;
210   struct sockaddr *caddr;
211   int reply;
212   socklen_t n;
213 
214   caddr = (struct sockaddr *) &scaddr;
215 
216   n = sizeof(scaddr);
217   if(getsockname(bufio_getfd(docp->ftp_control), caddr, &n))
218   {
219     xperror("FTP control getsockname");
220     docp->datasock = NULL;
221     return -1;
222   }
223 
224 
225   if(!cfg.ftp_activec || (priv_cfg.ftp_proxy && cfg.ftp_dirtyp))
226   {
227 #ifdef HAVE_INET6
228     if(caddr->sa_family == AF_INET6)
229     {
230       sprintf(buf, "EPSV\r\n");
231       DEBUG_PROTOC("%s", buf);
232 
233       ftp_control_write(docp, buf, strlen(buf));
234 
235       mbuf = NULL;
236 
237       if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
238       {
239         int h[16], p[2], hal, af, pal;
240         abs_addr haddr;
241 
242         _free(mbuf) if(reply == 600)
243         {
244           docp->ftp_fatal_err = TRUE;
245           return -1;
246         }
247         sprintf(buf, "LPSV\r\n");
248         DEBUG_PROTOC("%s", buf);
249 
250         ftp_control_write(docp, buf, strlen(buf));
251 
252         mbuf = NULL;
253 
254         if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
255         {
256           docp->ftp_fatal_err = (reply == 600);
257           _free(mbuf);
258           return -1;
259         }
260         n = sscanf(mbuf,
261           "%d %*[^0-9]%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
262           &reply, &af, &hal, &h[0], &h[1], &h[2], &h[3],
263           &h[4], &h[5], &h[6], &h[7], &h[8], &h[9],
264           &h[10], &h[11], &h[12], &h[13], &h[14], &h[15], &pal, &p[0], &p[1]);
265         if(n != 22 || reply != 228 || af != 6 || hal != 16 || pal != 2)
266         {
267           xprintf(1,
268             gettext("Error parsing FTP response to %s command - %s\n"),
269             "LPSV", mbuf);
270           _free(mbuf);
271           return -1;
272         }
273         _free(mbuf);
274         docp->ftp_pasv_port = (p[0] << 8) + p[1];
275         haddr.family = AF_INET6;
276         for(n = 0; n < 16; n++)
277           haddr.addr[n] = (unsigned char) h[n];
278         docp->ftp_pasv_host = dns_get_abs_addr_ip(&haddr);
279       }
280       else
281       {
282         int port;
283         char d[4];
284 
285         n = sscanf(mbuf, "%d %*[^0-9(]\(%c%c%c%d%c", &reply,
286           &d[0], &d[1], &d[2], &port, &d[3]);
287         if(n != 6 || reply != 229 ||
288           d[0] != d[1] || d[0] != d[2] || d[0] != d[3])
289         {
290           xprintf(1,
291             gettext("Error parsing FTP response to %s command - %s\n"),
292             "EPSV", mbuf);
293           _free(mbuf);
294           return -1;
295         }
296         _free(mbuf);
297         docp->ftp_pasv_port = port;
298         docp->ftp_pasv_host = dns_get_sockaddr_ip(caddr);
299       }
300     }
301     else
302 #endif
303     {
304       int h0, h1, h2, h3, p0, p1;
305 
306       sprintf(buf, "PASV\r\n");
307       DEBUG_PROTOC("%s", buf);
308 
309       ftp_control_write(docp, buf, strlen(buf));
310 
311       mbuf = NULL;
312 
313       if((reply = ftp_get_response(docp, &mbuf, TRUE)) >= 400)
314       {
315         docp->ftp_fatal_err = (reply == 600);
316         _free(mbuf);
317         return -1;
318       }
319 
320       if(!mbuf)
321       {
322         return -1;
323       }
324 
325       n = sscanf(mbuf, "%d %*[^0-9]%d,%d,%d,%d,%d,%d", &reply,
326         &h0, &h1, &h2, &h3, &p0, &p1);
327 
328 
329       if(n != 7 || reply != 227)
330       {
331         xprintf(1, gettext("Error parsing FTP response to %s command - %s\n"),
332           "PASV", mbuf);
333         _free(mbuf);
334         return -1;
335       }
336       _free(mbuf);
337 
338       docp->ftp_pasv_port = (p0 << 8) + p1;
339 
340       sprintf(buf, "%d.%d.%d.%d", h0, h1, h2, h3);
341       docp->ftp_pasv_host = tl_strdup(buf);
342     }
343   }
344   else
345   {
346     struct sockaddr_storage saddr;
347     struct sockaddr *addr;
348     char *p;
349     int port;
350 
351     addr = (struct sockaddr *) &saddr;
352 
353     if(!docp->datasock)
354     {
355       int bfd;
356       abs_addr laddr;
357       memset(laddr.addr, '\0', sizeof(laddr.addr));
358       laddr.family = caddr->sa_family;
359 
360       if(priv_cfg.local_ip)
361       {
362         memcpy(laddr.addr, cfg.local_ip_addr.addr, sizeof(laddr.addr));
363         laddr.family = cfg.local_ip_addr.family;
364       }
365 
366       bfd = net_bindport(&laddr, cfg.active_ftp_min_port,
367         cfg.active_ftp_max_port);
368 
369       if(!(docp->datasock = bufio_sock_fdopen(bfd)))
370       {
371         xperror("bind");
372         return -1;
373       }
374     }
375 
376     n = sizeof(saddr);
377     if(getsockname(bufio_getfd(docp->datasock), addr, &n))
378     {
379       xperror("FTP data getsockname");
380       bufio_close(docp->datasock);
381       docp->datasock = NULL;
382       return -1;
383     }
384 
385     port = dns_get_sockaddr_port(addr);
386     mbuf = dns_get_sockaddr_ip(caddr);
387 #ifdef HAVE_INET6
388     if(caddr->sa_family == AF_INET6)
389     {
390       snprintf(buf, sizeof(buf), "EPRT |2|%s|%d|\r\n", mbuf, port);
391       _free(mbuf);
392 
393       ftp_control_write(docp, buf, strlen(buf));
394       DEBUG_PROTOC("%s", buf);
395 
396       if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
397       {
398         unsigned char *h;
399 
400         if(reply == 600)
401         {
402           bufio_close(docp->datasock);
403           docp->datasock = NULL;
404           docp->ftp_fatal_err = TRUE;
405           return -1;
406         }
407         h = ((struct sockaddr_in6 *) caddr)->sin6_addr.s6_addr;
408 
409         sprintf(buf,
410           "LPRT 6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d\r\n",
411           h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10],
412           h[11], h[12], h[13], h[14], h[15], port / 256, port % 256);
413 
414         ftp_control_write(docp, buf, strlen(buf));
415         DEBUG_PROTOC("%s", buf);
416 
417         if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
418         {
419           bufio_close(docp->datasock);
420           docp->datasock = NULL;
421           docp->ftp_fatal_err = (reply == 600);
422           return -1;
423         }
424       }
425     }
426     else
427 #endif
428     {
429       for(p = mbuf; (p = strchr(p, '.')); *p = ',');
430       snprintf(buf, sizeof(buf), "PORT %s,%d,%d\r\n", mbuf, port / 256, port % 256);
431       _free(mbuf);
432 
433       ftp_control_write(docp, buf, strlen(buf));
434       DEBUG_PROTOC("%s", buf);
435 
436       if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
437       {
438         bufio_close(docp->datasock);
439         docp->datasock = NULL;
440         docp->ftp_fatal_err = (reply == 600);
441         return -1;
442       }
443     }
444   }
445 
446   return 0;
447 }
448 
ftp_do_login_handshake(doc * docp,char * ruser,char * user,char * password)449 static int ftp_do_login_handshake(doc * docp, char *ruser, char *user,
450   char *password)
451 {
452   ftp_handshake_info *fhi;
453 
454   fhi = ftp_handshake_info_data_find(docp->doc_url->p.ftp.host,
455     docp->doc_url->p.ftp.port);
456 
457   if(!fhi)
458     fhi = ftp_handshake_info_data_find("", DEFAULT_FTP_PORT);
459 
460   if(fhi)
461   {
462     if(ftp_do_login_handshake_cust(fhi, docp, ruser, password))
463     {
464       docp->ftp_fatal_err = TRUE;
465       docp->errcode = ERR_FTP_LOGIN_HANDSHAKE;
466       return -1;
467     }
468   }
469   else
470   {
471     char buf[2048];
472     int reply;
473 
474     if(priv_cfg.ftp_proxy_user && priv_cfg.ftp_proxy &&
475       !cfg.ftp_via_http && !cfg.ftp_dirtyp)
476     {
477       snprintf(buf, sizeof(buf), "USER %s\r\n", priv_cfg.ftp_proxy_user);
478       ftp_control_write(docp, buf, strlen(buf));
479       DEBUG_PROTOC("%s", buf);
480 
481       if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
482       {
483         docp->ftp_fatal_err = TRUE;
484         docp->errcode = ERR_FTP_BPROXYUSER;
485         return -1;
486       }
487     }
488     else
489       reply = 0;
490 
491     if(priv_cfg.ftp_proxy_pass && priv_cfg.ftp_proxy &&
492       !cfg.ftp_via_http && !cfg.ftp_dirtyp)
493     {
494 
495       if(reply == 331)  /*** we need password ***/
496       {
497         snprintf(buf, sizeof(buf), "PASS %s\r\n", priv_cfg.ftp_proxy_pass);
498         ftp_control_write(docp, buf, strlen(buf));
499         DEBUG_PROTOC("%s", buf);
500 
501         if(ftp_get_response(docp, NULL, TRUE) >= 400)
502         {
503           docp->ftp_fatal_err = TRUE;
504           docp->errcode = ERR_FTP_BPROXYPASS;
505           return -1;
506         }
507       }
508     }
509 
510     snprintf(buf, sizeof(buf), "USER %s\r\n", user);
511     ftp_control_write(docp, buf, strlen(buf));
512     DEBUG_PROTOC("%s", buf);
513 
514     if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
515     {
516       docp->ftp_fatal_err = TRUE;
517       docp->errcode = ERR_FTP_BUSER;
518       return -1;
519     }
520 
521     if(reply == 331)  /*** we need password ***/
522     {
523       snprintf(buf, sizeof(buf), "PASS %s\r\n", password);
524       ftp_control_write(docp, buf, strlen(buf));
525       DEBUG_PROTOC("%s", buf);
526 
527       if(ftp_get_response(docp, NULL, TRUE) >= 400)
528       {
529         docp->ftp_fatal_err = TRUE;
530         docp->errcode = ERR_FTP_BPASS;
531         return -1;
532       }
533     }
534   }
535 
536   return 0;
537 }
538 
539 #define CLOSE_CONTROL \
540   bufio_close(docp->ftp_control);\
541   docp->ftp_control = NULL;
542 
ftp_open_control_connection(doc * docp,char * host,int port,char * ruser,char * user,char * password)543 static bufio *ftp_open_control_connection(doc * docp, char *host, int port,
544   char *ruser, char *user, char *password)
545 {
546 
547   docp->errcode = ERR_NOERROR;
548   docp->ftp_fatal_err = FALSE;
549   docp->ftp_respc = 0;
550 
551   if(!docp->ftp_control)
552   {
553     if(priv_cfg.ftp_proxy && cfg.ftp_dirtyp)
554     {
555       if(!(docp->datasock =
556           bufio_sock_fdopen(net_connect(priv_cfg.ftp_proxy,
557               cfg.ftp_proxy_port, docp))))
558       {
559         if(_h_errno_ != 0)
560           xherror(priv_cfg.ftp_proxy);
561         else
562           xperror("net_connect");
563 
564         docp->errcode = ERR_PROXY_CONNECT;
565         return NULL;
566       }
567 
568       if(http_dumy_proxy_connect(docp, host, port, priv_cfg.ftp_proxy,
569           cfg.ftp_proxy_port))
570       {
571         docp->errcode = ERR_PROXY_CONNECT;
572         return NULL;
573       }
574       docp->ftp_control = docp->datasock;
575       docp->datasock = NULL;
576     }
577     else
578     {
579       if(!(docp->ftp_control =
580           bufio_sock_fdopen(net_connect(host, port, docp))))
581       {
582         if(_h_errno_ != 0)
583           xherror(host);
584         else
585           xperror("net_connect");
586 
587         docp->errcode = ERR_FTP_CONNECT;
588         docp->ftp_fatal_err = TRUE;
589         return NULL;
590       }
591     }
592     if(ftp_get_response(docp, NULL, TRUE) >= 400)
593     {
594       CLOSE_CONTROL;
595       docp->ftp_fatal_err = TRUE;
596       docp->errcode = ERR_FTP_CONNECT;
597       return NULL;
598     }
599 #ifdef USE_SSL
600     if(docp->doc_url->type == URLT_FTPS)
601     {
602       char buf[2048];
603       int reply;
604       bufio *ssl_sock;
605 
606       sprintf(buf, "AUTH SSL\r\n");
607       ftp_control_write(docp, buf, strlen(buf));
608       DEBUG_PROTOC("%s", buf);
609 
610       reply = ftp_get_response(docp, NULL, TRUE);
611 
612       /*** 234 code is used by SafeGossip ***/
613       /*** thank to Martijn ...           ***/
614       if(reply != 334 && reply != 234)
615       {
616         CLOSE_CONTROL;
617         docp->ftp_fatal_err = (reply == 600);
618         docp->errcode = ERR_FTPS_UNSUPORTED;
619         return NULL;
620       }
621 
622       ssl_sock = my_ssl_do_connect(docp, docp->ftp_control, NULL);
623 
624       if(!ssl_sock)
625       {
626         if(!docp->errcode)
627           docp->errcode = ERR_FTPS_CONNECT;
628         CLOSE_CONTROL;
629         return NULL;
630       }
631       else
632       {
633         docp->ftp_control = ssl_sock;
634       }
635     }
636 #endif
637 
638     if(ftp_do_login_handshake(docp, ruser, user, password))
639     {
640       CLOSE_CONTROL;
641       return NULL;
642     }
643 
644 #ifdef IP_TOS
645 #ifdef IPTOS_LOWDELAY
646     if(docp->ftp_control)
647     {
648       int v = IPTOS_LOWDELAY;
649       if(setsockopt(bufio_getfd(docp->ftp_control),
650           IPPROTO_IP, IP_TOS, (char *) &v, sizeof(v)))
651       {
652         perror("ftp: setsockopt TOS - LOWDELAY failed");
653       }
654     }
655 #endif
656 #endif
657 
658   }
659 #ifdef DEBUG
660   else
661   {
662     if(cfg.debug)
663       xprintf(1, gettext("Re-using established FTP control connection\n"));
664   }
665 #endif
666 
667   return docp->ftp_control;
668 }
669 
ftp_set_transfer_type(doc * docp,char * type)670 static int ftp_set_transfer_type(doc * docp, char *type)
671 {
672   char buf[20];
673   int reply;
674 
675   snprintf(buf, sizeof(buf), "TYPE %s\r\n", type);
676   ftp_control_write(docp, buf, strlen(buf));
677   DEBUG_PROTOC("%s", buf);
678 
679   if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
680   {
681     CLOSE_CONTROL;
682     docp->ftp_fatal_err = (reply == 600);
683     docp->errcode = ERR_FTP_UNKNOWN;
684     return -1;
685   }
686 
687   return 0;
688 }
689 
ftp_send_list_command(doc * docp,char * filename)690 static int ftp_send_list_command(doc * docp, char *filename)
691 {
692   char buf[2148];
693   int l;
694 
695   l = strlen(filename) - 1;
696   if(l)
697   {
698     if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))
699       l--;
700   }
701 
702   if(cfg.ftp_list)
703     strcpy(buf, "LIST");
704   else
705     strcpy(buf, "NLST");
706 
707   if(cfg.ftp_list_options)
708   {
709     strcat(buf, " ");
710     strncat(buf, cfg.ftp_list_options, sizeof(buf) - strlen(buf));
711     buf[sizeof(buf) - 1] = '\0';
712   }
713 
714   if(l)
715   {
716     strncat(buf, " ", sizeof(buf) - strlen(buf));
717     buf[sizeof(buf) - 1] = '\0';
718     strncat(buf, filename + 1, sizeof(buf) - strlen(buf));
719     buf[sizeof(buf) - 1] = '\0';
720   }
721 
722   strncat(buf, "\r\n", sizeof(buf) - strlen(buf));
723   buf[sizeof(buf) - 1] = '\0';
724 
725   ftp_control_write(docp, buf, strlen(buf));
726   DEBUG_PROTOC("%s", buf);
727 
728   return 0;
729 }
730 
ftp_check_directory_existence(doc * docp,char * filename)731 static int ftp_check_directory_existence(doc * docp, char *filename)
732 {
733   int rv = 0;
734 
735   if(cfg.ftp_list && cfg.fix_wuftpd)
736   {
737     int l;
738     char buf[2148];
739     char *mbuf;
740 
741     l = strlen(filename) - 1;
742     if(l)
743     {
744       if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))
745         l--;
746     }
747 
748     strcpy(buf, "STAT -d1 ");
749     if(l)
750     {
751       strncat(buf, filename + 1, sizeof(buf) - strlen(buf));
752       buf[sizeof(buf) - 1] = '\0';
753       strncat(buf, "\r\n", sizeof(buf) - strlen(buf));
754       buf[sizeof(buf) - 1] = '\0';
755     }
756     else
757     {
758       /* we can assume that login directory exists */
759       return 0;
760     }
761 
762     ftp_control_write(docp, buf, strlen(buf));
763     DEBUG_PROTOC("%s", buf);
764 
765     mbuf = NULL;
766     if(ftp_get_response(docp, &mbuf, TRUE) == 213)
767     {
768       char *p;
769 
770       p = mbuf + strcspn(mbuf, "\r\n");
771       p += strspn(p, "\r\n");
772       if(strncmp(filename + 1, p, strcspn(p, "\r\n")))
773         rv = -1;
774     }
775 
776     _free(mbuf);
777   }
778 
779   return rv;
780 }
781 
782 /****************************************************************/
783 /* otvorenie spojenia na FTP server, prihlasenie + zahajenie    */
784 /* prenosu suboru / adresara                                    */
785 /* FIXME: Translate me!                                         */
786 /****************************************************************/
ftp_connect(doc * docp,char * host,int port,char * ruser,char * user,char * password,char * filename,bool_t * is_dir)787 static bufio *ftp_connect(doc * docp, char *host, int port, char *ruser,
788   char *user, char *password, char *filename, bool_t * is_dir)
789 {
790   char buf[2148];
791   int reply;
792   char *mbuf;
793 
794   docp->errcode = ERR_NOERROR;
795   docp->ftp_fatal_err = FALSE;
796   docp->ftp_respc = 0;
797 
798   if(!(docp->ftp_control =
799       ftp_open_control_connection(docp, host, port, ruser, user, password)))
800     return NULL;
801 
802   if(!tl_is_dirname(filename) && cfg.mode != MODE_FTPDIR)
803   {
804     if(docp->doc_url->extension &&
805       ((ftp_url_extension *) docp->doc_url->extension)->size > 0)
806     {
807       docp->totsz = ((ftp_url_extension *) docp->doc_url->extension)->size;
808       reply = 213;
809       DEBUG_PROTOC("taking stored size\n");
810     }
811     else
812     {
813       snprintf(buf, sizeof(buf), "SIZE %s\r\n", filename + 1);
814       ftp_control_write(docp, buf, strlen(buf));
815       DEBUG_PROTOC("%s", buf);
816 
817 
818       mbuf = NULL;
819       if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)
820       {
821         int sz;
822 
823         sscanf(mbuf, "%d %d", &reply, &sz);
824         docp->totsz = sz;
825       }
826       else
827       {
828         if(reply == 600)
829         {
830           docp->errcode = ERR_READ;
831           docp->ftp_fatal_err = TRUE;
832           _free(mbuf);
833           return NULL;
834         }
835       }
836 
837       _free(mbuf);
838     }
839 
840     if(reply != 550)  /*** file doesn't exist or not plain file  == 550 ***/
841     {
842       if(!cfg.always_mdtm &&
843         docp->doc_url->extension &&
844         ((ftp_url_extension *) docp->doc_url->extension)->time != 0)
845       {
846         docp->dtime = ((ftp_url_extension *) docp->doc_url->extension)->time;
847         reply = 213;
848         DEBUG_PROTOC("taking stored MDTM %d\n", (int)
849           ((ftp_url_extension *) docp->doc_url->extension)->time);
850       }
851       else
852       {
853         snprintf(buf, sizeof(buf), "MDTM %s\r\n", filename + 1);
854         ftp_control_write(docp, buf, strlen(buf));
855         DEBUG_PROTOC("%s", buf);
856 
857         mbuf = NULL;
858         if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)
859         {
860           sscanf(mbuf, "%d %2147s", &reply, buf);
861           if(strlen(buf) == 14)
862           {
863             docp->dtime = time_ftp_scn(buf);
864           }
865         }
866         else
867         {
868           if(reply == 600)
869           {
870             docp->ftp_fatal_err = TRUE;
871             docp->errcode = ERR_READ;
872             _free(mbuf);
873             return NULL;
874           }
875         }
876         _free(mbuf);
877       }
878 
879       DEBUG_PROTOC("Size: file %d, remote %d; time: file %d, remote %d\n",
880         docp->origsize, docp->totsz, docp->origtime, docp->dtime);
881 
882       if(docp->origsize && (docp->totsz >= 0)
883         && (docp->origsize != docp->totsz))
884       {
885         xprintf(1, gettext("Size differs, regeting whole\n"));
886         docp->rest_pos = 0;
887       }
888       else if(docp->origtime && docp->dtime)
889       {
890         if((difftime(docp->dtime, docp->origtime) > 0))
891         {
892           if(docp->rest_pos)
893           {
894             docp->rest_pos = 0;
895             xprintf(1,
896               gettext("Modified from last download - regeting whole\n"));
897           }
898         }
899         else if((cfg.mode == MODE_SYNC || cfg.mode == MODE_MIRROR)
900           && !docp->rest_pos)
901         {
902           docp->errcode = ERR_FTP_ACTUAL;
903           return NULL;
904         }
905       }
906 
907       if(docp->check_limits)
908       {
909         cond_info_t condp;
910         int r;
911 
912         condp.level = 3;
913         condp.urlnr = docp->doc_nr;
914         condp.size = docp->totsz;
915         condp.time = docp->dtime;
916         condp.mimet = NULL;
917         condp.full_tag = NULL;
918         condp.params = NULL;
919         condp.html_doc = NULL;
920         condp.html_doc_offset = 0;
921         condp.tag = NULL;
922         condp.attrib = NULL;
923 
924         r = url_append_condition(docp->doc_url, &condp);
925 
926         if(!r)
927         {
928           switch (condp.reason)
929           {
930           case CONDT_MAX_SIZE:
931             docp->errcode = ERR_BIGGER;
932             break;
933           case CONDT_MIN_SIZE:
934             docp->errcode = ERR_SMALLER;
935             break;
936           case CONDT_NEWER_THAN:
937           case CONDT_OLDER_THAN:
938             docp->errcode = ERR_OUTTIME;
939             break;
940           case CONDT_USER_CONDITION:
941             docp->errcode = ERR_SCRIPT_DISABLED;
942             break;
943           default:
944             docp->errcode = ERR_RDISABLED;
945             break;
946           }
947           return NULL;
948         }
949       }
950 
951       if(ftp_set_transfer_type(docp, "I"))
952       {
953         docp->ftp_fatal_err = TRUE;
954         docp->errcode = ERR_FTP_DATACON;
955         return NULL;
956       }
957 
958       if(ftp_open_data_init(docp))
959       {
960         bufio_close(docp->ftp_control);
961         docp->ftp_control = NULL;
962         docp->errcode = ERR_FTP_DATACON;
963         return NULL;
964       }
965 
966       if(docp->rest_pos)
967       {
968         char *rsp;
969 
970         sprintf(buf, "REST %ld\r\n", (long) docp->rest_pos);
971         ftp_control_write(docp, buf, strlen(buf));
972         DEBUG_PROTOC("%s", buf);
973         if((reply = ftp_get_response(docp, &rsp, TRUE)) >= 400)
974         {
975           _free(rsp);
976           if(reply == 600)
977           {
978             docp->ftp_fatal_err = TRUE;
979             bufio_close(docp->datasock);
980             docp->datasock = NULL;
981             docp->errcode = ERR_READ;
982             return NULL;
983           }
984           docp->errcode = ERR_FTP_NOREGET;
985         }
986         else
987         {
988           sprintf(buf, "%ld", (long) docp->rest_pos);
989           if(!strstr(rsp + 3, buf))
990           {
991             xprintf(1,
992               gettext
993               ("Warning: FTP server understands REST command, but can't handle it properly.\n"));
994             docp->errcode = ERR_FTP_NOREGET;
995           }
996           _free(rsp);
997         }
998       }
999 
1000       snprintf(buf, sizeof(buf), "RETR %s\r\n", filename + 1);
1001       ftp_control_write(docp, buf, strlen(buf));
1002       DEBUG_PROTOC("%s", buf);
1003 
1004         /** check control connection if there is available  **/
1005         /** server response. This is required to properly   **/
1006         /** establish support active data connections, also **/
1007         /** in case of error                                **/
1008       if(!cfg.ftp_activec ||
1009         tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)
1010       {
1011         if(!ftp_open_data_finish(docp))
1012         {
1013           docp->ftp_fatal_err = TRUE;
1014           if(!docp->errcode)
1015             docp->errcode = ERR_FTP_DATACON;
1016           return NULL;
1017         }
1018       }
1019 
1020       if(!((reply = ftp_get_response(docp, NULL, TRUE)) >= 400))
1021       {
1022         docp->errcode = ERR_NOERROR;
1023 
1024         if(!ftp_open_data_finish(docp))
1025         {
1026           docp->ftp_fatal_err = TRUE;
1027           if(!docp->errcode)
1028             docp->errcode = ERR_FTP_DATACON;
1029           return NULL;
1030         }
1031 
1032         return docp->datasock;
1033       }
1034 
1035       if(reply == 600)
1036       {
1037         docp->ftp_fatal_err = TRUE;
1038         bufio_close(docp->datasock);
1039         docp->datasock = NULL;
1040         docp->errcode = ERR_READ;
1041         return NULL;
1042       }
1043       docp->errcode = ERR_FTP_GET;
1044     }
1045     else
1046     {
1047       docp->errcode = ERR_FTP_GET;
1048     }
1049   }
1050 
1051   if(((docp->doc_url->extension &&
1052         ((ftp_url_extension *) docp->doc_url->extension)->type == FTP_TYPE_D)
1053       || !docp->doc_url->extension) && ((docp->check_limits
1054         && cfg.condition.ftpdir) || !docp->check_limits))
1055   {
1056     if(ftp_check_directory_existence(docp, filename))
1057     {
1058       docp->errcode = ERR_FTP_NODIR;
1059       docp->ftp_respc = 550;
1060       if(docp->datasock)
1061       {
1062         bufio_close(docp->datasock);
1063         docp->datasock = NULL;
1064       }
1065       return NULL;
1066     }
1067 
1068     if(ftp_set_transfer_type(docp, "A"))
1069     {
1070       return NULL;
1071     }
1072 
1073     if(!docp->datasock)
1074     {
1075       if(ftp_open_data_init(docp))
1076       {
1077         bufio_close(docp->ftp_control);
1078         docp->ftp_control = NULL;
1079         docp->errcode = ERR_FTP_DATACON;
1080         return NULL;
1081       }
1082     }
1083 
1084     ftp_send_list_command(docp, filename);
1085 
1086     /** check control connection if there is available  **/
1087     /** server response. This is required to properly   **/
1088     /** establish support active data connections, also **/
1089     /** in case of error                                **/
1090     if(!cfg.ftp_activec ||
1091       tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)
1092     {
1093       if(!ftp_open_data_finish(docp))
1094       {
1095         docp->ftp_fatal_err = TRUE;
1096         if(!docp->errcode)
1097           docp->errcode = ERR_FTP_DATACON;
1098         return NULL;
1099       }
1100     }
1101 
1102     if(!((reply = ftp_get_response(docp, NULL, TRUE)) >= 400))
1103     {
1104       docp->errcode = ERR_NOERROR;
1105       *is_dir = TRUE;
1106 
1107       if(!ftp_open_data_finish(docp))
1108       {
1109         docp->ftp_fatal_err = TRUE;
1110         if(!docp->errcode)
1111           docp->errcode = ERR_FTP_DATACON;
1112         return NULL;
1113       }
1114 
1115       return docp->datasock;
1116     }
1117     docp->ftp_fatal_err = (reply == 600);
1118     docp->errcode = *is_dir ? ERR_FTP_NODIR : ERR_FTP_GET;
1119   }
1120   else if(!cfg.condition.ftpdir && reply == 550 && *is_dir)
1121   {
1122     docp->errcode = ERR_FTP_DIRNO;
1123   }
1124 
1125   if(docp->datasock)
1126   {
1127     bufio_close(docp->datasock);
1128     docp->datasock = NULL;
1129   }
1130 
1131   return NULL;
1132 }
1133 
1134 /********************************************************/
1135 /* pre dane FTP URL vracia deskriptor datoveho spojenia */
1136 /* FIXME: Translate me!                                 */
1137 /********************************************************/
ftp_get_data_socket(doc * docp)1138 bufio *ftp_get_data_socket(doc * docp)
1139 {
1140   char *user, *ruser;
1141   char *password;
1142   char pom[100];
1143   bufio *s;
1144   bool_t sdir;
1145   char *tmp_path;
1146 
1147   user = url_get_user(docp->doc_url, NULL);
1148   password = url_get_pass(docp->doc_url, NULL);
1149 
1150   if(!user)
1151     user = "anonymous";
1152   ruser = user;
1153 
1154   if(!password)
1155     password = cfg.send_from ? priv_cfg.from : "pavuk@domain.xx";
1156 
1157   if(priv_cfg.ftp_proxy && !cfg.ftp_dirtyp)
1158   {
1159     snprintf(pom, sizeof(pom), "%s@%s %hu", user, docp->doc_url->p.ftp.host,
1160       docp->doc_url->p.ftp.port);
1161     user = pom;
1162   }
1163 
1164   sdir = docp->doc_url->p.ftp.dir;
1165   tmp_path = url_decode_str(docp->doc_url->p.ftp.path,
1166     strlen(docp->doc_url->p.ftp.path));
1167 
1168   s = ftp_connect(docp, priv_cfg.ftp_proxy && !cfg.ftp_dirtyp ?
1169     priv_cfg.ftp_proxy : docp->doc_url->p.ftp.host,
1170     priv_cfg.ftp_proxy && !cfg.ftp_dirtyp ?
1171     priv_cfg.ftp_proxy_port : docp->doc_url->p.ftp.port,
1172     ruser, user, password, tmp_path, &sdir);
1173 
1174   _free(tmp_path);
1175 
1176   if(sdir != docp->doc_url->p.ftp.dir)
1177   {
1178     docp->doc_url->p.ftp.dir = sdir;
1179     url_changed_filename(docp->doc_url);
1180   }
1181 
1182   return s;
1183 }
1184 
1185 /*******************************/
1186 /* remove document from server */
1187 /*******************************/
ftp_remove(doc * docp)1188 int ftp_remove(doc * docp)
1189 {
1190   char *cmd;
1191   char *filename;
1192   int reply;
1193 
1194   if(docp->doc_url->type != URLT_FTP && docp->doc_url->type != URLT_FTPS)
1195     return 0;
1196 
1197   if(docp->doc_url->p.ftp.dir)
1198     return 0;
1199 
1200   xprintf(1, "Deleting remote document ...\n");
1201 
1202   filename = url_decode_str(docp->doc_url->p.ftp.path,
1203     strlen(docp->doc_url->p.ftp.path));
1204 
1205   cmd = tl_str_concat(NULL, "DELE ", filename + 1, "\r\n", NULL);
1206   ftp_control_write(docp, cmd, strlen(cmd));
1207   DEBUG_PROTOC("%s", cmd);
1208 
1209   _free(filename);
1210   _free(cmd);
1211 
1212   if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)
1213   {
1214     if(reply == 600)
1215     {
1216       docp->ftp_fatal_err = TRUE;
1217       return -1;
1218     }
1219   }
1220 
1221   return 0;
1222 }
1223 
1224 /********************************************************/
1225 /* z FTP adresara urobi HTML dokument                   */
1226 /* FIXME: Translate me!                                 */
1227 /********************************************************/
ftp_nlst_dir_to_html(doc * docp)1228 static void ftp_nlst_dir_to_html(doc * docp)
1229 {
1230   char *p, *n, *res = NULL;
1231   char pom[8192];
1232   int tsize;
1233   bool_t last = 1;
1234   int ilen;
1235 
1236   snprintf(pom, sizeof(pom),
1237     gettext("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
1238       "<HTML>\n<TITLE>\nDirectory of %s://%s:%hu%s\n</TITLE>\n<BODY>\n"
1239       "<H1 ALIGN=CENTER><B>List of FTP directory %s://%s:%hu/%s </H1><BR><UL>"),
1240     prottable[docp->doc_url->type].urlid, docp->doc_url->p.ftp.host,
1241     docp->doc_url->p.ftp.port, docp->doc_url->p.ftp.path,
1242     prottable[docp->doc_url->type].urlid, docp->doc_url->p.ftp.host,
1243     docp->doc_url->p.ftp.port, docp->doc_url->p.ftp.path);
1244 
1245   res = tl_strdup(pom);
1246   tsize = strlen(pom);
1247 
1248   p = docp->contents;
1249 
1250   while(*p)
1251   {
1252     ilen = strcspn(p, "\r\n");
1253     if(*(p + ilen))
1254       *(p + ilen) = '\0';
1255     else
1256       last = 0;
1257 
1258     _strtrchr(p, '\\', '/');
1259     n = strrchr(p, '/');
1260     if(n)
1261       n++;
1262     else
1263       n = p;
1264 
1265     n = url_encode_str(n, URL_PATH_UNSAFE);
1266 
1267     if(docp->doc_url->p.ftp.user && docp->doc_url->p.ftp.password)
1268     {
1269       snprintf(pom, sizeof(pom),
1270         "<LI><A HREF=\"%s://%s:%s@%s:%hu%s%s%s\">&quot;%s&quot;</A>\n",
1271         prottable[docp->doc_url->type].urlid,
1272         docp->doc_url->p.ftp.user, docp->doc_url->p.ftp.password,
1273         docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1274         docp->doc_url->p.ftp.path,
1275         tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1276     }
1277     else if(docp->doc_url->p.ftp.user)
1278     {
1279       snprintf(pom, sizeof(pom),
1280         "<LI><A HREF=\"%s://%s@%s:%hu%s%s%s\">&quot;%s&quot;</A>\n",
1281         prottable[docp->doc_url->type].urlid,
1282         docp->doc_url->p.ftp.user,
1283         docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1284         docp->doc_url->p.ftp.path,
1285         tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1286     }
1287     else
1288       snprintf(pom, sizeof(pom),
1289         "<LI><A HREF=\"%s://%s:%hu%s%s%s\">&quot;%s&quot;</A>\n",
1290         prottable[docp->doc_url->type].urlid,
1291         docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1292         docp->doc_url->p.ftp.path,
1293         tl_is_dirname(docp->doc_url->p.ftp.path) ? "" : "/", n, n);
1294 
1295     _free(n);
1296 
1297     tsize += strlen(pom);
1298     res = _realloc(res, tsize + 1);
1299 
1300     strcat(res, pom);
1301     p += ilen + last;
1302     p += strspn(p, "\r\n");
1303   }
1304 
1305   tsize += 22;
1306   res = _realloc(res, tsize + 1);
1307 
1308   strcat(res, "</UL>\n</BODY>\n</HTML>\n");
1309 
1310   free(docp->contents);
1311 
1312   docp->contents = res;
1313   docp->size = tsize;
1314 }
1315 
ftp_list_unix_perm_parse(char * str)1316 static int ftp_list_unix_perm_parse(char *str)
1317 {
1318   int perm = 0;
1319   int i;
1320   char *s;
1321 
1322   if(strlen(str) != 10)
1323     return -1;
1324 
1325   for(s = str + 1, i = 0; i < 3; i++, s += 3)
1326   {
1327     perm <<= 3;
1328     if(s[0] == 'r')
1329       perm += 4;
1330     if(s[1] == 'w')
1331       perm += 2;
1332     if(s[2] == 'x')
1333       perm += 1;
1334   }
1335   return perm;
1336 }
1337 
ftp_list_unix_perm_type(char * str)1338 static int ftp_list_unix_perm_type(char *str)
1339 {
1340   switch (str[0])
1341   {
1342   case 'd':
1343     return FTP_TYPE_D;
1344   case 'l':
1345     return FTP_TYPE_L;
1346   default:
1347     return FTP_TYPE_F;
1348   }
1349 }
1350 
ftp_list_unix_get_slink(char * str,char ** nm,char ** ln)1351 static void ftp_list_unix_get_slink(char *str, char **nm, char **ln)
1352 {
1353   char *p;
1354 
1355   *ln = NULL;
1356   *nm = str;
1357 
1358   if((p = strstr(str, " -> ")))
1359   {
1360     *p = '\0';
1361     *ln = p + 4;
1362   }
1363 }
1364 
ftp_list_get_month_index(char * month)1365 static int ftp_list_get_month_index(char *month)
1366 {
1367   static const char *months[] = { "jan", "feb", "mar", "apr", "may", "jun",
1368     "jul", "aug", "sep", "oct", "nov", "dec", NULL
1369   };
1370   int i;
1371 
1372   if(strlen(month) != 3)
1373     return -1;
1374 
1375   /* make lowercase month */
1376   for(i = 0; i < 3; ++i)
1377   {
1378     month[i] = tolower(month[i]);
1379   }
1380 
1381   i = 0;
1382   while(months[i] != NULL)
1383   {
1384     if(strcmp(month, months[i]) == 0)
1385       return i + 1;
1386     i++;
1387   }
1388 
1389   return 0;
1390 }
1391 
1392 
ftp_list_get_date(char * date)1393 static time_t ftp_list_get_date(char *date)
1394 {
1395   int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
1396   char m[PATH_MAX];
1397   int ok = 0;
1398 
1399   static int our_year = 0;
1400   static int our_month = 0;
1401 
1402   static char result[32];
1403   time_t t;
1404 
1405   if(our_year == 0)
1406   {
1407     time_t t;
1408     struct tm *ptm;
1409 
1410     t = time(NULL);
1411     ptm = gmtime(&t);
1412 
1413     our_year = ptm->tm_year;
1414     our_month = ptm->tm_mon;
1415   }
1416 
1417   if(sscanf(date, "%3[a-zA-Z] %2d %02d:%02d", m, &day, &hour, &minute) == 4)
1418   {
1419     month = ftp_list_get_month_index(m);
1420     if(month <= 0)
1421       return 0;
1422 
1423     if(day < 1 || day > 31)
1424       return 0;
1425     if(hour < 0 || hour > 24)
1426       return 0;
1427     if(minute < 0 || minute > 60)
1428       return 0;
1429 
1430     year = 0;
1431     second = 0;
1432 
1433     ok = 1;
1434   }
1435 
1436   if(!ok && sscanf(date, "%3[a-zA-Z] %2d %04d", m, &day, &year) == 3)
1437   {
1438     month = ftp_list_get_month_index(m);
1439 
1440     if(month <= 0)
1441       return 0;
1442     if(day < 1 || day > 31)
1443       return 0;
1444     if(year < 1995 || year > 2100)
1445       return 0;
1446 
1447     hour = 0;
1448     second = 0;
1449     minute = 0;
1450 
1451     ok = 1;
1452   }
1453 
1454   if(!ok)
1455     return 0;
1456 
1457   if(year == 0)
1458   {
1459     year = our_year;
1460     if((month - 1) > our_month)
1461       year--;
1462   }
1463 
1464   if(year < 1900)
1465     year += 1900;
1466 
1467   sprintf(result, "%04d%02d%02d%02d%02d%02d",
1468     year, month, day, hour, minute, second);
1469 
1470   t = time_ftp_scn(result);
1471 
1472   /*
1473      printf ("Time conversion: %s == %s (%d)\n", date, result, (int) t);
1474    */
1475 
1476   return t;
1477 }
1478 
ftp_list_unix_parse_line(char * str,char ** fname,ftp_url_extension * ret)1479 static ftp_url_extension *ftp_list_unix_parse_line(char *str, char **fname,
1480   ftp_url_extension * ret)
1481 {
1482   char pom[2000];
1483   char name[2000];
1484   char attrib[2000];
1485   char month[2000];
1486   char rest[2000];
1487   unsigned int pi, day;
1488   unsigned long size;
1489   char *nm, *sln;
1490 
1491   *fname = NULL;
1492 
1493   if(str[0] == 'b' ||           /* block device */
1494     str[0] == 'u' ||            /* character device unbuffered */
1495     str[0] == 'c' ||            /* character device */
1496     str[0] == 'p' ||            /* FIFO */
1497     str[0] == 's')              /* socket */
1498   {
1499     /* we don't support devices, FIFOs and sockets creation */
1500     return NULL;
1501   }
1502   /* for SYS V style ls -l */
1503   else if(sscanf(str, "%1999s %u %1999s %1999s %lu %1999s %u %1999s %1999[^\n\r]",
1504           attrib, &pi, pom, pom, &size, month, &day, rest, name) != 9)
1505   {
1506     /* for old BSD style ls -l */
1507     if(sscanf(str, "%1999s %u %1999s %lu %1999s %u %1999s %1999[^\n\r]",
1508               attrib, &pi, pom, &size, month, &day, rest, name) != 8)
1509     {
1510       return NULL;
1511     }
1512   }
1513   ret->size = size;
1514 
1515   ret->type = ftp_list_unix_perm_type(attrib);
1516   ret->perm = ftp_list_unix_perm_parse(attrib);
1517   if(ret->perm == -1)
1518     return NULL;
1519   ftp_list_unix_get_slink(name, &nm, &sln);
1520 
1521   ret->slink = tl_strdup(sln);
1522   snprintf(pom, sizeof(pom), "%s %d %s", month, day, rest);
1523   ret->time = ftp_list_get_date(pom);
1524   *fname = tl_strdup(nm);
1525 
1526   return ret;
1527 }
1528 
ftp_list_epfl_parse_line(char * str,char ** fname,ftp_url_extension * ret)1529 static ftp_url_extension *ftp_list_epfl_parse_line(char *str, char **fname,
1530   ftp_url_extension * ret)
1531 {
1532   char *p, *strtokbuf;
1533 
1534   *fname = NULL;
1535 
1536   if(*str != '+')
1537   {
1538     return NULL;
1539   }
1540 
1541   p = strchr(str, '\x09');
1542   if(!p)
1543   {
1544     return NULL;
1545   }
1546   *fname = tl_strdup(p + 1);
1547   *p = '\0';
1548 
1549   ret->type = FTP_TYPE_F;
1550   ret->size = 0;
1551 
1552   p = strtokc_r(str + 1, ',', &strtokbuf);
1553 
1554   while(p)
1555   {
1556     switch (*p)
1557     {
1558     case 'r':
1559       ret->type = FTP_TYPE_F;
1560       break;
1561     case '/':
1562       ret->type = FTP_TYPE_D;
1563       break;
1564     case 's':
1565       ret->size = _atoi(p + 1);
1566       break;
1567     }
1568     p = strtokc_r(NULL, ',', &strtokbuf);
1569   }
1570   ret->slink = NULL;
1571   ret->time = 0;
1572   ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1573 
1574 
1575   return ret;
1576 }
1577 
ftp_list_novel_parse_line(char * str,char ** fname,ftp_url_extension * ret)1578 static ftp_url_extension *ftp_list_novel_parse_line(char *str, char **fname,
1579   ftp_url_extension * ret)
1580 {
1581   char pom[2000];
1582   char name[4000];
1583   char attrib[2000];
1584   unsigned int pi;
1585   unsigned long size;
1586 
1587   *fname = NULL;
1588 
1589   if(sscanf(str, "%1999s %u %1999s %lu %1999s %u %1999s %3999[^\n\r]",
1590      attrib, &pi, pom, &size, pom, &pi, pom, name) != 8)
1591   {
1592     return NULL;
1593   }
1594   ret->size = size;
1595 
1596   ret->type = *attrib == 'd' ? FTP_TYPE_D : FTP_TYPE_F;
1597   ret->slink = NULL;
1598   ret->time = 0;
1599   ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1600 
1601   *fname = tl_strdup(name);
1602 
1603   return ret;
1604 }
1605 
ftp_list_vms_parse_line(char * str,char ** fname,ftp_url_extension * ret)1606 static ftp_url_extension *ftp_list_vms_parse_line(char *str, char **fname,
1607   ftp_url_extension * ret)
1608 {
1609   int l;
1610   char *p = str;
1611 
1612   *fname = NULL;
1613 
1614   l = strcspn(p, " ");
1615 
1616   ret->type = strncmp(p + l - 6, ".DIR;", 5) ? FTP_TYPE_F : FTP_TYPE_D;
1617 
1618   if(ret->type == FTP_TYPE_D)
1619     *fname = tl_strndup(p, l - 6);
1620   else
1621     *fname = tl_strndup(p, l - 2);
1622   lowerstr(*fname);
1623 
1624   ret->slink = NULL;
1625   ret->time = 0;
1626   ret->size = 0;
1627   ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1628 
1629   return ret;
1630 }
1631 
ftp_list_windos_parse_line(char * str,char ** fname,ftp_url_extension * ret)1632 static ftp_url_extension *ftp_list_windos_parse_line(char *str, char **fname,
1633   ftp_url_extension * ret)
1634 {
1635   char pom[2000];
1636   char pom2[2000];
1637   int ti;
1638 
1639   *fname = NULL;
1640 
1641   if(sscanf(str, "%2d-%2d-%2d  %2d:%2d%*[AP]M %1999s %1999[^\n\r]",
1642       &ti, &ti, &ti, &ti, &ti, pom2, pom) != 7)
1643     return NULL;
1644 
1645   ret->slink = NULL;
1646   ret->time = 0;
1647   ret->perm = (4 << 6) + (2 << 6) + (2 << 3) + 2;
1648 
1649   if(strstr(pom2, "<DIR>"))
1650   {
1651     ret->type = FTP_TYPE_D;
1652     ret->size = 0;
1653   }
1654   else
1655   {
1656     ret->type = FTP_TYPE_F;
1657     ret->size = atoi(pom2);
1658   }
1659 
1660   *fname = tl_strdup(pom);
1661 
1662   return ret;
1663 }
1664 
1665 /********************************************************/
1666 /* z vypisu FTP adresara urobi HTML dokument            */
1667 /* FIXME: Translate me!                                 */
1668 /********************************************************/
ftp_list_unix_dir_to_html(doc * docp)1669 static void ftp_list_unix_dir_to_html(doc * docp)
1670 {
1671   char *p, *res = NULL;
1672   char pom[8192];
1673   char urlstr[4096];
1674   int tsize;
1675   ftp_url_extension *ext = NULL;
1676   ftp_url_extension exta;
1677   char *name, *tmp;
1678   int ilen;
1679   bool_t last = 1;
1680   enum
1681   { FTP_DT_UNIXL, FTP_DT_VMS, FTP_DT_WINDOS } type;
1682 
1683   snprintf(pom, sizeof(pom),
1684     gettext("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
1685       "<HTML>\n<TITLE>\nDirectory of %s://%s:%hu%s\n</TITLE>\n<BODY>\n"
1686       "<H1 ALIGN=CENTER><B>List of FTP directory %s://%s:%hu/%s </H1><BR><UL>"),
1687     prottable[docp->doc_url->type].urlid,
1688     docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1689     docp->doc_url->p.ftp.path, prottable[docp->doc_url->type].urlid,
1690     docp->doc_url->p.ftp.host, docp->doc_url->p.ftp.port,
1691     docp->doc_url->p.ftp.path);
1692 
1693   res = tl_strdup(pom);
1694   tsize = strlen(pom);
1695 
1696   /*** skip first total line ***/
1697   if(!strncmp(docp->contents, "total ", 6))
1698   {
1699     type = FTP_DT_UNIXL;
1700     p = docp->contents + strcspn(docp->contents, "\r\n");
1701     p += strspn(p, "\r\n");
1702   }
1703   else if(!strncmp(docp->contents, "Directory ", 10) ||
1704     !strncmp(docp->contents + strspn(docp->contents, " \r\n"), "Directory ",
1705       10))
1706   {
1707     type = FTP_DT_VMS;
1708     p = docp->contents + strspn(docp->contents, " \r\n");
1709     p += strcspn(p, "\r\n");
1710     p += strspn(p, "\r\n");
1711   }
1712   else
1713   {
1714     int ti;
1715 
1716     if(sscanf(docp->contents,
1717         "%2d-%2d-%2d  %2d:%2d%*[AP]M %8191s %8191[^\n\r]",
1718         &ti, &ti, &ti, &ti, &ti, pom, pom) == 7)
1719     {
1720       type = FTP_DT_WINDOS;
1721       p = docp->contents;
1722     }
1723     else
1724     {
1725       type = FTP_DT_UNIXL;
1726       p = docp->contents;
1727     }
1728   }
1729 
1730   while(*p)
1731   {
1732     ilen = strcspn(p, "\r\n");
1733     if(*(p + ilen))
1734       *(p + ilen) = '\0';
1735     else
1736       last = 0;
1737 
1738     if(type == FTP_DT_UNIXL)
1739     {
1740       if(*p == '+')
1741         ext = ftp_list_epfl_parse_line(p, &name, &exta);
1742       else if(*(p + 1) == '[')
1743         ext = ftp_list_novel_parse_line(p, &name, &exta);
1744       else
1745         ext = ftp_list_unix_parse_line(p, &name, &exta);
1746     }
1747     else if(type == FTP_DT_VMS)
1748     {
1749       if(strncmp(p, "Total of ", 9) && *p && *p != ' ')
1750         ext = ftp_list_vms_parse_line(p, &name, &exta);
1751     }
1752     else if(type == FTP_DT_WINDOS)
1753     {
1754       ext = ftp_list_windos_parse_line(p, &name, &exta);
1755     }
1756 
1757     if(!ext)
1758     {
1759       xprintf(1, gettext("ERROR: unable to parse FTP list line :\n\t%s\n"),
1760         p);
1761       p += ilen + last;
1762       p += strspn(p, "\r\n");
1763       continue;
1764     }
1765 
1766     if(!name || !strcmp(name, ".") || !strcmp(name, ".."))
1767     {
1768       p += ilen + last;
1769       p += strspn(p, "\r\n");
1770       continue;
1771     }
1772 
1773     tmp = name;
1774     name = url_encode_str(name, URL_PATH_UNSAFE);
1775     _free(tmp);
1776 
1777     if(docp->doc_url->p.ftp.user && docp->doc_url->p.ftp.password)
1778     {
1779       snprintf(urlstr, sizeof(urlstr), "%s://%s:%s@%s:%hu%s%s%s%s",
1780         prottable[docp->doc_url->type].urlid,
1781         docp->doc_url->p.ftp.user,
1782         docp->doc_url->p.ftp.password,
1783         docp->doc_url->p.ftp.host,
1784         docp->doc_url->p.ftp.port,
1785         docp->doc_url->p.ftp.path,
1786         tl_is_dirname(docp->doc_url->p.ftp.path) ?
1787         "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1788     }
1789     else if(docp->doc_url->p.ftp.user)
1790     {
1791       snprintf(urlstr, sizeof(urlstr), "%s://%s@%s:%hu%s%s%s%s",
1792         prottable[docp->doc_url->type].urlid,
1793         docp->doc_url->p.ftp.user,
1794         docp->doc_url->p.ftp.host,
1795         docp->doc_url->p.ftp.port,
1796         docp->doc_url->p.ftp.path,
1797         tl_is_dirname(docp->doc_url->p.ftp.path) ?
1798         "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1799     }
1800     else
1801       snprintf(urlstr, sizeof(urlstr), "%s://%s:%hu%s%s%s%s",
1802         prottable[docp->doc_url->type].urlid,
1803         docp->doc_url->p.ftp.host,
1804         docp->doc_url->p.ftp.port,
1805         docp->doc_url->p.ftp.path,
1806         tl_is_dirname(docp->doc_url->p.ftp.path) ?
1807         "" : "/", name, (ext->type == FTP_TYPE_D) ? "/" : "");
1808 
1809     snprintf(pom, sizeof(pom),
1810       "<LI><A PAVUKEXT=\"FTPINF %u %hu %lu %u %s\" HREF=\"%s\">&quot;%s&quot;</A> (%lub)\n",
1811       (unsigned int) ext->type, ext->perm, (long)ext->size,
1812       (unsigned int) ext->time, (ext->slink ? ext->slink : ""), urlstr, name,
1813       (long)ext->size);
1814 
1815     _free(name);
1816     _free(ext->slink);
1817 
1818     tsize += strlen(pom);
1819     res = _realloc(res, tsize + 1);
1820     strcat(res, pom);
1821 
1822     p += ilen + last;
1823     p += strspn(p, "\r\n");
1824   }
1825 
1826   tsize += 22;
1827   res = _realloc(res, tsize + 1);
1828 
1829   strcat(res, "</UL>\n</BODY>\n</HTML>\n");
1830 
1831   free(docp->contents);
1832 
1833   docp->contents = res;
1834   docp->size = tsize;
1835 }
1836 
ftp_dir_to_html(doc * docp)1837 void ftp_dir_to_html(doc * docp)
1838 {
1839   if(!docp->contents)
1840     return;
1841 
1842   if(!cfg.ftp_list)
1843     ftp_nlst_dir_to_html(docp);
1844   else
1845   {
1846     ftp_list_unix_dir_to_html(docp);
1847   }
1848 }
1849 
ftp_url_ext_free(ftp_url_extension * fext)1850 void ftp_url_ext_free(ftp_url_extension * fext)
1851 {
1852   _free(fext->slink);
1853   _free(fext);
1854 }
1855 
ftp_url_ext_new(int type,int perm,ssize_t size,char * slink,time_t time)1856 ftp_url_extension *ftp_url_ext_new(int type, int perm, ssize_t size,
1857   char *slink, time_t time)
1858 {
1859   ftp_url_extension *rv;
1860 
1861   rv = _malloc(sizeof(ftp_url_extension));
1862 
1863   rv->perm = perm;
1864   rv->size = size;
1865   rv->type = type;
1866   rv->slink = slink;
1867   rv->time = time;
1868 
1869   return rv;
1870 }
1871 
ftp_url_ext_dup(ftp_url_extension * ext)1872 ftp_url_extension *ftp_url_ext_dup(ftp_url_extension * ext)
1873 {
1874   return ftp_url_ext_new(ext->type, ext->perm, ext->size,
1875     tl_strdup(ext->slink), ext->time);
1876 }
1877 
ftp_parse_ftpinf_ext(char * str)1878 ftp_url_extension *ftp_parse_ftpinf_ext(char *str)
1879 {
1880   char pom[8192];
1881   unsigned int t, p, s, tt;
1882   int num;
1883 
1884   if(strncmp(str, "FTPINF", 6))
1885     return NULL;
1886 
1887   num = sscanf(str, "FTPINF %u %u %u %u %8191[^\n\r]", &t, &p, &s, &tt, pom);
1888 
1889   if(num < 4)
1890     return NULL;
1891 
1892   return ftp_url_ext_new(t, p, s, (num == 5) ? tl_strdup(pom) : NULL, tt);
1893 }
1894 
ftp_make_symlink(url * urlp)1895 int ftp_make_symlink(url * urlp) /* FIXME: Security */
1896 {
1897   char pom[PATH_MAX];
1898   char *frompath, *topath;
1899   char *p;
1900   ftp_url_extension *ext = (ftp_url_extension *) urlp->extension;
1901   int rv;
1902 
1903   frompath = tl_strdup(url_to_filename(urlp, TRUE));
1904 
1905   if(!cfg.preserve_links)
1906   {
1907     if(ext->slink[0] == '/')
1908     {
1909       p = urlp->p.ftp.path;
1910       urlp->p.ftp.path = ext->slink;
1911       topath = tl_strdup(url_get_local_name_real(urlp, NULL, FALSE));
1912       urlp->p.ftp.path = p;
1913     }
1914     else
1915     {
1916       strcpy(pom, urlp->p.ftp.path);
1917       p = strrchr(pom, '/');
1918       if(p)
1919         *(p + 1) = '\0';
1920       strcat(pom, ext->slink);
1921 
1922       p = urlp->p.ftp.path;
1923       urlp->p.ftp.path = pom;
1924       topath = tl_strdup(url_get_local_name_real(urlp, NULL, FALSE));
1925       urlp->p.ftp.path = p;
1926     }
1927     p = topath;
1928     topath = get_relative_path(frompath, p);
1929     _free(p);
1930   }
1931   else
1932     topath = NULL;
1933 
1934   /* don't make links to directory index files */
1935   /* but rather to directories                 */
1936   if(topath && tl_is_dirname(ext->slink))
1937   {
1938     p = tl_get_basename(topath);
1939     if(p > topath)
1940       *(p) = '\0';
1941   }
1942 
1943   xprintf(1, gettext("Making symlink \"%s\" to \"%s\"\n"),
1944     frompath, topath ? topath : ext->slink);
1945 
1946   if(makealldirs(frompath))
1947     xperror(frompath);
1948 
1949   if(!access(frompath, F_OK))
1950   {
1951     if(unlink(frompath))
1952       xperror(frompath);
1953   }
1954 
1955   rv = symlink(topath ? topath : ext->slink, frompath);
1956 
1957   if(rv == -1)
1958     xperror("topath");
1959 
1960   _free(topath);
1961   _free(frompath);
1962 
1963   return rv;
1964 }
1965 
ftp_handshake_info_free(ftp_handshake_info * fhi)1966 void ftp_handshake_info_free(ftp_handshake_info * fhi)
1967 {
1968   _free(fhi->host);
1969 
1970   for(; fhi->infos; fhi->infos = dllist_remove_entry(fhi->infos, fhi->infos))
1971   {
1972     ftp_handshake_info_data *d = (ftp_handshake_info_data *) fhi->infos->data;
1973     _free(d->cmd);
1974     _free(d);
1975   }
1976 }
1977 
ftp_handshake_info_parse(char * host,char * str)1978 ftp_handshake_info *ftp_handshake_info_parse(char *host, char *str)
1979 {
1980   ftp_handshake_info *rv = _malloc(sizeof(ftp_handshake_info));
1981   ftp_handshake_info_data *d;
1982   char *p;
1983   char **array;
1984   int i, ok;
1985 
1986   rv->infos = NULL;
1987   p = strchr(host, ':');
1988   if(p)
1989   {
1990     rv->host = tl_strndup(host, p - host);
1991     rv->port = _atoi(p + 1);
1992     if(!rv->port)
1993       rv->port = DEFAULT_FTP_PORT;
1994   }
1995   else
1996   {
1997     rv->host = tl_strdup(host);
1998     rv->port = DEFAULT_FTP_PORT;
1999   }
2000 
2001   array = tl_str_split(str, "\\");
2002 
2003   d = NULL;
2004   ok = TRUE;
2005   if(array)
2006   {
2007     for(i = 0; array[i]; i++)
2008     {
2009       if(!ok)
2010       {
2011         _free(array[i]);
2012         continue;
2013       }
2014 
2015       if(!d)
2016       {
2017         d = _malloc(sizeof(ftp_handshake_info_data));
2018         d->cmd = array[i];
2019         d->response = 0;
2020         array[i] = NULL;
2021       }
2022       else
2023       {
2024         d->response = _atoi(array[i]);
2025         if(!d->response && errno == ERANGE)
2026           ok = FALSE;
2027         _free(array[i]);
2028         rv->infos = dllist_append(rv->infos, (dllist_t) d);
2029         d = NULL;
2030       }
2031     }
2032     if(d)
2033     {
2034       _free(d->cmd);
2035       _free(d);
2036       ok = FALSE;
2037     }
2038 
2039     _free(array);
2040   }
2041   else
2042     ok = FALSE;
2043 
2044   if(!ok)
2045   {
2046     ftp_handshake_info_free(rv);
2047     rv = NULL;
2048   }
2049 
2050   return rv;
2051 }
2052 
ftp_handshake_info_dup(ftp_handshake_info * fhi)2053 ftp_handshake_info *ftp_handshake_info_dup(ftp_handshake_info * fhi)
2054 {
2055   dllist *ptr;
2056   ftp_handshake_info *rv = _malloc(sizeof(ftp_handshake_info));
2057 
2058   rv->host = tl_strdup(fhi->host);
2059   rv->port = fhi->port;
2060   rv->infos = NULL;
2061 
2062   for(ptr = fhi->infos; ptr; ptr = ptr->next)
2063   {
2064     ftp_handshake_info_data *d1, *d2;
2065 
2066     d1 = (ftp_handshake_info_data *) ptr->data;
2067 
2068     d2 = _malloc(sizeof(ftp_handshake_info_data));
2069     d2->response = d1->response;
2070     d2->cmd = tl_strdup(d1->cmd);
2071 
2072     rv->infos = dllist_append(rv->infos, (dllist_t) d2);
2073   }
2074 
2075   return rv;
2076 }
2077 
ftp_handshake_info_data_dump(ftp_handshake_info * fhi)2078 char *ftp_handshake_info_data_dump(ftp_handshake_info * fhi)
2079 {
2080   ftp_handshake_info_data *d;
2081   dllist *ptr;
2082   char pom[512];
2083   char *rv = NULL;
2084 
2085   if(fhi->infos)
2086   {
2087     d = (ftp_handshake_info_data *) fhi->infos->data;
2088     snprintf(pom, sizeof(pom), "%s\\%d", d->cmd, d->response);
2089     rv = tl_strdup(pom);
2090 
2091     for(ptr = fhi->infos->next; ptr; ptr = ptr->next)
2092     {
2093       d = (ftp_handshake_info_data *) ptr->data;
2094       snprintf(pom, sizeof(pom), "\\%s\\%d", d->cmd, d->response);
2095       rv = tl_str_append(rv, pom);
2096     }
2097   }
2098   return rv;
2099 }
2100 
ftp_handshake_info_data_find(char * host,int port)2101 static ftp_handshake_info *ftp_handshake_info_data_find(char *host, int port)
2102 {
2103   dllist *ptr;
2104 
2105   for(ptr = priv_cfg.ftp_login_hs; ptr; ptr = ptr->next)
2106   {
2107     ftp_handshake_info *fhi = (ftp_handshake_info *) ptr->data;
2108 
2109     if((fhi->port == port || !host[0]) && !strcmp(fhi->host, host))
2110       return fhi;
2111   }
2112 
2113   return NULL;
2114 }
2115 
ftp_handshake_expand_cmd(char * cmd,doc * docp,char * user,char * password)2116 static char *ftp_handshake_expand_cmd(char *cmd, doc * docp, char *user,
2117   char *password) /* FIXME: Security */
2118 {
2119   char ocmd[2048];
2120   char *p, *op;
2121 
2122   p = cmd;
2123   op = ocmd;
2124   *op = '\0';
2125 
2126   while(*p)
2127   {
2128     if(*p == '%')
2129     {
2130       p++;
2131       switch (*p)
2132       {
2133       case 'u':
2134         strcpy(op, user);
2135         break;
2136       case 'U':
2137         strcpy(op, priv_cfg.ftp_proxy_user);
2138         break;
2139       case 'p':
2140         strcpy(op, password);
2141         break;
2142       case 'P':
2143         strcpy(op, priv_cfg.ftp_proxy_pass);
2144         break;
2145       case 'h':
2146         strcpy(op, docp->doc_url->p.ftp.host);
2147         break;
2148       case 's':
2149         sprintf(op, "%hu", docp->doc_url->p.ftp.port);
2150         break;
2151       default:
2152         *op = '%';
2153         op++;
2154         *op = *p;
2155         op++;
2156         *op = '\0';
2157         break;
2158       }
2159       p++;
2160       while(*op)
2161         op++;
2162     }
2163     else
2164     {
2165       *op = *p;
2166       op++;
2167       p++;
2168       *op = '\0';
2169     }
2170   }
2171   strcat(ocmd, "\r\n");
2172 
2173   return tl_strdup(ocmd);
2174 }
2175 
ftp_do_login_handshake_cust(ftp_handshake_info * fhi,doc * docp,char * user,char * password)2176 static int ftp_do_login_handshake_cust(ftp_handshake_info * fhi, doc * docp,
2177   char *user, char *password)
2178 {
2179   dllist *ptr;
2180 
2181   for(ptr = fhi->infos; ptr; ptr = ptr->next)
2182   {
2183     ftp_handshake_info_data *d = (ftp_handshake_info_data *) ptr->data;
2184     char *cmd;
2185     int response;
2186 
2187     cmd = ftp_handshake_expand_cmd(d->cmd, docp, user, password);
2188     ftp_control_write(docp, cmd, strlen(cmd));
2189     DEBUG_PROTOC("%s", cmd);
2190     _free(cmd);
2191 
2192     response = ftp_get_response(docp, NULL, TRUE);
2193 
2194     if(response != d->response)
2195       return -1;
2196   }
2197 
2198   return 0;
2199 }
2200