mirror of https://github.com/asterisk/asterisk
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							751 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
	
	
							751 lines
						
					
					
						
							17 KiB
						
					
					
				| %{
 | |
| /*
 | |
|  * Copyright (c) 2004 Jann Fischer. All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. Neither the name of the University nor the names of its contributors
 | |
|  *    may be used to endorse or promote products derived from this software
 | |
|  *    without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | |
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | |
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * These are the grammatic definitions in yacc syntax to parse MIME conform
 | |
|  * messages.
 | |
|  *
 | |
|  * TODO:
 | |
|  *	- honour parse flags passed to us (partly done)
 | |
|  *	- parse Content-Disposition header (partly done)
 | |
|  *	- parse Content-Encoding header
 | |
|  */
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <assert.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #include "mimeparser.h"
 | |
| #include "mm.h"
 | |
| #include "mm_internal.h"
 | |
| 
 | |
| int set_boundary(char *,struct parser_state *);
 | |
| int mimeparser_yywrap(void);
 | |
| void reset_environ(struct parser_state *pstate);
 | |
| int PARSER_initialize(struct parser_state *pstate, void *yyscanner);
 | |
| 
 | |
| typedef void *yyscan_t;
 | |
| 
 | |
| static char *PARSE_readmessagepart(size_t, size_t, size_t, size_t *,yyscan_t, struct parser_state *);
 | |
| FILE *mimeparser_yyget_in (yyscan_t yyscanner );
 | |
| 
 | |
| %}
 | |
| 
 | |
| %pure-parser
 | |
| %parse-param {struct parser_state *pstate}
 | |
| %parse-param {void *yyscanner}
 | |
| %lex-param {void *yyscanner}
 | |
| 
 | |
| %union
 | |
| {
 | |
| 	int number;
 | |
| 	char *string;
 | |
| 	struct s_position position;
 | |
| }
 | |
| 
 | |
| %token ANY
 | |
| %token COLON 
 | |
| %token DASH
 | |
| %token DQUOTE
 | |
| %token ENDOFHEADERS
 | |
| %token EOL
 | |
| %token EOM
 | |
| %token EQUAL
 | |
| %token MIMEVERSION_HEADER
 | |
| %token SEMICOLON
 | |
| 
 | |
| %token <string> CONTENTDISPOSITION_HEADER
 | |
| %token <string> CONTENTENCODING_HEADER
 | |
| %token <string> CONTENTTYPE_HEADER
 | |
| %token <string> MAIL_HEADER
 | |
| %token <string> HEADERVALUE
 | |
| %token <string> BOUNDARY
 | |
| %token <string> ENDBOUNDARY
 | |
| %token <string> CONTENTTYPE_VALUE 
 | |
| %token <string> TSPECIAL
 | |
| %token <string> WORD
 | |
| 
 | |
| %token <position> BODY
 | |
| %token <position> PREAMBLE
 | |
| %token <position> POSTAMBLE
 | |
| 
 | |
| %type  <string> content_disposition
 | |
| %type  <string> contenttype_parameter_value
 | |
| %type  <string> mimetype
 | |
| %type  <string> body
 | |
| 
 | |
| %start message
 | |
| 
 | |
| %%
 | |
| 
 | |
| /* This is a parser for a MIME-conform message, which is in either single
 | |
|  * part or multi part format.
 | |
|  */
 | |
| message : 
 | |
| 	multipart_message
 | |
| 	|
 | |
| 	singlepart_message
 | |
| 	;
 | |
| 
 | |
| multipart_message:
 | |
| 	headers preamble 
 | |
| 	{ 
 | |
| 		mm_context_attachpart(pstate->ctx, pstate->current_mimepart);
 | |
| 		pstate->current_mimepart = mm_mimepart_new();
 | |
| 		pstate->have_contenttype = 0;
 | |
| 	}
 | |
| 	mimeparts endboundary postamble
 | |
