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