Annotation of embedaddon/php/win32/sendmail.c, revision 1.1

1.1     ! misho       1: /* 
        !             2:  *    PHP Sendmail for Windows.
        !             3:  *
        !             4:  *  This file is rewriten specificly for PHPFI.  Some functionality
        !             5:  *  has been removed (MIME and file attachments).  This code was 
        !             6:  *  modified from code based on code writen by Jarle Aase.
        !             7:  *
        !             8:  *  This class is based on the original code by Jarle Aase, see bellow:
        !             9:  *  wSendmail.cpp  It has been striped of some functionality to match
        !            10:  *  the requirements of phpfi.
        !            11:  *
        !            12:  *  Very simple SMTP Send-mail program for sending command-line level
        !            13:  *  emails and CGI-BIN form response for the Windows platform.
        !            14:  *
        !            15:  *  The complete wSendmail package with source code can be located
        !            16:  *  from http://www.jgaa.com
        !            17:  *
        !            18:  */
        !            19: 
        !            20: /* $Id: sendmail.c 287783 2009-08-26 21:59:54Z pajoye $ */
        !            21: 
        !            22: #include "php.h"                               /*php specific */
        !            23: #include <stdio.h>
        !            24: #include <stdlib.h>
        !            25: #ifndef NETWARE
        !            26: #include <winsock2.h>
        !            27: #include "time.h"
        !            28: #else  /* NETWARE */
        !            29: #include <netware/sendmail_nw.h>
        !            30: #endif /* NETWARE */
        !            31: #include <string.h>
        !            32: #include <math.h>
        !            33: #ifndef NETWARE
        !            34: #include <malloc.h>
        !            35: #include <memory.h>
        !            36: #include <winbase.h>
        !            37: #endif /* NETWARE */
        !            38: #include "sendmail.h"
        !            39: #include "php_ini.h"
        !            40: #include "inet.h"
        !            41: 
        !            42: #if HAVE_PCRE || HAVE_BUNDLED_PCRE
        !            43: #include "ext/pcre/php_pcre.h"
        !            44: #endif
        !            45: 
        !            46: #include "ext/standard/php_string.h"
        !            47: #include "ext/date/php_date.h"
        !            48: 
        !            49: /*enum
        !            50:    {
        !            51:    DO_CONNECT = WM_USER +1
        !            52:    };
        !            53:  */
        !            54: 
        !            55: /* '*error_message' has to be passed around from php_mail() */
        !            56: #define SMTP_ERROR_RESPONSE_SPEC       "SMTP server response: %s"
        !            57: /* Convinient way to handle error messages from the SMTP server.
        !            58:    response is ecalloc()d in Ack() itself and efree()d here
        !            59:    because the content is in *error_message now */
        !            60: #define SMTP_ERROR_RESPONSE(response)  { \
        !            61:                                                                                        if (response && error_message) { \
        !            62:                                                                                                if (NULL != (*error_message = ecalloc(1, sizeof(SMTP_ERROR_RESPONSE_SPEC) + strlen(response)))) { \
        !            63:                                                                                                        snprintf(*error_message, sizeof(SMTP_ERROR_RESPONSE_SPEC) + strlen(response), SMTP_ERROR_RESPONSE_SPEC, response); \
        !            64:                                                                                                } \
        !            65:                                                                                                efree(response); \
        !            66:                                                                                        } \
        !            67:                                                                                }
        !            68: #define SMTP_SKIP_SPACE(str)   { while (isspace(*str)) { str++; } }
        !            69: 
        !            70: 
        !            71: #ifndef THREAD_SAFE
        !            72: char Buffer[MAIL_BUFFER_SIZE];
        !            73: 
        !            74: /* socket related data */
        !            75: SOCKET sc;
        !            76: #ifndef NETWARE
        !            77: WSADATA Data;
        !            78: struct hostent *adr;
        !            79: int WinsockStarted;
        !            80: /* values set by the constructor */
        !            81: char *AppName;
        !            82: #endif /* NETWARE */
        !            83: SOCKADDR_IN sock_in;
        !            84: char MailHost[HOST_NAME_LEN];
        !            85: char LocalHost[HOST_NAME_LEN];
        !            86: #endif
        !            87: char seps[] = " ,\t\n";
        !            88: #ifndef NETWARE
        !            89: char *php_mailer = "PHP 5 WIN32";
        !            90: #else
        !            91: char *php_mailer = "PHP 5 NetWare";
        !            92: #endif /* NETWARE */
        !            93: 
        !            94: /* Error messages */
        !            95: static char *ErrorMessages[] =
        !            96: {
        !            97:        {"Success"}, /* 0 */
        !            98:        {"Bad arguments from form"}, /* 1 */
        !            99:        {"Unable to open temporary mailfile for read"},
        !           100:        {"Failed to Start Sockets"},
        !           101:        {"Failed to Resolve Host"},
        !           102:        {"Failed to obtain socket handle"}, /* 5 */
        !           103:        {"Failed to connect to mailserver, verify your \"SMTP\" setting in php.ini"},
        !           104:        {"Failed to Send"},
        !           105:        {"Failed to Receive"},
        !           106:        {"Server Error"},
        !           107:        {"Failed to resolve the host IP name"}, /* 10 */
        !           108:        {"Out of memory"},
        !           109:        {"Unknown error"},
        !           110:        {"Bad Message Contents"},
        !           111:        {"Bad Message Subject"},
        !           112:        {"Bad Message destination"}, /* 15 */
        !           113:        {"Bad Message Return Path"},
        !           114:        {"Bad Mail Host"},
        !           115:        {"Bad Message File"},
        !           116:        {"\"sendmail_from\" not set in php.ini or custom \"From:\" header missing"},
        !           117:        {"Mailserver rejected our \"sendmail_from\" setting"}, /* 20 */
        !           118:        {"Error while trimming mail header with PCRE, please file a bug report at http://bugs.php.net/"} /* 21 */
        !           119: };
        !           120: 
        !           121: /* This pattern converts all single occurences of \n (Unix)
        !           122:  * withour a leading \r to \r\n and all occurences of \r (Mac)
        !           123:  * without a trailing \n to \r\n
        !           124:  * Thx to Nibbler from ircnet/#linuxger
        !           125:  */
        !           126: #define PHP_WIN32_MAIL_UNIFY_PATTERN   "/(\r\n?)|\n/"
        !           127: #define PHP_WIN32_MAIL_UNIFY_REPLACE   "\r\n"
        !           128: 
        !           129: /* This pattern removes \r\n from the start of the string,
        !           130:  * \r\n from the end of the string and also makes sure every line
        !           131:  * is only wrapped with a single \r\n (thus reduces multiple
        !           132:  * occurences of \r\n between lines to a single \r\n) */
        !           133: #define PHP_WIN32_MAIL_RMVDBL_PATTERN  "/^\r\n|(\r\n)+$/m"
        !           134: #define PHP_WIN32_MAIL_RMVDBL_REPLACE  ""
        !           135: 
        !           136: /* This pattern escapes \n. inside the message body. It prevents
        !           137:  * premature end of message if \n.\n or \r\n.\r\n is encountered
        !           138:  * and ensures that \n. sequences are properly displayed in the
        !           139:  * message body. */
        !           140: #define PHP_WIN32_MAIL_DOT_PATTERN     "\n."
        !           141: #define PHP_WIN32_MAIL_DOT_REPLACE     "\n.."
        !           142: 
        !           143: /* This function is meant to unify the headers passed to to mail()
        !           144:  * This means, use PCRE to transform single occurences of \n or \r in \r\n
        !           145:  * As a second step we also eleminate all \r\n occurences which are:
        !           146:  * 1) At the start of the header
        !           147:  * 2) At the end of the header
        !           148:  * 3) Two or more occurences in the header are removed so only one is left
        !           149:  *
        !           150:  * Returns NULL on error, or the new char* buffer on success.
        !           151:  * You have to take care and efree() the buffer on your own.
        !           152:  */
        !           153: static char *php_win32_mail_trim_header(char *header TSRMLS_DC)
        !           154: {
        !           155: 
        !           156: #if HAVE_PCRE || HAVE_BUNDLED_PCRE
        !           157:        
        !           158:        char *result, *result2;
        !           159:        int result_len;
        !           160:        zval *replace;
        !           161: 
        !           162:        if (!header) {
        !           163:                return NULL;
        !           164:        }
        !           165: 
        !           166:        MAKE_STD_ZVAL(replace);
        !           167:        ZVAL_STRING(replace, PHP_WIN32_MAIL_UNIFY_REPLACE, 0);
        !           168: 
        !           169:        result = php_pcre_replace(PHP_WIN32_MAIL_UNIFY_PATTERN, sizeof(PHP_WIN32_MAIL_UNIFY_PATTERN)-1,
        !           170:                                                          header, strlen(header),
        !           171:                                                          replace,
        !           172:                                                          0,
        !           173:                                                          &result_len,
        !           174:                                                          -1,
        !           175:                                                          NULL TSRMLS_CC);
        !           176:        if (NULL == result) {
        !           177:                FREE_ZVAL(replace);
        !           178:                return NULL;
        !           179:        }
        !           180: 
        !           181:        ZVAL_STRING(replace, PHP_WIN32_MAIL_RMVDBL_REPLACE, 0);
        !           182: 
        !           183:        result2 = php_pcre_replace(PHP_WIN32_MAIL_RMVDBL_PATTERN, sizeof(PHP_WIN32_MAIL_RMVDBL_PATTERN)-1,
        !           184:                                                           result, result_len,
        !           185:                                                           replace,
        !           186:                                                           0,
        !           187:                                                           &result_len,
        !           188:                                                           -1,
        !           189:                                                           NULL TSRMLS_CC);
        !           190:        efree(result);
        !           191:        FREE_ZVAL(replace);
        !           192:        return result2;
        !           193: #else
        !           194:        /* In case we don't have PCRE support (for whatever reason...) simply do nothing and return the unmodified header */
        !           195:        return estrdup(header);
        !           196: #endif
        !           197: }
        !           198: 
        !           199: /*********************************************************************
        !           200: // Name:  TSendMail
        !           201: // Input:   1) host:    Name of the mail host where the SMTP server resides
        !           202: //                      max accepted length of name = 256
        !           203: //          2) appname: Name of the application to use in the X-mailer
        !           204: //                      field of the message. if NULL is given the application
        !           205: //                      name is used as given by the GetCommandLine() function
        !           206: //                      max accespted length of name = 100
        !           207: // Output:  1) error:   Returns the error code if something went wrong or
        !           208: //                      SUCCESS otherwise.
        !           209: //
        !           210: //  See SendText() for additional args!
        !           211: //********************************************************************/
        !           212: PHPAPI int TSendMail(char *host, int *error, char **error_message,
        !           213:                          char *headers, char *Subject, char *mailTo, char *data,
        !           214:                          char *mailCc, char *mailBcc, char *mailRPath TSRMLS_DC)
        !           215: {
        !           216:        int ret;
        !           217:        char *RPath = NULL;
        !           218:        char *headers_lc = NULL; /* headers_lc is only created if we've a header at all */
        !           219:        char *pos1 = NULL, *pos2 = NULL;
        !           220: 
        !           221: #ifndef NETWARE
        !           222:        WinsockStarted = FALSE;
        !           223: #endif
        !           224: 
        !           225:        if (host == NULL) {
        !           226:                *error = BAD_MAIL_HOST;
        !           227:                return FAILURE;
        !           228:        } else if (strlen(host) >= HOST_NAME_LEN) {
        !           229:                *error = BAD_MAIL_HOST;
        !           230:                return FAILURE;
        !           231:        } else {
        !           232:                strcpy(MailHost, host);
        !           233:        }
        !           234: 
        !           235:        if (headers) {
        !           236:                char *pos = NULL;
        !           237:                size_t i;
        !           238: 
        !           239:                /* Use PCRE to trim the header into the right format */
        !           240:                if (NULL == (headers = php_win32_mail_trim_header(headers TSRMLS_CC))) {
        !           241:                        *error = W32_SM_PCRE_ERROR;
        !           242:                        return FAILURE;
        !           243:                }
        !           244: 
        !           245:                /* Create a lowercased header for all the searches so we're finally case
        !           246:                 * insensitive when searching for a pattern. */
        !           247:                if (NULL == (headers_lc = estrdup(headers))) {
        !           248:                        efree(headers);
        !           249:                        *error = OUT_OF_MEMORY;
        !           250:                        return FAILURE;
        !           251:                }
        !           252:                for (i = 0; i < strlen(headers_lc); i++) {
        !           253:                        headers_lc[i] = tolower(headers_lc[i]);
        !           254:                }
        !           255:        }
        !           256:  
        !           257:        /* Fall back to sendmail_from php.ini setting */
        !           258:        if (mailRPath && *mailRPath) {
        !           259:                RPath = estrdup(mailRPath);
        !           260:        } else if (INI_STR("sendmail_from")) {
        !           261:                RPath = estrdup(INI_STR("sendmail_from"));
        !           262:        } else if (     headers_lc &&
        !           263:                                (pos1 = strstr(headers_lc, "from:")) &&
        !           264:                                ((pos1 == headers_lc) || (*(pos1-1) == '\n'))
        !           265:        ) {
        !           266:                /* Real offset is memaddress from the original headers + difference of
        !           267:                 * string found in the lowercase headrs + 5 characters to jump over   
        !           268:                 * the from: */
        !           269:                pos1 = headers + (pos1 - headers_lc) + 5;
        !           270:                if (NULL == (pos2 = strstr(pos1, "\r\n"))) {
        !           271:                        RPath = estrndup(pos1, strlen(pos1));
        !           272:                } else {
        !           273:                        RPath = estrndup(pos1, pos2 - pos1);
        !           274:                }
        !           275:        } else {
        !           276:                if (headers) {
        !           277:                        efree(headers);
        !           278:                        efree(headers_lc);
        !           279:                }
        !           280:                *error = W32_SM_SENDMAIL_FROM_NOT_SET;
        !           281:                return FAILURE;
        !           282:        }
        !           283: 
        !           284:        /* attempt to connect with mail host */
        !           285:        *error = MailConnect();
        !           286:        if (*error != 0) {
        !           287:                if (RPath) {
        !           288:                        efree(RPath);
        !           289:                }
        !           290:                if (headers) {
        !           291:                        efree(headers);
        !           292:                        efree(headers_lc);
        !           293:                }
        !           294:                /* 128 is safe here, the specifier in snprintf isn't longer than that */
        !           295:                if (NULL == (*error_message = ecalloc(1, HOST_NAME_LEN + 128))) {
        !           296:                        return FAILURE;
        !           297:                }
        !           298:                snprintf(*error_message, HOST_NAME_LEN + 128,
        !           299:                        "Failed to connect to mailserver at \"%s\" port %d, verify your \"SMTP\" "
        !           300:                        "and \"smtp_port\" setting in php.ini or use ini_set()",
        !           301:                        MailHost, !INI_INT("smtp_port") ? 25 : INI_INT("smtp_port"));
        !           302:                return FAILURE;
        !           303:        } else {
        !           304:                ret = SendText(RPath, Subject, mailTo, mailCc, mailBcc, data, headers, headers_lc, error_message TSRMLS_CC);
        !           305:                TSMClose();
        !           306:                if (RPath) {
        !           307:                        efree(RPath);
        !           308:                }
        !           309:                if (headers) {
        !           310:                        efree(headers);
        !           311:                        efree(headers_lc);
        !           312:                }
        !           313:                if (ret != SUCCESS) {
        !           314:                        *error = ret;
        !           315:                        return FAILURE;
        !           316:                }
        !           317:                return SUCCESS;
        !           318:        }
        !           319: }
        !           320: 
        !           321: //********************************************************************
        !           322: // Name:  TSendMail::~TSendMail
        !           323: // Input:
        !           324: // Output:
        !           325: // Description: DESTRUCTOR
        !           326: // Author/Date:  jcar 20/9/96
        !           327: // History:
        !           328: //********************************************************************/
        !           329: PHPAPI void TSMClose()
        !           330: {
        !           331:        Post("QUIT\r\n");
        !           332:        Ack(NULL);
        !           333:        /* to guarantee that the cleanup is not made twice and 
        !           334:           compomise the rest of the application if sockets are used
        !           335:           elesewhere 
        !           336:        */
        !           337: 
        !           338:        shutdown(sc, 0); 
        !           339:        closesocket(sc);
        !           340: }
        !           341: 
        !           342: 
        !           343: /*********************************************************************
        !           344: // Name:  char *GetSMErrorText
        !           345: // Input:   Error index returned by the menber functions
        !           346: // Output:  pointer to a string containing the error description
        !           347: // Description:
        !           348: // Author/Date:  jcar 20/9/96
        !           349: // History:
        !           350: //*******************************************************************/
        !           351: PHPAPI char *GetSMErrorText(int index)
        !           352: {
        !           353:        if (MIN_ERROR_INDEX <= index && index < MAX_ERROR_INDEX) {
        !           354:                return (ErrorMessages[index]);
        !           355: 
        !           356:        } else {
        !           357:                return (ErrorMessages[UNKNOWN_ERROR]);
        !           358: 
        !           359:        }
        !           360: }
        !           361: 
        !           362: 
        !           363: /*********************************************************************
        !           364: // Name:  SendText
        !           365: // Input:       1) RPath:   return path of the message
        !           366: //                                  Is used to fill the "Return-Path" and the
        !           367: //                                  "X-Sender" fields of the message.
        !           368: //                  2) Subject: Subject field of the message. If NULL is given
        !           369: //                                  the subject is set to "No Subject"
        !           370: //                  3) mailTo:  Destination address
        !           371: //                  4) data:        Null terminated string containing the data to be send.
        !           372: //                  5,6) headers of the message. Note that the second
        !           373: //                  parameter, headers_lc, is actually a lowercased version of
        !           374: //                  headers. The should match exactly (in terms of length),
        !           375: //                  only differ in case
        !           376: // Output:      Error code or SUCCESS
        !           377: // Description:
        !           378: // Author/Date:  jcar 20/9/96
        !           379: // History:
        !           380: //*******************************************************************/
        !           381: static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char *mailBcc, char *data, 
        !           382:                         char *headers, char *headers_lc, char **error_message TSRMLS_DC)
        !           383: {
        !           384:        int res;
        !           385:        char *p;
        !           386:        char *tempMailTo, *token, *pos1, *pos2;
        !           387:        char *server_response = NULL;
        !           388:        char *stripped_header  = NULL;
        !           389:        char *data_cln;
        !           390:        int data_cln_len;
        !           391: 
        !           392:        /* check for NULL parameters */
        !           393:        if (data == NULL)
        !           394:                return (BAD_MSG_CONTENTS);
        !           395:        if (mailTo == NULL)
        !           396:                return (BAD_MSG_DESTINATION);
        !           397:        if (RPath == NULL)
        !           398:                return (BAD_MSG_RPATH);
        !           399: 
        !           400:        /* simple checks for the mailto address */
        !           401:        /* have ampersand ? */
        !           402:        /* mfischer, 20020514: I commented this out because it really
        !           403:           seems bogus. Only a username for example may still be a
        !           404:           valid address at the destination system.
        !           405:        if (strchr(mailTo, '@') == NULL)
        !           406:                return (BAD_MSG_DESTINATION);
        !           407:        */
        !           408: 
        !           409:        snprintf(Buffer, sizeof(Buffer), "HELO %s\r\n", LocalHost);
        !           410: 
        !           411:        /* in the beggining of the dialog */
        !           412:        /* attempt reconnect if the first Post fail */
        !           413:        if ((res = Post(Buffer)) != SUCCESS) {
        !           414:                MailConnect();
        !           415:                if ((res = Post(Buffer)) != SUCCESS) {
        !           416:                        return (res);
        !           417:                }
        !           418:        }
        !           419:        if ((res = Ack(&server_response)) != SUCCESS) {
        !           420:                SMTP_ERROR_RESPONSE(server_response);
        !           421:                return (res);
        !           422:        }
        !           423: 
        !           424:        SMTP_SKIP_SPACE(RPath);
        !           425:        FormatEmailAddress(Buffer, RPath, "MAIL FROM:<%s>\r\n");
        !           426:        if ((res = Post(Buffer)) != SUCCESS) {
        !           427:                return (res);
        !           428:        }
        !           429:        if ((res = Ack(&server_response)) != SUCCESS) {
        !           430:                SMTP_ERROR_RESPONSE(server_response);
        !           431:                return W32_SM_SENDMAIL_FROM_MALFORMED;
        !           432:        }
        !           433: 
        !           434:        tempMailTo = estrdup(mailTo);
        !           435:        /* Send mail to all rcpt's */
        !           436:        token = strtok(tempMailTo, ",");
        !           437:        while (token != NULL)
        !           438:        {
        !           439:                SMTP_SKIP_SPACE(token);
        !           440:                FormatEmailAddress(Buffer, token, "RCPT TO:<%s>\r\n");
        !           441:                if ((res = Post(Buffer)) != SUCCESS) {
        !           442:                        efree(tempMailTo);
        !           443:                        return (res);
        !           444:                }
        !           445:                if ((res = Ack(&server_response)) != SUCCESS) {
        !           446:                        SMTP_ERROR_RESPONSE(server_response);
        !           447:                        efree(tempMailTo);
        !           448:                        return (res);
        !           449:                }
        !           450:                token = strtok(NULL, ",");
        !           451:        }
        !           452:        efree(tempMailTo);
        !           453: 
        !           454:        if (mailCc && *mailCc) {
        !           455:                tempMailTo = estrdup(mailCc);
        !           456:                /* Send mail to all rcpt's */
        !           457:                token = strtok(tempMailTo, ",");
        !           458:                while (token != NULL)
        !           459:                {
        !           460:                        SMTP_SKIP_SPACE(token);
        !           461:                        FormatEmailAddress(Buffer, token, "RCPT TO:<%s>\r\n");
        !           462:                        if ((res = Post(Buffer)) != SUCCESS) {
        !           463:                                efree(tempMailTo);
        !           464:                                return (res);
        !           465:                        }
        !           466:                        if ((res = Ack(&server_response)) != SUCCESS) {
        !           467:                                SMTP_ERROR_RESPONSE(server_response);
        !           468:                                efree(tempMailTo);
        !           469:                                return (res);
        !           470:                        }
        !           471:                        token = strtok(NULL, ",");
        !           472:                }
        !           473:                efree(tempMailTo);
        !           474:        }
        !           475:        /* Send mail to all Cc rcpt's */
        !           476:        else if (headers && (pos1 = strstr(headers_lc, "cc:")) && ((pos1 == headers_lc) || (*(pos1-1) == '\n'))) {
        !           477:                /* Real offset is memaddress from the original headers + difference of
        !           478:                 * string found in the lowercase headrs + 3 characters to jump over
        !           479:                 * the cc: */
        !           480:                pos1 = headers + (pos1 - headers_lc) + 3;
        !           481:                if (NULL == (pos2 = strstr(pos1, "\r\n"))) {
        !           482:                        tempMailTo = estrndup(pos1, strlen(pos1));
        !           483:                } else {
        !           484:                        tempMailTo = estrndup(pos1, pos2 - pos1);
        !           485:                }
        !           486: 
        !           487:                token = strtok(tempMailTo, ",");
        !           488:                while (token != NULL)
        !           489:                {
        !           490:                        SMTP_SKIP_SPACE(token);
        !           491:                        FormatEmailAddress(Buffer, token, "RCPT TO:<%s>\r\n");
        !           492:                        if ((res = Post(Buffer)) != SUCCESS) {
        !           493:                                efree(tempMailTo);
        !           494:                                return (res);
        !           495:                        }
        !           496:                        if ((res = Ack(&server_response)) != SUCCESS) {
        !           497:                                SMTP_ERROR_RESPONSE(server_response);
        !           498:                                efree(tempMailTo);
        !           499:                                return (res);
        !           500:                        }
        !           501:                        token = strtok(NULL, ",");
        !           502:                }
        !           503:                efree(tempMailTo);
        !           504:        }
        !           505: 
        !           506:        /* Send mail to all Bcc rcpt's
        !           507:           This is basically a rip of the Cc code above.
        !           508:           Just don't forget to remove the Bcc: from the header afterwards. */
        !           509:        if (mailBcc && *mailBcc) {
        !           510:                tempMailTo = estrdup(mailBcc);
        !           511:                /* Send mail to all rcpt's */
        !           512:                token = strtok(tempMailTo, ",");
        !           513:                while (token != NULL)
        !           514:                {
        !           515:                        SMTP_SKIP_SPACE(token);
        !           516:                        FormatEmailAddress(Buffer, token, "RCPT TO:<%s>\r\n");
        !           517:                        if ((res = Post(Buffer)) != SUCCESS) {
        !           518:                                efree(tempMailTo);
        !           519:                                return (res);
        !           520:                        }
        !           521:                        if ((res = Ack(&server_response)) != SUCCESS) {
        !           522:                                SMTP_ERROR_RESPONSE(server_response);
        !           523:                                efree(tempMailTo);
        !           524:                                return (res);
        !           525:                        }
        !           526:                        token = strtok(NULL, ",");
        !           527:                }
        !           528:                efree(tempMailTo);
        !           529:        }
        !           530:        else if (headers) {
        !           531:                if (pos1 = strstr(headers_lc, "bcc:")) {
        !           532:                        /* Real offset is memaddress from the original headers + difference of
        !           533:                         * string found in the lowercase headrs + 4 characters to jump over
        !           534:                         * the bcc: */
        !           535:                        pos1 = headers + (pos1 - headers_lc) + 4;
        !           536:                        if (NULL == (pos2 = strstr(pos1, "\r\n"))) {
        !           537:                                tempMailTo = estrndup(pos1, strlen(pos1));
        !           538:                                /* Later, when we remove the Bcc: out of the
        !           539:                                   header we know it was the last thing. */
        !           540:                                pos2 = pos1;
        !           541:                        } else {
        !           542:                                tempMailTo = estrndup(pos1, pos2 - pos1);
        !           543:                        }
        !           544: 
        !           545:                        token = strtok(tempMailTo, ",");
        !           546:                        while (token != NULL)
        !           547:                        {
        !           548:                                SMTP_SKIP_SPACE(token);
        !           549:                                FormatEmailAddress(Buffer, token, "RCPT TO:<%s>\r\n");
        !           550:                                if ((res = Post(Buffer)) != SUCCESS) {
        !           551:                                        efree(tempMailTo);
        !           552:                                        return (res);
        !           553:                                }
        !           554:                                if ((res = Ack(&server_response)) != SUCCESS) {
        !           555:                                        SMTP_ERROR_RESPONSE(server_response);
        !           556:                                        efree(tempMailTo);
        !           557:                                        return (res);
        !           558:                                }
        !           559:                                token = strtok(NULL, ",");
        !           560:                        }
        !           561:                        efree(tempMailTo);
        !           562: 
        !           563:                        /* Now that we've identified that we've a Bcc list,
        !           564:                           remove it from the current header. */
        !           565:                        if (NULL == (stripped_header = ecalloc(1, strlen(headers)))) {
        !           566:                                return OUT_OF_MEMORY;
        !           567:                        }
        !           568:                        /* headers = point to string start of header
        !           569:                           pos1    = pointer IN headers where the Bcc starts
        !           570:                           '4'     = Length of the characters 'bcc:'
        !           571:                           Because we've added +4 above for parsing the Emails
        !           572:                           we've to substract them here. */
        !           573:                        memcpy(stripped_header, headers, pos1 - headers - 4);
        !           574:                        if (pos1 != pos2) {
        !           575:                                /* if pos1 != pos2 , pos2 points to the rest of the headers.
        !           576:                                   Since pos1 != pos2 if "\r\n" was found, we know those characters
        !           577:                                   are there and so we jump over them (else we would generate a new header
        !           578:                                   which would look like "\r\n\r\n". */
        !           579:                                memcpy(stripped_header + (pos1 - headers - 4), pos2 + 2, strlen(pos2) - 2);
        !           580:                        }
        !           581:                }
        !           582:        }
        !           583: 
        !           584:        /* Simplify the code that we create a copy of stripped_header no matter if
        !           585:           we actually strip something or not. So we've a single efree() later. */
        !           586:        if (headers && !stripped_header) {
        !           587:                if (NULL == (stripped_header = estrndup(headers, strlen(headers)))) {
        !           588:                        return OUT_OF_MEMORY;
        !           589:                }
        !           590:        }
        !           591: 
        !           592:        if ((res = Post("DATA\r\n")) != SUCCESS) {
        !           593:                if (stripped_header) {
        !           594:                        efree(stripped_header);
        !           595:                }
        !           596:                return (res);
        !           597:        }
        !           598:        if ((res = Ack(&server_response)) != SUCCESS) {
        !           599:                SMTP_ERROR_RESPONSE(server_response);
        !           600:                if (stripped_header) {
        !           601:                        efree(stripped_header);
        !           602:                }
        !           603:                return (res);
        !           604:        }
        !           605: 
        !           606:        /* send message header */
        !           607:        if (Subject == NULL) {
        !           608:                res = PostHeader(RPath, "No Subject", mailTo, stripped_header TSRMLS_CC);
        !           609:        } else {
        !           610:                res = PostHeader(RPath, Subject, mailTo, stripped_header TSRMLS_CC);
        !           611:        }
        !           612:        if (stripped_header) {
        !           613:                efree(stripped_header);
        !           614:        }
        !           615:        if (res != SUCCESS) {
        !           616:                return (res);
        !           617:        }
        !           618: 
        !           619:        /* Escape \n. sequences
        !           620:         * We use php_str_to_str() and not php_str_replace_in_subject(), since the latter
        !           621:         * uses ZVAL as it's parameters */
        !           622:        data_cln = php_str_to_str(data, strlen(data), PHP_WIN32_MAIL_DOT_PATTERN, sizeof(PHP_WIN32_MAIL_DOT_PATTERN) - 1,
        !           623:                                        PHP_WIN32_MAIL_DOT_REPLACE, sizeof(PHP_WIN32_MAIL_DOT_REPLACE) - 1, &data_cln_len);
        !           624:        if (!data_cln) {
        !           625:                data_cln = estrdup("");
        !           626:                data_cln_len = 1;               
        !           627:        }
        !           628: 
        !           629:        /* send message contents in 1024 chunks */
        !           630:        {
        !           631:                char c, *e2, *e = data_cln + data_cln_len;
        !           632:                p = data_cln;
        !           633: 
        !           634:                while (e - p > 1024) {
        !           635:                        e2 = p + 1024;
        !           636:                        c = *e2;
        !           637:                        *e2 = '\0';
        !           638:                        if ((res = Post(p)) != SUCCESS) {
        !           639:                                efree(data_cln);
        !           640:                                return(res);
        !           641:                        }
        !           642:                        *e2 = c;
        !           643:                        p = e2;
        !           644:                }
        !           645:                if ((res = Post(p)) != SUCCESS) {
        !           646:                        efree(data_cln);
        !           647:                        return(res);
        !           648:                }
        !           649:        }
        !           650: 
        !           651:        efree(data_cln);
        !           652: 
        !           653:        /*send termination dot */
        !           654:        if ((res = Post("\r\n.\r\n")) != SUCCESS)
        !           655:                return (res);
        !           656:        if ((res = Ack(&server_response)) != SUCCESS) {
        !           657:                SMTP_ERROR_RESPONSE(server_response);
        !           658:                return (res);
        !           659:        }
        !           660: 
        !           661:        return (SUCCESS);
        !           662: }
        !           663: 
        !           664: static int addToHeader(char **header_buffer, const char *specifier, char *string)
        !           665: {
        !           666:        if (NULL == (*header_buffer = erealloc(*header_buffer, strlen(*header_buffer) + strlen(specifier) + strlen(string) + 1))) {
        !           667:                return 0;
        !           668:        }
        !           669:        sprintf(*header_buffer + strlen(*header_buffer), specifier, string);
        !           670:        return 1;
        !           671: }
        !           672: 
        !           673: /*********************************************************************
        !           674: // Name:  PostHeader
        !           675: // Input:       1) return path
        !           676: //              2) Subject
        !           677: //              3) destination address
        !           678: //              4) headers
        !           679: // Output:      Error code or Success
        !           680: // Description:
        !           681: // Author/Date:  jcar 20/9/96
        !           682: // History:
        !           683: //********************************************************************/
        !           684: static int PostHeader(char *RPath, char *Subject, char *mailTo, char *xheaders TSRMLS_DC)
        !           685: {
        !           686:        /* Print message header according to RFC 822 */
        !           687:        /* Return-path, Received, Date, From, Subject, Sender, To, cc */
        !           688: 
        !           689:        int res;
        !           690:        char *header_buffer;
        !           691:        char *headers_lc = NULL;
        !           692:        size_t i;
        !           693: 
        !           694:        if (xheaders) {
        !           695:                if (NULL == (headers_lc = estrdup(xheaders))) {
        !           696:                        return OUT_OF_MEMORY;
        !           697:                }
        !           698:                for (i = 0; i < strlen(headers_lc); i++) {
        !           699:                        headers_lc[i] = tolower(headers_lc[i]);
        !           700:                }
        !           701:        }
        !           702: 
        !           703:        header_buffer = ecalloc(1, MAIL_BUFFER_SIZE);
        !           704: 
        !           705:        if (!xheaders || !strstr(headers_lc, "date:")) {
        !           706:                time_t tNow = time(NULL);
        !           707:                char *dt = php_format_date("r", 1, tNow, 1 TSRMLS_CC);
        !           708: 
        !           709:                snprintf(header_buffer, MAIL_BUFFER_SIZE, "Date: %s\r\n", dt);
        !           710:                efree(dt);
        !           711:        }
        !           712: 
        !           713:        if (!headers_lc || !strstr(headers_lc, "from:")) {
        !           714:                if (!addToHeader(&header_buffer, "From: %s\r\n", RPath)) {
        !           715:                        goto PostHeader_outofmem;
        !           716:                }
        !           717:        }
        !           718:        if (!addToHeader(&header_buffer, "Subject: %s\r\n", Subject)) {
        !           719:                goto PostHeader_outofmem;
        !           720:        }
        !           721: 
        !           722:        /* Only add the To: field from the $to parameter if isn't in the custom headers */
        !           723:        if ((headers_lc && (!strstr(headers_lc, "\r\nto:") && (strncmp(headers_lc, "to:", 3) != 0))) || !headers_lc) {
        !           724:                if (!addToHeader(&header_buffer, "To: %s\r\n", mailTo)) {
        !           725:                        goto PostHeader_outofmem;
        !           726:                }
        !           727:        }
        !           728:        if (xheaders) {
        !           729:                if (!addToHeader(&header_buffer, "%s\r\n", xheaders)) {
        !           730:                        goto PostHeader_outofmem;
        !           731:                }
        !           732:        }
        !           733: 
        !           734:        if (headers_lc) {
        !           735:                efree(headers_lc);
        !           736:        }
        !           737:        if ((res = Post(header_buffer)) != SUCCESS) {
        !           738:                efree(header_buffer);
        !           739:                return (res);
        !           740:        }
        !           741:        efree(header_buffer);
        !           742: 
        !           743:        if ((res = Post("\r\n")) != SUCCESS) {
        !           744:                return (res);
        !           745:        }
        !           746: 
        !           747:        return (SUCCESS);
        !           748: 
        !           749: PostHeader_outofmem:
        !           750:        if (headers_lc) {
        !           751:                efree(headers_lc);
        !           752:        }
        !           753:        return OUT_OF_MEMORY;
        !           754: }
        !           755: 
        !           756: 
        !           757: 
        !           758: /*********************************************************************
        !           759: // Name:  MailConnect
        !           760: // Input:   None
        !           761: // Output:  None
        !           762: // Description: Connect to the mail host and receive the welcome message.
        !           763: // Author/Date:  jcar 20/9/96
        !           764: // History:
        !           765: //********************************************************************/
        !           766: static int MailConnect()
        !           767: {
        !           768: 
        !           769:        int res, namelen;
        !           770:        short portnum;
        !           771:        struct hostent *ent;
        !           772:        IN_ADDR addr;
        !           773: #ifdef HAVE_IPV6
        !           774:        IN6_ADDR addr6;
        !           775: #endif
        !           776: 
        !           777:        /* Create Socket */
        !           778:        if ((sc = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        !           779:                return (FAILED_TO_OBTAIN_SOCKET_HANDLE);
        !           780:        }
        !           781: 
        !           782:        /* Get our own host name */
        !           783:        if (gethostname(LocalHost, HOST_NAME_LEN)) {
        !           784:                return (FAILED_TO_GET_HOSTNAME);
        !           785:        }
        !           786: 
        !           787:        ent = gethostbyname(LocalHost);
        !           788: 
        !           789:        if (!ent) {
        !           790:                return (FAILED_TO_GET_HOSTNAME);
        !           791:        }
        !           792: 
        !           793:        namelen = strlen(ent->h_name);
        !           794: 
        !           795: #ifdef HAVE_IPV6
        !           796:        if (inet_pton(AF_INET, ent->h_name, &addr) == 1 || inet_pton(AF_INET6, ent->h_name, &addr6) == 1)
        !           797: #else
        !           798:        if (inet_pton(AF_INET, ent->h_name, &addr) == 1)
        !           799: #endif
        !           800:        {
        !           801:                if (namelen + 2 >= HOST_NAME_LEN) {
        !           802:                        return (FAILED_TO_GET_HOSTNAME);
        !           803:                }
        !           804: 
        !           805:                strcpy(LocalHost, "[");
        !           806:                strcpy(LocalHost + 1, ent->h_name);
        !           807:                strcpy(LocalHost + namelen + 1, "]");
        !           808:        } else {
        !           809:                if (namelen >= HOST_NAME_LEN) {
        !           810:                        return (FAILED_TO_GET_HOSTNAME);
        !           811:                }
        !           812: 
        !           813:                strcpy(LocalHost, ent->h_name);
        !           814:        }
        !           815: 
        !           816:        /* Resolve the servers IP */
        !           817:        /*
        !           818:        if (!isdigit(MailHost[0])||!gethostbyname(MailHost))
        !           819:        {
        !           820:                return (FAILED_TO_RESOLVE_HOST);
        !           821:        }
        !           822:        */
        !           823: 
        !           824:        portnum = (short) INI_INT("smtp_port");
        !           825:        if (!portnum) {
        !           826:                portnum = 25;
        !           827:        }
        !           828: 
        !           829:        /* Connect to server */
        !           830:        sock_in.sin_family = AF_INET;
        !           831:        sock_in.sin_port = htons(portnum);
        !           832:        sock_in.sin_addr.S_un.S_addr = GetAddr(MailHost);
        !           833: 
        !           834:        if (connect(sc, (LPSOCKADDR) & sock_in, sizeof(sock_in))) {
        !           835:                return (FAILED_TO_CONNECT);
        !           836:        }
        !           837: 
        !           838:        /* receive Server welcome message */
        !           839:        res = Ack(NULL);
        !           840:        return (res);
        !           841: }
        !           842: 
        !           843: 
        !           844: /*********************************************************************
        !           845: // Name:  Post
        !           846: // Input:
        !           847: // Output:
        !           848: // Description:
        !           849: // Author/Date:  jcar 20/9/96
        !           850: // History:
        !           851: //********************************************************************/
        !           852: static int Post(LPCSTR msg)
        !           853: {
        !           854:        int len = strlen(msg);
        !           855:        int slen;
        !           856:        int index = 0;
        !           857: 
        !           858:        while (len > 0) {
        !           859:                if ((slen = send(sc, msg + index, len, 0)) < 1)
        !           860:                        return (FAILED_TO_SEND);
        !           861:                len -= slen;
        !           862:                index += slen;
        !           863:        }
        !           864:        return (SUCCESS);
        !           865: }
        !           866: 
        !           867: 
        !           868: 
        !           869: /*********************************************************************
        !           870: // Name:  Ack
        !           871: // Input:
        !           872: // Output:
        !           873: // Description:
        !           874: // Get the response from the server. We only want to know if the
        !           875: // last command was successful.
        !           876: // Author/Date:  jcar 20/9/96
        !           877: // History:
        !           878: //********************************************************************/
        !           879: static int Ack(char **server_response)
        !           880: {
        !           881:        static char buf[MAIL_BUFFER_SIZE];
        !           882:        int rlen;
        !           883:        int Index = 0;
        !           884:        int Received = 0;
        !           885: 
        !           886: again:
        !           887: 
        !           888:        if ((rlen = recv(sc, buf + Index, ((MAIL_BUFFER_SIZE) - 1) - Received, 0)) < 1) {
        !           889:                return (FAILED_TO_RECEIVE);
        !           890:        }
        !           891:        Received += rlen;
        !           892:        buf[Received] = 0;
        !           893:        /*err_msg   fprintf(stderr,"Received: (%d bytes) %s", rlen, buf + Index); */
        !           894: 
        !           895:        /* Check for newline */
        !           896:        Index += rlen;
        !           897:        
        !           898:        /* SMPT RFC says \r\n is the only valid line ending, who are we to argue ;)
        !           899:         * The response code must contain at least 5 characters ex. 220\r\n */
        !           900:        if (Received < 5 || buf[Received - 1] != '\n' || buf[Received - 2] != '\r') {
        !           901:                goto again;
        !           902:        }
        !           903: 
        !           904:        if (buf[0] > '3') {
        !           905:                /* If we've a valid pointer, return the SMTP server response so the error message contains more information */
        !           906:                if (server_response) {
        !           907:                        int dec = 0;
        !           908:                        /* See if we have something like \r, \n, \r\n or \n\r at the end of the message and chop it off */
        !           909:                        if (Received > 2) {
        !           910:                                if (buf[Received-1] == '\n' || buf[Received-1] == '\r') {
        !           911:                                        dec++;
        !           912:                                        if (buf[Received-2] == '\r' || buf[Received-2] == '\n') {
        !           913:                                                dec++;
        !           914:                                        }
        !           915:                                }
        !           916: 
        !           917:                        }
        !           918:                        *server_response = estrndup(buf, Received - dec);
        !           919:                }
        !           920:                return (SMTP_SERVER_ERROR);
        !           921:        }
        !           922: 
        !           923:        return (SUCCESS);
        !           924: }
        !           925: 
        !           926: 
        !           927: /*********************************************************************
        !           928: // Name:  unsigned long GetAddr (LPSTR szHost)
        !           929: // Input:
        !           930: // Output:
        !           931: // Description: Given a string, it will return an IP address.
        !           932: //   - first it tries to convert the string directly
        !           933: //   - if that fails, it tries o resolve it as a hostname
        !           934: //
        !           935: // WARNING: gethostbyname() is a blocking function
        !           936: // Author/Date:  jcar 20/9/96
        !           937: // History:
        !           938: //********************************************************************/
        !           939: static unsigned long GetAddr(LPSTR szHost)
        !           940: {
        !           941:        LPHOSTENT lpstHost;
        !           942:        u_long lAddr = INADDR_ANY;
        !           943: 
        !           944:        /* check that we have a string */
        !           945:        if (*szHost) {
        !           946: 
        !           947:                /* check for a dotted-IP address string */
        !           948:                lAddr = inet_addr(szHost);
        !           949: 
        !           950:                /* If not an address, then try to resolve it as a hostname */
        !           951:                if ((lAddr == INADDR_NONE) && (strcmp(szHost, "255.255.255.255"))) {
        !           952: 
        !           953:                        lpstHost = gethostbyname(szHost);
        !           954:                        if (lpstHost) {         /* success */
        !           955:                                lAddr = *((u_long FAR *) (lpstHost->h_addr));
        !           956:                        } else {
        !           957:                                lAddr = INADDR_ANY;             /* failure */
        !           958:                        }
        !           959:                }
        !           960:        }
        !           961:        return (lAddr);
        !           962: } /* end GetAddr() */
        !           963: 
        !           964: 
        !           965: /*********************************************************************
        !           966: // Name:  int FormatEmailAddress
        !           967: // Input: 
        !           968: // Output:
        !           969: // Description: Formats the email address to remove any content ouside
        !           970: //   of the angle brackets < > as per RFC 2821.
        !           971: //
        !           972: //   Returns the invalidly formatted mail address if the < > are 
        !           973: //   unbalanced (the SMTP server should reject it if it's out of spec.)
        !           974: //  
        !           975: // Author/Date:  garretts 08/18/2009
        !           976: // History:
        !           977: //********************************************************************/
        !           978: static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString) {
        !           979:        char *tmpAddress1, *tmpAddress2;
        !           980:        int result;
        !           981: 
        !           982:        if( (tmpAddress1 = strchr(EmailAddress, '<')) && (tmpAddress2 = strchr(tmpAddress1, '>'))  ) {
        !           983:                *tmpAddress2 = 0; // terminate the string temporarily.
        !           984:                result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString , tmpAddress1+1);
        !           985:                *tmpAddress2 = '>'; // put it back the way it was.
        !           986:                return result;
        !           987:        } 
        !           988:        return snprintf(Buf, MAIL_BUFFER_SIZE , FormatString , EmailAddress );
        !           989: } /* end FormatEmailAddress() */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>