Return to mail.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */