Exemple #1
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;
			}
		}
	}
}
Exemple #2
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;
    }
}