diff options
Diffstat (limited to 'win32/sendmail.c')
| -rw-r--r-- | win32/sendmail.c | 511 | 
1 files changed, 511 insertions, 0 deletions
diff --git a/win32/sendmail.c b/win32/sendmail.c new file mode 100644 index 0000000000..7adf4d7bf3 --- /dev/null +++ b/win32/sendmail.c @@ -0,0 +1,511 @@ + +/*  + *    PHP Sendmail for Windows. + * + *  This file is rewriten specificly for PHPFI.  Some functionality + *  has been removed (MIME and file attachments).  This code was  + *  modified from code based on code writen by Jarle Aase. + * + *  This class is based on the original code by Jarle Aase, see bellow: + *  wSendmail.cpp  It has been striped of some functionality to match + *  the requirements of phpfi. + * + *  Very simple SMTP Send-mail program for sending command-line level + *  emails and CGI-BIN form response for the Windows platform. + * + *  The complete wSendmail package with source code can be downloaded + *  from http://virtual.icr.com.au:80/jgaa/cgi-bin.htm + * + */ + +#ifdef THREAD_SAFE +#include "tls.h" +#endif +#include "php.h"				/*php specific */ +#include <stdio.h> +#include <stdlib.h> +#include <winsock.h> +#include "time.h" +#include <string.h> +#include <malloc.h> +#include <memory.h> +#include <winbase.h> +#include "sendmail.h" + + +/* +   extern int _daylight; +   extern long _timezone; + */ +/*enum +   { +   DO_CONNECT = WM_USER +1 +   }; + */ + +static char *days[] = +{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static char *months[] = +{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +#ifndef THREAD_SAFE +char Buffer[MAIL_BUFFER_SIZE]; + +// socket related data +SOCKET sc; +WSADATA Data; +struct hostent *adr; +SOCKADDR_IN sock_in; +int WinsockStarted; +// values set by the constructor +char *AppName; +char MailHost[HOST_NAME_LEN]; +char LocalHost[HOST_NAME_LEN]; +#endif +char seps[] = " ,\t\n"; +char *php_mailer = "PHP 3.0 WIN32"; + +char *get_header(char *h, char *headers); + +// Error messages +static char *ErrorMessages[] = +{ +	{"Success"}, +	{"Bad arguments from form"}, +	{"Unable to open temporary mailfile for read"}, +	{"Failed to Start Sockets"}, +	{"Failed to Resolve Host"}, +	{"Failed to obtain socket handle"}, +	{"Failed to Connect"}, +	{"Failed to Send"}, +	{"Failed to Receive"}, +	{"Server Error"}, +	{"Failed to resolve the host IP name"}, +	{"Out of memory"}, +	{"Unknown error"}, +	{"Bad Message Contents"}, +	{"Bad Message Subject"}, +	{"Bad Message destination"}, +	{"Bad Message Return Path"}, +	{"Bad Mail Host"}, +	{"Bad Message File"}, +	{"PHP Internal error: php3.ini sendmail from variable not set!"} +}; + + + +//******************************************************************** +// Name:  TSendMail +// Input:   1) host:    Name of the mail host where the SMTP server resides +//                      max accepted length of name = 256 +//          2) appname: Name of the application to use in the X-mailer +//                      field of the message. if NULL is given the application +//                      name is used as given by the GetCommandLine() function +//                      max accespted length of name = 100 +// Output:  1) error:   Returns the error code if something went wrong or +//                      SUCCESS otherwise. +// +//  See SendText() for additional args! +//******************************************************************** +int TSendMail(char *host, int *error, +			  char *headers, char *Subject, char *mailTo, char *data) +{ +	int ret; +	char *RPath = NULL; +	TLS_VARS; + +	GLOBAL(WinsockStarted) = FALSE; + +	if (host == NULL) { +		*error = BAD_MAIL_HOST; +		return BAD_MAIL_HOST; +	} else if (strlen(host) >= HOST_NAME_LEN) { +		*error = BAD_MAIL_HOST; +		return BAD_MAIL_HOST; +	} else { +		strcpy(GLOBAL(MailHost), host); +	} + +	if (php3_ini.sendmail_from){ +		RPath = estrdup(php3_ini.sendmail_from); +		} else { +			return 19; +	} + +	// attempt to connect with mail host +	*error = MailConnect(); +	if (*error != 0) { +		if(RPath)efree(RPath); +		return *error; +	} else { +		ret = SendText(RPath, Subject, mailTo, data, headers); +		TSMClose(); +		if (ret != SUCCESS) { +			*error = ret; +		} +		if(RPath)efree(RPath); +		return ret; +	} +} + +//******************************************************************** +// Name:  TSendMail::~TSendMail +// Input: +// Output: +// Description: DESTRUCTOR +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +void TSMClose() +{ +	TLS_VARS; + +	Post("QUIT\n"); +	Ack(); +	// to guarantee that the cleanup is not made twice and +	// compomise the rest of the application if sockets are used +	// elesewhere +} + + +//******************************************************************** +// Name:  char *GetSMErrorText +// Input:   Error index returned by the menber functions +// Output:  pointer to a string containing the error description +// Description: +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +char *GetSMErrorText(int index) +{ + +	if ((index > MAX_ERROR_INDEX) || (index < MIN_ERROR_INDEX)) +		return (ErrorMessages[UNKNOWN_ERROR]); +	else +		return (ErrorMessages[index]); +} + + +//******************************************************************** +// Name:  TSendText +// Input:       1) RPath:   return path of the message +//                                  Is used to fill the "Return-Path" and the +//                                  "X-Sender" fields of the message. +//                  2) Subject: Subject field of the message. If NULL is given +//                                  the subject is set to "No Subject" +//                  3) mailTo:  Destination address +//                  4) data:        Null terminated string containing the data to be send. +// Output:      Error code or SUCCESS +// Description: +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +int SendText(char *RPath, char *Subject, char *mailTo, char *data, char *headers) +{ + +	int res, i; +	char *p; +	TLS_VARS; + +	// check for NULL parameters +	if (data == NULL) +		return (BAD_MSG_CONTENTS); +	if (mailTo == NULL) +		return (BAD_MSG_DESTINATION); +	if (RPath == NULL) +		return (BAD_MSG_RPATH); + +	// simple checks for the mailto address +	// have ampersand ? +	if (strchr(mailTo, '@') == NULL) +		return (BAD_MSG_DESTINATION); + +	sprintf(GLOBAL(Buffer), "HELO %s\n", GLOBAL(LocalHost)); + +	// in the beggining of the dialog +	// attempt reconnect if the first Post fail +	if ((res = Post(GLOBAL(Buffer))) != SUCCESS) { +		MailConnect(); +		if ((res = Post(GLOBAL(Buffer))) != SUCCESS) +			return (res); +	} +	if ((res = Ack()) != SUCCESS) +		return (res); + +	sprintf(GLOBAL(Buffer), "MAIL FROM:<%s>\n", RPath); +	if ((res = Post(GLOBAL(Buffer))) != SUCCESS) +		return (res); +	if ((res = Ack()) != SUCCESS) +		return (res); + + +	sprintf(GLOBAL(Buffer), "RCPT TO:<%s>\n", mailTo); +	if ((res = Post(GLOBAL(Buffer))) != SUCCESS) +		return (res); +	if ((res = Ack()) != SUCCESS) +		return (res); + +	if ((res = Post("DATA\n")) != SUCCESS) +		return (res); +	if ((res = Ack()) != SUCCESS) +		return (res); + + +	// send message header +	if (Subject == NULL) +		res = PostHeader(RPath, "No Subject", mailTo, headers); +	else +		res = PostHeader(RPath, Subject, mailTo, headers); +	if (res != SUCCESS) +		return (res); + + +	// send message contents in 1024 chunks +	if (strlen(data) <= 1024) { +		if ((res = Post(data)) != SUCCESS) +			return (res); +	} else { +		p = data; +		while (1) { +			if (*p == '\0') +				break; +			if (strlen(p) >= 1024) +				i = 1024; +			else +				i = strlen(p); + +			// put next chunk in buffer +			strncpy(GLOBAL(Buffer), p, i); +			GLOBAL(Buffer)[i] = '\0'; +			p += i; + +			// send chunk +			if ((res = Post(GLOBAL(Buffer))) != SUCCESS) +				return (res); +		} +	} + +	//send termination dot +	if ((res = Post("\r\n.\r\n")) != SUCCESS) +		return (res); +	if ((res = Ack()) != SUCCESS) +		return (res); + +	return (SUCCESS); +} + + + +//******************************************************************** +// Name:  PostHeader +// Input:       1) return path +//                  2) Subject +//                  3) destination address +//                  4) DoMime flag +// Output:      Error code or Success +// Description: +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +int PostHeader(char *RPath, char *Subject, char *mailTo, char *xheaders) +{ + +	// Print message header according to RFC 822 +	// Return-path, Received, Date, From, Subject, Sender, To, cc + +	time_t tNow = time(NULL); +	struct tm *tm = localtime(&tNow); +	int zoneh = abs(_timezone); +	int zonem, res; +	char *p; +	TLS_VARS; + +	p = GLOBAL(Buffer); +	zoneh /= (60 * 60); +	zonem = (abs(_timezone) / 60) - (zoneh * 60); + +	p += sprintf(p, "Date: %s, %02d %s %04d %02d:%02d:%02d %s%02d%02d\r\n", +				 days[tm->tm_wday], +				 tm->tm_mday, +				 months[tm->tm_mon], +				 tm->tm_year + 1900, +				 tm->tm_hour, +				 tm->tm_min, +				 tm->tm_sec, +				 (_timezone > 0) ? "+" : (_timezone < 0) ? "-" : "", +				 zoneh, +				 zonem); + +	if(xheaders && strnicmp("From:",xheaders,5)){ +		p += sprintf(p, "From: %s\r\n", RPath); +	} +	p += sprintf(p, "Subject: %s\r\n", Subject); +	p += sprintf(p, "To: %s\r\n", mailTo); +	if(xheaders){ +		p += sprintf(p, "%s\r\n", xheaders); +	} + +	if ((res = Post(GLOBAL(Buffer))) != SUCCESS) +		return (res); + +	if ((res = Post("\r\n")) != SUCCESS) +		return (res); + +	return (SUCCESS); +} + + + +//******************************************************************** +// Name:  MailConnect +// Input:   None +// Output:  None +// Description: Connect to the mail host and receive the welcome message. +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +int MailConnect() +{ + +	int res; +	TLS_VARS; + + +	// Create Socket +	if ((GLOBAL(sc) = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) +		return (FAILED_TO_OBTAIN_SOCKET_HANDLE); + +	// Get our own host name +	if (gethostname(GLOBAL(LocalHost), HOST_NAME_LEN)) +		return (FAILED_TO_GET_HOSTNAME); + +	// Resolve the servers IP +	//if (!isdigit(GLOBAL(MailHost)[0])||!gethostbyname(GLOBAL(MailHost))) +	//{ +	//	return (FAILED_TO_RESOLVE_HOST); +	//} + +	// Connect to server +	GLOBAL(sock_in).sin_family = AF_INET; +	GLOBAL(sock_in).sin_port = htons(25); +	GLOBAL(sock_in).sin_addr.S_un.S_addr = GetAddr(GLOBAL(MailHost)); + +	if (connect(GLOBAL(sc), (LPSOCKADDR) & GLOBAL(sock_in), sizeof(GLOBAL(sock_in)))) +		return (FAILED_TO_CONNECT); + +	// receive Server welcome message +	res = Ack(); +	return (res); +} + + + + + + +//******************************************************************** +// Name:  Post +// Input: +// Output: +// Description: +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +int Post(LPCSTR msg) +{ +	int len = strlen(msg); +	int slen; +	int index = 0; +	TLS_VARS; + +	while (len > 0) { +		if ((slen = send(GLOBAL(sc), msg + index, len, 0)) < 1) +			return (FAILED_TO_SEND); +		len -= slen; +		index += slen; +	} +	return (SUCCESS); +} + + + +//******************************************************************** +// Name:  Ack +// Input: +// Output: +// Description: +// Get the response from the server. We only want to know if the +// last command was successful. +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +int Ack() +{ +	static char *buf; +	int rlen; +	int Index = 0; +	int Received = 0; +	TLS_VARS; + +	if (!buf) +		if ((buf = (char *) malloc(1024 * 4)) == NULL) +			return (OUT_OF_MEMORY); + +  again: + +	if ((rlen = recv(GLOBAL(sc), buf + Index, ((1024 * 4) - 1) - Received, 0)) < 1) +		return (FAILED_TO_RECEIVE); + +	Received += rlen; +	buf[Received] = 0; +	//err_msg   fprintf(stderr,"Received: (%d bytes) %s", rlen, buf + Index); + +	// Check for newline +	Index += rlen; +	if ((buf[Received - 2] != '\r') || (buf[Received - 1] != '\n')) +		// err_msg          fprintf(stderr,"Incomplete server message. Awaiting CRLF\n"); +		goto again;				// Incomplete data. Line must be terminated by CRLF + +	if (buf[0] > '3') +		return (SMTP_SERVER_ERROR); + +	return (SUCCESS); +} + + +//******************************************************************** +// Name:  unsigned long GetAddr (LPSTR szHost) +// Input: +// Output: +// Description: Given a string, it will return an IP address. +//   - first it tries to convert the string directly +//   - if that fails, it tries o resolve it as a hostname +// +// WARNING: gethostbyname() is a blocking function +// Author/Date:  jcar 20/9/96 +// History: +//******************************************************************** +unsigned long GetAddr(LPSTR szHost) +{ +	LPHOSTENT lpstHost; +	u_long lAddr = INADDR_ANY; + +	/* check that we have a string */ +	if (*szHost) { + +		/* check for a dotted-IP address string */ +		lAddr = inet_addr(szHost); + +		/* If not an address, then try to resolve it as a hostname */ +		if ((lAddr == INADDR_NONE) && (strcmp(szHost, "255.255.255.255"))) { + +			lpstHost = gethostbyname(szHost); +			if (lpstHost) {		/* success */ +				lAddr = *((u_long FAR *) (lpstHost->h_addr)); +			} else { +				lAddr = INADDR_ANY;		/* failure */ +			} +		} +	} +	return (lAddr); +}								/* end GetAddr() */  | 
