moriyoshi Tue Feb 18 13:49:47 2003 EDT
Modified files:
/php4/ext/mbstring mbstring.c
Log:
Fixed mb_send_mail() so that Content-Type and Content-Transfer-Encoding
headers are overridable by additional header parameters.
This patch fixes bug #21985 and bug #22064.
Index: php4/ext/mbstring/mbstring.c
diff -u php4/ext/mbstring/mbstring.c:1.161 php4/ext/mbstring/mbstring.c:1.162
--- php4/ext/mbstring/mbstring.c:1.161 Mon Feb 10 22:55:08 2003
+++ php4/ext/mbstring/mbstring.c Tue Feb 18 13:49:47 2003
@@ -17,7 +17,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: mbstring.c,v 1.161 2003/02/11 03:55:08 moriyoshi Exp $ */
+/* $Id: mbstring.c,v 1.162 2003/02/18 18:49:47 moriyoshi Exp $ */
/*
* PHP4 Multibyte String module "mbstring"
@@ -55,6 +55,7 @@
#include "mbstring.h"
#include "ext/standard/php_string.h"
#include "ext/standard/php_mail.h"
+#include "ext/standard/php_smart_str.h"
#include "ext/standard/url.h"
#include "main/php_output.h"
#include "ext/standard/info.h"
@@ -2648,6 +2649,194 @@
* Sends an email message with MIME scheme
*/
#if HAVE_SENDMAIL
+
+#define APPEND_ONE_CHAR(ch) do { \
+ if (token.a > 0) { \
+ smart_str_appendc(&token, ch); \
+ } else {\
+ token.len++; \
+ } \
+} while (0)
+
+#define SEPARATE_SMART_STR(str) do {\
+ if ((str)->a == 0) { \
+ char *tmp_ptr; \
+ (str)->a = 1; \
+ while ((str)->a < (str)->len) { \
+ (str)->a <<= 1; \
+ } \
+ tmp_ptr = emalloc((str)->a + 1); \
+ memcpy(tmp_ptr, (str)->c, (str)->len); \
+ (str)->c = tmp_ptr; \
+ } \
+} while (0)
+
+static void my_smart_str_dtor(smart_str *s)
+{
+ if (s->a > 0) {
+ smart_str_free(s);
+ }
+}
+
+static int _php_mbstr_parse_mail_headers(HashTable *ht, const char *str, size_t
+str_len)
+{
+ const char *ps;
+ size_t icnt;
+ int state = 0;
+ int crlf_state = -1;
+
+ smart_str token = { 0, 0, 0 };
+ smart_str fld_name = { 0, 0, 0 }, fld_val = { 0, 0, 0 };
+
+ ps = str;
+ icnt = str_len;
+
+ while (icnt > 0) {
+ switch (*ps) {
+ case ':':
+ if (crlf_state == 1) {
+ APPEND_ONE_CHAR('\r');
+ }
+
+ if (state == 0 || state == 1) {
+ fld_name = token;
+
+ state = 2;
+ } else {
+ APPEND_ONE_CHAR(*ps);
+ }
+
+ crlf_state = 0;
+ break;
+
+ case '\n':
+ if (crlf_state == -1) {
+ goto out;
+ }
+ crlf_state = -1;
+ break;
+
+ case '\r':
+ if (crlf_state == 1) {
+ APPEND_ONE_CHAR('\r');
+ } else {
+ crlf_state = 1;
+ }
+ break;
+
+ case ' ': case '\t':
+ if (crlf_state == -1) {
+ if (state == 3) {
+ /* continuing from the previous line */
+ SEPARATE_SMART_STR(&token);
+ state = 4;
+ } else {
+ /* simply skipping this new line */
+ state = 5;
+ }
+ } else {
+ if (crlf_state == 1) {
+ APPEND_ONE_CHAR('\r');
+ }
+ if (state == 1 || state == 3) {
+ APPEND_ONE_CHAR(*ps);
+ }
+ }
+ crlf_state = 0;
+ break;
+
+ default:
+ switch (state) {
+ case 0:
+ token.c = (char *)ps;
+ token.len = 0;
+ token.a = 0;
+ state = 1;
+ break;
+
+ case 2:
+ if (crlf_state != -1) {
+ token.c = (char *)ps;
+ token.len = 0;
+ token.a = 0;
+
+ state = 3;
+ break;
+ }
+ /* break is missing intentionally */
+
+ case 3:
+ if (crlf_state == -1) {
+ fld_val = token;
+
+ if (fld_name.c != NULL &&
+fld_val.c != NULL) {
+ char *dummy;
+
+ /* FIXME: some locale
+free implementation is
+ * really required
+here,,, */
+
+SEPARATE_SMART_STR(&fld_name);
+
+php_strtoupper(fld_name.c, fld_name.len);
+
+ zend_hash_update(ht,
+(char *)fld_name.c, fld_name.len, &fld_val, sizeof(smart_str), (void **)&dummy);
+
+
+my_smart_str_dtor(&fld_name);
+ }
+
+ memset(&fld_name, 0,
+sizeof(smart_str));
+ memset(&fld_val, 0,
+sizeof(smart_str));
+
+ token.c = (char *)ps;
+ token.len = 0;
+ token.a = 0;
+
+ state = 1;
+ }
+ break;
+
+ case 4:
+ APPEND_ONE_CHAR(' ');
+ state = 3;
+ break;
+ }
+
+ if (crlf_state == 1) {
+ APPEND_ONE_CHAR('\r');
+ }
+
+ APPEND_ONE_CHAR(*ps);
+
+ crlf_state = 0;
+ break;
+ }
+ ps++, icnt--;
+ }
+out:
+ if (state == 2) {
+ token.c = "";
+ token.len = 0;
+ token.a = 0;
+
+ state = 3;
+ }
+ if (state == 3) {
+ fld_val = token;
+
+ if (fld_name.c != NULL && fld_val.c != NULL) {
+ void *dummy;
+
+ /* FIXME: some locale free implementation is
+ * really required here,,, */
+ SEPARATE_SMART_STR(&fld_name);
+ php_strtoupper(fld_name.c, fld_name.len);
+
+ zend_hash_update(ht, (char *)fld_name.c, fld_name.len,
+&fld_val, sizeof(smart_str), (void **)&dummy);
+
+ my_smart_str_dtor(&fld_name);
+ }
+ }
+ return state;
+}
+
PHP_FUNCTION(mb_send_mail)
{
int n;
@@ -2661,6 +2850,10 @@
int subject_len;
char *extra_cmd=NULL;
int extra_cmd_len;
+ struct {
+ int cnt_type:1;
+ int cnt_trans_enc:1;
+ } suppressed_hdrs = { 0, 0 };
char *message_buf=NULL, *subject_buf=NULL, *p;
mbfl_string orig_str, conv_str;
@@ -2672,7 +2865,10 @@
mbfl_memory_device device; /* automatic allocateable buffer for
additional header */
const mbfl_language *lang;
int err = 0;
-
+ HashTable ht_headers;
+ smart_str *s;
+ extern void mbfl_memory_device_unput(mbfl_memory_device *device TSRMLS_DC);
+
/* initialize */
mbfl_memory_device_init(&device, 0, 0 TSRMLS_CC);
mbfl_string_init(&orig_str);
@@ -2693,6 +2889,71 @@
return;
}
+ zend_hash_init(&ht_headers, 0, NULL, (dtor_func_t) my_smart_str_dtor, 0);
+
+ if (headers != NULL) {
+ _php_mbstr_parse_mail_headers(&ht_headers, headers, headers_len);
+ }
+
+ if (zend_hash_find(&ht_headers, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1,
+(void **)&s) == SUCCESS) {
+ char *tmp;
+ char *param_name;
+ char *charset = NULL;
+
+ SEPARATE_SMART_STR(s);
+ smart_str_0(s);
+
+ p = strchr(s->c, ';');
+
+ if (p != NULL) {
+ /* skipping the padded spaces */
+ do {
+ ++p;
+ } while (*p == ' ' || *p == '\t');
+
+ if (*p != '\0') {
+ if ((param_name = php_strtok_r(p, "= ", &tmp)) !=
+NULL) {
+ if (strcasecmp(param_name, "charset") == 0) {
+ enum mbfl_no_encoding _tran_cs =
+tran_cs;
+
+ charset = php_strtok_r(NULL, "= ",
+&tmp);
+ if (charset != NULL) {
+ _tran_cs =
+mbfl_name2no_encoding(charset);
+ }
+
+ if (_tran_cs ==
+mbfl_no_encoding_invalid) {
+ php_error_docref(NULL
+TSRMLS_CC, E_WARNING, "Unsupported charset \"%s\" - will be regarded as ascii",
+charset);
+ _tran_cs =
+mbfl_no_encoding_ascii;
+ }
+ tran_cs = _tran_cs;
+ }
+ }
+ }
+ }
+ suppressed_hdrs.cnt_type = 1;
+ }
+
+ if (zend_hash_find(&ht_headers, "CONTENT-TRANSFER-ENCODING",
+sizeof("CONTENT-TRANSFER-ENCODING") - 1, (void **)&s) == SUCCESS) {
+ enum mbfl_no_encoding _body_enc;
+ SEPARATE_SMART_STR(s);
+ smart_str_0(s);
+
+ _body_enc = mbfl_name2no_encoding(s->c);
+ switch (_body_enc) {
+ case mbfl_no_encoding_base64:
+ case mbfl_no_encoding_7bit:
+ case mbfl_no_encoding_8bit:
+ body_enc = _body_enc;
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+"Unsupported transfer encoding \"%s\" - will be regarded as 8bit", s->c);
+ body_enc = mbfl_no_encoding_8bit;
+ break;
+ }
+ suppressed_hdrs.cnt_trans_enc = 1;
+ }
+
/* To: */
if (to == NULL || to_len <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing To: field");
@@ -2750,29 +3011,43 @@
}
/* other headers */
-#define PHP_MBSTR_MAIL_MIME_HEADER1 "Mime-Version: 1.0\nContent-Type: text/plain"
-#define PHP_MBSTR_MAIL_MIME_HEADER2 "; charset="
-#define PHP_MBSTR_MAIL_MIME_HEADER3 "\nContent-Transfer-Encoding: "
+#define PHP_MBSTR_MAIL_MIME_HEADER1 "Mime-Version: 1.0"
+#define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain"
+#define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset="
+#define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: "
if (headers != NULL) {
p = headers;
n = headers_len;
mbfl_memory_device_strncat(&device, p, n TSRMLS_CC);
- if (p[n - 1] != '\n') {
+ if (n > 0 && p[n - 1] != '\n') {
mbfl_memory_device_strncat(&device, "\n", 1 TSRMLS_CC);
}
}
+
mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1,
sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1 TSRMLS_CC);
- p = (char *)mbfl_no2preferred_mime_name(tran_cs);
- if (p != NULL) {
+ mbfl_memory_device_strncat(&device, "\n", 1 TSRMLS_CC);
+
+ if (!suppressed_hdrs.cnt_type) {
mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2,
sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1 TSRMLS_CC);
+
+ p = (char *)mbfl_no2preferred_mime_name(tran_cs);
+ if (p != NULL) {
+ mbfl_memory_device_strncat(&device,
+PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1 TSRMLS_CC);
+ mbfl_memory_device_strcat(&device, p TSRMLS_CC);
+ }
+ mbfl_memory_device_strncat(&device, "\n", 1 TSRMLS_CC);
+ }
+ if (!suppressed_hdrs.cnt_trans_enc) {
+ mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4,
+sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1 TSRMLS_CC);
+ p = (char *)mbfl_no2preferred_mime_name(body_enc);
+ if (p == NULL) {
+ p = "7bit";
+ }
mbfl_memory_device_strcat(&device, p TSRMLS_CC);
+ mbfl_memory_device_strncat(&device, "\n", 1 TSRMLS_CC);
}
- mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3,
sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1 TSRMLS_CC);
- p = (char *)mbfl_no2preferred_mime_name(body_enc);
- if (p == NULL) {
- p = "7bit";
- }
- mbfl_memory_device_strcat(&device, p TSRMLS_CC);
+
+ mbfl_memory_device_unput(&device TSRMLS_CC);
mbfl_memory_device_output('\0', &device TSRMLS_CC);
headers = (char *)device.buffer;
@@ -2789,7 +3064,15 @@
efree((void *)message_buf);
}
mbfl_memory_device_clear(&device TSRMLS_CC);
+ zend_hash_destroy(&ht_headers);
}
+
+#undef APPEND_ONE_CHAR
+#undef SEPARATE_SMART_STR
+#undef PHP_MBSTR_MAIL_MIME_HEADER1
+#undef PHP_MBSTR_MAIL_MIME_HEADER2
+#undef PHP_MBSTR_MAIL_MIME_HEADER3
+#undef PHP_MBSTR_MAIL_MIME_HEADER4
#else /* HAVE_SENDMAIL */
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php