| 	{
 | |
| 		dprintf2(pstate,"This was a multipart message\n");
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| singlepart_message:	
 | |
| 	headers body
 | |
| 	{
 | |
| 		dprintf2(pstate,"This was a single part message\n");
 | |
| 		mm_context_attachpart(pstate->ctx, pstate->current_mimepart);
 | |
| 	}
 | |
| 	;
 | |
| 	
 | |
| headers :
 | |
| 	header headers
 | |
| 	|
 | |
| 	end_headers
 | |
| 	{
 | |
| 		/* If we did not find a Content-Type header for the current
 | |
| 		 * MIME part (or envelope), we create one and attach it.
 | |
| 		 * According to the RFC, a type of "text/plain" and a
 | |
| 		 * charset of "us-ascii" can be assumed.
 | |
| 		 */
 | |
| 		struct mm_content *ct;
 | |
| 		struct mm_param *param;
 | |
| 
 | |
| 		if (!pstate->have_contenttype) {
 | |
| 			ct = mm_content_new();
 | |
| 			mm_content_settype(ct, "text/plain");
 | |
| 			
 | |
| 			param = mm_param_new();
 | |
| 			param->name = xstrdup("charset");
 | |
| 			param->value = xstrdup("us-ascii");
 | |
| 
 | |
| 			mm_content_attachtypeparam(ct, param);
 | |
| 			mm_mimepart_attachcontenttype(pstate->current_mimepart, ct);
 | |
| 		}	
 | |
| 		pstate->have_contenttype = 0;
 | |
| 	}
 | |
| 	|
 | |
| 	header
 | |
| 	;
 | |
| 
 | |
| preamble:
 | |
| 	PREAMBLE
 | |
| 	{
 | |
| 		char *preamble;
 | |
| 		size_t offset;
 | |
| 		
 | |
| 		if ($1.start != $1.end) {
 | |
| 			preamble = PARSE_readmessagepart(0, $1.start, $1.end,
 | |
| 			    &offset,yyscanner,pstate);
 | |
| 			if (preamble == NULL) {
 | |
| 				return(-1);
 | |
| 			}
 | |
| 			pstate->ctx->preamble = preamble;
 | |
| 			dprintf2(pstate,"PREAMBLE:\n%s\n", preamble);
 | |
| 		}
 | |
| 	}
 | |
| 	|
 | |
| 	;
 | |
| 
 | |
| postamble:
 | |
| 	POSTAMBLE
 | |
| 	{
 | |
| 	}
 | |
| 	|
 | |
| 	;
 | |
| 
 | |
| mimeparts:
 | |
| 	mimeparts mimepart
 | |
| 	|
 | |
| 	mimepart
 | |
| 	;
 | |
| 
 | |
| mimepart:
 | |
| 	boundary headers body
 | |
| 	{
 | |
| 
 | |
| 		if (mm_context_attachpart(pstate->ctx, pstate->current_mimepart) == -1) {
 | |
| 			mm_errno = MM_ERROR_ERRNO;
 | |
| 			return(-1);
 | |
| 		}	
 | |
| 
 | |
| 		pstate->temppart = mm_mimepart_new();
 | |
| 		pstate->current_mimepart = pstate->temppart;
 | |
| 		pstate->mime_parts++;
 | |
| 	}
 | |
| 	;
 | |
| 	
 | |
| header	:
 | |
| 	mail_header
 | |
| 	|
 | |
| 	contenttype_header
 | |
| 	{
 | |
| 		pstate->have_contenttype = 1;
 | |
| 		if (mm_content_iscomposite(pstate->envelope->type)) {
 | |
| 			pstate->ctx->messagetype = MM_MSGTYPE_MULTIPART;
 | |
| 		} else {
 | |
| 			pstate->ctx->messagetype = MM_MSGTYPE_FLAT;
 | |
| 		}	
 | |
| 	}
 | |
| 	|
 | |
| 	contentdisposition_header
 | |
| 	|
 | |
| 	contentencoding_header
 | |
| 	|
 | |
| 	mimeversion_header
 | |
| 	|
 | |
| 	invalid_header
 | |
| 	{
 | |
| 		if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 			mm_errno = MM_ERROR_PARSE;
 | |
| 			mm_error_setmsg("invalid header encountered");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVHDR */
 | |
| 		}
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| mail_header:
 | |
| 	MAIL_HEADER COLON WORD EOL
 | |
| 	{
 | |
| 		struct mm_mimeheader *hdr;
 | |
| 		hdr = mm_mimeheader_generate($1, $3);
 | |
| 		mm_mimepart_attachheader(pstate->current_mimepart, hdr);
 | |
| 	}
 | |
| 	|
 | |
| 	MAIL_HEADER COLON EOL
 | |
| 	{
 | |
| 		struct mm_mimeheader *hdr;
 | |
| 
 | |
| 		if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 			mm_errno = MM_ERROR_MIME;
 | |
| 			mm_error_setmsg("invalid header encountered");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVHDR */
 | |
| 		}	
 | |
| 		
 | |
| 		hdr = mm_mimeheader_generate($1, xstrdup(""));
 | |
| 		mm_mimepart_attachheader(pstate->current_mimepart, hdr);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| contenttype_header:
 | |
| 	CONTENTTYPE_HEADER COLON mimetype EOL
 | |
| 	{
 | |
| 		mm_content_settype(pstate->ctype, "%s", $3);
 | |
| 		mm_mimepart_attachcontenttype(pstate->current_mimepart, pstate->ctype);
 | |
| 		dprintf2(pstate,"Content-Type -> %s\n", $3);
 | |
| 		pstate->ctype = mm_content_new();
 | |
| 	}
 | |
| 	|
 | |
| 	CONTENTTYPE_HEADER COLON mimetype contenttype_parameters EOL
 | |
| 	{
 | |
| 		mm_content_settype(pstate->ctype, "%s", $3);
 | |
| 		mm_mimepart_attachcontenttype(pstate->current_mimepart, pstate->ctype);
 | |
| 		dprintf2(pstate,"Content-Type (P) -> %s\n", $3);
 | |
| 		pstate->ctype = mm_content_new();
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| contentdisposition_header:
 | |
| 	CONTENTDISPOSITION_HEADER COLON content_disposition EOL
 | |
| 	{
 | |
| 		dprintf2(pstate,"Content-Disposition -> %s\n", $3);
 | |
| 		pstate->ctype->disposition_type = xstrdup($3);
 | |
| 	}
 | |
| 	|
 | |
| 	CONTENTDISPOSITION_HEADER COLON content_disposition content_disposition_parameters EOL
 | |
| 	{
 | |
| 		dprintf2(pstate,"Content-Disposition (P) -> %s; params\n", $3);
 | |
| 		pstate->ctype->disposition_type = xstrdup($3);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| content_disposition:
 | |
| 	WORD
 | |
| 	{
 | |
| 		/*
 | |
| 		 * According to RFC 2183, the content disposition value may
 | |
| 		 * only be "inline", "attachment" or an extension token. We
 | |
| 		 * catch invalid values here if we are not in loose parsing
 | |
| 		 * mode.
 | |
| 		 */
 | |
| 		if (strcasecmp($1, "inline") && strcasecmp($1, "attachment")
 | |
| 		    && strncasecmp($1, "X-", 2)) {
 | |
| 			if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 				mm_errno = MM_ERROR_MIME;
 | |
| 				mm_error_setmsg("invalid content-disposition");
 | |
| 				return(-1);
 | |
| 			}	
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVHDR */
 | |
| 		}	
 | |
| 		$$ = $1;
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| contentencoding_header:
 | |
| 	CONTENTENCODING_HEADER COLON WORD EOL
 | |
| 	{
 | |
| 		dprintf2(pstate,"Content-Transfer-Encoding -> %s\n", $3);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| mimeversion_header:
 | |
| 	MIMEVERSION_HEADER COLON WORD EOL
 | |
| 	{
 | |
| 		dprintf2(pstate,"MIME-Version -> '%s'\n", $3);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| invalid_header:
 | |
| 	any EOL
 | |
| 	;
 | |
| 
 | |
| any:
 | |
| 	any ANY
 | |
| 	|
 | |
| 	ANY
 | |
| 	;
 | |
| 	
 | |
| mimetype:
 | |
| 	WORD '/' WORD
 | |
| 	{
 | |
| 		char type[255];
 | |
| 		snprintf(type, sizeof(type), "%s/%s", $1, $3);
 | |
| 		$$ = type;
 | |
| 	}	
 | |
| 	;
 | |
| 
 | |
| contenttype_parameters: 
 | |
| 	SEMICOLON contenttype_parameter contenttype_parameters
 | |
| 	|
 | |
| 	SEMICOLON contenttype_parameter
 | |
| 	|
 | |
| 	SEMICOLON
 | |
| 	{
 | |
| 		if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 			mm_errno = MM_ERROR_MIME;
 | |
| 			mm_error_setmsg("invalid Content-Type header");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVHDR */
 | |
| 		}	
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| content_disposition_parameters:
 | |
| 	SEMICOLON content_disposition_parameter content_disposition_parameters
 | |
| 	|
 | |
| 	SEMICOLON content_disposition_parameter
 | |
| 	|
 | |
| 	SEMICOLON
 | |
| 	{	
 | |
| 		if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 			mm_errno = MM_ERROR_MIME;
 | |
| 			mm_error_setmsg("invalid Content-Disposition header");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVHDR */
 | |
| 		}
 | |
| 	}	
 | |
| 	;
 | |
| 
 | |
| contenttype_parameter:	
 | |
| 	WORD EQUAL contenttype_parameter_value
 | |
| 	{
 | |
| 		struct mm_param *param;
 | |
| 		param = mm_param_new();
 | |
| 		
 | |
| 		dprintf2(pstate,"Param: '%s', Value: '%s'\n", $1, $3);
 | |
| 		
 | |
| 		/* Catch an eventual boundary identifier */
 | |
| 		if (!strcasecmp($1, "boundary")) {
 | |
| 			if (pstate->lstate.boundary_string == NULL) {
 | |
| 				set_boundary($3,pstate);
 | |
| 			} else {
 | |
| 				if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 					mm_errno = MM_ERROR_MIME;
 | |
| 					mm_error_setmsg("duplicate boundary "
 | |
| 					    "found");
 | |
| 					return -1;
 | |
| 				} else {
 | |
| 					/* TODO: attach MM_WARNING_DUPPARAM */
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		param->name = xstrdup($1);
 | |
| 		param->value = xstrdup($3);
 | |
| 
 | |
| 		mm_content_attachtypeparam(pstate->ctype, param);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| content_disposition_parameter:
 | |
| 	WORD EQUAL contenttype_parameter_value
 | |
| 	{
 | |
| 		struct mm_param *param;
 | |
| 		param = mm_param_new();
 | |
| 		
 | |
| 		param->name = xstrdup($1);
 | |
| 		param->value = xstrdup($3);
 | |
| 
 | |
| 		mm_content_attachdispositionparam(pstate->ctype, param);
 | |
| 
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| contenttype_parameter_value:
 | |
| 	WORD
 | |
| 	{
 | |
| 		dprintf2(pstate,"contenttype_param_val: WORD=%s\n", $1);
 | |
| 		$$ = $1;
 | |
| 	}
 | |
| 	|
 | |
| 	TSPECIAL
 | |
| 	{
 | |
| 		dprintf2(pstate,"contenttype_param_val: TSPECIAL\n");
 | |
| 		/* For broken MIME implementation */
 | |
| 		if (pstate->parsemode != MM_PARSE_LOOSE) {
 | |
| 			mm_errno = MM_ERROR_MIME;
 | |
| 			mm_error_setmsg("tspecial without quotes");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		} else {
 | |
| 			/* TODO: attach MM_WARNING_INVAL */
 | |
| 		}	
 | |
| 		$$ = $1;
 | |
| 	}
 | |
| 	|
 | |
| 	'"' TSPECIAL '"'
 | |
| 	{
 | |
| 		dprintf2(pstate,"contenttype_param_val: \"TSPECIAL\"\n" );
 | |
| 		$$ = $2;
 | |
| 	}
 | |
| 	;
 | |
| 	
 | |
| end_headers	:
 | |
| 	ENDOFHEADERS
 | |
| 	{
 | |
| 		dprintf2(pstate,"End of headers at line %d\n", pstate->lstate.lineno);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| boundary	:
 | |
| 	BOUNDARY EOL
 | |
| 	{
 | |
| 		if (pstate->lstate.boundary_string == NULL) {
 | |
| 			mm_errno = MM_ERROR_PARSE;
 | |
| 			mm_error_setmsg("internal incosistency");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		if (strcmp(pstate->lstate.boundary_string, $1)) {
 | |
| 			mm_errno = MM_ERROR_PARSE;
 | |
| 			mm_error_setmsg("invalid boundary: '%s' (%d)", $1, strlen($1));
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		dprintf2(pstate,"New MIME part... (%s)\n", $1);
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| endboundary	:
 | |
| 	ENDBOUNDARY
 | |
| 	{
 | |
| 		if (pstate->lstate.endboundary_string == NULL) {
 | |
| 			mm_errno = MM_ERROR_PARSE;
 | |
| 			mm_error_setmsg("internal incosistency");
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		if (strcmp(pstate->lstate.endboundary_string, $1)) {
 | |
| 			mm_errno = MM_ERROR_PARSE;
 | |
| 			mm_error_setmsg("invalid end boundary: %s", $1);
 | |
| 			mm_error_setlineno(pstate->lstate.lineno);
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		dprintf2(pstate,"End of MIME message\n");
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| body:
 | |
| 	BODY
 | |
| 	{
 | |
| 		char *body;
 | |
| 		size_t offset;
 | |
| 
 | |
| 		dprintf2(pstate,"BODY (%d/%d), SIZE %d\n", $1.start, $1.end, $1.end - $1.start);
 | |
| 
 | |
| 		body = PARSE_readmessagepart($1.opaque_start, $1.start, $1.end,
 | |
| 		    &offset,yyscanner,pstate);
 | |
| 
 | |
| 		if (body == NULL) {
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		pstate->current_mimepart->opaque_body = body;
 | |
| 		pstate->current_mimepart->body = body + offset;
 | |
| 		pstate->current_mimepart->opaque_length = $1.end - $1.start - 2 + offset;
 | |
| 		pstate->current_mimepart->length = pstate->current_mimepart->opaque_length - offset;
 | |
| 	}
 | |
| 	;
 | |
| 
 | |
| %%
 | |
| 
 | |
| /*
 | |
|  * This function gets the specified part from the currently parsed message.
 | |
|  */
 | |
| static char *
 | |
| PARSE_readmessagepart(size_t opaque_start, size_t real_start, size_t end, 
 | |
|     size_t *offset, yyscan_t yyscanner, struct parser_state *pstate)
 | |
| {
 | |
| 	size_t body_size;
 | |
| 	size_t current;
 | |
| 	size_t start;
 | |
| 	char *body;
 | |
| 
 | |
| 	/* calculate start and offset markers for the opaque and
 | |
| 	 * header stripped body message.
 | |
| 	 */
 | |
| 	if (opaque_start > 0) {
 | |
| 		/* Multipart message */
 | |
| 		if (real_start) {
 | |
| 			if (real_start < opaque_start) {
 | |
| 				mm_errno = MM_ERROR_PARSE;
 | |
| 				mm_error_setmsg("internal incosistency (S:%d/O:%d)",
 | |
| 				    real_start,
 | |
| 				    opaque_start);
 | |
| 				return(NULL);
 | |
| 			}
 | |
| 			start = opaque_start;
 | |
| 			*offset = real_start - start;
 | |
| 		/* Flat message */	
 | |
| 		} else {	
 | |
| 			start = opaque_start;
 | |
| 			*offset = 0;
 | |
| 		}	
 | |
| 	} else {
 | |
| 		start = real_start;
 | |
| 		*offset = 0;
 | |
| 	}
 | |
| 
 | |
| 	/* The next three cases should NOT happen anytime */
 | |
| 	if (end <= start) {
 | |
| 		mm_errno = MM_ERROR_PARSE;
 | |
| 		mm_error_setmsg("internal incosistency,2");
 | |
| 		mm_error_setlineno(pstate->lstate.lineno);
 | |
| 		return(NULL);
 | |
| 	}
 | |
| 	if (start < *offset) {
 | |
| 		mm_errno = MM_ERROR_PARSE;
 | |
| 		mm_error_setmsg("internal incosistency, S:%d,O:%d,L:%d", start, offset, pstate->lstate.lineno);
 | |
| 		mm_error_setlineno(pstate->lstate.lineno);
 | |
| 		return(NULL);
 | |
| 	}	
 | |
| 	if (start < 0 || end < 0) {
 | |
| 		mm_errno = MM_ERROR_PARSE;
 | |
| 		mm_error_setmsg("internal incosistency,4");
 | |
| 		mm_error_setlineno(pstate->lstate.lineno);
 | |
| 		return(NULL);
 | |
| 	}	
 | |
| 
 | |
| 	/* XXX: do we want to enforce a maximum body size? make it a
 | |
| 	 * parser option? */
 | |
| 
 | |
| 	/* Read in the body message */
 | |
| 	body_size = end - start;
 | |
| 
 | |
| 	if (body_size < 1) {
 | |
| 		mm_errno = MM_ERROR_PARSE;
 | |
| 		mm_error_setmsg("size of body cannot be < 1");
 | |
| 		mm_error_setlineno(pstate->lstate.lineno);
 | |
| 		return(NULL);
 | |
| 	}	
 | |
| 	
 | |
| 	body = (char *)malloc(body_size + 1);
 | |
| 	if (body == NULL) {
 | |
| 		mm_errno = MM_ERROR_ERRNO;
 | |
| 		return(NULL);
 | |
| 	}	
 | |
| 		
 | |
| 	/* Get the message body either from a stream or a memory
 | |
| 	 * buffer.
 | |
| 	 */
 | |
| 	if (mimeparser_yyget_in(yyscanner) != NULL) {
 | |
| 		FILE *x = mimeparser_yyget_in(yyscanner);
 | |
| 		current = ftell(x);
 | |
| 		fseek(x, start - 1, SEEK_SET);
 | |
| 		fread(body, body_size - 1, 1, x);
 | |
| 		fseek(x, current, SEEK_SET);
 | |
| 	} else if (pstate->lstate.message_buffer != NULL) {
 | |
| 		strlcpy(body, pstate->lstate.message_buffer + start - 1, body_size);
 | |
| 	} 
 | |
| 	
 | |
| 	return(body);
 | |
| 
 | |
| }
 | |
| 
 | |
| int
 | |
| yyerror(struct parser_state *pstate, void *yyscanner, const char *str)
 | |
| {
 | |
| 	mm_errno = MM_ERROR_PARSE;
 | |
| 	mm_error_setmsg("%s", str);
 | |
| 	mm_error_setlineno(pstate->lstate.lineno);
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| int 
 | |
| mimeparser_yywrap(void)
 | |
| {
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets the boundary value for the current message
 | |
|  */
 | |
| int 
 | |
| set_boundary(char *str, struct parser_state *pstate)
 | |
| {
 | |
| 	size_t blen;
 | |
| 
 | |
| 	blen = strlen(str);
 | |
| 
 | |
| 	pstate->lstate.boundary_string = (char *)malloc(blen + 3);
 | |
| 	pstate->lstate.endboundary_string = (char *)malloc(blen + 5);
 | |
| 
 | |
| 	if (pstate->lstate.boundary_string == NULL || pstate->lstate.endboundary_string == NULL) {
 | |
| 		if (pstate->lstate.boundary_string != NULL) {
 | |
| 			free(pstate->lstate.boundary_string);
 | |
| 		}
 | |
| 		if (pstate->lstate.endboundary_string != NULL) {
 | |
| 			free(pstate->lstate.endboundary_string);
 | |
| 		}	
 | |
| 		return -1;
 | |
| 	}
 | |
| 	
 | |
| 	pstate->ctx->boundary = xstrdup(str);
 | |
| 
 | |
| 	snprintf(pstate->lstate.boundary_string, blen + 3, "--%s", str);
 | |
| 	snprintf(pstate->lstate.endboundary_string, blen + 5, "--%s--", str);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Debug printf()
 | |
|  */
 | |
| int
 | |
| dprintf2(struct parser_state *pstate, const char *fmt, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	char *msg;
 | |
| 	if (pstate->debug == 0) return 1;
 | |
| 
 | |
| 	va_start(ap, fmt);
 | |
| 	vasprintf(&msg, fmt, ap);
 | |
| 	va_end(ap);
 | |
| 
 | |
| 	fprintf(stderr, "%s", msg);
 | |
| 	free(msg);
 | |
| 
 | |
| 	return 0;
 | |
| 	
 | |
| }
 | |
| 
 | |
| void reset_environ(struct parser_state *pstate)
 | |
| {
 | |
| 	pstate->lstate.lineno = 0;
 | |
| 	pstate->lstate.boundary_string = NULL;
 | |
| 	pstate->lstate.endboundary_string = NULL;
 | |
| 	pstate->lstate.message_buffer = NULL;
 | |
| 	pstate->mime_parts = 0;
 | |
| 	pstate->debug = 0;
 | |
| 	pstate->envelope = NULL;
 | |
| 	pstate->temppart = NULL;
 | |
| 	pstate->ctype = NULL;
 | |
| 	pstate->current_mimepart = NULL;
 | |
| 
 | |
| 	pstate->have_contenttype = 0;
 | |
| }
 | |
| /**
 | |
|  * Initializes the parser engine.
 | |
|  */
 | |
| int
 | |
| PARSER_initialize(struct parser_state *pstate, void *yyscanner)
 | |
| {
 | |
| 	void reset_lexer_state(void *yyscanner, struct parser_state *);
 | |
| #if 0
 | |
| 	if (pstate->ctx != NULL) {
 | |
| 		xfree(pstate->ctx);
 | |
| 		pstate->ctx = NULL;
 | |
| 	}
 | |
| 	if (pstate->envelope != NULL) {
 | |
| 		xfree(pstate->envelope);
 | |
| 		pstate->envelope = NULL;
 | |
| 	}	
 | |
| 	if (pstate->ctype != NULL) {
 | |
| 		xfree(pstate->ctype);
 | |
| 		pstate->ctype = NULL;
 | |
| 	}	
 | |
| #endif
 | |
| 	/* yydebug = 1; */
 | |
| 	reset_environ(pstate);
 | |
| 	reset_lexer_state(yyscanner,pstate);
 | |
| 
 | |
| 	pstate->envelope = mm_mimepart_new();
 | |
| 	pstate->current_mimepart = pstate->envelope;
 | |
| 	pstate->ctype = mm_content_new();
 | |
| 
 | |
| 	pstate->have_contenttype = 0;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| 
 |