diff options
Diffstat (limited to 'ext/mailparse/mailparse.c')
-rwxr-xr-x | ext/mailparse/mailparse.c | 306 |
1 files changed, 170 insertions, 136 deletions
diff --git a/ext/mailparse/mailparse.c b/ext/mailparse/mailparse.c index ed8672c886..37095e478a 100755 --- a/ext/mailparse/mailparse.c +++ b/ext/mailparse/mailparse.c @@ -52,6 +52,7 @@ function_entry mailparse_functions[] = { PHP_FE(mailparse_msg_get_part_data, NULL) PHP_FE(mailparse_msg_extract_part, NULL) PHP_FE(mailparse_msg_extract_part_file, NULL) + PHP_FE(mailparse_msg_extract_whole_part_file, NULL) PHP_FE(mailparse_msg_create, NULL) PHP_FE(mailparse_msg_free, NULL) @@ -124,6 +125,7 @@ PHP_MINFO_FUNCTION(mailparse) { php_info_print_table_start(); php_info_print_table_header(2, "mailparse support", "enabled"); + php_info_print_table_row(2, "Revision", "$Revision$"); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); @@ -313,7 +315,7 @@ PHP_FUNCTION(mailparse_rfc822_parse_addresses) } /* }}} */ -/* {{{ proto int mailparse_determine_best_xfer_encoding(resource fp) +/* {{{ proto string mailparse_determine_best_xfer_encoding(resource fp) Figures out the best way of encoding the content read from the file pointer fp, which must be seek-able */ PHP_FUNCTION(mailparse_determine_best_xfer_encoding) { @@ -322,41 +324,36 @@ PHP_FUNCTION(mailparse_determine_best_xfer_encoding) int linelen = 0; int c; enum mbfl_no_encoding bestenc = mbfl_no_encoding_7bit; - void * what; - int type; + php_stream *stream; char * name; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) { WRONG_PARAM_COUNT; } - what = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); - ZEND_VERIFY_RESOURCE(what); - - if (type == php_file_le_stream()) { - php_stream *stream = (php_stream*)what; + stream = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(stream); - php_stream_rewind(stream); - while(!php_stream_eof(stream)) { - c = php_stream_getc(stream); - if (c == EOF) - break; - if (c > 0x80) - bestenc = mbfl_no_encoding_8bit; - else if (c == 0) { - bestenc = mbfl_no_encoding_base64; - longline = 0; - break; - } - if (c == '\n') - linelen = 0; - else if (++linelen > 200) - longline = 1; + php_stream_rewind(stream); + while(!php_stream_eof(stream)) { + c = php_stream_getc(stream); + if (c == EOF) + break; + if (c > 0x80) + bestenc = mbfl_no_encoding_8bit; + else if (c == 0) { + bestenc = mbfl_no_encoding_base64; + longline = 0; + break; } - if (longline) - bestenc = mbfl_no_encoding_qprint; - php_stream_rewind(stream); + if (c == '\n') + linelen = 0; + else if (++linelen > 200) + longline = 1; } + if (longline) + bestenc = mbfl_no_encoding_qprint; + php_stream_rewind(stream); name = (char *)mbfl_no2preferred_mime_name(bestenc); if (name) @@ -510,7 +507,7 @@ PHP_FUNCTION(mailparse_msg_parse_file) zval **filename; struct rfc2045 *rfcbuf; char *filebuf; - FILE *fp; + php_stream *stream; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &filename) == FAILURE) { WRONG_PARAM_COUNT; @@ -519,9 +516,8 @@ PHP_FUNCTION(mailparse_msg_parse_file) convert_to_string_ex(filename); /* open file and read it in */ - fp = VCWD_FOPEN(Z_STRVAL_PP(filename), "r"); - if (fp == NULL) { - zend_error(E_WARNING, "%s(): unable to open file %s", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename)); + stream = php_stream_open_wrapper(Z_STRVAL_PP(filename), "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL); + if (stream == NULL) { RETURN_FALSE; } @@ -531,14 +527,14 @@ PHP_FUNCTION(mailparse_msg_parse_file) if (rfcbuf) { ZEND_REGISTER_RESOURCE(return_value, rfcbuf, le_rfc2045); - while(!feof(fp)) { - int got = fread(filebuf, sizeof(char), MAILPARSE_BUFSIZ, fp); + while(!php_stream_eof(stream)) { + int got = php_stream_read(stream, filebuf, MAILPARSE_BUFSIZ); if (got > 0) { rfc2045_parse(rfcbuf, filebuf, got); } } - fclose(fp); } + php_stream_close(stream); efree(filebuf); } /* }}} */ @@ -661,140 +657,178 @@ static int extract_callback_stdout(const char *p, size_t n, void *ptr) return 0; } -/* {{{ proto void mailparse_msg_extract_part(resource rfc2045, string msgbody[, string callbackfunc]) - Extracts/decodes a message section. If callbackfunc is not specified, the contents will be sent to "stdout" */ -PHP_FUNCTION(mailparse_msg_extract_part) +/* callback for decoding to a stream */ +static int extract_callback_stream(const char *p, size_t n, void *ptr) +{ + TSRMLS_FETCH(); + php_stream_write((php_stream*)ptr, p, n); + return 0; +} + + +#define MAILPARSE_DECODE_NONE 0 /* include headers and leave section untouched */ +#define MAILPARSE_DECODE_8BIT 1 /* decode body into 8-bit */ +#define MAILPARSE_DECODE_NOHEADERS 2 /* don't include the headers */ +static int extract_part(struct rfc2045 *rfcbuf, int decode, php_stream *src, void *callbackdata, + rfc2045_decode_user_func_t callback TSRMLS_DC) { - zval **arg, **bodystr, **cbfunc; - struct rfc2045 *rfcbuf; off_t start, end, body; off_t nlines; off_t nbodylines; + off_t start_pos; + char *filebuf = NULL; + int ret = FAILURE; + + /* figure out where the message part starts/ends */ + rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines); - switch(ZEND_NUM_ARGS()) { - case 3: - if (zend_get_parameters_ex(3, &arg, &bodystr, &cbfunc) == FAILURE) { - WRONG_PARAM_COUNT; - } - if (Z_TYPE_PP(cbfunc) != IS_ARRAY) - convert_to_string_ex(cbfunc); - break; - case 2: - if (zend_get_parameters_ex(2, &arg, &bodystr) == FAILURE) { - WRONG_PARAM_COUNT; - } - cbfunc = NULL; - break; - } - convert_to_string_ex(bodystr); + start_pos = decode & MAILPARSE_DECODE_NOHEADERS ? body : start; - if (Z_TYPE_PP(arg) == IS_RESOURCE && Z_LVAL_PP(arg) == 0) { - RETURN_FALSE; + if (decode & MAILPARSE_DECODE_8BIT) + rfc2045_cdecode_start(rfcbuf, callback, callbackdata); + + if (php_stream_seek(src, start_pos, SEEK_SET) == -1) { + zend_error(E_WARNING, "%s(): unable to seek to section start", get_active_function_name(TSRMLS_C)); + goto cleanup; } - mailparse_fetch_rfc2045_resource(rfcbuf, arg); - - - rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines); + + filebuf = emalloc(MAILPARSE_BUFSIZ); + + while (start_pos < end) + { + size_t n = MAILPARSE_BUFSIZ - 1; - if (cbfunc) - rfc2045_cdecode_start(rfcbuf, (rfc2045_decode_user_func_t)&extract_callback_user_func, *cbfunc); - else - rfc2045_cdecode_start(rfcbuf, &extract_callback_stdout, NULL); + if ((off_t)n > end - start_pos) + n = end - start_pos; + + n = php_stream_read(src, filebuf, n); + + if (n == 0) + { + zend_error(E_WARNING, "%s(): error reading from file at offset %d", get_active_function_name(TSRMLS_C), start_pos); + goto cleanup; + } - if (Z_STRLEN_PP(bodystr) < end) - end = Z_STRLEN_PP(bodystr); - else - end = end-body; + filebuf[n] = '\0'; + + if (decode & MAILPARSE_DECODE_8BIT) + rfc2045_cdecode(rfcbuf, filebuf, n); + else + callback(filebuf, n, callbackdata); - rfc2045_cdecode(rfcbuf, Z_STRVAL_PP(bodystr) + body, end); - rfc2045_cdecode_end(rfcbuf); + start_pos += n; + } + ret = SUCCESS; - RETURN_TRUE; +cleanup: + if (decode & MAILPARSE_DECODE_8BIT) + rfc2045_cdecode_end(rfcbuf); + if (filebuf) + efree(filebuf); + + return ret; } -/* }}} */ -/* {{{ proto string mailparse_msg_extract_part_file(resource rfc2045, string filename [, string callbackfunc]) - Extracts/decodes a message section, decoding the transfer encoding */ -PHP_FUNCTION(mailparse_msg_extract_part_file) +static void mailparse_do_extract(INTERNAL_FUNCTION_PARAMETERS, int decode, int isfile) { - zval **arg, **filename, **cbfunc; + zval *part, *filename, *callbackfunc = NULL; struct rfc2045 *rfcbuf; - char *filebuf = NULL; - FILE *fp = NULL; - off_t start, end, body; - off_t nlines; - off_t nbodylines; + php_stream *srcstream = NULL, *deststream = NULL; + rfc2045_decode_user_func_t cbfunc = NULL; + void *cbdata = NULL; + int close_src_stream = 0; - switch(ZEND_NUM_ARGS()) { - case 3: - if (zend_get_parameters_ex(3, &arg, &filename, &cbfunc) == FAILURE) { - WRONG_PARAM_COUNT; - } - if (Z_TYPE_PP(cbfunc) != IS_ARRAY) - convert_to_string_ex(cbfunc); - break; - case 2: - if (zend_get_parameters_ex(2, &arg, &filename) == FAILURE) { - WRONG_PARAM_COUNT; - } - cbfunc = NULL; - break; + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &part, &filename, &callbackfunc)) { + RETURN_FALSE; } - convert_to_string_ex(filename); - if (Z_TYPE_PP(arg) == IS_RESOURCE && Z_LVAL_PP(arg) == 0) { + if (Z_TYPE_P(part) == IS_RESOURCE && Z_LVAL_P(part) == 0) { RETURN_FALSE; } - mailparse_fetch_rfc2045_resource(rfcbuf, arg); - - /* figure out where the message part starts/ends */ - rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines); + mailparse_fetch_rfc2045_resource(rfcbuf, &part); - if (cbfunc) - rfc2045_cdecode_start(rfcbuf, (rfc2045_decode_user_func_t)&extract_callback_user_func, *cbfunc); - else - rfc2045_cdecode_start(rfcbuf, &extract_callback_stdout, NULL); + /* filename can be a filename or a stream */ + if (Z_TYPE_P(filename) == IS_RESOURCE) { + srcstream = (php_stream*)zend_fetch_resource(&filename TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(srcstream); + } else if (isfile) { + convert_to_string_ex(&filename); + srcstream = php_stream_open_wrapper(Z_STRVAL_P(filename), "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL); + } else { + /* filename is the actual data */ + srcstream = php_stream_memory_open(TEMP_STREAM_READONLY, Z_STRVAL_P(filename), Z_STRLEN_P(filename)); + close_src_stream = 1; + } - /* open file and read it in */ - fp = VCWD_FOPEN(Z_STRVAL_PP(filename), "rb"); - if (fp == NULL) { - zend_error(E_WARNING, "%s(): unable to open file %s", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename)); + if (srcstream == NULL) { RETURN_FALSE; } - if (fseek(fp, body, SEEK_SET) == -1) - { - zend_error(E_WARNING, "%s(): unable to seek to section start", get_active_function_name(TSRMLS_C)); - RETVAL_FALSE; - goto cleanup; + + if (callbackfunc != NULL) { + if (Z_TYPE_P(callbackfunc) == IS_NULL) { + cbfunc = extract_callback_stream; + cbdata = deststream = php_stream_memory_create(TEMP_STREAM_DEFAULT); + } else if (Z_TYPE_P(callbackfunc) == IS_RESOURCE) { + deststream = (php_stream*)zend_fetch_resource(&callbackfunc TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(deststream); + cbfunc = extract_callback_stream; + cbdata = deststream; + deststream = NULL; /* don't free this one */ + } else { + if (Z_TYPE_P(callbackfunc) != IS_ARRAY) + convert_to_string_ex(&callbackfunc); + cbfunc = (rfc2045_decode_user_func_t)&extract_callback_user_func; + cbdata = callbackfunc; + } + } else { + cbfunc = extract_callback_stdout; + cbdata = NULL; } - filebuf = emalloc(MAILPARSE_BUFSIZ); + RETVAL_FALSE; + + if (SUCCESS == extract_part(rfcbuf, decode, srcstream, cbdata, cbfunc TSRMLS_CC)) { - while (body < end) - { - size_t n = MAILPARSE_BUFSIZ; + if (deststream != NULL) { + /* return it's contents as a string */ + char *membuf = NULL; + size_t memlen = 0; + membuf = php_stream_memory_get_buffer(deststream, &memlen); + RETVAL_STRINGL(membuf, memlen, 1); - if ((off_t)n > end-body) - n=end-body; - n = fread(filebuf, sizeof(char), n, fp); - if (n == 0) - { - zend_error(E_WARNING, "%s(): error reading from file \"%s\", offset %d", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename), body); - RETVAL_FALSE; - goto cleanup; + } else { + RETVAL_TRUE; } - rfc2045_cdecode(rfcbuf, filebuf, n); - body += n; } - RETVAL_TRUE; -cleanup: - rfc2045_cdecode_end(rfcbuf); - if (fp) - fclose(fp); - if (filebuf) - efree(filebuf); + if (deststream) + php_stream_close(deststream); + if (close_src_stream && srcstream) + php_stream_close(srcstream); +} + +/* {{{ proto void mailparse_msg_extract_part(resource rfc2045, string msgbody[, string callbackfunc]) + Extracts/decodes a message section. If callbackfunc is not specified, the contents will be sent to "stdout" */ +PHP_FUNCTION(mailparse_msg_extract_part) +{ + mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_8BIT | MAILPARSE_DECODE_NOHEADERS, 0); +} +/* }}} */ + +/* {{{ proto string mailparse_msg_extract_whole_part_file(resource rfc2045, string filename [, string callbackfunc]) + Extracts a message section including headers without decoding the transfer encoding */ +PHP_FUNCTION(mailparse_msg_extract_whole_part_file) +{ + mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_NONE, 1); +} +/* }}} */ + +/* {{{ proto string mailparse_msg_extract_part_file(resource rfc2045, string filename [, string callbackfunc]) + Extracts/decodes a message section, decoding the transfer encoding */ +PHP_FUNCTION(mailparse_msg_extract_part_file) +{ + mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_8BIT | MAILPARSE_DECODE_NOHEADERS, 1); } /* }}} */ |