diff options
Diffstat (limited to 'main/minimime/mimeparser.y')
-rw-r--r-- | main/minimime/mimeparser.y | 748 |
1 files changed, 0 insertions, 748 deletions
diff --git a/main/minimime/mimeparser.y b/main/minimime/mimeparser.y deleted file mode 100644 index 7c32a290d..000000000 --- a/main/minimime/mimeparser.y +++ /dev/null @@ -1,748 +0,0 @@ -%{ -/* - * 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); - -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; -} - - |