⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rcmd.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* rcmd.c
 *
 * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
 * All rights reserved.
 *
 */

#include "syshdrs.h"

#if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT))
#	define NO_SIGNALS 1
#endif

#ifndef NO_SIGNALS

#ifdef HAVE_SIGSETJMP
static sigjmp_buf gBrokenCtrlJmp;
#else
static jmp_buf gBrokenCtrlJmp;
#endif	/* HAVE_SIGSETJMP */

static void
BrokenCtrl(int UNUSED(signumIgnored))
{
	LIBNCFTP_USE_VAR(signumIgnored); 		/* Shut up gcc */
#ifdef HAVE_SIGSETJMP
	siglongjmp(gBrokenCtrlJmp, 1);
#else
	longjmp(gBrokenCtrlJmp, 1);
#endif	/* HAVE_SIGSETJMP */
}	/* BrokenCtrl */

#endif	/* NO_SIGNALS */


/* A 'Response' parameter block is simply zeroed to be considered init'ed. */
ResponsePtr
InitResponse(void)
{
	ResponsePtr rp;

	rp = (ResponsePtr) calloc(SZ(1), sizeof(Response));
	if (rp != NULL)
		InitLineList(&rp->msg);
	return (rp);
}	/* InitResponse */




/* If we don't print it to the screen, we may want to save it to our
 * trace log.
 */
void
TraceResponse(const FTPCIPtr cip, ResponsePtr rp)
{
	LinePtr lp;

	if (rp != NULL)	{
		lp = rp->msg.first;
		if (lp != NULL) {
			PrintF(cip, "%3d: %s\n", rp->code, lp->line);
			for (lp = lp->next; lp != NULL; lp = lp->next)
				PrintF(cip, "     %s\n", lp->line);
		}
	}
}	/* TraceResponse */





void
PrintResponse(const FTPCIPtr cip, LineListPtr llp)
{
	LinePtr lp;

	if (llp != NULL) {
		for (lp = llp->first; lp != NULL; lp = lp->next)
			PrintF(cip, "%s\n", lp->line);
	}
}	/* PrintResponse */





static void
SaveLastResponse(const FTPCIPtr cip, ResponsePtr rp)
{
	if (rp == NULL) {
		cip->lastFTPCmdResultStr[0] = '\0';
		cip->lastFTPCmdResultNum = -1;
		DisposeLineListContents(&cip->lastFTPCmdResultLL);
	} else if ((rp->msg.first == NULL) || (rp->msg.first->line == NULL)) {
		cip->lastFTPCmdResultStr[0] = '\0';
		cip->lastFTPCmdResultNum = rp->code;
		DisposeLineListContents(&cip->lastFTPCmdResultLL);
	} else {
		(void) STRNCPY(cip->lastFTPCmdResultStr, rp->msg.first->line);
		cip->lastFTPCmdResultNum = rp->code;

		/* Dispose previous command's line list. */
		DisposeLineListContents(&cip->lastFTPCmdResultLL);

		/* Save this command's line list. */
		cip->lastFTPCmdResultLL = rp->msg;
	}
}	/* SaveLastResponse */



void
DoneWithResponse(const FTPCIPtr cip, ResponsePtr rp)
{
	/* Dispose space taken up by the Response, and clear it out
	 * again.  For some reason, I like to return memory to zeroed
	 * when not in use.
	 */
	if (rp != NULL) {
		TraceResponse(cip, rp);
		if (cip->printResponseProc != 0) {
			if ((rp->printMode & kResponseNoProc) == 0)
				(*cip->printResponseProc)(cip, rp);
		}
		if ((rp->printMode & kResponseNoSave) == 0)
			SaveLastResponse(cip, rp);
		else
			DisposeLineListContents(&rp->msg);
		(void) memset(rp, 0, sizeof(Response));
		free(rp);
	}
}	/* DoneWithResponse */




/* This takes an existing Response and recycles it, by clearing out
 * the current contents.
 */
void
ReInitResponse(const FTPCIPtr cip, ResponsePtr rp)
{
	if (rp != NULL) {
		TraceResponse(cip, rp);
		if (cip->printResponseProc != 0) {
			if ((rp->printMode & kResponseNoProc) == 0)
				(*cip->printResponseProc)(cip, rp);
		}
		if ((rp->printMode & kResponseNoSave) == 0)
			SaveLastResponse(cip, rp);
		else
			DisposeLineListContents(&rp->msg);
		(void) memset(rp, 0, sizeof(Response));
	}
}	/* ReInitResponse */




#ifndef NO_SIGNALS

/* Since the control stream is defined by the Telnet protocol (RFC 854),
 * we follow Telnet rules when reading the control stream.  We use this
 * routine when we want to read a response from the host.
 */
