Code:
//mail_un.cpp
#ifdef OC_UNIX
#include <stdio.h>
#include <stdlib.h>
#include <amsios.h>
#include <string.h>
#include <time.h>
#include <amsdefs.h>
#include <mail.h>
/* generic socket DLL support */
#include "gensocks.h"
#define MAXOUTLINE 255
int SMTPSock;
#define SERVER_SIZE 256 // #defines (bleah!) from Beverly Brown "beverly@datacube.com"
#define SENDER_SIZE 256
#define MAX_PATH 256
enum BOOL { FALSE1, TRUE1};
char SMTPHost[SERVER_SIZE];
char Sender[SENDER_SIZE];
char *Recipients;
char my_hostname[1024];
char *destination = "";
char *cc_list = "";
char *bcc_list = "";
char *loginname = "";
char *senderid = "";
char *subject = "";
int mime = 0;
int quiet = 0;
char *usage[] =
{
"Blat v1.5: WinNT console utility to mail a file via SMTP",
"",
"syntax:",
"Blat <filename> -t <recipient> [optional switches (see below)]",
"Blat -install <server addr> <sender's addr> [-q]",
"Blat -h [-q]",
"",
"-install <server addr> <sender's addr>: set's default SMTP server and sender",
"",
"<filename> : file with the message body ('-' for console input, end with ^Z)",
"-t <recipient>: recipient list (comma separated)",
"-s <subj> : subject line",
"-f <sender> : overrides the default sender address (must be known to server)",
"-i <addr> : a 'From:' address, not necessarily known to the SMTP server.",
"-c <recipient>: carbon copy recipient list (comma separated)",
"-b <recipient>: blind carbon copy recipient list (comma separated)",
"-h : displays this help.",
"-mime : MIME Quoted-Printable Content-Transfer-Encoding.",
"-q : supresses *all* output.",
"-server <addr>: overrides the default SMTP server to be used.",
"",
"Note that if the '-i' option is used, <sender> is included in 'Reply-to:'",
"and 'Sender:' fields in the header of the message."
};
const NMLINES = 22;
void
gensock_error (char * function, int retval)
{
if ( ! quiet )
{
switch ( retval )
{
case 4001:
cout << "Error: Malloc failed (possibly out of memory).";
break;
case 4002:
cout << "Error: Error sending data.";
break;
case 4003:
cout << "Error: Error initializing gensock.dll.";
break;
case 4004:
cout << "Error: Version not supported.";
break;
case 4005:
cout << "Error: The winsock version specified by gensock is not supported by this winsock.dll.";
break;
case 4006:
cout << "Error: Network not ready.";
break;
case 4007:
cout << "Error: Can't resolve (mailserver) hostname.";
break;
case 4008:
cout << "Error: Can't create a socket (too many simultaneous links?)";
break;
case 4009:
cout << "Error: Error reading socket.";
break;
case 4010:
cout << "Error: Not a socket.";
break;
case 4011:
cout << "Error: Busy.";
break;
case 4012:
cout << "Error: Error closing socket.";
break;
case 4013:
cout << "Error: Wait a bit (possible timeout).";
break;
case 4014:
cout << "Error: Can't resolve service.";
break;
case 4015:
cout << "Error: Can't connect to mailserver (timed out if winsock.dll error 10060)";
break;
case 4016:
cout << "Error: Connection to mailserver was dropped.";
break;
case 4017:
cout << "Error: Mail server refused connection.";
break;
default:
cout << "error " << retval << " in function '" << function;
}
}
}
int open_smtp_socket( void )
{
int retval;
retval = gensock_connect ( SMTPHost, "smtp", &SMTPSock);
if (retval)
{
if (retval == ERR_CANT_RESOLVE_SERVICE)
{
retval = gensock_connect (SMTPHost,
"25",
&SMTPSock);
if (retval)
{
gensock_error ("gensock_connect", retval);
return -1;
}
}
// error other than can't resolve service
else
{
gensock_error ("gensock_connect", retval);
return -1;
}
}
return 0;
}
int close_smtp_socket( void )
{
int retval;
if ( (retval = gensock_close (SMTPSock)) )
{
gensock_error ("gensock_close", retval);
return -1;
}
return (0);
}
int get_smtp_line( void )
{
char ch = '.';
char in_data [MAXOUTLINE];
char * index;
int retval = 0;
index = in_data;
while (ch != '\n')
{
if ( (retval = gensock_getchar (SMTPSock, 0, &ch) ) )
{
gensock_error ("gensock_getchar", retval);
return -1;
}
else
{
*index = ch;
index++;
}
}
return atoi(in_data);
}
int put_smtp_line( int sock, char * line, unsigned int nchars )
{
int retval;
if ( (retval = gensock_put_data (sock, line, (unsigned long) nchars)))
{
gensock_error ("gensock_put_data", retval);
return -1;
}
return (0);
}
int putline_internal (int sock, char * line, unsigned int nchars)
{
int retval;
if ((retval =
gensock_put_data (sock,
(char *) line,
(unsigned long) nchars)))
{
switch (retval)
{
case ERR_NOT_CONNECTED:
gensock_error( "SMTP server has closed the connection", retval );
break;
default:
gensock_error ("gensock_put_data", retval);
}
return -1;
}
return (0);
}
void smtp_error (char * message)
{
if ( ! quiet )
cout << message << "\n";
put_smtp_line (SMTPSock, "QUIT\r\n", 6);
close_smtp_socket();
}
// 'destination' is the address the message is to be sent to
// 'message' is a pointer to a null-terminated 'string' containing the
// entire text of the message.
int prepare_smtp_message(char * MailAddress, char * destination)
{
char out_data[MAXOUTLINE];
char str[1024];
char *ptr;
int len, startLen;
if ( open_smtp_socket() )
return -1;
if ( get_smtp_line() != 220 )
{
smtp_error ("SMTP server error");
return ( -1);
}
sprintf( out_data, "HELO %s\r\n", my_hostname);
put_smtp_line( SMTPSock, out_data, strlen (out_data) );
if ( get_smtp_line() != 250 )
{
smtp_error ("SMTP server error");
return -1;
}
sprintf (out_data, "MAIL From:<%s>\r\n", loginname);
put_smtp_line( SMTPSock, out_data, strlen (out_data) );
if (get_smtp_line() != 250)
{
smtp_error ("The mail server doesn't like the sender name,\nhave you set your mail address correctly?");
return -1;
}
// do a series of RCPT lines for each name in address line
for (ptr = destination; *ptr; ptr += len + 1)
{
// if there's only one token left, then len will = startLen,
// and we'll iterate once only
startLen = strlen (ptr);
if ((len = strcspn (ptr, " ,\n\t\r")) != startLen)
{
ptr[len] = '\0'; // replace delim with NULL char
while (strchr (" ,\n\t\r", ptr[len + 1])) // eat white space
ptr[len++] = '\0';
}
sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
putline_internal( SMTPSock, out_data, strlen (out_data) );
if (get_smtp_line() != 250)
{
sprintf (str, "The mail server doesn't like the name %s.\nHave you set the 'To: ' field correctly?", ptr);
smtp_error (str);
return -1;
}
if (len == startLen) // last token, we're done
break;
}
sprintf (out_data, "DATA\r\n");
put_smtp_line (SMTPSock, out_data, strlen (out_data));
if (get_smtp_line() != 354)
{
smtp_error ("Mail server error accepting message data");
return -1;
}
return (0);
}
int transform_and_send_edit_data( int sock, char * editptr )
{
char *index;
char *header_end;
char previous_char = 'x';
unsigned int send_len;
int retval;
BOOL done = FALSE1;
send_len = strlen(editptr);
index = editptr;
header_end = strstr (editptr, "\r\n\r\n");
while (!done)
{
// room for extra char for double dot on end case
while ((unsigned int) (index - editptr) < send_len)
{
switch (*index)
{
case '.':
if (previous_char == '\n')
/* send _two_ dots... */
if ((retval = gensock_put_data_buffered (sock, index, 1)))
return (retval);
if ((retval = gensock_put_data_buffered (sock, index, 1)))
return (retval);
break;
case '\r':
// watch for soft-breaks in the header, and ignore them
if (index < header_end && (strncmp (index, "\r\r\n", 3) == 0))
index += 2;
else
if (previous_char != '\r')
if ((retval = gensock_put_data_buffered (sock, index, 1)))
return (retval);
// soft line-break (see EM_FMTLINES), skip extra CR */
break;
default:
if ((retval = gensock_put_data_buffered (sock, index, 1)))
return (retval);
}
previous_char = *index;
index++;
}
if ( (unsigned int) (index - editptr) == send_len)
done = TRUE1;
}
// this handles the case where the user doesn't end the last
// line with a <return>
if (editptr[send_len - 1] != '\n')
{
if ((retval = gensock_put_data_buffered (sock, "\r\n.\r\n", 5)))
return (retval);
}
else
if ((retval = gensock_put_data_buffered (sock, ".\r\n", 3)))
return (retval);
/* now make sure it's all sent... */
if ((retval = gensock_put_data_flush(sock)))
return (retval);
return (TRUE);
}
int send_smtp_edit_data (char * message)
{
transform_and_send_edit_data( SMTPSock, message );
if (get_smtp_line() != 250)
{
smtp_error ("Message not accepted by server");
return -1;
}
return (0);
}
int finish_smtp_message( void )
{
return put_smtp_line( SMTPSock, "QUIT\r\n", 6 );
}
// MIME Quoted-Printable Content-Transfer-Encoding
#define MimeHexChar "0123456789ABCDEF";
void ConvertToQuotedPrintable(char ThisChar, int * CurrPos, char * buffer)
{
int ThisValue;
div_t result;
// char buffer[8];
char HexTable[17] = MimeHexChar;
ThisValue = (256 + (unsigned int) ThisChar) % 256;
if (ThisValue == 13)
{
sprintf( buffer, "%s", "\0" );
return ;
}
else if (ThisValue == 10)
{
sprintf( buffer, "%s", "\r\n" );
(*CurrPos) = 0;
return ;
}
else if ((ThisValue < 33) |
(ThisValue == 61) |
(ThisValue > 126))
{
result = div(ThisValue, 16);
buffer[0] = '=';
(*CurrPos)++;
buffer[1] = HexTable[result.quot];
(*CurrPos)++;
buffer[2] = HexTable[result.rem];
(*CurrPos)++;
buffer[3] = '\0';
}
else
{
buffer[0] = ThisChar;
(*CurrPos)++;
buffer[1] = '\0';
}
if (*CurrPos > 71)
{
strcat(buffer, "=\r\n"); /* Add soft line break */
(*CurrPos) = 0;
}
}
int send_mail ( char * in_buffer,
char * in_recipients,
char * in_subject,
char * in_sender,
char * in_copy_recipients,
char * in_blind_recipients,
char * in_server,
char * in_hostname,
char * in_loginname,
char * error
) /* Array of environment variable strings */
{
int impersonating = 0;
int penguin = 0;
int i, j;
int retcode;
int hours, minutes;
int dest_len, cc_len, bcc_len;
// by default Blat is very noisy!
quiet = 0;
// by default Blat does not use mime Quoted-Printable Content-Transfer-Encoding!
mime = 0;
Sender[0] = '\0';
SMTPHost[0] = '\0';
// thanks to Beverly Brown "beverly@datacube.com" for
// fixing the argument parsing, I "fixed" the brackets
// to conform approximately to our "style" :-)
// Starts here
subject = in_subject;
cc_list = in_copy_recipients;
bcc_list = in_blind_recipients;
destination = in_recipients;
strcpy(SMTPHost, in_server);
loginname = in_loginname;
//IR-GSAFX0569 set the senderid to in_sender rather than loginname
senderid = in_sender;
//senderid = loginname;
strcpy(my_hostname, in_hostname);
if ((SMTPHost[0] == '\0') || (loginname[0] == '\0'))
{
if ( ! quiet )
{
printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username\n");
printf( "or use '-server <server name>' and '-f <user name>'\n");
printf( "aborting, nothing sent\n" );
}
return 12;
}
if (destination)
dest_len = strlen(destination);
else
dest_len = 0;
if (cc_list)
cc_len = strlen(cc_list);
else
cc_len = 0;
if (bcc_list)
bcc_len = strlen(bcc_list);
else
bcc_len = 0;
char *temp = new char [ dest_len + \
cc_len + bcc_len + 4 ];
// build the recipients list
Recipients = new char [ dest_len + \
cc_len + bcc_len + 4 ];
// Parse the "To:" line
for (i = j = 0; i < (int) strlen(destination); i++)
{
// strip white space
while (destination[i] == ' ')
i++;
// look for comments in brackets, and omit
if (destination[i] == '(')
{
while (destination[i] != ')')
i++;
i++;
}
// look for comments in quotes, and omit
if (destination[i] == '\'')
{
i++;
while (destination[i] != '\'')
i++;
i++;
}
temp[j++] = destination[i];
}
temp[j] = '\0'; // End of list added!
strcpy( Recipients, temp);
// Parse the "Cc:" line
for (i = j = 0; i < cc_len; i++)
{
// strip white space
while (cc_list[i] == ' ')
i++;
// look for comments in brackets, and omit
if (cc_list[i] == '(')
{
while (cc_list[i] != ')')
i++;
i++;
}
// look for comments in quotes, and omit
if (cc_list[i] == '\'')
{
i++;
while (cc_list[i] != '\'')
i++;
i++;
}
temp[j++] = cc_list[i];
}
temp[j] = '\0'; // End of list added!
if ( cc_len > 0 )
{
strcat(Recipients, "," );
strcat(Recipients, temp);
}
// Parse the "Bcc:" line
for (i = j = 0; i < bcc_len; i++)
{
// strip white space
while (bcc_list[i] == ' ')
i++;
// look for comments in brackets, and omit
if (bcc_list[i] == '(')
{
while (bcc_list[i] != ')')
i++;
i++;
}
// look for comments in quotes, and omit
if (bcc_list[i] == '\'')
{
i++;
while (bcc_list[i] != '\'')
i++;
i++;
}
temp[j++] = bcc_list[i];
}
temp[j] = '\0'; // End of list added!
if ( bcc_len > 0 )
{
strcat(Recipients, "," );
strcat(Recipients, temp);
}
// create a header for the message
char tmpstr[256];
char header[2048];
int headerlen;
sprintf( tmpstr, "From: %s\r\n", senderid );
strcat( header, tmpstr );
if ( impersonating )
{
sprintf( tmpstr, "Sender: %s\r\n", loginname );
strcat( header, tmpstr );
if (!(penguin == 1))
{
sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
strcat( header, tmpstr );
}
}
if ( subject )
{
sprintf( tmpstr, "Subject: %s\r\n", subject );
strcat( header, tmpstr );
}
sprintf( tmpstr, "To: %s\r\n", destination );
strcat( header, tmpstr );
if ( cc_list )
{
// Add line for the Carbon Copies
sprintf( tmpstr, "Cc: %s\r\n", cc_list );
strcat( header, tmpstr );
}
strcat( header, "X-Mailer: <WinNT's Blat ver 1.5>\r\n" );
strcat (header, "\r\n");
headerlen = strlen (header);
long filesize = strlen(in_buffer);
char *buffer = new char[(3 * (filesize + filesize / 72)) + headerlen + 1];
char *tmpptr;
// put the header at the top...
strcpy ( buffer, header);
// point to the end of header
tmpptr = buffer + headerlen;
strcpy (tmpptr, in_buffer);
// make some noise about what we are doing
if ( ! quiet )
{
if (subject)
cout << "Subject:" << subject << '\n';
if (loginname)
cout << "Login name is " << loginname << '\n';
}
// send the message to the SMTP server!
retcode = prepare_smtp_message( loginname, Recipients );
if ( !retcode )
{
retcode = send_smtp_edit_data( buffer );
if ( !retcode )
finish_smtp_message();
close_smtp_socket();
}
delete [] temp;
delete [] buffer;
delete [] Recipients;
return (retcode);
}
#endif