pgpprsasc.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,441 行 · 第 1/5 页

C
2,441
字号
		/*
		 * This is the "start" position.  Check if we are
		 * buffering and flush buffers if we are not.  Then go
		 * to the next state.
		 */

		if (!ctx->buffering) {
			*error = flushBuffers (ctx);
			if (*error)
				break;
		}

		ctx->state++;
		/* FALLTHROUGH */
	case 1:
case_1:
		/* call readline until we have EOB or EOL */

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		if (ctx->eol || ctx->eob)
			ctx->state++;
		else
			break;

		/* FALLTHROUGH */
	case 2:
		/*
		 * check the line for BEGIN.  If it is not a begin
		 * then we should output this line. If it is a begin,
		 * then we need to parse it as an armor beginning.
		 * Use the special "bracketcmp" routine which ignores material in
		 * angle brackets "<>" as some mailers may stick those in front of
		 * our message to turn off some rich text features.
		 */

		if (ctx->armorlen > sizeof (prefix1) - 1 &&
			0==bracketcmp (ctx->armorline, ctx->armorlen,
						   prefix1, sizeof (prefix1) - 1, &bracketlen)) {
			ctx->state = 9;
			goto case_9;
		}

		/*
		 * check the line to see if it is the beginning of a
		 * PGP binary message.  This check is only done the
		 * first time through this loop, using ctx->annotation
		 * as the loop detector.  If this is a PGP message,
		 * then treat it as such and buffer the data for
		 * processing through a parser.
		 */

		if (! ctx->annotation) {
			if (pgpFileTypePGP (ctx->armorline, ctx->armorlen))
			{
				/*
				 * ooh, a binary PGP message fed into the
				 * ascii armor parser!
				 */
				ctx->state = 50;
				goto case_50;
			}
		}

#if MIMEPARSE
		/*
		 * Look for either the MIME content-type message, or what looks
		 * like a MIME message boundary (in case we don't have headers).
		 */
		if (ctx->armorlen > sizeof (prefix_mime1) &&
			!strncasecmp (ctx->armorline, prefix_mime1,
						  sizeof (prefix_mime1) - 1)) {
			/* MIME header */
			ctx->state = 60;
			goto case_60;
		}

		/*
		 * If no_mime_headers, we have only a body, so assume that a line
		 * starting with -- is a pgp/mime signed part.  This is not a very
		 * good assumption in general, so we will assume that we had some
		 * reason to think so.
		 */
		if (ctx->no_mime_headers && ctx->eol &&
			ctx->armorlen > 2 && !memcmp (ctx->armorline, "--", 2) &&
			ctx->eol) {
			/* Potential MIME initial body indicator */
			ctx->state = 70;
			goto case_70;
		}
#endif

		ctx->state++;
		/* FALLTHROUGH */
	case 3:
case_3:
		/* send annotation if we need to */
		if (! ctx->annotation) {
			*error = sendAnnotate (ctx, myself,
					       PGPANN_NONPGP_BEGIN, NULL, 0);
			if (*error)
				break;
			ctx->annotation = PGPANN_NONPGP_END;
			ctx->depth_at_ann = ctx->scope_depth;
		}
		ctx->state++;
		/* FALLTHROUGH */
	case 4:
case_4:
		/* output armorline buffer */
		while (ctx->armorlen) {
			retval = writeExtraData (ctx, ctx->armorptr,
						 ctx->armorlen, error);
			ctx->armorptr += retval;
			ctx->armorlen -= retval;
			if (*error)
				return written;
		}
		ctx->armorptr = ctx->armorline;
		ctx->state++;
		/* FALLTHROUGH */
	case 5:
		/*
		 * if EOL == 1, clear state and goto state 1, otherwise
		 * read data and return to state 4 to output the line.
		 */
		if (ctx->eol == 1) {
			ctx->eol = 0;
			ctx->eob = 0;
			ctx->state = 1;
			goto case_1;
		}

		if (!size)
			break;

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		ctx->state = 4;
		goto case_4;

	case 9:
case_9:
		/*
		 * parse begin line.  If this is not a valid begin
		 * line, assume that it is not and output it as
		 * non-PGP text (in state 3).
		 * bracketlen holds extra characters to skip from our parsing
		 */
		ptr = ctx->armorline + sizeof (prefix1) - 1 + bracketlen;
		lineused = ctx->armorlen - (sizeof (prefix1) - 1) - bracketlen;
		bracketlen = 0;
		thispart = maxparts = 0;

		do {
			if (lineused == 0) {
				/* not a valid BEGIN line */
				ctx->state = 3;
				goto case_3;
			}

		} while (isspace (ptr[--lineused]));

		/* temporarily null-terminate this string */
		temp_c = ptr[++lineused];
		ptr[lineused] = '\0';

		if (!memcmp (ptr, signedmsg, sizeof (signedmsg))) {
			/* This is a clearsigned message */

			if (ctx->eol) {
				/*
				 * This looks like a clearsigned
				 * message. jump into the clearsigned
				 * parser and parse it.
				 */
				ctx->state = 30;
				goto case_30;
			}
			/*
			 * Someone is playing with us.. This is an
			 * error.
			 */
			goto err_case_9;
		}

		/* skip the "whatever" in "-----BEGIN PGP whatever" */
		while (isalnum (*ptr) || *ptr == ' ') {
			ptr++;
			lineused--;
		}

		/* check for multipart */
			if (*ptr == ',') {
			/* "-----BEGIN PGP whatever, PART x[/y]-----" */
			if (memcmp (ptr, prefix2, sizeof (prefix2) - 1))
				goto err_case_9;
			ptr += sizeof (prefix2) - 1;
			lineused -= sizeof (prefix2) - 1;

			thispart = strtoul ((char *)ptr, (char **)&num, 10);
			if (num == NULL || thispart < 0 || thispart > 999)
				goto err_case_9;

			lineused -= (num - ptr);
			ptr = num;

			/*
			 * now check for "/y", if it exists.  It is
			 * legal for it not to exist, but it must have
			 * either a 'y' here or a messageID.
			 */

			if (*ptr == '/') {
				maxparts = strtoul ((char *)ptr+1,
				(char **)&num, 10);
				if (!num || maxparts < 2 || maxparts > 999)
					goto err_case_9;
				lineused -= (num - ptr);
				ptr = num;
			}
		} else {
			thispart = maxparts = 1;
		}
		if (memcmp (ptr, suffix, sizeof (suffix)))
			goto err_case_9;
		ctx->thispart = thispart;
		ctx->maxparts = maxparts;
		ctx->state = 10;
		goto case_10;
		err_case_9:
		ptr[lineused] = temp_c;
		ctx->state = 3;
		goto case_3;

	case 10:
case_10:
		/* Send end-annotation (if we sent a begin annotation) */
		if (ctx->annotation) {
			pgpAssert (ctx->depth_at_ann == ctx->scope_depth);
			*error = sendAnnotate (ctx, myself, ctx->annotation,
					       NULL, 0);
			if (*error)
				break;
			ctx->annotation = 0;
		}
		ctx->firstheader = TRUE; /* Help us recognize doubleline mode */
		ctx->state++;
		/* FALLTHROUGH */
	case 11:
