home *** CD-ROM | disk | FTP | other *** search
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream.h>
- /* generic socket DLL support */
- #include "gensock.h"
-
- #ifdef WIN32
- #define __far far
- #define huge far
- #define __near near
- #endif
-
- #define MAXOUTLINE 255
-
- HANDLE gensock_lib = 0;
-
- int (FAR PASCAL *pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
- int (FAR PASCAL *pgensock_getchar) (socktag st, int wait, char FAR * ch);
- int (FAR PASCAL *pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
- int (FAR PASCAL *pgensock_close) (socktag st);
- int (FAR PASCAL *pgensock_gethostname) (char FAR * name, int namelen);
- int (FAR PASCAL *pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
- int (FAR PASCAL *pgensock_put_data_flush) (socktag st);
-
-
- socktag SMTPSock;
- char SMTPHost[128];
- char Sender[128];
- char *Recipients;
- char my_hostname[1024];
- char *destination="";
- char *cc_list="";
- char *loginname="";
- char *senderid="";
- char *subject="";
-
- char *usage[]= {
- "Blat: WinNT console utility to mail a file to a user via SMTP",
- "",
- "syntax:",
- "Blat <filename> [-s <subject>] -t <recipient> -f <address> [-i <address>]",
- "Blat -SMTP <server address>",
- "Blat -h",
- "",
- "-SMTP <server address> <senders address>: set's the address of the SMTP server to be used",
- "",
- "<filename>: the file with the message body",
- "-s <subject>: the (optional) subject line",
- "-t <recipient>: the recipient's address",
- "-f <sender>: the sender's address (must be known to the SMTP server)",
- "-i <address>: a 'From:' address, not necessarily known to the SMTP server.",
- "-h: displays this help.",
- "",
- "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=18;
-
- void
- gensock_error (char * function, int retval)
- {
- cout << "error " << retval << " in function '" << function;
- }
-
- // loads the GENSOCK DLL file
- int load_gensock()
- {
- if( (gensock_lib = LoadLibrary("gensock.dll")) == NULL )
- {
- cout << "Couldn't load 'GENSOCK.DLL'\n";
- return -1;
- }
-
- if(
- ( pgensock_connect =
- ( int (FAR PASCAL *)(char FAR *, char FAR *, socktag FAR *) )
- GetProcAddress(gensock_lib, "gensock_connect")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_connect\n";
- return -1;
- }
-
- if (
- ( pgensock_getchar =
- ( int (FAR PASCAL *) (socktag, int, char FAR *) )
- GetProcAddress(gensock_lib, "gensock_getchar")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_getchar\n";
- return -1;
- }
-
- if(
- ( pgensock_put_data =
- ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
- GetProcAddress(gensock_lib, "gensock_put_data")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_put_data\n";
- return -1;
- }
-
- if(
- ( pgensock_close =
- (int (FAR PASCAL *) (socktag) )
- GetProcAddress(gensock_lib, "gensock_close")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_close\n";
- return -1;
- }
-
- if(
- ( pgensock_gethostname =
- (int (FAR PASCAL *) (char FAR *, int) )
- GetProcAddress(gensock_lib, "gensock_gethostname")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_gethostname\n";
- return -1;
- }
-
- if(
- ( pgensock_put_data_buffered =
- ( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
- GetProcAddress(gensock_lib, "gensock_put_data_buffered")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_put_data_buffered\n";
- return -1;
- }
-
- if(
- ( pgensock_put_data_flush =
- ( int (FAR PASCAL *) (socktag) )
- GetProcAddress(gensock_lib, "gensock_put_data_flush")
- ) == NULL
- )
- {
- cout << "couldn't getprocaddress for gensock_put_data_flush\n";
- return -1;
- }
-
- return 0;
- }
-
- int open_smtp_socket( void )
- {
- int retval;
-
- /* load the library if it's not loaded */
- // if (!gensock_lib)
- if ( ( retval = load_gensock() ) ) return ( retval );
-
- if ( (retval = (*pgensock_connect) ((LPSTR) SMTPHost,
- (LPSTR)"smtp",
- &SMTPSock)))
- {
- if (retval == ERR_CANT_RESOLVE_SERVICE)
- {
- if ((retval = (*pgensock_connect) ((LPSTR)SMTPHost,
- (LPSTR)"25",
- &SMTPSock)))
- {
- gensock_error ("gensock_connect", retval);
- return -1;
- }
- }
- // error other than can't resolve service
- else
- {
- gensock_error ("gensock_connect", retval);
- return -1;
- }
- }
-
- // we wait to do this until here because WINSOCK is
- // guaranteed to be already initialized at this point.
-
- // get the local hostname (needed by SMTP)
- if ((retval = (*pgensock_gethostname) (my_hostname, sizeof(my_hostname))))
- {
- gensock_error ("gensock_gethostname", retval);
- return -1;
- }
- // strcpy( my_hostname, "pcfchb.dbs.aber.ac.uk");
- return 0;
- }
-
-
- int close_smtp_socket( void )
- {
- int retval;
-
- if( (retval = (*pgensock_close) (SMTPSock)) )
- {
- gensock_error ("gensock_close", retval);
- return -1;
- }
- FreeLibrary( gensock_lib );
- 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 = (*pgensock_getchar) (SMTPSock, 0, &ch) ) )
- {
- gensock_error ("gensock_getchar", retval);
- return -1;
- }
- else
- {
- *index = ch;
- index++;
- }
- }
-
- /* this is to support multi-line responses, common with */
- /* servers that speak ESMTP */
-
- /* I know, I know, it's a hack 8^) */
- if( in_data[3] == '-' ) return( get_smtp_line() );
- else return atoi(in_data);
- }
-
- int put_smtp_line( socktag sock, char far * line, unsigned int nchars )
- {
- int retval;
-
- if( (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars)))
- {
- gensock_error ("gensock_put_data", retval);
- return -1;
- }
- return (0);
- }
-
- int putline_internal (socktag sock, char * line, unsigned int nchars)
- {
- int retval;
-
- if ((retval =
- (*pgensock_put_data) (sock,
- (char FAR *) 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)
- {
- 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( socktag sock, char * editptr )
- {
- char *index;
- char *header_end;
- char previous_char = 'x';
- unsigned int send_len;
- int retval;
- BOOL done = 0;
-
- send_len = lstrlen(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 = (*pgensock_put_data_buffered) (sock, index, 1))) return (retval);
- if ((retval = (*pgensock_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 = (*pgensock_put_data_buffered) (sock, index, 1)))
- return (retval);
- // soft line-break (see EM_FMTLINES), skip extra CR */
- break;
- default:
- if ((retval = (*pgensock_put_data_buffered) (sock, index, 1)))
- return (retval);
- }
- previous_char = *index;
- index++;
- }
- if( (unsigned int) (index - editptr) == send_len) done = 1;
- }
-
- // this handles the case where the user doesn't end the last
- // line with a <return>
-
- if (editptr[send_len-1] != '\n')
- {
- if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n.\r\n", 5)))
- return (retval);
- }
- else
- if ((retval = (*pgensock_put_data_buffered) (sock, ".\r\n", 3)))
- return (retval);
-
- /* now make sure it's all sent... */
- if ((retval = (*pgensock_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 );
- }
-
- // create a registry entries for this program
- int CreateRegEntry( void )
- {
- HKEY hKey1;
- DWORD dwDisposition;
- LONG lRetCode;
-
- /* try to create the .INI file key */
- lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,
- "SOFTWARE\\Public Domain\\Blat",
- 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL, &hKey1,&dwDisposition
- );
-
- /* if we failed, note it, and leave */
- if (lRetCode != ERROR_SUCCESS)
- {
- printf ("Error in creating blat key in the registry\n");
- return 10;
- }
-
- /* try to set a section value */
- lRetCode = RegSetValueEx( hKey1,"SMTP server",0,REG_SZ, (BYTE *) &SMTPHost[0], (strlen(SMTPHost)+1));
-
- /* if we failed, note it, and leave */
- if (lRetCode != ERROR_SUCCESS)
- {
- printf ( "Error in setting SMTP server value in the registry\n");
- return 11;
- }
-
- /* try to set another section value */
- lRetCode = RegSetValueEx( hKey1,"Sender",0,REG_SZ, (BYTE *) &Sender[0], (strlen(Sender)+1));
-
- /* if we failed, note it, and leave */
- if (lRetCode != ERROR_SUCCESS)
- {
- printf ( "Error in setting sender address value in the registry\n");
- return 11;
- }
-
- return 0;
- }
-
- // get the registry entries for this program
- int GetRegEntry( void )
- {
- HKEY hKey1;
- DWORD dwType;
- DWORD dwBytesRead;
- LONG lRetCode;
-
- // open the registry key in read mode
- lRetCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
- "SOFTWARE\\Public Domain\\Blat",
- 0, KEY_READ, &hKey1
- );
-
- // read the value of the SMTP server entry
- lRetCode = RegQueryValueEx( hKey1, "SMTP server", NULL , &dwType, (BYTE *) &SMTPHost, &dwBytesRead);
- // if we failed, note it, and leave
- if( lRetCode != ERROR_SUCCESS )
- {
- printf( "Error in reading SMTP server value from the registry\n" );
- return 12;
- }
-
- // read the value of the SMTP server entry
- lRetCode = RegQueryValueEx( hKey1, "Sender", NULL , &dwType, (BYTE *) &Sender, &dwBytesRead);
- // if we failed, note it, and leave
- if( lRetCode != ERROR_SUCCESS )
- {
- printf( "Error in reading senders user name from the registry\n" );
- return 12;
- }
-
- return 0;
- }
-
-
- int main( int argc, /* Number of strings in array argv */
- char *argv[], /* Array of command-line argument strings */
- char **envp ) /* Array of environment variable strings */
- {
-
- if(argc<2)
- {
- // must have at least file name to send
- for(int i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
- return 1;
- }
-
- // check for SMTP server initialization
- if((argc>=3) && (lstrcmpi("-SMTP",argv[1])==0))
- {
- strcpy( SMTPHost, argv[2] );
- if (*(argv[3]))
- strcpy( Sender, argv[3] );
- else
- strcpy( Sender, "" );
-
- if( CreateRegEntry() == 0 )
- printf("\nSMTP server set to %s\n", SMTPHost );
- return 0;
- }
- else
- if( GetRegEntry() )
- {
- printf( "to set the SMTP server's address and the user name at that address do:\nblat -SMTP server username\n");
- printf( "aborting, nothing sent\n" );
- return 12;
- }
-
- // get file name from argv[1]
- char *filename=argv[1];
-
- // make sure filename exists, get full pathname
- OFSTRUCT of;
- if(lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST)==HFILE_ERROR)
- {
- cout<<filename<<" does not exist\n";
- return 2;
- }
-
- int next_arg=2;
- int impersonating = 0;
- senderid = Sender;
- loginname = Sender;
-
- for(;argc >= (next_arg+2);)
- {
- if(lstrcmpi("-h",argv[next_arg])==0)
- {
- for(int i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
- return 1;
- }
-
- // is argv[2] "-SMTP"? If so, indicate error and return
- if(lstrcmpi("-SMTP",argv[next_arg])==0)
- {
- printf( "to set the SMTP server's address and the user name at that address do:\nblat -SMTP server username");
- return 6;
- }
-
- // is argv[2] "-s"? If so, argv[3] is the subject
- if(lstrcmpi("-s",argv[next_arg])==0)
- {
- subject=argv[next_arg+1];
- next_arg += 2;
- }
-
- // is argv[2] "-c"? If so, argv[3] is the carbon-copy list
- if(lstrcmpi("-c",argv[next_arg])==0)
- {
- cc_list=argv[next_arg+1];
- next_arg += 2;
- }
-
- // is next argv "-t"? If so, succeeding argv is the destination
- if(lstrcmpi("-t",argv[next_arg])==0)
- {
- destination=argv[next_arg+1];
- next_arg += 2;
- }
-
- //is next argv '-f'? If so, succeeding argv is the loginname
- if(lstrcmp("-f",argv[next_arg])==0)
- {
- loginname=argv[next_arg+1];
- next_arg += 2;
- if( ! impersonating ) senderid = loginname;
- }
-
- //is next argv '-i'? If so, succeeding argv is the sender id
- if(lstrcmp("-i",argv[next_arg])==0)
- {
- senderid=argv[next_arg+1];
- next_arg += 2;
- impersonating = 1;
- }
- }
-
- // build the recipients list
- Recipients = new char [ strlen(destination) + strlen(cc_list) + 2 ];
- strcpy( Recipients, destination );
- if( strlen(cc_list) > 0 )
- {
- strcat(Recipients, "," );
- strcat(Recipients, cc_list );
- }
-
- // create a header for the message
- char tmpstr[256];
- char header[1024];
- int headerlen;
- SYSTEMTIME curtime;
- TIME_ZONE_INFORMATION tzinfo;
- char * days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
- char * months[] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
- DWORD retval;
-
- GetLocalTime( &curtime );
- retval = GetTimeZoneInformation( &tzinfo );
-
- // rfc1036&rfc822 acceptable format
- // Mon, 29 Jun 94 02:15:23 GMT
- sprintf (tmpstr, "Date: %s, %.2d %s %.2d %.2d:%.2d:%.2d ",
- days[curtime.wDayOfWeek],
- curtime.wDay,
- months[curtime.wMonth - 1],
- curtime.wYear,
- curtime.wHour,
- curtime.wMinute,
- curtime.wSecond);
- strcpy( header, tmpstr );
- for(int i=0;i<32;i++)
- {
- if( retval == TIME_ZONE_ID_STANDARD ) tmpstr[i] = (char) tzinfo.StandardName[i];
- else tmpstr[i] = (char) tzinfo.DaylightName[i];
- }
- strcat( header, tmpstr );
- strcat( header, "\r\n" );
- sprintf( tmpstr, "From: %s\r\n", senderid );
- strcat( header, tmpstr );
- if( impersonating )
- {
- sprintf( tmpstr, "Sender: %s\r\n", loginname );
- strcat( header, tmpstr );
- sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
- strcat( header, tmpstr );
- }
- if( *subject )
- {
- sprintf( tmpstr, "Subject: %s\r\n", subject );
- strcat( header, tmpstr );
- }
- else
- {
- sprintf( tmpstr, "Subject: Contents of file: %s\r\n", filename );
- 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.0>\r\n" );
- strcat( header, "\r\n" );
-
- headerlen = strlen( header );
-
- //get the text of the file into a string buffer
- HANDLE fileh;
- if((fileh=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,NULL))==INVALID_HANDLE_VALUE)
- {
- cout<<"error reading "<<filename<<", aborting\n";
- delete [] Recipients;
- return 3;
- }
- if(GetFileType(fileh)!=FILE_TYPE_DISK)
- {
- cout<<"Sorry, I can only mail messages from disk files...\n";
- delete [] Recipients;
- return 4;
- }
- DWORD filesize = GetFileSize( fileh,NULL );
- char *buffer = new char[filesize+headerlen+1];
- char *tmpptr;
-
- // put the header at the top...
- strcpy( buffer, header );
- // point to the end of the header
- tmpptr = buffer + headerlen;
- // and put the whole file there
- DWORD dummy;
- if(!ReadFile(fileh,tmpptr,filesize,&dummy,NULL))
- {
- cout<<"error reading "<<filename<<", aborting\n";
- CloseHandle(fileh);
- delete [] buffer;
- delete [] Recipients;
- return 5;
- }
- CloseHandle(fileh);
-
- cout<<"Sending "<<filename<<" to "<<(lstrlen(Recipients)?
- Recipients:"<unspecified>")<<'\n';
- if(lstrlen(subject))
- cout<<"Subject:"<<subject<<'\n';
- if(lstrlen(loginname))
- cout<<"Login name is "<<loginname<<'\n';
-
- if( !prepare_smtp_message( loginname, Recipients ) )
- {
- if( !send_smtp_edit_data( buffer ) )
- finish_smtp_message();
- close_smtp_socket();
- }
-
- delete [] buffer;
- delete [] Recipients;
- return 0;
- }
-
-
-
-
-