39#define SENDMAIL_DEBUG 0
48#define SMTP_ERROR_RESPONSE_SPEC "SMTP server response: %s"
52#define SMTP_ERROR_RESPONSE(response) { \
53 if (response && error_message) { \
54 *error_message = ecalloc(1, sizeof(SMTP_ERROR_RESPONSE_SPEC) + strlen(response)); \
55 snprintf(*error_message, sizeof(SMTP_ERROR_RESPONSE_SPEC) + strlen(response), SMTP_ERROR_RESPONSE_SPEC, response); \
59#define SMTP_SKIP_SPACE(str) { while (isspace(*str)) { str++; } }
66static char *ErrorMessages[] =
69 {
"Bad arguments from form"},
70 {
"Unable to open temporary mailfile for read"},
71 {
"Failed to Start Sockets"},
72 {
"Failed to Resolve Host"},
73 {
"Failed to obtain socket handle"},
74 {
"Failed to connect to mailserver, verify your \"SMTP\" setting in php.ini"},
76 {
"Failed to Receive"},
78 {
"Failed to resolve the host IP name"},
81 {
"Bad Message Contents"},
82 {
"Bad Message Subject"},
83 {
"Bad Message destination"},
84 {
"Bad Message Return Path"},
87 {
"\"sendmail_from\" not set in php.ini or custom \"From:\" header missing"},
88 {
"Mailserver rejected our \"sendmail_from\" setting"},
89 {
"Error while trimming mail header with PCRE, please file a bug report at https://github.com/php/php-src/issues"}
97#define PHP_WIN32_MAIL_UNIFY_PATTERN "/(\r\n?)|\n/"
98#define PHP_WIN32_MAIL_UNIFY_REPLACE "\r\n"
104#define PHP_WIN32_MAIL_RMVDBL_PATTERN "/^\r\n|(\r\n)+$/m"
105#define PHP_WIN32_MAIL_RMVDBL_REPLACE ""
111#define PHP_WIN32_MAIL_DOT_PATTERN "\n."
112#define PHP_WIN32_MAIL_DOT_REPLACE "\n.."
179 const char *headers,
const char *Subject,
const char *mailTo,
const char *
data,
180 char *mailCc,
char *mailBcc,
char *mailRPath)
185 const char *pos1 =
NULL, *pos2 =
NULL;
194 strcpy(
PW32G(mail_host), host);
201 if (
NULL == (headers_trim = php_win32_mail_trim_header(headers))) {
208 headers_lc = zend_string_tolower(headers_trim);
212 if (mailRPath && *mailRPath) {
214 }
else if (
INI_STR(
"sendmail_from")) {
216 }
else if (headers_lc) {
225 }
else if (pos1 !=
ZSTR_VAL(headers_lc) && *(pos1-1) !=
'\n') {
226 if (
strlen(pos1) >=
sizeof(
"from:")) {
227 lookup = pos1 +
sizeof(
"from:");
239 pos1 = headers + (pos1 -
lookup) + 5;
243 RPath =
estrndup(pos1, pos2 - pos1);
251 zend_string_release(headers_trim);
252 zend_string_release(headers_lc);
260 *
error = MailConnect();
266 zend_string_release(headers_trim);
267 zend_string_release(headers_lc);
272 "Failed to connect to mailserver at \"%s\" port " ZEND_ULONG_FMT ", verify your \"SMTP\" "
273 "and \"smtp_port\" setting in php.ini or use ini_set()",
277 ret = SendText(RPath, Subject, mailTo, mailCc, mailBcc,
data, headers ?
ZSTR_VAL(headers_trim) :
NULL, headers ?
ZSTR_VAL(headers_lc) :
NULL, error_message);
283 zend_string_release(headers_trim);
284 zend_string_release(headers_lc);
327 return (ErrorMessages[index]);
336static char *find_address(
char *list,
char **
state)
349 if (*
p ==
'\\' && in_quotes) {
355 }
else if (*
p ==
'"') {
356 in_quotes = !in_quotes;
357 }
else if (*
p ==
',' && !in_quotes) {
385static int SendText(
char *RPath,
const char *Subject,
const char *mailTo,
char *mailCc,
char *mailBcc,
const char *
data,
386 const char *headers,
char *headers_lc,
char **error_message)
390 char *tempMailTo, *token, *token_state;
391 const char *pos1, *pos2;
392 char *server_response =
NULL;
393 char *stripped_header =
NULL;
418 int err = MailConnect();
433 FormatEmailAddress(
PW32G(mail_buffer), RPath,
"MAIL FROM:<%s>\r\n");
444 token = find_address(tempMailTo, &token_state);
445 while (token !=
NULL)
448 FormatEmailAddress(
PW32G(mail_buffer), token,
"RCPT TO:<%s>\r\n");
458 token = find_address(
NULL, &token_state);
462 if (mailCc && *mailCc) {
465 token = find_address(tempMailTo, &token_state);
466 while (token !=
NULL)
469 FormatEmailAddress(
PW32G(mail_buffer), token,
"RCPT TO:<%s>\r\n");
479 token = find_address(
NULL, &token_state);
484 else if (headers && (pos1 =
strstr(headers_lc,
"cc:")) && ((pos1 == headers_lc) || (*(pos1-1) ==
'\n'))) {
488 pos1 = headers + (pos1 - headers_lc) + 3;
493 while (pos2[2] ==
' ' || pos2[2] ==
'\t') {
494 pos3 =
strstr(pos2 + 2,
"\r\n");
502 tempMailTo =
estrndup(pos1, pos2 - pos1);
505 token = find_address(tempMailTo, &token_state);
506 while (token !=
NULL)
509 FormatEmailAddress(
PW32G(mail_buffer), token,
"RCPT TO:<%s>\r\n");
519 token = find_address(
NULL,&token_state);
527 if (mailBcc && *mailBcc) {
530 token = find_address(tempMailTo, &token_state);
531 while (token !=
NULL)
534 FormatEmailAddress(
PW32G(mail_buffer), token,
"RCPT TO:<%s>\r\n");
544 token = find_address(
NULL, &token_state);
549 if ((pos1 =
strstr(headers_lc,
"bcc:")) && (pos1 == headers_lc || *(pos1-1) ==
'\n')) {
553 pos1 = headers + (pos1 - headers_lc) + 4;
560 const char *pos3 = pos2;
561 while (pos2[2] ==
' ' || pos2[2] ==
'\t') {
562 pos3 =
strstr(pos2 + 2,
"\r\n");
570 tempMailTo =
estrndup(pos1, pos2 - pos1);
578 token = find_address(tempMailTo, &token_state);
579 while (token !=
NULL)
582 FormatEmailAddress(
PW32G(mail_buffer), token,
"RCPT TO:<%s>\r\n");
592 token = find_address(
NULL, &token_state);
604 memcpy(stripped_header, headers, pos1 - headers - 4);
610 memcpy(stripped_header + (pos1 - headers - 4), pos2 + 2,
strlen(pos2) - 2);
617 if (headers && !stripped_header) {
622 if (stripped_header) {
623 efree(stripped_header);
629 if (stripped_header) {
630 efree(stripped_header);
636 if (Subject ==
NULL) {
637 res = PostHeader(RPath,
"No Subject", mailTo, stripped_header);
639 res = PostHeader(RPath, Subject, mailTo, stripped_header);
641 if (stripped_header) {
642 efree(stripped_header);
662 while (e -
p > 1024) {
667 zend_string_free(data_cln);
674 zend_string_free(data_cln);
679 zend_string_free(data_cln);
692static int addToHeader(
char **header_buffer,
const char *specifier,
const char *
string)
694 size_t header_buffer_size =
strlen(*header_buffer);
695 size_t total_size = header_buffer_size +
strlen(specifier) +
strlen(
string) + 1;
696 *header_buffer =
erealloc(*header_buffer, total_size);
697 snprintf(*header_buffer + header_buffer_size, total_size - header_buffer_size, specifier,
string);
712static int PostHeader(
char *RPath,
const char *Subject,
const char *mailTo,
char *xheaders)
719 char *headers_lc =
NULL;
723 size_t headers_lc_len;
725 headers_lc =
estrdup(xheaders);
726 headers_lc_len =
strlen(headers_lc);
728 for (i = 0; i < headers_lc_len; i++) {
729 headers_lc[i] = tolower(headers_lc[i]);
735 if (!xheaders || !
strstr(headers_lc,
"date:")) {
740 zend_string_free(dt);
743 if (!headers_lc || !
strstr(headers_lc,
"from:")) {
744 if (!addToHeader(&header_buffer,
"From: %s\r\n", RPath)) {
745 goto PostHeader_outofmem;
748 if (!addToHeader(&header_buffer,
"Subject: %s\r\n", Subject)) {
749 goto PostHeader_outofmem;
753 if ((headers_lc && (!
strstr(headers_lc,
"\r\nto:") && (
strncmp(headers_lc,
"to:", 3) != 0))) || !headers_lc) {
754 if (!addToHeader(&header_buffer,
"To: %s\r\n", mailTo)) {
755 goto PostHeader_outofmem;
759 if (!addToHeader(&header_buffer,
"%s\r\n", xheaders)) {
760 goto PostHeader_outofmem;
768 efree(header_buffer);
771 efree(header_buffer);
796static int MailConnect()
843 strcpy(
PW32G(mail_local_host),
"[");
844 strcpy(
PW32G(mail_local_host) + 1, ent->h_name);
852 strcpy(
PW32G(mail_local_host), ent->h_name);
863 portnum = (short)
INI_INT(
"smtp_port");
870 sock_in.sin_port = htons(portnum);
871 sock_in.sin_addr.S_un.S_addr = GetAddr(
PW32G(mail_host));
873 if (connect(
PW32G(mail_socket), (LPSOCKADDR) & sock_in,
sizeof(sock_in))) {
892static int Post(LPCSTR
msg)
905 if ((slen = send(
PW32G(mail_socket),
msg + index,
len, 0)) < 1)
925static int Ack(
char **server_response)
950 if (Received < 5 ||
buf[Received - 1] !=
'\n' ||
buf[Received - 2] !=
'\r') {
956 if (server_response) {
960 if (
buf[Received-1] ==
'\n' ||
buf[Received-1] ==
'\r') {
962 if (
buf[Received-2] ==
'\r' ||
buf[Received-2] ==
'\n') {
989static unsigned long GetAddr(LPSTR szHost)
992 u_long lAddr = INADDR_ANY;
998 lAddr = inet_addr(szHost);
1005 lAddr = *((u_long
FAR *) (lpstHost->h_addr));
1015static char *get_angle_addr(
char *address)
1018 char *p1 = address, *p2;
1021 if (*p1 ==
'\\' && in_quotes) {
1022 if (p1[1] ==
'\0') {
1027 }
else if (*p1 ==
'"') {
1028 in_quotes = !in_quotes;
1029 }
else if (*p1 ==
'<' && !in_quotes) {
1037 if (*p2 ==
'\\' && in_quotes) {
1038 if (p2[1] ==
'\0') {
1043 }
else if (*p2 ==
'"') {
1044 in_quotes = !in_quotes;
1045 }
else if (*p2 ==
'>' && !in_quotes) {
1068static int FormatEmailAddress(
char* Buf,
char* EmailAddress,
char* FormatString) {
1072 if ((tmpAddress = get_angle_addr(EmailAddress)) !=
NULL) {
printf(string $format, mixed ... $values)
strpbrk(string $string, string $characters)
header(string $header, bool $replace=true, int $response_code=0)
gethostbyname(string $hostname)
strstr(string $haystack, string $needle, bool $before_needle=false)
zend_ffi_ctype_name_buf buf
PHPAPI zend_string * php_format_date(const char *format, size_t format_len, time_t ts, bool localtime)
unsigned const char * pos
PHPAPI zend_string * php_pcre_replace(zend_string *regex, zend_string *subject_str, const char *subject, size_t subject_len, zend_string *replace_str, size_t limit, size_t *replace_count)
PHPAPI zend_string * php_str_to_str(const char *haystack, size_t length, const char *needle, size_t needle_len, const char *str, size_t str_len)
PHPAPI void TSMClose(void)
#define PHP_WIN32_MAIL_DOT_PATTERN
#define PHP_WIN32_MAIL_DOT_REPLACE
#define PHP_WIN32_MAIL_RMVDBL_PATTERN
#define PHP_WIN32_MAIL_UNIFY_PATTERN
PHPAPI char * GetSMErrorText(int index)
PHPAPI int TSendMail(const char *host, int *error, char **error_message, const char *headers, const char *Subject, const char *mailTo, const char *data, char *mailCc, char *mailBcc, char *mailRPath)
#define SMTP_ERROR_RESPONSE(response)
#define SMTP_SKIP_SPACE(str)
#define PHP_WIN32_MAIL_UNIFY_REPLACE
#define W32_SM_PCRE_ERROR
#define FAILED_TO_GET_HOSTNAME
#define FAILED_TO_RECEIVE
#define FAILED_TO_CONNECT
#define W32_SM_SENDMAIL_FROM_MALFORMED
#define W32_SM_SENDMAIL_FROM_NOT_SET
#define FAILED_TO_OBTAIN_SOCKET_HANDLE
#define BAD_MSG_DESTINATION
#define SMTP_SERVER_ERROR
#define estrndup(s, length)
#define ecalloc(nmemb, size)
#define erealloc(ptr, size)
strncmp(string $string1, string $string2, int $length)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
struct _zend_string zend_string
#define ZSTR_EMPTY_ALLOC()