case_11:
	/* read until EOL to get to end of the last line */

		ctx->armorptr = ctx->armorline;
		ctx->armorlen = 0;
		while (ctx->eol != 1) {
			ctx->armorlen = 1;	/* Preserve 1st char for doublespace logic */
			retval = readLine (ctx, buf, size);
			written += retval;
			buf += retval;
			size -= retval;

			if (!size)
				return written;
		}
		ctx->eol = 0;
		ctx->eob = 0;
		ctx->armorlen = 0;
		ctx->state++;
		/* FALLTHROUGH */
	case 12:
		/* call readline until we have EOB or EOL */

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		if (ctx->eol || ctx->eob)
			ctx->state++;
		else
			break;

		/* FALLTHROUGH */
	case 13:
		/*
		 * If this line is blank, go to state 15. If it is
		 * not blank, process it as a header and then goto
		 * state 11.
		 * If it is blank and firstheader is true, go into doublespace mode
		 * and keep parsing.
		 */

		ptr = ctx->armorline;
		lineused = ctx->armorlen;

		/* Find trailing white space... */
		while (lineused && isspace (ptr[lineused - 1]))
			lineused--;

		if (ctx->firstheader) {
			ctx->firstheader = FALSE;
			if (lineused == 0) {
				/* First line is blank after ----BEGIN PGP, doublespace mode */
				ctx->doublespace = 1;
				ctx->state = 11;
				goto case_11;
			}
		}

		if (lineused) {
			int err;
			/* temporarily null-terminate this string */
			temp_c = ptr[lineused];
			ptr[lineused] = '\0';

			err = parseHeader (ctx, ptr, lineused);
			if (err) {
				*error = sendAnnotate (ctx, myself,
						       PGPANN_ARMOR_BADHEADER,
						       ctx->armorline,
						       lineused);
				ptr[lineused] = temp_c;
				if (*error)
					break;

				/* XXX: Ignore bad headers? */
			}

			ctx->state = 11;
			goto case_11;
		}
		/* this is an empty line; now go deal with Armorlines */

		ctx->state++;
		/* FALLTHROUGH */
	case 14:
		/* state 14 is obsolete */
		ctx->state++;
		/* FALLTHROUGH */
	case 15:
		/* get the message and part information */

		if (!ctx->part) {
		/* This is true for all normal armor messages */
			msg = getMessage (ctx, ctx->messageid, ctx->maxparts);
			if (!msg) {
				/* This is an error */
				*error = PGPERR_NOMEM;
				break;
			}
			part = getPart (ctx, msg, ctx->thispart);
			if (!part) {
				/* This is an error too */
				*error = PGPERR_NOMEM;
				break;
			}
			ctx->part = part;
		}
		ctx->expectcrc = 0;
		ctx->state++;
		/* FALLTHROUGH */
	case 16:
		/*
		 * Either try to make the message writable or send an
		 * annotation saying we have a message part.
		 */

		msg = ctx->part->msg;
		if (ctx->thispart == 1) {
			*error = writeMessage (ctx, msg);
			if (*error)
				break;
		} else {
			byte *b;

			b = (byte *)pgpAlloc(kPGPPrsAscCmdBufSize);
			if (b == NULL)
			{
				*error = PGPERR_NOMEM;
				break;
			}

			i = 0;
			memcpy (b, &ctx->thispart, sizeof (ctx->thispart));
			i += sizeof (ctx->thispart);

			memcpy (b+i, &ctx->maxparts, sizeof (ctx->maxparts));
			i += sizeof (ctx->maxparts);

			memcpy (b+i, ctx->messageid,
				strlen (ctx->messageid));
			i += strlen (ctx->messageid);

			*error = sendAnnotate (ctx, myself, PGPANN_ARMOR_PART,
					       b, i);
			pgpFree(b);
			if (*error)
				break;
		}
		ctx->state++;
		/* FALLTHROUGH */
	case 17:
case_17:
		/* read until EOL to get to end of the last line */

		ctx->armorptr = ctx->armorline;
		ctx->armorlen = 0;
		while (ctx->eol != 1) {
			ctx->armorlen = 1;	/* Preserve 1st char for doublespace logic */
			retval = readLine (ctx, buf, size);
			written += retval;
			buf += retval;
			size -= retval;

			if (!size)
				return written;
		}
		ctx->eol = 0;
		ctx->eob = 0;
		ctx->armorlen = 0;
		ctx->state++;
		/* FALLTHROUGH */
	case 18:
		/* call readline until we have EOB or EOL */

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		if (ctx->eol || ctx->eob)
			ctx->state++;
		else
			break;

		/* FALLTHROUGH */
	case 19:
		/*
		 * make sure this is not a CRC line. If it is a CRC
		 * then goto state 21. if it is not a CRC line, then
		 * it must be an armorline. So, process it as an
		 * armor line and then fallthrough to state 20 to
		 * output it.
		 */

		if (ctx->armorline[0] == '=') {
			/* This looks like a CRC */
			ctx->state = 21;
			goto case_21;
		}

		/* Make sure we're not expecting a CRC */
		if (ctx->expectcrc) {
			*error = sendAnnotate (ctx, myself, PGPANN_ARMOR_NOCRC,
					       ctx->armorline, ctx->armorlen);
			if (*error)
				break;

			/* Well, maybe this is an end? */
			ctx->state = 24;
			goto case_24;
		}

		/* find the end of the armorline */
		inlen = ctx->armorlen;
		while (inlen && isspace (ctx->armorline[inlen - 1]))
			inlen--;

		/* check the length of the armorline */
		if (inlen > 68) { /* 68 == 64 + 2*"=3D" extra space */
			*error = sendAnnotate (ctx, myself,
					       PGPANN_ARMOR_TOOLONG,
					       ctx->armorline, ctx->armorlen);
			if (*error)
				break;

			ctx->state = 26;
			goto case_26;
		}

		i = dearmorLine (ctx, inlen);
		if (i > 48 || i < 1) {

⌨️ 快捷键说明

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