The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ftplib.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* ftplib.c - callable ftp access routines */
3 /* Copyright (C) 1996-2000 Thomas Pfau, pfau@cnj.digex.net */
4 /* 73 Catherine Street, South Bound Brook, NJ, 08880 */
5 /* */
6 /* This library is free software; you can redistribute it and/or */
7 /* modify it under the terms of the GNU Library General Public */
8 /* License as published by the Free Software Foundation; either */
9 /* version 2 of the License, or (at your option) any later version. */
10 /* */
11 /* This library 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 GNU */
14 /* Library General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Library General Public */
17 /* License along with this progam; if not, write to the */
18 /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
19 /* Boston, MA 02111-1307, USA. */
20 /* */
21 /***************************************************************************/
22 // changes made by Lorn Potter <llornkcor@handhelds.org>
23 //
24 #if defined(__unix__) || defined(__VMS)
25 #include <unistd.h>
26 #endif
27 #if defined(_WIN32)
28 #include <windows.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <ctype.h>
36 
37 #if defined(__unix__)
38 
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <netdb.h>
47 #include <arpa/inet.h>
48 
49 #elif defined(VMS)
50 
51 #include <types.h>
52 #include <socket.h>
53 #include <in.h>
54 #include <netdb.h>
55 #include <inet.h>
56 
57 #elif defined(_WIN32)
58 
59 #include <winsock.h>
60 
61 #ifndef socklen_t
62 #define socklen_t int
63 #endif
64 
65 #endif
66 
67 #define BUILDING_LIBRARY
68 #include "ftplib.h"
69 
70 #if defined(_WIN32)
71 #define SETSOCKOPT_OPTVAL_TYPE (const char *)
72 #else
73 #define SETSOCKOPT_OPTVAL_TYPE (void *)
74 #endif
75 
76 #define FTPLIB_BUFSIZ 8192
77 #define ACCEPT_TIMEOUT 10
78 
79 #define FTPLIB_CONTROL 0
80 #define FTPLIB_READ 1
81 #define FTPLIB_WRITE 2
82 
83 #if !defined FTPLIB_DEFMODE
84 #define FTPLIB_DEFMODE FTPLIB_PASSIVE
85 #endif
86 
87 #ifdef ANDROID
88 #include <android/log.h>
89 #define perror(M) __android_log_write(ANDROID_LOG_DEBUG, "perror_ftplib", M)
90 #define lllog(M) __android_log_write(ANDROID_LOG_DEBUG, "ftplib", M)
91 #else
92 #define lllog(M) fprintf(stderr, M);
93 #endif
94 
95 void *mymemccpy(void *dst, const void *src, int c, size_t n)
96 {
97  char* q = dst;
98  const char* p = src;
99  const char* p_end = p + n;
100  char ch = ~(char)c; /* ensure ch != c */
101 
102  for (;;) {
103  if (ch == c || p >= p_end) break;
104  *q++ = ch = *p++;
105 
106  if (ch == c || p >= p_end) break;
107  *q++ = ch = *p++;
108 
109  if (ch == c || p >= p_end) break;
110  *q++ = ch = *p++;
111 
112  if (ch == c || p >= p_end) break;
113  *q++ = ch = *p++;
114  }
115 
116  if (p >= p_end && ch != c)
117  return NULL;
118 
119  return q;
120 }
121 
122 
123 struct NetBuf {
124  char *cput,*cget;
125  int handle;
127  char *buf;
128  int dir;
131  int cmode;
132  struct timeval idletime;
135  void *idlearg;
136  void *writerarg;
137  int xfered;
138  int cbbytes;
139  int xfered1;
140  char response[256];
141 };
142 
143 #if 0
144 static char *version =
145 "ftplib Release 3.1-1 9/16/00, copyright 1996-2000 Thomas Pfau";
146 #endif
147 
148 GLOBALDEF int ftplib_debug = 0;
149 
150 #if defined(__unix__) || defined(VMS)
151 #define net_read read
152 #define net_write write
153 #define net_close close
154 #elif defined(_WIN32)
155 #define net_read(x,y,z) recv(x,y,z,0)
156 #define net_write(x,y,z) send(x,y,z,0)
157 #define net_close closesocket
158 #endif
159 
160 #if defined(NEED_MEMCCPY)
161 /*
162  * VAX C does not supply a memccpy routine so I provide my own
163  */
164 void *memccpy(void *dest, const void *src, int c, size_t n)
165 {
166  int i=0;
167  const unsigned char *ip=src;
168  unsigned char *op=dest;
169 
170  while (i < n)
171  {
172  if ((*op++ = *ip++) == c)
173  break;
174  i++;
175  }
176  if (i == n)
177  return NULL;
178  return op;
179 }
180 #endif
181 #if defined(NEED_STRDUP)
182 /*
183  * strdup - return a malloc'ed copy of a string
184  */
185 char *strdup(const char *src)
186 {
187  int l = strlen(src) + 1;
188  char *dst = malloc(l);
189  if (dst)
190  strcpy(dst,src);
191  return dst;
192 }
193 #endif
194 
195 /*
196  * socket_wait - wait for socket to receive or flush data
197  *
198  * return 1 if no user callback, otherwise, return value returned by
199  * user callback
200  */
201 static int socket_wait(netbuf *ctl)
202 {
203  fd_set fd,*rfd = NULL,*wfd = NULL;
204  struct timeval tv;
205  int rv = 0;
206  if ((ctl->dir == FTPLIB_CONTROL) || (ctl->idlecb == NULL))
207  return 1;
208  if (ctl->dir == FTPLIB_WRITE)
209  wfd = &fd;
210  else
211  rfd = &fd;
212  FD_ZERO(&fd);
213  do
214  {
215  FD_SET(ctl->handle,&fd);
216  tv = ctl->idletime;
217  rv = select(ctl->handle+1, rfd, wfd, NULL, &tv);
218  if (rv == -1)
219  {
220  rv = 0;
221  strncpy(ctl->ctrl->response, strerror(errno),
222  sizeof(ctl->ctrl->response));
223  break;
224  }
225  else if (rv > 0)
226  {
227  rv = 1;
228  break;
229  }
230  }
231  while ((rv = ctl->idlecb(ctl, ctl->xfered, ctl->idlearg)));
232  return rv;
233 }
234 
235 /*
236  * read a line of text
237  *
238  * return -1 on error or bytecount
239  */
240 static int readline(char *buf,int max,netbuf *ctl)
241 {
242  int x,retval = 0;
243  char *end,*bp=buf;
244  int eof = 0;
245 
246  if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ))
247  return -1;
248  if (max == 0)
249  return 0;
250  do
251  {
252  if (ctl->cavail > 0)
253  {
254  x = (max >= ctl->cavail) ? ctl->cavail : max-1;
255  end = mymemccpy(bp,ctl->cget,'\n',x);
256  if (end != NULL) {
257  x = (int)(end - bp);
258  }
259  retval += x;
260  bp += x;
261  *bp = '\0';
262  max -= x;
263  ctl->cget += x;
264  ctl->cavail -= x;
265  if (end != NULL)
266  {
267  bp -= 2;
268  if (strcmp(bp,"\r\n") == 0)
269  {
270  *bp++ = '\n';
271  *bp++ = '\0';
272  --retval;
273  }
274  break;
275  }
276  }
277  if (max == 1)
278  {
279  *buf = '\0';
280  break;
281  }
282  if (ctl->cput == ctl->cget)
283  {
284  ctl->cput = ctl->cget = ctl->buf;
285  ctl->cavail = 0;
286  ctl->cleft = FTPLIB_BUFSIZ;
287  }
288  if (eof)
289  {
290  if (retval == 0)
291  retval = -1;
292  break;
293  }
294  if (!socket_wait(ctl))
295  return retval;
296  if ((x = (int)net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1)
297  {
298  perror("read");
299  retval = -1;
300  break;
301  }
302  if (x == 0) //< ctl->cleft)
303  eof = 1;
304  ctl->cleft -= x;
305  ctl->cavail += x;
306  ctl->cput += x;
307  }
308  while (1);
309  return retval;
310 }
311 
312 /*
313  * write lines of text
314  *
315  * return -1 on error or bytecount
316  */
317 static int writeline(char *buf, int len, netbuf *nData)
318 {
319  int x, nb=0, w;
320  char *ubp = buf, *nbp;
321  char lc=0;
322 
323  if (nData->dir != FTPLIB_WRITE)
324  return -1;
325  nbp = nData->buf;
326  for (x=0; x < len; x++)
327  {
328  if ((*ubp == '\n') && (lc != '\r'))
329  {
330  if (nb == FTPLIB_BUFSIZ)
331  {
332  if (!socket_wait(nData))
333  return x;
334  w = (int)net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
335  if (w != FTPLIB_BUFSIZ)
336  {
337  if (ftplib_debug > 1)
338  printf("net_write(1) returned %d, errno = %d\n", w, errno);
339  return(-1);
340  }
341  nb = 0;
342  }
343  nbp[nb++] = '\r';
344  }
345  if (nb == FTPLIB_BUFSIZ)
346  {
347  if (!socket_wait(nData))
348  return x;
349  w = (int)net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
350  if (w != FTPLIB_BUFSIZ)
351  {
352  if (ftplib_debug > 1)
353  printf("net_write(2) returned %d, errno = %d\n", w, errno);
354  return(-1);
355  }
356  nb = 0;
357  }
358  nbp[nb++] = lc = *ubp++;
359  }
360  if (nb)
361  {
362  if (!socket_wait(nData))
363  return x;
364  w = (int)net_write(nData->handle, nbp, nb);
365  if (w != nb)
366  {
367  if (ftplib_debug > 1)
368  printf("net_write(3) returned %d, errno = %d\n", w, errno);
369  return(-1);
370  }
371  }
372  return len;
373 }
374 
375 /*
376  * read a response from the server
377  *
378  * return 0 if first char doesn't match
379  * return 1 if first char matches
380  */
381 static int readresp(char c, netbuf *nControl)
382 {
383  char match[5];
384  if (readline(nControl->response,256,nControl) == -1)
385  {
386  perror("Control socket read failed");
387  return 0;
388  }
389  if (ftplib_debug > 1)
390  fprintf(stderr,"%s",nControl->response);
391  if (nControl->response[3] == '-')
392  {
393  strncpy(match,nControl->response,3);
394  match[3] = ' ';
395  match[4] = '\0';
396  do
397  {
398  if (readline(nControl->response,256,nControl) == -1)
399  {
400  perror("Control socket read failed");
401  return 0;
402  }
403  if (ftplib_debug > 1)
404  fprintf(stderr,"%s",nControl->response);
405  }
406  while (strncmp(nControl->response,match,4));
407  }
408  if (nControl->response[0] == c)
409  return 1;
410  return 0;
411 }
412 
413 /*
414  * FtpInit for stupid operating systems that require it (Windows NT)
415  */
416 GLOBALDEF void FtpInit(void)
417 {
418 #if defined(_WIN32)
419  WORD wVersionRequested;
420  WSADATA wsadata;
421  int err;
422  wVersionRequested = MAKEWORD(1,1);
423  if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0)
424  if (ftplib_debug > 1)
425  fprintf(stderr,"Network failed to start: %d\n",err);
426 #endif
427 }
428 
429 /*
430  * FtpLastResponse - return a pointer to the last response received
431  */
432 GLOBALDEF char *FtpLastResponse(netbuf *nControl)
433 {
434  if ((nControl) && (nControl->dir == FTPLIB_CONTROL))
435  return nControl->response;
436  return NULL;
437 }
438 
439 /*
440  * FtpConnect - connect to remote server
441  *
442  * return 1 if connected, 0 if not
443  */
444 GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
445 {
446  int sControl, stat, flags, oldflags;
447  struct sockaddr_in sin;
448  struct hostent *phe;
449  struct servent *pse;
450  int on=1;
451  netbuf *ctrl;
452  char *lhost;
453  char *pnum;
454  struct timeval tv;
455  fd_set wr;
456 
457  memset(&sin,0,sizeof(sin));
458  sin.sin_family = AF_INET;
459  lhost = strdup(host);
460  pnum = strchr(lhost,':');
461  if (pnum == NULL)
462  {
463 #if defined(VMS) || defined(ANDROID)
464  sin.sin_port = htons(21);
465 #else
466  if ((pse = getservbyname("ftp","tcp")) == NULL)
467  {
468  perror("getservbyname");
469  return 0;
470  }
471  sin.sin_port = pse->s_port;
472 #endif
473  }
474  else
475  {
476  *pnum++ = '\0';
477  if (isdigit(*pnum))
478  sin.sin_port = htons(atoi(pnum));
479  else
480  {
481  pse = getservbyname(pnum,"tcp");
482  sin.sin_port = pse->s_port;
483  }
484  }
485  if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
486  {
487  if ((phe = gethostbyname(lhost)) == NULL)
488  {
489  perror("gethostbyname");
490  return 0;
491  }
492 
493  memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
494 
495  }
496  free(lhost);
497 
498  sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
499  if (sControl == -1)
500  {
501  perror("socket");
502  return 0;
503  }
504 
505  if ( setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
506  SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
507  {
508  perror("setsockopt");
509  net_close(sControl);
510  return 0;
511  }
512 
513 #if defined(_WIN32)
514  if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
515  {
516  perror("connect");
517  net_close(sControl);
518  return 0;
519  }
520 #else
521  //set nonblocking for connection timeout
522  flags = fcntl( sControl, F_GETFL,0);
523  oldflags=flags;
524  fcntl( sControl, F_SETFL, O_NONBLOCK|flags);
525 
526  stat=connect( sControl, (struct sockaddr *)&sin, sizeof(sin));
527  if (stat < 0)
528  {
529  if (errno != EWOULDBLOCK && errno != EINPROGRESS)
530  {
531  perror("connect");
532  net_close(sControl);
533  return 0;
534  }
535  }
536 
537  FD_ZERO(&wr);
538  FD_SET( sControl, &wr);
539 
540  tv.tv_sec = ACCEPT_TIMEOUT;
541  tv.tv_usec = 0;
542 
543  stat = select(sControl+1, 0, &wr, 0, &tv);
544 
545  if (stat < 1)
546  {
547  // time out has expired,
548  // or an error has ocurred
549  perror("timeout");
550  net_close(sControl);
551  return 0;
552  }
553 
554  if (ftplib_debug > 1)
555  printf("connected\n");
556 
557  //set original flags
558  fcntl( sControl, F_SETFL, oldflags);
559 #endif
560 
561  ctrl = calloc(1,sizeof(netbuf));
562  if (ctrl == NULL)
563  {
564  perror("calloc");
565  net_close(sControl);
566  return 0;
567  }
568  ctrl->buf = malloc(FTPLIB_BUFSIZ);
569  if (ctrl->buf == NULL)
570  {
571  perror("calloc");
572  net_close(sControl);
573  free(ctrl);
574  return 0;
575  }
576  ctrl->handle = sControl;
577  ctrl->dir = FTPLIB_CONTROL;
578  ctrl->ctrl = NULL;
579  ctrl->cmode = FTPLIB_DEFMODE;
580  ctrl->idlecb = NULL;
581  ctrl->writercb = NULL;
582  ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
583  ctrl->idlearg = NULL;
584  ctrl->writerarg = NULL;
585  ctrl->xfered = 0;
586  ctrl->xfered1 = 0;
587  ctrl->cbbytes = 0;
588  if (readresp('2', ctrl) == 0)
589  {
590  net_close(sControl);
591  free(ctrl->buf);
592  free(ctrl);
593  return 0;
594  }
595  *nControl = ctrl;
596  return 1;
597 }
598 
599 /*
600  * FtpOptions - change connection options
601  *
602  * returns 1 if successful, 0 on error
603  */
604 GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl)
605 {
606  int v,rv=0;
607  switch (opt)
608  {
609  case FTPLIB_CONNMODE:
610  v = (int) val;
611  if ((v == FTPLIB_PASSIVE) || (v == FTPLIB_PORT))
612  {
613  nControl->cmode = v;
614  rv = 1;
615  }
616  break;
617  case FTPLIB_CALLBACK:
618  nControl->idlecb = (FtpCallback) val;
619  rv = 1;
620  break;
622  nControl->writercb = (FtpCallbackWriter) val;
623  rv = 1;
624  break;
625  case FTPLIB_IDLETIME:
626  v = (int) val;
627  rv = 1;
628  nControl->idletime.tv_sec = v / 1000;
629  nControl->idletime.tv_usec = (v % 1000) * 1000;
630  break;
631  case FTPLIB_CALLBACKARG:
632  rv = 1;
633  nControl->idlearg = (void *) val;
634  break;
636  rv = 1;
637  nControl->writerarg = (void *) val;
638  break;
640  rv = 1;
641  nControl->cbbytes = (int) val;
642  break;
643  }
644  return rv;
645 }
646 
647 /*
648  * FtpSendCmd - send a command and wait for expected response
649  *
650  * return 1 if proper response received, 0 otherwise
651  */
652 static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl)
653 {
654  char buf[256];
655  if (nControl->dir != FTPLIB_CONTROL)
656  return 0;
657  if (ftplib_debug > 2)
658  fprintf(stderr,"%s\n",cmd);
659  if ((strlen(cmd) + 3) > sizeof(buf))
660  return 0;
661  sprintf(buf,"%s\r\n",cmd);
662  if (net_write(nControl->handle,buf,strlen(buf)) <= 0)
663  {
664  perror("write");
665  return 0;
666  }
667  return readresp(expresp, nControl);
668 }
669 
670 /*
671  * FtpLogin - log in to remote server
672  *
673  * return 1 if logged in, 0 otherwise
674  */
675 GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl)
676 {
677  char tempbuf[64];
678 
679  if (((strlen(user) + 7) > sizeof(tempbuf)) ||
680  ((strlen(pass) + 7) > sizeof(tempbuf)))
681  return 0;
682  sprintf(tempbuf,"USER %s",user);
683  if (!FtpSendCmd(tempbuf,'3',nControl))
684  {
685  if (nControl->response[0] == '2')
686  return 1;
687  return 0;
688  }
689  sprintf(tempbuf,"PASS %s",pass);
690  return FtpSendCmd(tempbuf,'2',nControl);
691 }
692 
693 /*
694  * FtpOpenPort - set up data connection
695  *
696  * return 1 if successful, 0 otherwise
697  */
698 static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir)
699 {
700  int sData;
701  union {
702  struct sockaddr sa;
703  struct sockaddr_in in;
704  } sin;
705  struct linger lng = { 0, 0 };
706  socklen_t l;
707  int on=1;
708  netbuf *ctrl;
709  char *cp;
710  unsigned int v[6];
711  char buf[256];
712 
713  if (nControl->dir != FTPLIB_CONTROL)
714  return -1;
715  if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
716  {
717  sprintf(nControl->response, "Invalid direction %d\n", dir);
718  return -1;
719  }
720  if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE))
721  {
722  sprintf(nControl->response, "Invalid mode %c\n", mode);
723  return -1;
724  }
725  l = sizeof(sin);
726  if (nControl->cmode == FTPLIB_PASSIVE)
727  {
728  memset(&sin, 0, l);
729  sin.in.sin_family = AF_INET;
730  if (!FtpSendCmd("PASV",'2',nControl))
731  return -1;
732  cp = strchr(nControl->response,'(');
733  if (cp == NULL)
734  return -1;
735  cp++;
736  sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
737  sin.sa.sa_data[2] = v[2];
738  sin.sa.sa_data[3] = v[3];
739  sin.sa.sa_data[4] = v[4];
740  sin.sa.sa_data[5] = v[5];
741  sin.sa.sa_data[0] = v[0];
742  sin.sa.sa_data[1] = v[1];
743  }
744  else
745  {
746  if (getsockname(nControl->handle, &sin.sa, &l) < 0)
747  {
748  perror("getsockname");
749  return 0;
750  }
751  }
752  sData = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
753  if (sData == -1)
754  {
755  perror("socket");
756  return -1;
757  }
758  if (setsockopt(sData,SOL_SOCKET,SO_REUSEADDR,
759  SETSOCKOPT_OPTVAL_TYPE &on,sizeof(on)) == -1)
760  {
761  perror("setsockopt");
762  net_close(sData);
763  return -1;
764  }
765  if (setsockopt(sData,SOL_SOCKET,SO_LINGER,
766  SETSOCKOPT_OPTVAL_TYPE &lng,sizeof(lng)) == -1)
767  {
768  perror("setsockopt");
769  net_close(sData);
770  return -1;
771  }
772  if (nControl->cmode == FTPLIB_PASSIVE)
773  {
774  if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1)
775  {
776  perror("connect");
777  net_close(sData);
778  return -1;
779  }
780  }
781  else
782  {
783  sin.in.sin_port = 0;
784  if (bind(sData, &sin.sa, sizeof(sin)) == -1)
785  {
786  perror("bind");
787  net_close(sData);
788  return 0;
789  }
790  if (listen(sData, 1) < 0)
791  {
792  perror("listen");
793  net_close(sData);
794  return 0;
795  }
796  if (getsockname(sData, &sin.sa, &l) < 0)
797  return 0;
798  sprintf(buf, "PORT %d,%d,%d,%d,%d,%d",
799  (unsigned char) sin.sa.sa_data[2],
800  (unsigned char) sin.sa.sa_data[3],
801  (unsigned char) sin.sa.sa_data[4],
802  (unsigned char) sin.sa.sa_data[5],
803  (unsigned char) sin.sa.sa_data[0],
804  (unsigned char) sin.sa.sa_data[1]);
805  if (!FtpSendCmd(buf,'2',nControl))
806  {
807  net_close(sData);
808  return 0;
809  }
810  }
811  ctrl = calloc(1,sizeof(netbuf));
812  if (ctrl == NULL)
813  {
814  perror("calloc");
815  net_close(sData);
816  return -1;
817  }
818  if ((mode == 'A') && ((ctrl->buf = malloc(FTPLIB_BUFSIZ)) == NULL))
819  {
820  perror("calloc");
821  net_close(sData);
822  free(ctrl);
823  return -1;
824  }
825  ctrl->handle = sData;
826  ctrl->dir = dir;
827  ctrl->idletime = nControl->idletime;
828  ctrl->idlearg = nControl->idlearg;
829  ctrl->writerarg = nControl->writerarg;
830  ctrl->xfered = 0;
831  ctrl->xfered1 = 0;
832  ctrl->cbbytes = nControl->cbbytes;
833  if (ctrl->idletime.tv_sec || ctrl->idletime.tv_usec || ctrl->cbbytes)
834  ctrl->idlecb = nControl->idlecb;
835  else
836  ctrl->idlecb = NULL;
837  ctrl->writercb = nControl->writercb;
838  *nData = ctrl;
839  return 1;
840 }
841 
842 /*
843  * FtpAcceptConnection - accept connection from server
844  *
845  * return 1 if successful, 0 otherwise
846  */
847 static int FtpAcceptConnection(netbuf *nData, netbuf *nControl)
848 {
849  int sData;
850  struct sockaddr addr;
851  socklen_t l;
852  int i;
853  struct timeval tv;
854  fd_set mask;
855  int rv = 0;
856 
857  FD_ZERO(&mask);
858  FD_SET(nControl->handle, &mask);
859  FD_SET(nData->handle, &mask);
860  tv.tv_usec = 0;
861  tv.tv_sec = ACCEPT_TIMEOUT;
862  if (ftplib_debug > 1)
863  printf("<<<<<<<<<<<<<<<<%d\n",ACCEPT_TIMEOUT);
864  i = nControl->handle;
865  if (i < nData->handle)
866  i = nData->handle;
867  i = select(i+1, &mask, NULL, NULL, &tv);
868  if (i == -1)
869  {
870  strncpy(nControl->response, strerror(errno),
871  sizeof(nControl->response));
872  net_close(nData->handle);
873  nData->handle = 0;
874  rv = 0;
875  }
876  else if (i == 0)
877  {
878  strcpy(nControl->response, "timed out waiting for connection");
879  net_close(nData->handle);
880  nData->handle = 0;
881  rv = 0;
882  }
883  else
884  {
885  if (FD_ISSET(nData->handle, &mask))
886  {
887  l = sizeof(addr);
888  sData = accept(nData->handle, &addr, &l);
889  i = errno;
890  net_close(nData->handle);
891  if (sData > 0)
892  {
893  rv = 1;
894  nData->handle = sData;
895  }
896  else
897  {
898  strncpy(nControl->response, strerror(i),
899  sizeof(nControl->response));
900  nData->handle = 0;
901  rv = 0;
902  }
903  }
904  else if (FD_ISSET(nControl->handle, &mask))
905  {
906  net_close(nData->handle);
907  nData->handle = 0;
908  readresp('2', nControl);
909  rv = 0;
910  }
911  }
912  return rv;
913 }
914 
915 /*
916  * FtpAccess - return a handle for a data stream
917  *
918  * return 1 if successful, 0 otherwise
919  */
920 GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
921  netbuf **nData)
922 {
923  char buf[256];
924  int dir;
925  if ((path == NULL) &&
926  ((typ == FTPLIB_FILE_WRITE) || (typ == FTPLIB_FILE_READ)))
927  {
928  sprintf(nControl->response,
929  "Missing path argument for file transfer\n");
930  return 0;
931  }
932  sprintf(buf, "TYPE %c", mode);
933  if (!FtpSendCmd(buf, '2', nControl))
934  return 0;
935  switch (typ)
936  {
937  case FTPLIB_DIR:
938  strcpy(buf,"NLST");
939  dir = FTPLIB_READ;
940  break;
941  case FTPLIB_DIR_VERBOSE:
942  strcpy(buf,"LIST");
943  dir = FTPLIB_READ;
944  break;
945  case FTPLIB_FILE_READ:
946  strcpy(buf,"RETR");
947  dir = FTPLIB_READ;
948  break;
949  case FTPLIB_FILE_WRITE:
950  strcpy(buf,"STOR");
951  dir = FTPLIB_WRITE;
952  break;
953  default:
954  sprintf(nControl->response, "Invalid open type %d\n", typ);
955  return 0;
956  }
957  if (path != NULL)
958  {
959  int i = (int)strlen(buf);
960  buf[i++] = ' ';
961  if ((strlen(path) + i) >= sizeof(buf))
962  return 0;
963  strcpy(&buf[i],path);
964  }
965  if (FtpOpenPort(nControl, nData, mode, dir) == -1)
966  return 0;
967  if (!FtpSendCmd(buf, '1', nControl))
968  {
969  FtpClose(*nData);
970  *nData = NULL;
971  return 0;
972  }
973  (*nData)->ctrl = nControl;
974  nControl->data = *nData;
975  if (nControl->cmode == FTPLIB_PORT)
976  {
977  if (!FtpAcceptConnection(*nData,nControl))
978  {
979  FtpClose(*nData);
980  *nData = NULL;
981  nControl->data = NULL;
982  return 0;
983  }
984  }
985  return 1;
986 }
987 
988 /*
989  * FtpRead - read from a data connection
990  */
991 GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData)
992 {
993  int i;
994  if (nData->dir != FTPLIB_READ)
995  return 0;
996  if (nData->buf)
997  i = readline(buf, max, nData);
998  else
999  {
1000  i = socket_wait(nData);
1001  if (i != 1)
1002  return 0;
1003  i = (int)net_read(nData->handle, buf, max);
1004  }
1005  if (i == -1)
1006  return 0;
1007  nData->xfered += i;
1008  if (nData->idlecb && nData->cbbytes)
1009  {
1010  nData->xfered1 += i;
1011  if (nData->xfered1 > nData->cbbytes)
1012  {
1013  if (nData->idlecb(nData, nData->xfered, nData->idlearg) == 0)
1014  return 0;
1015  nData->xfered1 = 0;
1016  }
1017  }
1018  return i;
1019 }
1020 
1021 /*
1022  * FtpWrite - write to a data connection
1023  */
1024 GLOBALDEF int FtpWrite(void *buf, int len, netbuf *nData)
1025 {
1026  int i;
1027  if (nData->dir != FTPLIB_WRITE)
1028  return 0;
1029  if (nData->buf)
1030  i = writeline(buf, len, nData);
1031  else
1032  {
1033  socket_wait(nData);
1034  i = (int)net_write(nData->handle, buf, len);
1035  }
1036  if (i == -1)
1037  return 0;
1038  nData->xfered += i;
1039  if (nData->idlecb && nData->cbbytes)
1040  {
1041  nData->xfered1 += i;
1042  if (nData->xfered1 > nData->cbbytes)
1043  {
1044  nData->idlecb(nData, nData->xfered, nData->idlearg);
1045  nData->xfered1 = 0;
1046  }
1047  }
1048  return i;
1049 }
1050 
1051 /*
1052  * FtpClose - close a data connection
1053  */
1054 GLOBALDEF int FtpClose(netbuf *nData)
1055 {
1056  netbuf *ctrl;
1057  switch (nData->dir)
1058  {
1059  case FTPLIB_WRITE:
1060  /* potential problem - if buffer flush fails, how to notify user? */
1061  if (nData->buf != NULL)
1062  writeline(NULL, 0, nData);
1063  case FTPLIB_READ:
1064  if (nData->buf)
1065  free(nData->buf);
1066  shutdown(nData->handle,2);
1067  net_close(nData->handle);
1068  ctrl = nData->ctrl;
1069  free(nData);
1070  if (ctrl)
1071  {
1072  ctrl->data = NULL;
1073  return(readresp('2', ctrl));
1074  }
1075  return 1;
1076  case FTPLIB_CONTROL:
1077  if (nData->data)
1078  {
1079  nData->ctrl = NULL;
1080  FtpClose(nData);
1081  }
1082  net_close(nData->handle);
1083  free(nData);
1084  return 0;
1085  }
1086  return 1;
1087 }
1088 
1089 /*
1090  * FtpSite - send a SITE command
1091  *
1092  * return 1 if command successful, 0 otherwise
1093  */
1094 GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl)
1095 {
1096  char buf[256];
1097 
1098  if ((strlen(cmd) + 7) > sizeof(buf))
1099  return 0;
1100  sprintf(buf,"SITE %s",cmd);
1101  if (!FtpSendCmd(buf,'2',nControl))
1102  return 0;
1103  return 1;
1104 }
1105 
1106 /*
1107  * FtpSysType - send a SYST command
1108  *
1109  * Fills in the user buffer with the remote system type. If more
1110  * information from the response is required, the user can parse
1111  * it out of the response buffer returned by FtpLastResponse().
1112  *
1113  * return 1 if command successful, 0 otherwise
1114  */
1115 GLOBALDEF int FtpSysType(char *buf, int max, netbuf *nControl)
1116 {
1117  int l = max;
1118  char *b = buf;
1119  char *s;
1120  if (!FtpSendCmd("SYST",'2',nControl))
1121  return 0;
1122  s = &nControl->response[4];
1123  while ((--l) && (*s != ' '))
1124  *b++ = *s++;
1125  *b++ = '\0';
1126  return 1;
1127 }
1128 
1129 /*
1130  * FtpMkdir - create a directory at server
1131  *
1132  * return 1 if successful, 0 otherwise
1133  */
1134 GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl)
1135 {
1136  char buf[256];
1137 
1138  if ((strlen(path) + 6) > sizeof(buf))
1139  return 0;
1140  sprintf(buf,"MKD %s",path);
1141  if (!FtpSendCmd(buf,'2', nControl))
1142  return 0;
1143  return 1;
1144 }
1145 
1146 /*
1147  * FtpChdir - change path at remote
1148  *
1149  * return 1 if successful, 0 otherwise
1150  */
1151 GLOBALDEF int FtpChdir(const char *path, netbuf *nControl)
1152 {
1153  char buf[256];
1154 
1155  if ((strlen(path) + 6) > sizeof(buf))
1156  return 0;
1157  sprintf(buf,"CWD %s",path);
1158  if (!FtpSendCmd(buf,'2',nControl))
1159  return 0;
1160  return 1;
1161 }
1162 
1163 /*
1164  * FtpCDUp - move to parent directory at remote
1165  *
1166  * return 1 if successful, 0 otherwise
1167  */
1168 GLOBALDEF int FtpCDUp(netbuf *nControl)
1169 {
1170  if (!FtpSendCmd("CDUP",'2',nControl))
1171  return 0;
1172  return 1;
1173 }
1174 
1175 /*
1176  * FtpRmdir - remove directory at remote
1177  *
1178  * return 1 if successful, 0 otherwise
1179  */
1180 GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl)
1181 {
1182  char buf[256];
1183 
1184  if ((strlen(path) + 6) > sizeof(buf))
1185  return 0;
1186  sprintf(buf,"RMD %s",path);
1187  if (!FtpSendCmd(buf,'2',nControl))
1188  return 0;
1189  return 1;
1190 }
1191 
1192 /*
1193  * FtpPwd - get working directory at remote
1194  *
1195  * return 1 if successful, 0 otherwise
1196  */
1197 GLOBALDEF int FtpPwd(char *path, int max, netbuf *nControl)
1198 {
1199  int l = max;
1200  char *b = path;
1201  char *s;
1202  if (!FtpSendCmd("PWD",'2',nControl))
1203  return 0;
1204  s = strchr(nControl->response, '"');
1205  if (s == NULL)
1206  return 0;
1207  s++;
1208  while ((--l) && (*s) && (*s != '"'))
1209  *b++ = *s++;
1210  *b++ = '\0';
1211  return 1;
1212 }
1213 
1214 /*
1215  * FtpXfer - issue a command and transfer data
1216  *
1217  * return 1 if successful, 0 otherwise
1218  */
1219 static int FtpXfer(const char *localfile, const char *path,
1220  netbuf *nControl, int typ, int mode)
1221 {
1222  int l,c;
1223  char *dbuf;
1224  FILE *local = NULL;
1225  netbuf *nData;
1226  int rv=1;
1227  int writeResult = 0;
1228 
1229  if (localfile != NULL)
1230  {
1231  char ac[4] = "w";
1232  if (typ == FTPLIB_FILE_WRITE)
1233  ac[0] = 'r';
1234  if (mode == FTPLIB_IMAGE)
1235  ac[1] = 'b';
1236  local = fopen(localfile, ac);
1237  if (local == NULL)
1238  {
1239  strncpy(nControl->response, strerror(errno),
1240  sizeof(nControl->response));
1241  return 0;
1242  }
1243  }
1244  if (local == NULL)
1245  local = (typ == FTPLIB_FILE_WRITE) ? stdin : stdout;
1246  if (!FtpAccess(path, typ, mode, nControl, &nData))
1247  return 0;
1248  dbuf = malloc(FTPLIB_BUFSIZ);
1249  if (typ == FTPLIB_FILE_WRITE)
1250  {
1251  while ((l = (int)fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0)
1252  if ((c = FtpWrite(dbuf, l, nData)) < l)
1253  {
1254  if (ftplib_debug > 1)
1255  printf("short write: passed %d, wrote %d\n", l, c);
1256  rv = 0;
1257  break;
1258  }
1259  }
1260  else
1261  {
1262  while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0) {
1263  writeResult = (int)((nData->writercb) ? nData->writercb(nData, dbuf, l, nData->writerarg) : fwrite(dbuf, 1, l, local));
1264  if (writeResult <= 0)
1265  {
1266  perror("localstore write");
1267  rv = 0;
1268  break;
1269  }
1270  }
1271  }
1272  free(dbuf);
1273  fflush(local);
1274  if (localfile != NULL)
1275  fclose(local);
1276  FtpClose(nData);
1277  return rv;
1278 }
1279 
1280 /*
1281  * FtpNlst - issue an NLST command and write response to output
1282  *
1283  * return 1 if successful, 0 otherwise
1284  */
1285 GLOBALDEF int FtpNlst(const char *outputfile, const char *path,
1286  netbuf *nControl)
1287 {
1288  return FtpXfer(outputfile, path, nControl, FTPLIB_DIR, FTPLIB_ASCII);
1289 }
1290 
1291 /*
1292  * FtpDir - issue a LIST command and write response to output
1293  *
1294  * return 1 if successful, 0 otherwise
1295  */
1296 GLOBALDEF int FtpDir(const char *outputfile, const char *path, netbuf *nControl)
1297 {
1298  return FtpXfer(outputfile, path, nControl, FTPLIB_DIR_VERBOSE, FTPLIB_ASCII);
1299 }
1300 
1301 /*
1302  * FtpSize - determine the size of a remote file
1303  *
1304  * return 1 if successful, 0 otherwise
1305  */
1306 GLOBALDEF int FtpSize(const char *path, int *size, char mode, netbuf *nControl)
1307 {
1308  char cmd[256];
1309  int resp,sz,rv=1;
1310 
1311  if ((strlen(path) + 7) > sizeof(cmd))
1312  return 0;
1313  sprintf(cmd, "TYPE %c", mode);
1314  if (!FtpSendCmd(cmd, '2', nControl))
1315  return 0;
1316  sprintf(cmd,"SIZE %s",path);
1317  if (!FtpSendCmd(cmd,'2',nControl))
1318  rv = 0;
1319  else
1320  {
1321  if (sscanf(nControl->response, "%d %d", &resp, &sz) == 2)
1322  *size = sz;
1323  else
1324  rv = 0;
1325  }
1326  return rv;
1327 }
1328 
1329 /*
1330  * FtpModDate - determine the modification date of a remote file
1331  *
1332  * return 1 if successful, 0 otherwise
1333  */
1334 GLOBALDEF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl)
1335 {
1336  char buf[256];
1337  int rv = 1;
1338 
1339  if ((strlen(path) + 7) > sizeof(buf))
1340  return 0;
1341  sprintf(buf,"MDTM %s",path);
1342  if (!FtpSendCmd(buf,'2',nControl))
1343  rv = 0;
1344  else
1345  strncpy(dt, &nControl->response[4], max);
1346  return rv;
1347 }
1348 
1349 /*
1350  * FtpGet - issue a GET command and write received data to output
1351  *
1352  * return 1 if successful, 0 otherwise
1353  */
1354 GLOBALDEF int FtpGet(const char *outputfile, const char *path,
1355  char mode, netbuf *nControl)
1356 {
1357  return FtpXfer(outputfile, path, nControl, FTPLIB_FILE_READ, mode);
1358 }
1359 
1360 /*
1361  * FtpPut - issue a PUT command and send data from input
1362  *
1363  * return 1 if successful, 0 otherwise
1364  */
1365 GLOBALDEF int FtpPut(const char *inputfile, const char *path, char mode,
1366  netbuf *nControl)
1367 {
1368  return FtpXfer(inputfile, path, nControl, FTPLIB_FILE_WRITE, mode);
1369 }
1370 
1371 /*
1372  * FtpRename - rename a file at remote
1373  *
1374  * return 1 if successful, 0 otherwise
1375  */
1376 GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl)
1377 {
1378  char cmd[256];
1379 
1380  if (((strlen(src) + 7) > sizeof(cmd)) ||
1381  ((strlen(dst) + 7) > sizeof(cmd)))
1382  return 0;
1383  sprintf(cmd,"RNFR %s",src);
1384  if (!FtpSendCmd(cmd,'3',nControl))
1385  return 0;
1386  sprintf(cmd,"RNTO %s",dst);
1387  if (!FtpSendCmd(cmd,'2',nControl))
1388  return 0;
1389  return 1;
1390 }
1391 
1392 /*
1393  * FtpDelete - delete a file at remote
1394  *
1395  * return 1 if successful, 0 otherwise
1396  */
1397 GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl)
1398 {
1399  char cmd[256];
1400 
1401  if ((strlen(fnm) + 7) > sizeof(cmd))
1402  return 0;
1403  sprintf(cmd,"DELE %s",fnm);
1404  if (!FtpSendCmd(cmd,'2', nControl))
1405  return 0;
1406  return 1;
1407 }
1408 
1409 /*
1410  * FtpQuit - disconnect from remote
1411  *
1412  * return 1 if successful, 0 otherwise
1413  */
1414 GLOBALDEF void FtpQuit(netbuf *nControl)
1415 {
1416  if (nControl->dir != FTPLIB_CONTROL)
1417  return;
1418  FtpSendCmd("QUIT",'2',nControl);
1419  net_close(nControl->handle);
1420  free(nControl->buf);
1421  free(nControl);
1422 }
static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir)
Definition: ftplib.c:698
int cmode
Definition: ftplib.c:131
GLOBALDEF int FtpCDUp(netbuf *nControl)
Definition: ftplib.c:1168
#define FTPLIB_CALLBACK
Definition: ftplib.h:60
char * cget
Definition: ftplib.c:124
Definition: ftplib.c:123
GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData)
Definition: ftplib.c:991
int(* FtpCallbackWriter)(netbuf *nControl, const void *buffer, size_t size, void *arg)
Definition: ftplib.h:73
GLOBALDEF int FtpClose(netbuf *nData)
Definition: ftplib.c:1054
void * idlearg
Definition: ftplib.c:135
#define FTPLIB_DIR
Definition: ftplib.h:44
int dir
Definition: ftplib.c:128
int cleft
Definition: ftplib.c:126
#define FTPLIB_CALLBACK_WRITER
Definition: ftplib.h:64
GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl)
Definition: ftplib.c:1134
#define FTPLIB_DIR_VERBOSE
Definition: ftplib.h:45
int xfered1
Definition: ftplib.c:139
int handle
Definition: ftplib.c:125
netbuf * ctrl
Definition: ftplib.c:129
#define FTPLIB_IMAGE
Definition: ftplib.h:51
GLOBALDEF int FtpChdir(const char *path, netbuf *nControl)
Definition: ftplib.c:1151
#define FTPLIB_CALLBACK_WRITERARG
Definition: ftplib.h:65
GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl)
Definition: ftplib.c:1094
FtpCallbackWriter writercb
Definition: ftplib.c:134
#define FTPLIB_PORT
Definition: ftplib.h:57
GLOBALDEF void FtpInit(void)
Definition: ftplib.c:416
GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
Definition: ftplib.c:444
GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl)
Definition: ftplib.c:604
GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl)
Definition: ftplib.c:675
static int readline(char *buf, int max, netbuf *ctl)
Definition: ftplib.c:240
GLOBALDEF void FtpQuit(netbuf *nControl)
Definition: ftplib.c:1414
GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl)
Definition: ftplib.c:1397
#define FTPLIB_READ
Definition: ftplib.c:80
GLOBALDEF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl)
Definition: ftplib.c:1334
static int readresp(char c, netbuf *nControl)
Definition: ftplib.c:381
GLOBALDEF int FtpWrite(void *buf, int len, netbuf *nData)
Definition: ftplib.c:1024
GLOBALDEF int FtpPwd(char *path, int max, netbuf *nControl)
Definition: ftplib.c:1197
FtpCallback idlecb
Definition: ftplib.c:133
#define FTPLIB_FILE_READ
Definition: ftplib.h:46
#define SETSOCKOPT_OPTVAL_TYPE
Definition: ftplib.c:73
#define FTPLIB_FILE_WRITE
Definition: ftplib.h:47
char * malloc()
GLOBALDEF int FtpGet(const char *outputfile, const char *path, char mode, netbuf *nControl)
Definition: ftplib.c:1354
char * cput
Definition: ftplib.c:124
return NULL
Definition: regex.c:7953
#define FTPLIB_ASCII
Definition: ftplib.h:50
GLOBALDEF int ftplib_debug
Definition: ftplib.c:148
free(preg->fastmap)
#define ACCEPT_TIMEOUT
Definition: ftplib.c:77
static int FtpXfer(const char *localfile, const char *path, netbuf *nControl, int typ, int mode)
Definition: ftplib.c:1219
GLOBALDEF int FtpDir(const char *outputfile, const char *path, netbuf *nControl)
Definition: ftplib.c:1296
#define FTPLIB_WRITE
Definition: ftplib.c:81
int xfered
Definition: ftplib.c:137
GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl)
Definition: ftplib.c:1180
static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl)
Definition: ftplib.c:652
int cavail
Definition: ftplib.c:126
GLOBALDEF int FtpPut(const char *inputfile, const char *path, char mode, netbuf *nControl)
Definition: ftplib.c:1365
static int writeline(char *buf, int len, netbuf *nData)
Definition: ftplib.c:317
GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl, netbuf **nData)
Definition: ftplib.c:920
struct timeval idletime
Definition: ftplib.c:132
netbuf * data
Definition: ftplib.c:130
GLOBALDEF int FtpSize(const char *path, int *size, char mode, netbuf *nControl)
Definition: ftplib.c:1306
#define FTPLIB_PASSIVE
Definition: ftplib.h:56
int size
Definition: regex.c:5043
GLOBALDEF int FtpSysType(char *buf, int max, netbuf *nControl)
Definition: ftplib.c:1115
char response[256]
Definition: ftplib.c:140
void * mymemccpy(void *dst, const void *src, int c, size_t n)
Definition: ftplib.c:95
#define FTPLIB_DEFMODE
Definition: ftplib.c:84
void * writerarg
Definition: ftplib.c:136
GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl)
Definition: ftplib.c:1376
char * buf
Definition: ftplib.c:127
#define FTPLIB_IDLETIME
Definition: ftplib.h:61
int(* FtpCallback)(netbuf *nControl, int xfered, void *arg)
Definition: ftplib.h:72
static int socket_wait(netbuf *ctl)
Definition: ftplib.c:201
#define FTPLIB_CALLBACKARG
Definition: ftplib.h:62
#define FTPLIB_CONNMODE
Definition: ftplib.h:59
int cbbytes
Definition: ftplib.c:138
#define FTPLIB_CONTROL
Definition: ftplib.c:79
GLOBALDEF int FtpNlst(const char *outputfile, const char *path, netbuf *nControl)
Definition: ftplib.c:1285
GLOBALDEF char * FtpLastResponse(netbuf *nControl)
Definition: ftplib.c:432
static int FtpAcceptConnection(netbuf *nData, netbuf *nControl)
Definition: ftplib.c:847
#define FTPLIB_BUFSIZ
Definition: ftplib.c:76
#define FTPLIB_CALLBACKBYTES
Definition: ftplib.h:63