int
GetTelnetString(const FTPCIPtr cip, char *str, size_t siz, FILE *cin, FILE *cout)
{
	int c;
	size_t n;
	int eofError;
	char *cp;

	cp = str;
	--siz;		/* We'll need room for the \0. */

	if ((cin == NULL) || (cout == NULL)) {
		eofError = -1;
		goto done;
	}

	for (n = (size_t)0, eofError = 0; ; ) {
		c = fgetc(cin);
checkChar:
		if (c == EOF) {
eof:
			eofError = -1;
			break;
		} else if (c == '\r') {
			/* A telnet string can have a CR by itself.  But to denote that,
			 * the protocol uses \r\0;  an end of line is denoted \r\n.
			 */
			c = fgetc(cin);
			if (c == '\n') {
				/* Had \r\n, so done. */
				goto done;
			} else if (c == EOF) {
				goto eof;
			} else if (c == '\0') {
				c = '\r';
				goto addChar;
			} else {
				/* Telnet protocol violation! */
				goto checkChar;
			}
		} else if (c == '\n') {
			/* Really shouldn't get here.  If we do, the other side
			 * violated the TELNET protocol, since eoln's are CR/LF,
			 * and not just LF.
			 */
			PrintF(cip, "TELNET protocol violation:  raw LF.\n");
			goto done;
		} else if (c == IAC) {
			/* Since the control connection uses the TELNET protocol,
			 * we have to handle some of its commands ourselves.
			 * IAC is the protocol's escape character, meaning that
			 * the next character after the IAC (Interpret as Command)
			 * character is a telnet command.  But, if there just
			 * happened to be a character in the text stream with the
			 * same numerical value of IAC, 255, the sender denotes
			 * that by having an IAC followed by another IAC.
			 */

			/* Get the telnet command. */
			c = fgetc(cin);

			switch (c) {
				case WILL:
				case WONT:
					/* Get the option code. */
					c = fgetc(cin);

					/* Tell the other side that we don't want
					 * to do what they're offering to do.
					 */
					(void) fprintf(cout, "%c%c%c",IAC,DONT,c);
					(void) fflush(cout);
					break;
				case DO:
				case DONT:
					/* Get the option code. */
					c = fgetc(cin);

					/* The other side said they are DOing (or not)
					 * something, which would happen if our side
					 * asked them to.  Since we didn't do that,
					 * ask them to not do this option.
					 */
					(void) fprintf(cout, "%c%c%c",IAC,WONT,c);
					(void) fflush(cout);
					break;

				case EOF:
					goto eof;

				default:
					/* Just add this character, since it was most likely
					 * just an escaped IAC character.
					 */
					goto addChar;
			}
		} else {
addChar:
			/* If the buffer supplied has room, add this character to it. */
			if (n < siz) {
				*cp++ = c;
				++n;
			}
		}
	}

done:
	*cp = '\0';
	return (eofError);
}	/* GetTelnetString */

#endif	/* NO_SIGNALS */



/* Returns 0 if a response was read, or (-1) if an error occurs.
 * This reads the entire response text into a LineList, which is kept
 * in the 'Response' structure.
 */
int
GetResponse(const FTPCIPtr cip, ResponsePtr rp)
{
	longstring str;
	int eofError;
	str16 code;
	char *cp;
	int continuation;
	volatile FTPCIPtr vcip;
#ifdef NO_SIGNALS
	int result;
#else	/* NO_SIGNALS */
	volatile FTPSigProc osigpipe;
	int sj;
#endif	/* NO_SIGNALS */

	/* RFC 959 states that a reply may span multiple lines.  A single
	 * line message would have the 3-digit code <space> then the msg.
	 * A multi-line message would have the code <dash> and the first
	 * line of the msg, then additional lines, until the last line,
	 * which has the code <space> and last line of the msg.
	 *
	 * For example:
	 *	123-First line
	 *	Second line
	 *	234 A line beginning with numbers
	 *	123 The last line
	 */

#ifdef NO_SIGNALS
	vcip = cip;
#else	/* NO_SIGNALS */
	osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl);
	vcip = cip;

#ifdef HAVE_SIGSETJMP
	sj = sigsetjmp(gBrokenCtrlJmp, 1);
#else
	sj = setjmp(gBrokenCtrlJmp);
#endif	/* HAVE_SIGSETJMP */

	if (sj != 0) {
		(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
		FTPShutdownHost(vcip);
		vcip->errNo = kErrRemoteHostClosedConnection;
		return(vcip->errNo);
	}
#endif	/* NO_SIGNALS */

#ifdef NO_SIGNALS
	cp = str;
	eofError = 0;
	if (cip->dataTimedOut > 0) {
		/* Give up immediately unless the server had already
		 * sent a message. Odds are since the data is timed
		 * out, so is the control.
		 */
		if (SWaitUntilReadyForReading(cip->ctrlSocketR, 0) == 0) {
			/* timeout */
			Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
			FTPShutdownHost(vcip);
			cip->errNo = kErrControlTimedOut;
			return (cip->errNo);
		}
	}
	result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1);
	if (result == kTimeoutErr) {
		/* timeout */
		Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
		FTPShutdownHost(vcip);
		cip->errNo = kErrControlTimedOut;
		return (cip->errNo);
	} else if (result == 0) {
		/* eof */
		eofError = 1;
		rp->hadEof = 1;
		if (rp->eofOkay == 0)
			Error(cip, kDontPerror, "Remote host has closed the connection.\n");
		FTPShutdownHost(vcip);
		cip->errNo = kErrRemoteHostClosedConnection;
		return (cip->errNo);
	} else if (result < 0) {
		/* error */
		Error(cip, kDoPerror, "Could not read reply from control connection");
		FTPShutdownHost(vcip);
		cip->errNo = kErrInvalidReplyFromServer;
		return (cip->errNo);
	}

	if (str[result - 1] == '\n')
		str[result - 1] = '\0';

