?? ftplib.c
字號:
/***************************************************************************//* *//* ftplib.c - callable ftp access routines *//* Copyright (C) 1996, 1997, 1998 Thomas Pfau, pfau@cnj.digex.net *//* 73 Catherine Street, South Bound Brook, NJ, 08880 *//* *//* This library is free software; you can redistribute it and/or *//* modify it under the terms of the GNU Library General Public *//* License as published by the Free Software Foundation; either *//* version 2 of the License, or (at your option) any later version. *//* *//* This library is distributed in the hope that it will be useful, *//* but WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *//* Library General Public License for more details. *//* *//* You should have received a copy of the GNU Library General Public *//* License along with this progam; if not, write to the *//* Free Software Foundation, Inc., 59 Temple Place - Suite 330, *//* Boston, MA 02111-1307, USA. *//* *//***************************************************************************/#if defined(__unix__) || defined(__VMS)#include <unistd.h>#endif#if defined(_WIN32)#include <windows.h>#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <ctype.h>#if defined(__unix__)#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#elif defined(VMS)#include <types.h>#include <socket.h>#include <in.h>#include <netdb.h>#include <inet.h>#elif defined(_WIN32)#include <winsock.h>#endif#define BUILDING_LIBRARY#include "ftplib.h"#if defined(_WIN32)#define SETSOCKOPT_OPTVAL_TYPE (const char *)#else#define SETSOCKOPT_OPTVAL_TYPE (void *)#endif#define FTPLIB_BUFSIZ 8192#define ACCEPT_TIMEOUT 30#define FTPLIB_CONTROL 0#define FTPLIB_READ 1#define FTPLIB_WRITE 2#if !defined FTPLIB_DEFMODE#define FTPLIB_DEFMODE FTPLIB_PASSIVE#endifstruct NetBuf { char *cput,*cget; int handle; int cavail,cleft; char *buf; int dir; netbuf *ctrl; int cmode; struct timeval idletime; FtpCallback idlecb; void *idlearg; int xfered; int cbbytes; int xfered1; char response[256];};static char *version = "ftplib Release 3.1 6/xx/98, copyright 1996, 1997, 1998 Thomas Pfau";GLOBALDEF int ftplib_debug = 0;#if defined(__unix__) || defined(VMS)#define net_read read#define net_write write#define net_close close#elif defined(_WIN32)#define net_read(x,y,z) recv(x,y,z,0)#define net_write(x,y,z) send(x,y,z,0)#define net_close closesocket#endif#if defined(NEED_MEMCCPY)/* * VAX C does not supply a memccpy routine so I provide my own */void *memccpy(void *dest, const void *src, int c, size_t n){ int i=0; const unsigned char *ip=src; unsigned char *op=dest; while (i < n) { if ((*op++ = *ip++) == c) break; i++; } if (i == n) return NULL; return op;}#endif#if defined(NEED_STRDUP)/* * strdup - return a malloc'ed copy of a string */char *strdup(const char *src){ int l = strlen(src) + 1; char *dst = malloc(l); if (dst) strcpy(dst,src); return dst;}#endif/* * socket_wait - wait for socket to receive or flush data * * return 1 if no user callback, otherwise, return value returned by * user callback */static int socket_wait(netbuf *ctl){ fd_set fd,*rfd = NULL,*wfd = NULL; struct timeval tv; int rv = 0; if ((ctl->dir == FTPLIB_CONTROL) || (ctl->idlecb == NULL)) return 1; if (ctl->dir == FTPLIB_WRITE) wfd = &fd; else rfd = &fd; FD_ZERO(&fd); do { FD_SET(ctl->handle,&fd); tv = ctl->idletime; rv = select(ctl->handle+1, rfd, wfd, NULL, &tv); if (rv == -1) { rv = 0; strncpy(ctl->ctrl->response, strerror(errno), sizeof(ctl->ctrl->response)); break; } else if (rv > 0) { rv = 1; break; } } while ((rv = ctl->idlecb(ctl, ctl->xfered, ctl->idlearg))); return rv;}/* * read a line of text * * return -1 on error or bytecount */static int readline(char *buf,int max,netbuf *ctl)///*buf{ int x,retval = 0; char *end,*bp=buf; int eof = 0; if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ)) return -1; if (max == 0) return 0; do { if (ctl->cavail > 0) { x = (max >= ctl->cavail) ? ctl->cavail : max-1; end = memccpy(bp,ctl->cget,'\n',x); if (end != NULL) x = end - bp; retval += x; bp += x; *bp = '\0'; max -= x; ctl->cget += x; ctl->cavail -= x; if (end != NULL) { bp -= 2; if (strcmp(bp,"\r\n") == 0) { *bp++ = '\n'; *bp++ = '\0'; --retval; } break; } } if (max == 1) { *buf = '\0'; break; } if (ctl->cput == ctl->cget) { ctl->cput = ctl->cget = ctl->buf; ctl->cavail = 0; ctl->cleft = FTPLIB_BUFSIZ; } if (eof) { if (retval == 0) retval = -1; break; } if (!socket_wait(ctl)) return retval; if ((x = net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1) { perror("read"); retval = -1; break; } if (x == 0) eof = 1; ctl->cleft -= x; ctl->cavail += x; ctl->cput += x; } while (1); return retval;}/* * write lines of text * * return -1 on error or bytecount */static int writeline(char *buf, int len, netbuf *nData){ int x, nb=0, w; char *ubp = buf, *nbp; char lc=0; if (nData->dir != FTPLIB_WRITE) return -1; nbp = nData->buf; for (x=0; x < len; x++) { if ((*ubp == '\n') && (lc != '\r')) { if (nb == FTPLIB_BUFSIZ) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ); if (w != FTPLIB_BUFSIZ) { printf("net_write(1) returned %d, errno = %d\n", w, errno); return(-1); } nb = 0; } nbp[nb++] = '\r'; } if (nb == FTPLIB_BUFSIZ) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ); if (w != FTPLIB_BUFSIZ) { printf("net_write(2) returned %d, errno = %d\n", w, errno); return(-1); } nb = 0; } nbp[nb++] = lc = *ubp++; } if (nb) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, nb); if (w != nb) { printf("net_write(3) returned %d, errno = %d\n", w, errno); return(-1); } } return len;}/* * read a response from the server * * return 0 if first char doesn't match * return 1 if first char matches */static int readresp(char c, netbuf *nControl){ char match[5]; if (readline(nControl->response,256,nControl) == -1) { perror("Control socket read failed"); return 0; } if (ftplib_debug > 1) fprintf(stderr,"%s",nControl->response); if (nControl->response[3] == '-') { strncpy(match,nControl->response,3); match[3] = ' '; match[4] = '\0'; do { if (readline(nControl->response,256,nControl) == -1) { perror("Control socket read failed"); return 0; } if (ftplib_debug > 1) fprintf(stderr,"%s",nControl->response); } while (strncmp(nControl->response,match,4)); } if (nControl->response[0] == c) return 1; return 0;}/* * FtpInit for stupid operating systems that require it (Windows NT) */GLOBALDEF void FtpInit(void){#if defined(_WIN32) WORD wVersionRequested; WSADATA wsadata; int err; wVersionRequested = MAKEWORD(1,1); if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0) fprintf(stderr,"Network failed to start: %d\n",err);#endif}/* * FtpLastResponse - return a pointer to the last response received */GLOBALDEF char *FtpLastResponse(netbuf *nControl){ if ((nControl) && (nControl->dir == FTPLIB_CONTROL)) return nControl->response; return NULL;}/* * FtpConnect - connect to remote server * * return 1 if connected, 0 if not */GLOBALDEF int FtpConnect(const char *host, netbuf **nControl){ int sControl; struct sockaddr_in sin; struct hostent *phe; struct servent *pse; int on=1; netbuf *ctrl; char *lhost; char *pnum; memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; lhost = strdup(host); pnum = strchr(lhost,':'); if (pnum == NULL) {#if defined(VMS) sin.sin_port = htons(21);#else if ((pse = getservbyname("ftp","tcp")) == NULL) { perror("getservbyname"); return 0; } sin.sin_port = pse->s_port;#endif } else { *pnum++ = '\0'; if (isdigit(*pnum)) sin.sin_port = htons(atoi(pnum)); else { pse = getservbyname(pnum,"tcp"); sin.sin_port = pse->s_port; } } if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1) { if ((phe = gethostbyname(lhost)) == NULL) { perror("gethostbyname"); return 0; } memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); } free(lhost); sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);//////////////////////////////////// if (sControl == -1) { perror("socket"); return 0; } if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) { perror("setsockopt"); net_close(sControl); return 0; } if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1) { perror("connect"); net_close(sControl); return 0; } ctrl = calloc(1,sizeof(netbuf)); if (ctrl == NULL) { perror("calloc"); net_close(sControl); return 0; } ctrl->buf = malloc(FTPLIB_BUFSIZ); if (ctrl->buf == NULL) { perror("calloc"); net_close(sControl); free(ctrl); return 0; } ctrl->handle = sControl; ctrl->dir = FTPLIB_CONTROL; ctrl->ctrl = NULL; ctrl->cmode = FTPLIB_DEFMODE; ctrl->idlecb = NULL; ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0; ctrl->idlearg = NULL; ctrl->xfered = 0; ctrl->xfered1 = 0; ctrl->cbbytes = 0; if (readresp('2', ctrl) == 0) { net_close(sControl); free(ctrl->buf); free(ctrl); return 0; } *nControl = ctrl; return 1;}/* * FtpOptions - change connection options * * returns 1 if successful, 0 on error */GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl){ int v,rv=0; switch (opt) { case FTPLIB_CONNMODE: v = (int) val; if ((v == FTPLIB_PASSIVE) || (v == FTPLIB_PORT)) { nControl->cmode = v; rv = 1; } break; case FTPLIB_CALLBACK: nControl->idlecb = (FtpCallback) val; rv = 1; break; case FTPLIB_IDLETIME: v = (int) val; rv = 1; nControl->idletime.tv_sec = v / 1000; nControl->idletime.tv_usec = (v % 1000) * 1000; break; case FTPLIB_CALLBACKARG: rv = 1; nControl->idlearg = (void *) val; break; case FTPLIB_CALLBACKBYTES: rv = 1; nControl->cbbytes = (int) val; break; } return rv;}/* * FtpSendCmd - send a command and wait for expected response * * return 1 if proper response received, 0 otherwise */static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl){ char buf[256]; if (nControl->dir != FTPLIB_CONTROL) return 0; if (ftplib_debug > 2) fprintf(stderr,"%s\n",cmd); if ((strlen(cmd) + 3) > sizeof(buf)) return 0; sprintf(buf,"%s\r\n",cmd); if (net_write(nControl->handle,buf,strlen(buf)) <= 0) { perror("write"); return 0; } return readresp(expresp, nControl);}/* * FtpLogin - log in to remote server * * return 1 if logged in, 0 otherwise */GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl){ char tempbuf[64]; if (((strlen(user) + 7) > sizeof(tempbuf)) || ((strlen(pass) + 7) > sizeof(tempbuf))) return 0; sprintf(tempbuf,"USER %s",user); if (!FtpSendCmd(tempbuf,'3',nControl)) { if (nControl->response[0] == '2') return 1; return 0; } sprintf(tempbuf,"PASS %s",pass); return FtpSendCmd(tempbuf,'2',nControl);}/* * FtpOpenPort - set up data connection * * return 1 if successful, 0 otherwise */static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir){ int sData; union { struct sockaddr sa; struct sockaddr_in in; } sin; struct linger lng = { 0, 0 }; unsigned int l; int on=1; netbuf *ctrl; char *cp; unsigned int v[6]; char buf[256]; if (nControl->dir != FTPLIB_CONTROL) return -1; if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE)) { sprintf(nControl->response, "Invalid direction %d\n", dir); return -1; } if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE)) { sprintf(nControl->response, "Invalid mode %c\n", mode); return -1; } l = sizeof(sin); if (nControl->cmode == FTPLIB_PASSIVE) { memset(&sin, 0, l); sin.in.sin_family = AF_INET; if (!FtpSendCmd("PASV",'2',nControl)) return -1; cp = strchr(nControl->response,'('); if (cp == NULL) return -1; cp++; sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]); sin.sa.sa_data[2] = v[2]; sin.sa.sa_data[3] = v[3]; sin.sa.sa_data[4] = v[4]; sin.sa.sa_data[5] = v[5]; sin.sa.sa_data[0] = v[0]; sin.sa.sa_data[1] = v[1]; } else { if (getsockname(nControl->handle, &sin.sa, &l) < 0) { perror("getsockname"); return 0; } }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -