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

Reply via email to