Annotation of embedaddon/php/ext/standard/mail.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: Rasmus Lerdorf <rasmus@php.net> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: mail.c 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: #include <stdlib.h>
! 22: #include <ctype.h>
! 23: #include <stdio.h>
! 24: #include "php.h"
! 25: #include "ext/standard/info.h"
! 26: #include "ext/standard/php_string.h"
! 27: #include "ext/standard/basic_functions.h"
! 28:
! 29: #if HAVE_SYSEXITS_H
! 30: #include <sysexits.h>
! 31: #endif
! 32: #if HAVE_SYS_SYSEXITS_H
! 33: #include <sys/sysexits.h>
! 34: #endif
! 35:
! 36: #if PHP_SIGCHILD
! 37: #if HAVE_SIGNAL_H
! 38: #include <signal.h>
! 39: #endif
! 40: #endif
! 41:
! 42: #include "php_mail.h"
! 43: #include "php_ini.h"
! 44: #include "php_string.h"
! 45: #include "safe_mode.h"
! 46: #include "exec.h"
! 47:
! 48: #ifdef PHP_WIN32
! 49: #include "win32/sendmail.h"
! 50: #endif
! 51:
! 52: #ifdef NETWARE
! 53: #define EX_OK 0 /* successful termination */
! 54: #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
! 55: #endif
! 56:
! 57: #define SKIP_LONG_HEADER_SEP(str, pos) \
! 58: if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) { \
! 59: pos += 2; \
! 60: while (str[pos + 1] == ' ' || str[pos + 1] == '\t') { \
! 61: pos++; \
! 62: } \
! 63: continue; \
! 64: } \
! 65:
! 66: #define MAIL_ASCIIZ_CHECK(str, len) \
! 67: p = str; \
! 68: e = p + len; \
! 69: while ((p = memchr(p, '\0', (e - p)))) { \
! 70: *p = ' '; \
! 71: } \
! 72:
! 73: extern long php_getuid(void);
! 74:
! 75: /* {{{ proto int ezmlm_hash(string addr)
! 76: Calculate EZMLM list hash value. */
! 77: PHP_FUNCTION(ezmlm_hash)
! 78: {
! 79: char *str = NULL;
! 80: unsigned int h = 5381;
! 81: int j, str_len;
! 82:
! 83: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
! 84: return;
! 85: }
! 86:
! 87: for (j = 0; j < str_len; j++) {
! 88: h = (h + (h << 5)) ^ (unsigned long) (unsigned char) tolower(str[j]);
! 89: }
! 90:
! 91: h = (h % 53);
! 92:
! 93: RETURN_LONG((int) h);
! 94: }
! 95: /* }}} */
! 96:
! 97: /* {{{ proto int mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
! 98: Send an email message */
! 99: PHP_FUNCTION(mail)
! 100: {
! 101: char *to=NULL, *message=NULL, *headers=NULL, *headers_trimmed=NULL;
! 102: char *subject=NULL, *extra_cmd=NULL;
! 103: int to_len, message_len, headers_len = 0;
! 104: int subject_len, extra_cmd_len = 0, i;
! 105: char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
! 106: char *to_r, *subject_r;
! 107: char *p, *e;
! 108:
! 109: if (PG(safe_mode) && (ZEND_NUM_ARGS() == 5)) {
! 110: php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect. The fifth parameter is disabled in SAFE MODE");
! 111: RETURN_FALSE;
! 112: }
! 113:
! 114: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss", &to, &to_len, &subject, &subject_len, &message, &message_len,
! 115: &headers, &headers_len, &extra_cmd, &extra_cmd_len) == FAILURE
! 116: ) {
! 117: return;
! 118: }
! 119:
! 120: /* ASCIIZ check */
! 121: MAIL_ASCIIZ_CHECK(to, to_len);
! 122: MAIL_ASCIIZ_CHECK(subject, subject_len);
! 123: MAIL_ASCIIZ_CHECK(message, message_len);
! 124: if (headers) {
! 125: MAIL_ASCIIZ_CHECK(headers, headers_len);
! 126: headers_trimmed = php_trim(headers, headers_len, NULL, 0, NULL, 2 TSRMLS_CC);
! 127: }
! 128: if (extra_cmd) {
! 129: MAIL_ASCIIZ_CHECK(extra_cmd, extra_cmd_len);
! 130: }
! 131:
! 132: if (to_len > 0) {
! 133: to_r = estrndup(to, to_len);
! 134: for (; to_len; to_len--) {
! 135: if (!isspace((unsigned char) to_r[to_len - 1])) {
! 136: break;
! 137: }
! 138: to_r[to_len - 1] = '\0';
! 139: }
! 140: for (i = 0; to_r[i]; i++) {
! 141: if (iscntrl((unsigned char) to_r[i])) {
! 142: /* According to RFC 822, section 3.1.1 long headers may be separated into
! 143: * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
! 144: * To prevent these separators from being replaced with a space, we use the
! 145: * SKIP_LONG_HEADER_SEP to skip over them. */
! 146: SKIP_LONG_HEADER_SEP(to_r, i);
! 147: to_r[i] = ' ';
! 148: }
! 149: }
! 150: } else {
! 151: to_r = to;
! 152: }
! 153:
! 154: if (subject_len > 0) {
! 155: subject_r = estrndup(subject, subject_len);
! 156: for (; subject_len; subject_len--) {
! 157: if (!isspace((unsigned char) subject_r[subject_len - 1])) {
! 158: break;
! 159: }
! 160: subject_r[subject_len - 1] = '\0';
! 161: }
! 162: for (i = 0; subject_r[i]; i++) {
! 163: if (iscntrl((unsigned char) subject_r[i])) {
! 164: SKIP_LONG_HEADER_SEP(subject_r, i);
! 165: subject_r[i] = ' ';
! 166: }
! 167: }
! 168: } else {
! 169: subject_r = subject;
! 170: }
! 171:
! 172: if (force_extra_parameters) {
! 173: extra_cmd = php_escape_shell_cmd(force_extra_parameters);
! 174: } else if (extra_cmd) {
! 175: extra_cmd = php_escape_shell_cmd(extra_cmd);
! 176: }
! 177:
! 178: if (php_mail(to_r, subject_r, message, headers_trimmed, extra_cmd TSRMLS_CC)) {
! 179: RETVAL_TRUE;
! 180: } else {
! 181: RETVAL_FALSE;
! 182: }
! 183:
! 184: if (headers_trimmed) {
! 185: efree(headers_trimmed);
! 186: }
! 187:
! 188: if (extra_cmd) {
! 189: efree (extra_cmd);
! 190: }
! 191: if (to_r != to) {
! 192: efree(to_r);
! 193: }
! 194: if (subject_r != subject) {
! 195: efree(subject_r);
! 196: }
! 197: }
! 198: /* }}} */
! 199:
! 200: /* {{{ php_mail
! 201: */
! 202: PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC)
! 203: {
! 204: #if (defined PHP_WIN32 || defined NETWARE)
! 205: int tsm_err;
! 206: char *tsm_errmsg = NULL;
! 207: #endif
! 208: FILE *sendmail;
! 209: int ret;
! 210: char *sendmail_path = INI_STR("sendmail_path");
! 211: char *sendmail_cmd = NULL;
! 212: char *mail_log = INI_STR("mail.log");
! 213: char *hdr = headers;
! 214: #if PHP_SIGCHILD
! 215: void (*sig_handler)() = NULL;
! 216: #endif
! 217:
! 218: #define MAIL_RET(val) \
! 219: if (hdr != headers) { \
! 220: efree(hdr); \
! 221: } \
! 222: return val; \
! 223:
! 224: if (mail_log && *mail_log) {
! 225: char *tmp;
! 226: int l = spprintf(&tmp, 0, "mail() on [%s:%d]: To: %s -- Headers: %s\n", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), to, hdr ? hdr : "");
! 227: php_stream *stream = php_stream_open_wrapper(mail_log, "a", IGNORE_URL_WIN | REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR, NULL);
! 228:
! 229: if (hdr) { /* find all \r\n instances and replace them with spaces, so a log line is always one line long */
! 230: char *p = tmp;
! 231: while ((p = strpbrk(p, "\r\n"))) {
! 232: *p = ' ';
! 233: }
! 234: tmp[l - 1] = '\n';
! 235: }
! 236: if (stream) {
! 237: php_stream_write(stream, tmp, l);
! 238: php_stream_close(stream);
! 239: }
! 240: efree(tmp);
! 241: }
! 242: if (PG(mail_x_header)) {
! 243: char *tmp = zend_get_executed_filename(TSRMLS_C);
! 244: char *f;
! 245: size_t f_len;
! 246:
! 247: php_basename(tmp, strlen(tmp), NULL, 0,&f, &f_len TSRMLS_CC);
! 248:
! 249: if (headers != NULL) {
! 250: spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s\n%s", php_getuid(), f, headers);
! 251: } else {
! 252: spprintf(&hdr, 0, "X-PHP-Originating-Script: %ld:%s\n", php_getuid(), f);
! 253: }
! 254: efree(f);
! 255: }
! 256:
! 257: if (!sendmail_path) {
! 258: #if (defined PHP_WIN32 || defined NETWARE)
! 259: /* handle old style win smtp sending */
! 260: if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL TSRMLS_CC) == FAILURE) {
! 261: if (tsm_errmsg) {
! 262: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tsm_errmsg);
! 263: efree(tsm_errmsg);
! 264: } else {
! 265: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", GetSMErrorText(tsm_err));
! 266: }
! 267: MAIL_RET(0);
! 268: }
! 269: MAIL_RET(1);
! 270: #else
! 271: MAIL_RET(0);
! 272: #endif
! 273: }
! 274: if (extra_cmd != NULL) {
! 275: spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd);
! 276: } else {
! 277: sendmail_cmd = sendmail_path;
! 278: }
! 279:
! 280: #if PHP_SIGCHILD
! 281: /* Set signal handler of SIGCHLD to default to prevent other signal handlers
! 282: * from being called and reaping the return code when our child exits.
! 283: * The original handler needs to be restored after pclose() */
! 284: sig_handler = (void *)signal(SIGCHLD, SIG_DFL);
! 285: if (sig_handler == SIG_ERR) {
! 286: sig_handler = NULL;
! 287: }
! 288: #endif
! 289:
! 290: #ifdef PHP_WIN32
! 291: sendmail = popen(sendmail_cmd, "wb");
! 292: #else
! 293: /* Since popen() doesn't indicate if the internal fork() doesn't work
! 294: * (e.g. the shell can't be executed) we explicitely set it to 0 to be
! 295: * sure we don't catch any older errno value. */
! 296: errno = 0;
! 297: sendmail = popen(sendmail_cmd, "w");
! 298: #endif
! 299: if (extra_cmd != NULL) {
! 300: efree (sendmail_cmd);
! 301: }
! 302:
! 303: if (sendmail) {
! 304: #ifndef PHP_WIN32
! 305: if (EACCES == errno) {
! 306: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
! 307: pclose(sendmail);
! 308: #if PHP_SIGCHILD
! 309: /* Restore handler in case of error on Windows
! 310: Not sure if this applicable on Win but just in case. */
! 311: if (sig_handler) {
! 312: signal(SIGCHLD, sig_handler);
! 313: }
! 314: #endif
! 315: MAIL_RET(0);
! 316: }
! 317: #endif
! 318: fprintf(sendmail, "To: %s\n", to);
! 319: fprintf(sendmail, "Subject: %s\n", subject);
! 320: if (hdr != NULL) {
! 321: fprintf(sendmail, "%s\n", hdr);
! 322: }
! 323: fprintf(sendmail, "\n%s\n", message);
! 324: ret = pclose(sendmail);
! 325:
! 326: #if PHP_SIGCHILD
! 327: if (sig_handler) {
! 328: signal(SIGCHLD, sig_handler);
! 329: }
! 330: #endif
! 331:
! 332: #ifdef PHP_WIN32
! 333: if (ret == -1)
! 334: #else
! 335: #if defined(EX_TEMPFAIL)
! 336: if ((ret != EX_OK)&&(ret != EX_TEMPFAIL))
! 337: #elif defined(EX_OK)
! 338: if (ret != EX_OK)
! 339: #else
! 340: if (ret != 0)
! 341: #endif
! 342: #endif
! 343: {
! 344: MAIL_RET(0);
! 345: } else {
! 346: MAIL_RET(1);
! 347: }
! 348: } else {
! 349: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute mail delivery program '%s'", sendmail_path);
! 350: #if PHP_SIGCHILD
! 351: if (sig_handler) {
! 352: signal(SIGCHLD, sig_handler);
! 353: }
! 354: #endif
! 355: MAIL_RET(0);
! 356: }
! 357:
! 358: MAIL_RET(1); /* never reached */
! 359: }
! 360: /* }}} */
! 361:
! 362: /* {{{ PHP_MINFO_FUNCTION
! 363: */
! 364: PHP_MINFO_FUNCTION(mail)
! 365: {
! 366: char *sendmail_path = INI_STR("sendmail_path");
! 367:
! 368: #ifdef PHP_WIN32
! 369: if (!sendmail_path) {
! 370: php_info_print_table_row(2, "Internal Sendmail Support for Windows", "enabled");
! 371: } else {
! 372: php_info_print_table_row(2, "Path to sendmail", sendmail_path);
! 373: }
! 374: #else
! 375: php_info_print_table_row(2, "Path to sendmail", sendmail_path);
! 376: #endif
! 377: }
! 378: /* }}} */
! 379:
! 380: /*
! 381: * Local variables:
! 382: * tab-width: 4
! 383: * c-basic-offset: 4
! 384: * End:
! 385: * vim600: sw=4 ts=4 fdm=marker
! 386: * vim<600: sw=4 ts=4
! 387: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>