Beispiel #1
0
static void mime_content_disposition(MIME_NODE *node,
	const HEADER_OPTS *header_info)
{
	const char *cp = STR(node->buffer) + strlen(header_info->name) + 1;
	ssize_t tok_count;

#define PARSE_CONTENT_DISPOSITION(state, ptr) \
	header_token(state->token, MIME_MAX_TOKEN, \
		state->token_buffer, ptr, RFC2045_TSPECIALS, ';')

	while ((tok_count = PARSE_CONTENT_DISPOSITION(node->state, &cp)) > 0) {
		if (tok_count < 3 || node->state->token[1].type != '=')
			continue;
		if (TOKEN_MATCH(node->state->token[0], "filename")
			&& node->header_filename == NULL)
		{
			node->header_filename =
				acl_mystrdup(node->state->token[2].u.value);
		} else if (TOKEN_MATCH(node->state->token[0], "name")
			&& node->header_name == NULL)
		{
			node->header_name =
				acl_mystrdup(node->state->token[2].u.value);
		}
	}
}
Beispiel #2
0
/*
 *	Read a word from a buffer and advance pointer.
 *	This function knows about escapes and quotes.
 *
 *	At end-of-line, buf[0] is set to '\0'.
 *	Returns 0 or special token value.
 */
static FR_TOKEN getthing(const char **ptr, char *buf, int buflen, int tok,
			 const FR_NAME_NUMBER *tokenlist)
{
	char *s;
	const char *p;
	int	quote, end = 0;
	unsigned int	x;
	const FR_NAME_NUMBER*t;
	FR_TOKEN rcode;

	buf[0] = 0;

	/* Skip whitespace */
	p = *ptr;
	while (*p && isspace((int) *p))
		p++;

	if (*p == 0) {
		*ptr = p;
		return T_EOL;
	}

	/*
	 *	Might be a 1 or 2 character token.
	 */
	if (tok) for (t = tokenlist; t->name; t++) {
		if (TOKEN_MATCH(p, t->name)) {
			strcpy(buf, t->name);
			p += strlen(t->name);
			while (isspace((int) *p))
				p++;
			*ptr = p;
			return (FR_TOKEN) t->number;
		}
	}

	/* Read word. */
	quote = 0;
	if ((*p == '"') ||
	    (*p == '\'') ||
	    (*p == '`')) {
		quote = *p;
		end = 0;
		p++;
	}
	s = buf;

	while (*p && buflen-- > 1) {
		if (quote && (*p == '\\')) {
			p++;

			switch(*p) {
				case 'r':
					*s++ = '\r';
					break;
				case 'n':
					*s++ = '\n';
					break;
				case 't':
					*s++ = '\t';
					break;
				case '\0':
					*s++ = '\\';
					p--; /* force EOS */
					break;
				default:
					if (*p >= '0' && *p <= '9' &&
					    sscanf(p, "%3o", &x) == 1) {
						*s++ = x;
						p += 2;
					} else
						*s++ = *p;
					break;
			}
			p++;
			continue;
		}
		if (quote && (*p == quote)) {
			end = 1;
			p++;
			break;
		}
		if (!quote) {
			if (isspace((int) *p))
				break;
			if (tok) {
				for (t = tokenlist; t->name; t++)
					if (TOKEN_MATCH(p, t->name))
						break;
				if (t->name != NULL)
					break;
			}
		}
		*s++ = *p++;
	}
	*s++ = 0;

	if (quote && !end) {
		fr_strerror_printf("Unterminated string");
		return T_OP_INVALID;
	}

	/* Skip whitespace again. */
	while (*p && isspace((int) *p))
		p++;
	*ptr = p;

	/* we got SOME form of output string, even if it is empty */
	switch (quote) {
	default:
	  rcode = T_BARE_WORD;
	  break;

	case '\'':
	  rcode = T_SINGLE_QUOTED_STRING;
	  break;

	case '"':
	  rcode = T_DOUBLE_QUOTED_STRING;
	  break;

	case '`':
	  rcode = T_BACK_QUOTED_STRING;
	  break;
	}

	return rcode;
}
Beispiel #3
0
static void mime_content_type(MIME_NODE *node, const HEADER_OPTS *header_info)
{
	const char *cp;
	ssize_t tok_count;
	MIME_STATE *state = node->state;

#define PARSE_CONTENT_TYPE_HEADER(state, ptr) \
	header_token(state->token, MIME_MAX_TOKEN, \
		state->token_buffer, ptr, RFC2045_TSPECIALS, ';')

	cp = STR(node->buffer) + strlen(header_info->name) + 1;
	if ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) <= 0) {

		/*
		* other/whatever.
		*/
		node->ctype = MIME_CTYPE_OTHER;
		return;
	}

	/* tok_count > 0 */

	/*
	* message/whatever body parts start with another block of message
	* headers that we may want to look at. The partial and external-body
	* subtypes cannot be subjected to 8-bit -> 7-bit conversion, so we
	* must properly recognize them.
	*/
	if (TOKEN_MATCH(state->token[0], "message")) {
		node->ctype = MIME_CTYPE_MESSAGE;
		node->stype = MIME_STYPE_OTHER;
		if (tok_count >= 3 && state->token[1].type == '/') {
			if (TOKEN_MATCH(state->token[2], "rfc822"))
				node->stype = MIME_STYPE_RFC822;
			else if (TOKEN_MATCH(state->token[2], "partial"))
				node->stype = MIME_STYPE_PARTIAL;
			else if (TOKEN_MATCH(state->token[2], "external-body"))
				node->stype = MIME_STYPE_EXTERN_BODY;
		}
	}

	/*
	* multipart/digest has default content type message/rfc822,
	* multipart/whatever has default content type text/plain.
	*/
	else if (TOKEN_MATCH(state->token[0], "multipart")) {
		node->ctype = MIME_CTYPE_MULTIPART;
		if (tok_count >= 3 && state->token[1].type == '/') {
			if (TOKEN_MATCH(state->token[2], "digest")) {
				node->ctype = MIME_CTYPE_MESSAGE;
				node->stype = MIME_STYPE_RFC822;
			} else if (TOKEN_MATCH(state->token[2], "alternative")) {
				node->stype = MIME_STYPE_ALTERNATIVE;
			} else if (TOKEN_MATCH(state->token[2], "related")) {
				node->stype = MIME_STYPE_RELATED;
			} else if (TOKEN_MATCH(state->token[2], "mixed")) {
				node->stype = MIME_STYPE_MIXED;
			} else {
				node->stype = MIME_STYPE_OTHER;
			}
		} else {
			node->ctype = MIME_CTYPE_TEXT;
			node->stype = MIME_STYPE_PLAIN;
		}

		/*
		* Yes, this is supposed to capture multiple boundary strings,
		* which are illegal and which could be used to hide content in
		* an implementation dependent manner. The code below allows us
		* to find embedded message headers as long as the sender uses
		* only one of these same-level boundary strings.
		* 
		* Yes, this is supposed to ignore the boundary value type.
		*/
		while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
			if (tok_count < 3 || state->token[1].type != '=')
				continue;
			if (TOKEN_MATCH(state->token[0], "boundary")) {
				if (node->boundary == NULL)
					node->boundary = acl_vstring_alloc(256);
				/* 需要添加 "--" 做为分隔符的前导符 */
				SCP(node->boundary, "--");
				SCAT(node->boundary, state->token[2].u.value);
				break;
			}
		}
	}

	/*
	* text/whatever. Right now we don't really care if it is plain or
	* not, but we may want to recognize subtypes later, and then this
	* code can serve as an example.
	*/
	else if (TOKEN_MATCH(state->token[0], "text")) {
		node->ctype = MIME_CTYPE_TEXT;
		if (tok_count >= 3 && state->token[1].type == '/') {
			if (TOKEN_MATCH(state->token[2], "plain"))
				node->stype = MIME_STYPE_PLAIN;
			else if (TOKEN_MATCH(state->token[2], "html"))
				node->stype = MIME_STYPE_HTML;
			else
				node->stype = MIME_STYPE_OTHER;
		} else
			node->stype = MIME_STYPE_OTHER;

		while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
			if (tok_count < 3 || state->token[1].type != '=')
				continue;
			if (TOKEN_MATCH(state->token[0], "charset")
				&& node->charset == NULL)
			{
				node->charset = acl_mystrdup(state->token[2].u.value);
				break;
			}
		}

		/* 如果没有字符集, 则缺省采用 gb2312 */
		if (node->charset == NULL)
			node->charset = acl_mystrdup("gb2312");
	}
	else if (TOKEN_MATCH(state->token[0], "image")) {
		node->ctype = MIME_CTYPE_IMAGE;
		if (tok_count >= 3 && state->token[1].type == '/') {
			if (TOKEN_MATCH(state->token[2], "jpeg"))
				node->stype = MIME_STYPE_JPEG;
			else if (TOKEN_MATCH(state->token[2], "gif"))
				node->stype = MIME_STYPE_GIF;
			else if (TOKEN_MATCH(state->token[2], "bmp"))
				node->stype = MIME_STYPE_BMP;
			else if (TOKEN_MATCH(state->token[2], "png"))
				node->stype = MIME_STYPE_PNG;
			else
				node->stype = MIME_STYPE_OTHER;
		} else
			node->stype = MIME_STYPE_OTHER;

		while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
			if (tok_count < 3 || state->token[1].type != '=')
				continue;
			if (TOKEN_MATCH(state->token[0], "name")
				&& node->header_name == NULL)
			{
				node->header_name = acl_mystrdup(state->token[2].u.value);
				break;
			}
		}
	}
	else if (TOKEN_MATCH(state->token[0], "application")) {
		node->ctype = MIME_CTYPE_APPLICATION;
		if (tok_count >= 3 && state->token[1].type == '/') {
			if (TOKEN_MATCH(state->token[2], "octet-stream"))
				node->stype = MIME_STYPE_OCTET_STREAM;
			else
				node->stype = MIME_STYPE_OTHER;
		}
		while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
			if (tok_count < 3 || state->token[1].type != '=')
				continue;
			if (TOKEN_MATCH(state->token[0], "name")
				&& node->header_name == NULL)
			{
				node->header_name = acl_mystrdup(state->token[2].u.value);
				break;
			}
		}
	}
}
Beispiel #4
0
static void mime_state_content_type(MIME_STATE *state,
				            HEADER_OPTS *header_info)
{
    const char *cp;
    int     tok_count;
    int     def_ctype;
    int     def_stype;

#define TOKEN_MATCH(tok, text) \
    ((tok).type == HEADER_TOK_TOKEN && strcasecmp((tok).u.value, (text)) == 0)

#define RFC2045_TSPECIALS	"()<>@,;:\\\"/[]?="

#define PARSE_CONTENT_TYPE_HEADER(state, ptr) \
    header_token(state->token, MIME_MAX_TOKEN, \
	state->token_buffer, ptr, RFC2045_TSPECIALS, ';')

    cp = STR(state->output_buffer) + strlen(header_info->name) + 1;
    if ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) > 0) {

	/*
	 * text/whatever. Right now we don't really care if it is plain or
	 * not, but we may want to recognize subtypes later, and then this
	 * code can serve as an example.
	 */
	if (TOKEN_MATCH(state->token[0], "text")) {
	    state->curr_ctype = MIME_CTYPE_TEXT;
	    if (tok_count >= 3
		&& state->token[1].type == '/'
		&& TOKEN_MATCH(state->token[2], "plain"))
		state->curr_stype = MIME_STYPE_PLAIN;
	    else
		state->curr_stype = MIME_STYPE_OTHER;
	    return;
	}

	/*
	 * message/whatever body parts start with another block of message
	 * headers that we may want to look at. The partial and external-body
	 * subtypes cannot be subjected to 8-bit -> 7-bit conversion, so we
	 * must properly recognize them.
	 */
	if (TOKEN_MATCH(state->token[0], "message")) {
	    state->curr_ctype = MIME_CTYPE_MESSAGE;
	    state->curr_stype = MIME_STYPE_OTHER;
	    if (tok_count >= 3
		&& state->token[1].type == '/') {
		if (TOKEN_MATCH(state->token[2], "rfc822"))
		    state->curr_stype = MIME_STYPE_RFC822;
		else if (TOKEN_MATCH(state->token[2], "partial"))
		    state->curr_stype = MIME_STYPE_PARTIAL;
		else if (TOKEN_MATCH(state->token[2], "external-body"))
		    state->curr_stype = MIME_STYPE_EXTERN_BODY;
	    }
	    return;
	}

	/*
	 * multipart/digest has default content type message/rfc822,
	 * multipart/whatever has default content type text/plain.
	 */
	if (TOKEN_MATCH(state->token[0], "multipart")) {
	    state->curr_ctype = MIME_CTYPE_MULTIPART;
	    if (tok_count >= 3
		&& state->token[1].type == '/'
		&& TOKEN_MATCH(state->token[2], "digest")) {
		def_ctype = MIME_CTYPE_MESSAGE;
		def_stype = MIME_STYPE_RFC822;
	    } else {
		def_ctype = MIME_CTYPE_TEXT;
		def_stype = MIME_STYPE_PLAIN;
	    }

	    /*
	     * Yes, this is supposed to capture multiple boundary strings,
	     * which are illegal and which could be used to hide content in
	     * an implementation dependent manner. The code below allows us
	     * to find embedded message headers as long as the sender uses
	     * only one of these same-level boundary strings.
	     * 
	     * Yes, this is supposed to ignore the boundary value type.
	     */
	    while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
		if (tok_count >= 3
		    && TOKEN_MATCH(state->token[0], "boundary")
		    && state->token[1].type == '=') {
		    if (state->nesting_level > var_mime_maxdepth) {
			if (state->static_flags & MIME_OPT_REPORT_NESTING)
			    REPORT_ERROR(state, MIME_ERR_NESTING,
					 STR(state->output_buffer));
		    } else {
			mime_state_push(state, def_ctype, def_stype,
					state->token[2].u.value);
		    }
		}
	    }
	}
	return;
    }

    /*
     * other/whatever.
     */
    else {
	state->curr_ctype = MIME_CTYPE_OTHER;
	return;
    }
}