#else	/* NO_SIGNALS */
	/* Get the first line of the response. */
	eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout);

	cp = str;
	if (*cp == '\0') {
		if (eofError < 0) {
			/* No bytes read for reply, and EOF detected. */
			rp->hadEof = 1;
			if (rp->eofOkay == 0)
				Error(cip, kDontPerror, "Remote host has closed the connection.\n");
			FTPShutdownHost(vcip);
			cip->errNo = kErrRemoteHostClosedConnection;
			(void) signal(SIGPIPE, osigpipe);
			return(cip->errNo);
		}
	}
#endif	/* NO_SIGNALS */

	if (!isdigit((int) *cp)) {
		Error(cip, kDontPerror, "Invalid reply: \"%s\"\n", cp);
		cip->errNo = kErrInvalidReplyFromServer;
#ifndef NO_SIGNALS
		(void) signal(SIGPIPE, osigpipe);
#endif
		return (cip->errNo);
	}

	rp->codeType = *cp - '0';
	cp += 3;
	continuation = (*cp == '-');
	*cp++ = '\0';
	(void) STRNCPY(code, str);
	rp->code = atoi(code);
	(void) AddLine(&rp->msg, cp);
	if (eofError < 0) {
		/* Read reply, but EOF was there also. */
		rp->hadEof = 1;
	}

	while (continuation) {

#ifdef NO_SIGNALS
		result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1);
		if (result == kTimeoutErr) {
			/* timeout */
			Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n");
			FTPShutdownHost(vcip);
			cip->errNo = kErrControlTimedOut;
			return (cip->errNo);
		} else if (result == 0) {
			/* eof */
			eofError = 1;
			rp->hadEof = 1;
			if (rp->eofOkay == 0)
				Error(cip, kDontPerror, "Remote host has closed the connection.\n");
			FTPShutdownHost(vcip);
			cip->errNo = kErrRemoteHostClosedConnection;
			return (cip->errNo);
		} else if (result < 0) {
			/* error */
			Error(cip, kDoPerror, "Could not read reply from control connection");
			FTPShutdownHost(vcip);
			cip->errNo = kErrInvalidReplyFromServer;
			return (cip->errNo);
		}

		if (str[result - 1] == '\n')
			str[result - 1] = '\0';
#else	/* NO_SIGNALS */
		eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout);
		if (eofError < 0) {
			/* Read reply, but EOF was there also. */
			rp->hadEof = 1;
			continuation = 0;
		}
#endif	/* NO_SIGNALS */
		cp = str;
		if (strncmp(code, cp, SZ(3)) == 0) {
			cp += 3;
			if (*cp == ' ')
				continuation = 0;
			++cp;
		}
		(void) AddLine(&rp->msg, cp);
	}

	if (rp->code == 421) {
		/*
		 *   421 Service not available, closing control connection.
		 *       This may be a reply to any command if the service knows it
		 *       must shut down.
		 */
		if (rp->eofOkay == 0)
			Error(cip, kDontPerror, "Remote host has closed the connection.\n");
		FTPShutdownHost(vcip);
		cip->errNo = kErrRemoteHostClosedConnection;
#ifndef NO_SIGNALS
		(void) signal(SIGPIPE, osigpipe);
#endif
		return(cip->errNo);
	}

#ifndef NO_SIGNALS
	(void) signal(SIGPIPE, osigpipe);
#endif
	return (kNoErr);
}	/* GetResponse */




/* This creates the complete command text to send, and writes it
 * on the stream.
 */
#ifdef NO_SIGNALS

static int
SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
{
	longstring command;
	int result;

	if (cip->ctrlSocketW != kClosedFileDescriptor) {
#ifdef HAVE_VSNPRINTF
		(void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap);
		command[sizeof(command) - 1] = '\0';
#else
		(void) vsprintf(command, cmdspec, ap);
#endif
		if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse)))
			PrintF(cip, "Cmd: %s\n", command);
		else
			PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx");
		(void) STRNCAT(command, "\r\n");	/* Use TELNET end-of-line. */
		cip->lastFTPCmdResultStr[0] = '\0';
		cip->lastFTPCmdResultNum = -1;

		result = SWrite(cip->ctrlSocketW, command, strlen(command), (int) cip->ctrlTimeout, 0);

		if (result < 0) {
			cip->errNo = kErrSocketWriteFailed;
			Error(cip, kDoPerror, "Could not write to control stream.\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -