📄 open.c
字号:
{
ResponsePtr rp;
int result;
LinePtr lp;
char *cp, *p;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (cip->serverType == kServerTypeNetWareFTP) {
/* NetWare 5.00 server freaks out when
* you give it a command it doesn't
* recognize, so cheat here and return.
*/
cip->hasPASV = kCommandAvailable;
cip->hasSIZE = kCommandNotAvailable;
cip->hasMDTM = kCommandNotAvailable;
cip->hasREST = kCommandNotAvailable;
cip->NLSTfileParamWorks = kCommandAvailable;
cip->hasUTIME = kCommandNotAvailable;
cip->hasCLNT = kCommandNotAvailable;
cip->hasMLST = kCommandNotAvailable;
cip->hasMLSD = kCommandNotAvailable;
return (kNoErr);
}
rp = InitResponse();
if (rp == NULL) {
cip->errNo = kErrMallocFailed;
result = cip->errNo;
} else {
rp->printMode = (kResponseNoPrint|kResponseNoSave);
result = RCmd(cip, rp, "FEAT");
if (result < kNoErr) {
DoneWithResponse(cip, rp);
return (result);
} else if (result != 2) {
/* We cheat here and pre-populate some
* fields when the server is wu-ftpd.
* This server is very common and we
* know it has always had these.
*/
if (cip->serverType == kServerTypeWuFTPd) {
cip->hasPASV = kCommandAvailable;
cip->hasSIZE = kCommandAvailable;
cip->hasMDTM = kCommandAvailable;
cip->hasREST = kCommandAvailable;
cip->NLSTfileParamWorks = kCommandAvailable;
} else if (cip->serverType == kServerTypeNcFTPd) {
cip->hasPASV = kCommandAvailable;
cip->hasSIZE = kCommandAvailable;
cip->hasMDTM = kCommandAvailable;
cip->hasREST = kCommandAvailable;
cip->NLSTfileParamWorks = kCommandAvailable;
}
/* Newer commands are only shown in FEAT,
* so we don't have to do the "try it,
* then save that it didn't work" thing.
*/
cip->hasMLST = kCommandNotAvailable;
cip->hasMLSD = kCommandNotAvailable;
} else {
cip->hasFEAT = kCommandAvailable;
for (lp = rp->msg.first; lp != NULL; lp = lp->next) {
/* If first character was not a space it is
* either:
*
* (a) The header line in the response;
* (b) The trailer line in the response;
* (c) A protocol violation.
*/
cp = lp->line;
if (*cp++ != ' ')
continue;
if (ISTRNCMP(cp, "PASV", 4) == 0) {
cip->hasPASV = kCommandAvailable;
} else if (ISTRNCMP(cp, "SIZE", 4) == 0) {
cip->hasSIZE = kCommandAvailable;
} else if (ISTRNCMP(cp, "MDTM", 4) == 0) {
cip->hasMDTM = kCommandAvailable;
} else if (ISTRNCMP(cp, "REST", 4) == 0) {
cip->hasREST = kCommandAvailable;
} else if (ISTRNCMP(cp, "UTIME", 5) == 0) {
cip->hasUTIME = kCommandAvailable;
} else if (ISTRNCMP(cp, "MLST", 4) == 0) {
cip->hasMLST = kCommandAvailable;
cip->hasMLSD = kCommandAvailable;
FTPExamineMlstFeatures(cip, cp + 5);
} else if (ISTRNCMP(cp, "CLNT", 4) == 0) {
cip->hasCLNT = kCommandAvailable;
} else if (ISTRNCMP(cp, "Compliance Level: ", 18) == 0) {
/* Probably only NcFTPd will ever implement this.
* But we use it internally to differentiate
* between different NcFTPd implementations of
* IETF extensions.
*/
cip->ietfCompatLevel = atoi(cp + 18);
}
}
}
ReInitResponse(cip, rp);
result = RCmd(cip, rp, "HELP SITE");
if (result == 2) {
for (lp = rp->msg.first; lp != NULL; lp = lp->next) {
cp = lp->line;
if (strstr(cp, "RETRBUFSIZE") != NULL)
cip->hasRETRBUFSIZE = kCommandAvailable;
if (strstr(cp, "RBUFSZ") != NULL)
cip->hasRBUFSZ = kCommandAvailable;
/* See if RBUFSIZ matches (but not STORBUFSIZE) */
if (
((p = strstr(cp, "RBUFSIZ")) != NULL) &&
(
(p == cp) ||
((p > cp) && (!isupper(p[-1])))
)
)
cip->hasRBUFSIZ = kCommandAvailable;
if (strstr(cp, "STORBUFSIZE") != NULL)
cip->hasSTORBUFSIZE = kCommandAvailable;
if (strstr(cp, "SBUFSIZ") != NULL)
cip->hasSBUFSIZ = kCommandAvailable;
if (strstr(cp, "SBUFSZ") != NULL)
cip->hasSBUFSZ = kCommandAvailable;
if (strstr(cp, "BUFSIZE") != NULL)
cip->hasBUFSIZE = kCommandAvailable;
}
}
DoneWithResponse(cip, rp);
}
return (kNoErr);
} /* FTPQueryFeatures */
int
FTPCloseHost(const FTPCIPtr cip)
{
ResponsePtr rp;
int result;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
/* Data connection shouldn't be open normally. */
if (cip->dataSocket != kClosedFileDescriptor)
FTPAbortDataTransfer(cip);
result = kNoErr;
if (cip->connected != 0) {
rp = InitResponse();
if (rp == NULL) {
cip->errNo = kErrMallocFailed;
result = cip->errNo;
} else {
rp->eofOkay = 1; /* We are expecting EOF after this cmd. */
cip->eofOkay = 1;
(void) RCmd(cip, rp, "QUIT");
DoneWithResponse(cip, rp);
}
}
CloseControlConnection(cip);
/* Dispose dynamic data structures, so you won't leak
* if you OpenHost with this again.
*/
FTPDeallocateHost(cip);
return (result);
} /* FTPCloseHost */
void
FTPShutdownHost(const FTPCIPtr cip)
{
#ifdef SIGPIPE
FTPSigProc osigpipe;
#endif
if (cip == NULL)
return;
if (strcmp(cip->magic, kLibraryMagic))
return;
#ifdef SIGPIPE
osigpipe = signal(SIGPIPE, (FTPSigProc) SIG_IGN);
#endif
/* Linger could cause close to block, so unset it. */
if (cip->dataSocket != kClosedFileDescriptor)
(void) SetLinger(cip, cip->dataSocket, 0);
CloseDataConnection(cip); /* Shouldn't be open normally. */
/* Linger should already be turned off for this. */
CloseControlConnection(cip);
FTPDeallocateHost(cip);
#ifdef SIGPIPE
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif
} /* FTPShutdownHost */
void
URLCopyToken(char *dst, size_t dsize, const char *src, size_t howmuch)
{
char *dlim;
const char *slim;
unsigned int hc;
int c;
char h[4];
dlim = dst + dsize - 1; /* leave room for \0 */
slim = src + howmuch;
while (src < slim) {
c = *src++;
if (c == '\0')
break;
if (c == '%') {
/* hex representation */
if (src < slim + 2) {
h[0] = *src++;
h[1] = *src++;
h[2] = '\0';
hc = 0xeeff;
if ((sscanf(h, "%x", &hc) >= 0) && (hc != 0xeeff)) {
if (dst < dlim) {
*(unsigned char *)dst = (unsigned char) hc;
dst++;
}
}
} else {
break;
}
} else {
*dst++ = (char) c;
}
}
*dst = '\0';
} /* URLCopyToken */
int
FTPDecodeURL(
const FTPCIPtr cip, /* area pointed to may be modified */
char *const url, /* always modified */
LineListPtr cdlist, /* always modified */
char *const fn, /* always modified */
const size_t fnsize,
int *const xtype, /* optional; may be modified */
int *const wantnlst /* optional; always modified */
)
{
char *cp;
char *hstart, *hend;
char *h2start;
char *at1;
char portstr[32];
int port;
int sc;
char *lastslash;
char *parsestr;
char *tok;
char subdir[128];
char *semi;
InitLineList(cdlist);
*fn = '\0';
if (wantnlst != NULL)
*wantnlst = 0;
if (xtype != NULL)
*xtype = kTypeBinary;
cp = NULL; /* shut up warnings */
#ifdef HAVE_STRCASECMP
if (strncasecmp(url, "<URL:ftp://", 11) == 0) {
cp = url + strlen(url) - 1;
if (*cp != '>')
return (kMalformedURL); /* missing closing > */
*cp = '\0';
cp = url + 11;
} else if (strncasecmp(url, "ftp://", 6) == 0) {
cp = url + 6;
} else {
return (-1); /* not a RFC 1738 URL */
}
#else /* HAVE_STRCASECMP */
if (strncmp(url, "<URL:ftp://", 11) == 0) {
cp = url + strlen(url) - 1;
if (*cp != '>')
return (kMalformedURL); /* missing closing > */
*cp = '\0';
cp = url + 11;
} else if (strncmp(url, "ftp://", 6) == 0) {
cp = url + 6;
} else {
return (-1); /* not a RFC 1738 URL */
}
#endif /* HAVE_STRCASECMP */
/* //<user>:<password>@<host>:<port>/<url-path> */
at1 = NULL;
for (hstart = cp; ; cp++) {
if (*cp == '@') {
if (at1 == NULL)
at1 = cp;
else
return (kMalformedURL);
} else if ((*cp == '\0') || (*cp == '/')) {
hend = cp;
break;
}
}
sc = *hend;
*hend = '\0';
if (at1 == NULL) {
/* no user or password */
h2start = hstart;
} else {
*at1 = '\0';
cp = strchr(hstart, ':');
if (cp == NULL) {
/* whole thing is the user name then */
URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (at1 - hstart));
} else if (strchr(cp + 1, ':') != NULL) {
/* Too many colons */
return (kMalformedURL);
} else {
URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (cp - hstart));
URLCopyToken(cip->pass, sizeof(cip->pass), cp + 1, (size_t) (at1 - (cp + 1)));
}
*at1 = '@';
h2start = at1 + 1;
}
cp = strchr(h2start, ':');
if (cp == NULL) {
/* whole thing is the host then */
URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (hend - h2start));
} else if (strchr(cp + 1, ':') != NULL) {
/* Too many colons */
return (kMalformedURL);
} else {
URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (cp - h2start));
URLCopyToken(portstr, sizeof(portstr), cp + 1, (size_t) (hend - (cp + 1)));
port = atoi(portstr);
if (port > 0)
cip->port = port;
}
*hend = (char) sc;
if ((*hend == '\0') || ((*hend == '/') && (hend[1] == '\0'))) {
/* no path, okay */
return (0);
}
lastslash = strrchr(hend, '/');
if (lastslash == NULL) {
/* no path, okay */
return (0);
}
*lastslash = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -