1 /***************************************************************************/
2 /* */
3 /* ftplib.c - callable ftp access routines */
4 /* Copyright (C) 1996, 1997 Thomas Pfau, pfau@cnj.digex.net */
5 /* 73 Catherine Street, South Bound Brook, NJ, 08880 */
6 /* */
7 /* This library is free software; you can redistribute it and/or */
8 /* modify it under the terms of the GNU Library General Public */
9 /* License as published by the Free Software Foundation; either */
10 /* version 2 of the License, or (at your option) any later version. */
11 /* */
12 /* This library is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
15 /* Library General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU Library General Public */
18 /* License along with this progam; if not, write to the */
19 /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
20 /* Boston, MA 02111-1307, USA. */
21 /* */
22 /***************************************************************************/
23
24 #if defined(__unix__) || defined(__VMS)
25 #include <unistd.h>
26 #endif
27 #if defined(_WIN32)
28 #include <windows.h>
29 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #if defined(__unix__)
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <arpa/inet.h>
41 #elif defined(VMS)
42 #include <types.h>
43 #include <socket.h>
44 #include <in.h>
45 #include <netdb.h>
46 #include <inet.h>
47 #elif defined(_WIN32)
48 #include <winsock.h>
49 #endif
50
51 #define BUILDING_LIBRARY
52 #include "ftplib.h"
53
54 #if defined(_WIN32)
55 #define SETSOCKOPT_OPTVAL_TYPE (const char *)
56 #else
57 #define SETSOCKOPT_OPTVAL_TYPE (void *)
58 #endif
59
60 #define FTPLIB_BUFSIZ 8192
61 #define ACCEPT_TIMEOUT 30
62
63 #define FTPLIB_CONTROL 0
64 #define FTPLIB_READ 1
65 #define FTPLIB_WRITE 2
66
67 struct NetBuf {
68 char *cput,*cget;
69 int handle;
70 int cavail,cleft;
71 char *buf;
72 int dir;
73 char response[256];
74 };
75
76 static char *version =
77 "ftplib Release 3 12/xx/97, copyright 1996, 1997 Thomas Pfau";
78
79 GLOBALDEF int ftplib_debug = 0;
80 netbuf *DefaultNetbuf;
81
82 #if defined(__unix__) || defined(VMS)
83 #define net_read read
84 #define net_write write
85 #define net_close close
86 #elif defined(_WIN32)
87 #define net_read(x,y,z) recv(x,y,z,0)
88 #define net_write(x,y,z) send(x,y,z,0)
89 #define net_close closesocket
90 #endif
91
92 #if defined(VMS)
93 /*
94 * VAX C does not supply a memccpy routine so I provide my own
95 */
memccpy(void * dest,const void * src,int c,size_t n)96 void *memccpy(void *dest, const void *src, int c, size_t n)
97 {
98 int i=0;
99 const unsigned char *ip=src;
100 unsigned char *op=dest;
101
102 while (i < n)
103 {
104 if ((*op++ = *ip++) == c)
105 break;
106 i++;
107 }
108 if (i == n)
109 return NULL;
110 return op;
111 }
112 #endif
113
114 /*
115 * read a line of text
116 *
117 * return -1 on error or bytecount
118 */
readline(char * buf,int max,netbuf * ctl)119 static int readline(char *buf,int max,netbuf *ctl)
120 {
121 int x,retval = 0;
122 char *end,*bp=buf;
123 int eof = 0;
124
125 if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ))
126 return -1;
127 if (max == 0)
128 return 0;
129 do
130 {
131 if (ctl->cavail > 0)
132 {
133 x = (max >= ctl->cavail) ? ctl->cavail : max-1;
134 end = memccpy(bp,ctl->cget,'\n',x);
135 if (end != NULL)
136 x = end - bp;
137 retval += x;
138 bp += x;
139 *bp = '\0';
140 max -= x;
141 ctl->cget += x;
142 ctl->cavail -= x;
143 if (end != NULL)
144 {
145 bp -= 2;
146 if (strcmp(bp,"\r\n") == 0)
147 {
148 *bp++ = '\n';
149 *bp++ = '\0';
150 --retval;
151 }
152 break;
153 }
154 }
155 if (max == 1)
156 {
157 *buf = '\0';
158 break;
159 }
160 if (ctl->cput == ctl->cget)
161 {
162 ctl->cput = ctl->cget = ctl->buf;
163 ctl->cavail = 0;
164 ctl->cleft = FTPLIB_BUFSIZ;
165 }
166 if (eof)
167 {
168 if (retval == 0)
169 retval = -1;
170 break;
171 }
172 if ((x = net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1)
173 {
174 perror("read");
175 retval = -1;
176 break;
177 }
178 if (x == 0)
179 eof = 1;
180 ctl->cleft -= x;
181 ctl->cavail += x;
182 ctl->cput += x;
183 }
184 while (1);
185 return retval;
186 }
187
188 /*
189 * write lines of text
190 *
191 * return -1 on error or bytecount
192 */
writeline(char * buf,int len,netbuf * nData)193 static int writeline(char *buf, int len, netbuf *nData)
194 {
195 int x, nb=0, w;
196 char *ubp = buf, *nbp;
197 char lc=0;
198
199 if (nData->dir != FTPLIB_WRITE)
200 return -1;
201 nbp = nData->buf;
202 for (x=0; x < len; x++)
203 {
204 if ((*ubp == '\n') && (lc != '\r'))
205 {
206 if (nb == FTPLIB_BUFSIZ)
207 {
208 w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
209 if (w != FTPLIB_BUFSIZ)
210 {
211 printf("net_write(1) returned %d, errno = %d\n", w, errno);
212 return(-1);
213 }
214 nb = 0;
215 }
216 nbp[nb++] = '\r';
217 }
218 if (nb == FTPLIB_BUFSIZ)
219 {
220 w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
221 if (w != FTPLIB_BUFSIZ)
222 {
223 printf("net_write(2) returned %d, errno = %d\n", w, errno);
224 return(-1);
225 }
226 nb = 0;
227 }
228 nbp[nb++] = lc = *ubp++;
229 }
230 if (nb)
231 {
232 w = net_write(nData->handle, nbp, nb);
233 if (w != nb)
234 {
235 printf("net_write(3) returned %d, errno = %d\n", w, errno);
236 return(-1);
237 }
238 }
239 return len;
240 }
241
242 /*
243 * read a response from the server
244 *
245 * return 0 if first char doesn't match
246 * return 1 if first char matches
247 */
readresp(char c,netbuf * nControl)248 static int readresp(char c, netbuf *nControl)
249 {
250 char match[5];
251 if (readline(nControl->response,256,nControl) == -1)
252 {
253 perror("Control socket read failed");
254 return 0;
255 }
256 if (ftplib_debug > 1)
257 fprintf(stderr,"%s",nControl->response);
258 if (nControl->response[3] == '-')
259 {
260 strncpy(match,nControl->response,3);
261 match[3] = ' ';
262 match[4] = '\0';
263 do
264 {
265 if (readline(nControl->response,256,nControl) == -1)
266 {
267 perror("Control socket read failed");
268 return 0;
269 }
270 if (ftplib_debug > 1)
271 fprintf(stderr,"%s",nControl->response);
272 }
273 while (strncmp(nControl->response,match,4));
274 }
275 if (nControl->response[0] == c)
276 return 1;
277 return 0;
278 }
279
280 /*
281 * FtpInit for stupid operating systems that require it (Windows NT)
282 */
FtpInit(void)283 GLOBALDEF void FtpInit(void)
284 {
285 #if defined(_WIN32)
286 WORD wVersionRequested;
287 WSADATA wsadata;
288 int err;
289 wVersionRequested = MAKEWORD(1,1);
290 if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0)
291 fprintf(stderr,"Network failed to start: %d\n",err);
292 #endif
293 }
294
295 /*
296 * FtpLastResponse - return a pointer to the last response received
297 */
FtpLastResponse(netbuf * nControl)298 GLOBALDEF char *FtpLastResponse(netbuf *nControl)
299 {
300 if ((nControl) && (nControl->dir == FTPLIB_CONTROL))
301 return nControl->response;
302 return NULL;
303 }
304
305 /*
306 * FtpConnect - connect to remote server
307 *
308 * return 1 if connected, 0 if not
309 */
FtpConnect(const char * host,netbuf ** nControl)310 GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
311 {
312 int sControl;
313 struct sockaddr_in sin;
314 struct hostent *phe;
315 struct servent *pse;
316 int on=1;
317 netbuf *ctrl;
318 char *lhost;
319 char *pnum;
320
321 memset(&sin,0,sizeof(sin));
322 sin.sin_family = AF_INET;
323 lhost = strdup(host);
324 pnum = strchr(lhost,':');
325 if (pnum == NULL)
326 {
327 #if defined(VMS)
328 sin.sin_port = htons(21);
329 #else
330 if ((pse = getservbyname("ftp","tcp")) == NULL)
331 {
332 perror("getservbyname");
333 return 0;
334 }
335 sin.sin_port = pse->s_port;
336 #endif
337 }
338 else
339 {
340 *pnum++ = '\0';
341 if (isdigit(*pnum))
342 sin.sin_port = htons(atoi(pnum));
343 else
344 {
345 pse = getservbyname(pnum,"tcp");
346 sin.sin_port = pse->s_port;
347 }
348 }
349 if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
350 {
351 if ((phe = gethostbyname(lhost)) == NULL)
352 {
353 perror("gethostbyname");
354 return 0;
355 }
356 memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
357 }
358 free(lhost);
359 sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
360 if (sControl == -1)
361 {
362 perror("socket");
363 return 0;
364 }
365 if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
366 SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
367 {
368 perror("setsockopt");
369 net_close(sControl);
370 return 0;
371 }
372 if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
373 {
374 perror("connect");
375 net_close(sControl);
376 return 0;
377 }
378 ctrl = calloc(1,sizeof(netbuf));
379 if (ctrl == NULL)
380 {
381 perror("calloc");
382 net_close(sControl);
383 return 0;
384 }
385 ctrl->buf = malloc(FTPLIB_BUFSIZ);
386 if (ctrl->buf == NULL)
387 {
388 perror("calloc");
389 net_close(sControl);
390 free(ctrl);
391 return 0;
392 }
393 ctrl->handle = sControl;
394 ctrl->dir = FTPLIB_CONTROL;
395 if (readresp('2', ctrl) == 0)
396 {
397 net_close(sControl);
398 free(ctrl->buf);
399 free(ctrl);
400 return 0;
401 }
402 *nControl = ctrl;
403 return 1;
404 }
405
406 /*
407 * FtpSendCmd - send a command and wait for expected response
408 *
409 * return 1 if proper response received, 0 otherwise
410 */
FtpSendCmd(const char * cmd,char expresp,netbuf * nControl)411 static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl)
412 {
413 char buf[256];
414 if (nControl->dir != FTPLIB_CONTROL)
415 return 0;
416 if (ftplib_debug > 2)
417 fprintf(stderr,"%s\n",cmd);
418 sprintf(buf,"%s\r\n",cmd);
419 if (net_write(nControl->handle,buf,strlen(buf)) <= 0)
420 {
421 perror("write");
422 return 0;
423 }
424 return readresp(expresp, nControl);
425 }
426
427 /*
428 * FtpLogin - log in to remote server
429 *
430 * return 1 if logged in, 0 otherwise
431 */
FtpLogin(const char * user,const char * pass,netbuf * nControl)432 GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl)
433 {
434 char tempbuf[64];
435
436 sprintf(tempbuf,"USER %s",user);
437 if (!FtpSendCmd(tempbuf,'3',nControl))
438 {
439 if (nControl->response[0] == '2')
440 return 1;
441 return 0;
442 }
443 sprintf(tempbuf,"PASS %s",pass);
444 return FtpSendCmd(tempbuf,'2',nControl);
445 }
446
447 /*
448 * FtpOpenPort - set up data connection
449 *
450 * return 1 if successful, 0 otherwise
451 */
FtpOpenPort(netbuf * nControl,netbuf ** nData,int mode,int dir)452 static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir)
453 {
454 int sData;
455 union {
456 struct sockaddr sa;
457 struct sockaddr_in in;
458 } sin;
459 struct linger lng = { 0, 0 };
460 int l;
461 int on=1;
462 char *cp;
463 unsigned int v[6];
464 netbuf *ctrl;
465
466 if (nControl->dir != FTPLIB_CONTROL)
467 return -1;
468 if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
469 {
470 sprintf(nControl->response, "Invalid direction %d\n", dir);
471 return -1;
472 }
473 if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE))
474 {
475 sprintf(nControl->response, "Invalid mode %c\n", mode);
476 return -1;
477 }
478 l = sizeof(sin);
479 memset(&sin, 0, l);
480 sin.in.sin_family = AF_INET;
481 if (!FtpSendCmd("PASV",'2',nControl))
482 return -1;
483 cp = strchr(nControl->response,'(');
484 if (cp == NULL)
485 return -1;
486 cp++;
487 sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
488 sin.sa.sa_data[2] = v[2];
489 sin.sa.sa_data[3] = v[3];
490 sin.sa.sa_data[4] = v[4];
491 sin.sa.sa_data[5] = v[5];
492 sin.sa.sa_data[0] = v[0];
493 sin.sa.sa_data[1] = v[1];
494 sData = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
495 if (sData == -1)
496 {
497 perror("socket");
498 return -1;
499 }
500 if (setsockopt(sData,SOL_SOCKET,SO_REUSEADDR,
501 SETSOCKOPT_OPTVAL_TYPE &on,sizeof(on)) == -1)
502 {
503 perror("setsockopt");
504 net_close(sData);
505 return -1;
506 }
507 if (setsockopt(sData,SOL_SOCKET,SO_LINGER,
508 SETSOCKOPT_OPTVAL_TYPE &lng,sizeof(lng)) == -1)
509 {
510 perror("setsockopt");
511 net_close(sData);
512 return -1;
513 }
514 if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1)
515 {
516 perror("connect");
517 net_close(sData);
518 return -1;
519 }
520 ctrl = calloc(1,sizeof(netbuf));
521 if (ctrl == NULL)
522 {
523 perror("calloc");
524 net_close(sData);
525 return -1;
526 }
527 if ((mode == 'A') && ((ctrl->buf = malloc(FTPLIB_BUFSIZ)) == NULL))
528 {
529 perror("calloc");
530 net_close(sData);
531 free(ctrl);
532 return -1;
533 }
534 ctrl->handle = sData;
535 ctrl->dir = dir;
536 *nData = ctrl;
537 return 1;
538 }
539
540 /*
541 * FtpAccess - return a handle for a data stream
542 *
543 * return 1 if successful, 0 otherwise
544 */
FtpAccess(const char * path,int typ,int mode,netbuf * nControl,netbuf ** nData)545 GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
546 netbuf **nData)
547 {
548 char buf[256];
549 int dir;
550 if ((path == NULL) && ((typ == FTPLIB_FILE_WRITE) || (typ == FTPLIB_FILE_READ)))
551 {
552 sprintf(nControl->response, "Missing path argument for file transfer\n");
553 return 0;
554 }
555 sprintf(buf, "TYPE %c", mode);
556 if (!FtpSendCmd(buf, '2', nControl))
557 return 0;
558 switch (typ)
559 {
560 case FTPLIB_DIR:
561 strcpy(buf,"NLST");
562 dir = FTPLIB_READ;
563 break;
564 case FTPLIB_DIR_VERBOSE:
565 strcpy(buf,"LIST");
566 dir = FTPLIB_READ;
567 break;
568 case FTPLIB_FILE_READ:
569 strcpy(buf,"RETR");
570 dir = FTPLIB_READ;
571 break;
572 case FTPLIB_FILE_WRITE:
573 strcpy(buf,"STOR");
574 dir = FTPLIB_WRITE;
575 break;
576 default:
577 sprintf(nControl->response, "Invalid open type %d\n", typ);
578 return 0;
579 }
580 if (path != NULL)
581 sprintf(buf+strlen(buf)," %s",path);
582 if (FtpOpenPort(nControl, nData, mode, dir) == -1)
583 return 0;
584 if (!FtpSendCmd(buf, '1', nControl))
585 {
586 FtpClose(*nData);
587 *nData = NULL;
588 return 0;
589 }
590 return 1;
591 }
592
593 /*
594 * FtpRead - read from a data connection
595 */
FtpRead(void * buf,int max,netbuf * nData)596 GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData)
597 {
598 if (nData->dir != FTPLIB_READ)
599 return 0;
600 if (nData->buf)
601 return readline(buf, max, nData);
602 return net_read(nData->handle, buf, max);
603 }
604
605 /*
606 * FtpWrite - write to a data connection
607 */
FtpWrite(void * buf,int len,netbuf * nData)608 GLOBALDEF int FtpWrite(void *buf, int len, netbuf *nData)
609 {
610 if (nData->dir != FTPLIB_WRITE)
611 return 0;
612 if (nData->buf)
613 return writeline(buf, len, nData);
614 return net_write(nData->handle, buf, len);
615 }
616
617 /*
618 * FtpClose - close a data connection
619 */
FtpClose(netbuf * nData)620 GLOBALDEF int FtpClose(netbuf *nData)
621 {
622 if (nData->dir == FTPLIB_WRITE)
623 {
624 if (nData->buf != NULL)
625 writeline(NULL, 0, nData);
626 }
627 else if (nData->dir != FTPLIB_READ)
628 return 0;
629 if (nData->buf)
630 free(nData->buf);
631 shutdown(nData->handle,2);
632 net_close(nData->handle);
633 return 1;
634 }
635
636 /*
637 * FtpSite - send a SITE command
638 *
639 * return 1 if command successful, 0 otherwise
640 */
FtpSite(const char * cmd,netbuf * nControl)641 GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl)
642 {
643 char buf[256];
644 sprintf(buf,"SITE %s",cmd);
645 if (!FtpSendCmd(buf,'2',nControl))
646 return 0;
647 return 1;
648 }
649
650 /*
651 * FtpMkdir - create a directory at server
652 *
653 * return 1 if successful, 0 otherwise
654 */
FtpMkdir(const char * path,netbuf * nControl)655 GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl)
656 {
657 char buf[256];
658 sprintf(buf,"MKD %s",path);
659 if (!FtpSendCmd(buf,'2', nControl))
660 return 0;
661 return 1;
662 }
663
664 /*
665 * FtpChdir - change path at remote
666 *
667 * return 1 if successful, 0 otherwise
668 */
FtpChdir(const char * path,netbuf * nControl)669 GLOBALDEF int FtpChdir(const char *path, netbuf *nControl)
670 {
671 char buf[256];
672 sprintf(buf,"CWD %s",path);
673 if (!FtpSendCmd(buf,'2',nControl))
674 return 0;
675 return 1;
676 }
677
678 /*
679 * FtpRmdir - remove directory at remote
680 *
681 * return 1 if successful, 0 otherwise
682 */
FtpRmdir(const char * path,netbuf * nControl)683 GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl)
684 {
685 char buf[256];
686 sprintf(buf,"RMD %s",path);
687 if (!FtpSendCmd(buf,'2',nControl))
688 return 0;
689 return 1;
690 }
691
692 /*
693 * FtpXfer - issue a command and transfer data
694 *
695 * return 1 if successful, 0 otherwise
696 */
FtpXfer(const char * localfile,const char * path,netbuf * nControl,int typ,int mode)697 static int FtpXfer(const char *localfile, const char *path,
698 netbuf *nControl, int typ, int mode)
699 {
700 int l,c;
701 char *dbuf;
702 FILE *local = NULL;
703 netbuf *nData;
704
705 if (localfile != NULL)
706 {
707 local = fopen(localfile, (typ == FTPLIB_FILE_WRITE) ? "r" : "w");
708 if (local == NULL)
709 {
710 strcpy(nControl->response, strerror(errno));
711 return 0;
712 }
713 }
714 if (local == NULL)
715 local = (typ == FTPLIB_FILE_WRITE) ? stdin : stdout;
716 if (!FtpAccess(path, typ, mode, nControl, &nData))
717 return 0;
718 dbuf = malloc(FTPLIB_BUFSIZ);
719 if (typ == FTPLIB_FILE_WRITE)
720 {
721 while ((l = fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0)
722 if ((c = FtpWrite(dbuf, l, nData)) < l)
723 printf("short write: passed %d, wrote %d\n", l, c);
724 }
725 else
726 {
727 while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0)
728 if (fwrite(dbuf, 1, l, local) <= 0)
729 {
730 perror("localfile write");
731 break;
732 }
733 }
734 fflush(local);
735 if (localfile != NULL)
736 fclose(local);
737 FtpClose(nData);
738 free(dbuf);
739 return readresp('2', nControl);
740 }
741
742 /*
743 * FtpNlst - issue an NLST command and write response to output
744 *
745 * return 1 if successful, 0 otherwise
746 */
FtpNlst(const char * outputfile,const char * path,netbuf * nControl)747 GLOBALDEF int FtpNlst(const char *outputfile, const char *path,
748 netbuf *nControl)
749 {
750 return FtpXfer(outputfile, path, nControl, FTPLIB_DIR, FTPLIB_ASCII);
751 }
752
753 /*
754 * FtpDir - issue a LIST command and write response to output
755 *
756 * return 1 if successful, 0 otherwise
757 */
FtpDir(const char * outputfile,const char * path,netbuf * nControl)758 GLOBALDEF int FtpDir(const char *outputfile, const char *path, netbuf *nControl)
759 {
760 return FtpXfer(outputfile, path, nControl, FTPLIB_DIR_VERBOSE, FTPLIB_ASCII);
761 }
762
763 /*
764 * FtpGet - issue a GET command and write received data to output
765 *
766 * return 1 if successful, 0 otherwise
767 */
FtpGet(const char * outputfile,const char * path,char mode,netbuf * nControl)768 GLOBALDEF int FtpGet(const char *outputfile, const char *path,
769 char mode, netbuf *nControl)
770 {
771 return FtpXfer(outputfile, path, nControl, FTPLIB_FILE_READ, mode);
772 }
773
774 /*
775 * FtpPut - issue a PUT command and send data from input
776 *
777 * return 1 if successful, 0 otherwise
778 */
FtpPut(const char * inputfile,const char * path,char mode,netbuf * nControl)779 GLOBALDEF int FtpPut(const char *inputfile, const char *path, char mode,
780 netbuf *nControl)
781 {
782 return FtpXfer(inputfile, path, nControl, FTPLIB_FILE_WRITE, mode);
783 }
784
785 /*
786 * FtpRename - rename a file at remote
787 *
788 * return 1 if successful, 0 otherwise
789 */
FtpRename(const char * src,const char * dst,netbuf * nControl)790 GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl)
791 {
792 char cmd[256];
793 sprintf(cmd,"RNFR %s",src);
794 if (!FtpSendCmd(cmd,'3',nControl))
795 return 0;
796 sprintf(cmd,"RNTO %s",dst);
797 if (!FtpSendCmd(cmd,'2',nControl))
798 return 0;
799 return 1;
800 }
801
802 /*
803 * FtpDelete - delete a file at remote
804 *
805 * return 1 if successful, 0 otherwise
806 */
FtpDelete(const char * fnm,netbuf * nControl)807 GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl)
808 {
809 char cmd[256];
810 sprintf(cmd,"DELE %s",fnm);
811 if (!FtpSendCmd(cmd,'2', nControl))
812 return 0;
813 return 1;
814 }
815
816 /*
817 * FtpQuit - disconnect from remote
818 *
819 * return 1 if successful, 0 otherwise
820 */
FtpQuit(netbuf * nControl)821 GLOBALDEF void FtpQuit(netbuf *nControl)
822 {
823 if (nControl->dir != FTPLIB_CONTROL)
824 return;
825 FtpSendCmd("QUIT",'2',nControl);
826 net_close(nControl->handle);
827 free(nControl->buf);
828 free(nControl);
829 }
830