/*
 *	sm: pump mail into an SMTP server
 *	Author:	Raj Mathur (raju@sgi.com)
 *	Date:	971104
 *	Copyright (C) 1997 Silicon Graphics Inc.
 */
#include <stdio.h>
#include <netdb.h>
#include <memory.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>

static int
   done = 0 ;
static char
   LocalhostName [128] ;
static char
   *toUser ,
   *fromUser ;
/*
 *	Protos
 */
int
SendMail ( char *from , char *to , int Socket , char *data ) ;
int
Readbuf ( int Socket ) ,
   Writebuf ( int Socket , char *data ) ;
void
PrintTime ( void ) ;

void
CatchAlarm ( int i )
{
   done = 1 ;
}

char *
NetToQuad ( char *net )
{
   static char
      buf [20] ;
   sprintf ( buf , "%u.%u.%u.%u" ,
     	     (unsigned char) net [0] ,
	     (unsigned char) net [1] ,
	     (unsigned char) net [2] ,
	     (unsigned char) net [3] ) ;
   return buf ;
}

void
main ( int argc , char **argv )
{
   char
      file1kbuf [1024 + 1 ] =
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" ;
   char
      ServerHostName [128] ;
   static char
      *ServiceName = "smtp" ,
      *ProtoName = "tcp" ;
   struct hostent
      *tmp ,
      ServerHost ,
      Localhost ;
   unsigned char
      ServerAddr [4] ;
   struct servent
      *tmp2 ,
      SMTPService ;
   struct protoent
      *tmp3 ,
      TCPProto ;
   struct sockaddr_in
      Addr ;
   int
      Seconds ;
   int
      ServerSocket ;
   register int
      nMails = 0 ;
/*
 *	Process options.
 *	Options:
 *	program servername minutes to-user from-user
 */
   if ( argc != 5 )
   {
      fprintf ( stderr , "usage: %s servername seconds to-user from-user\n" , *argv ) ;
      exit ( 1 ) ;
   }
   strcpy ( ServerHostName , argv [1] ) ;
   Seconds = atoi ( argv [2] ) ;
   toUser = argv [3] ;
   fromUser = argv [4] ;
/*
 *	Find the server and service
 */
   if ( ( tmp = gethostbyname ( ServerHostName ) ) == NULL )
   {
      fprintf ( stderr , "gethostbyname(%s) failed: h_errno = %d\n" ,
		ServerHostName , h_errno ) ;
      exit ( 1 ) ;
   }
   ServerHost = *tmp ;
   memcpy ( ServerAddr , ServerHost . h_addr_list [0] ,
	    sizeof ( ServerAddr ) ) ;
   fprintf ( stderr , "Connecting to %s (%s)\n" ,
	     NetToQuad ( ServerAddr ) ,
	     ServerHost . h_name ) ;
   if ( gethostname ( LocalhostName , sizeof ( LocalhostName ) - 1 ) == -1 )
   {
      perror ( "cannot determine local hostname" ) ;
      exit ( 1 ) ;
   }
   if ( ( tmp = gethostbyname ( LocalhostName ) ) == NULL )
   {
      fprintf ( stderr , "gethostbyname(%s) failed: h_errno = %d\n" ,
		LocalhostName , h_errno ) ;
      exit ( 1 ) ;
   }
   Localhost = *tmp ;
   if ( ( tmp2 = getservbyname ( ServiceName , ProtoName ) ) == NULL )
   {
      fprintf ( stderr , "Cannot find service %s/%s: h_errno = %d\n" ,
		ServiceName , ProtoName , h_errno ) ;
      exit ( 1 ) ;
   }
   SMTPService = *tmp2 ;
   if ( ( tmp3 = getprotobyname ( ProtoName ) ) == NULL )
   {
      printf ( "unable to locate protocol %s: h_errno = %d\n" , ProtoName ,
	       h_errno ) ;
      exit ( 1 ) ;
   }
   TCPProto = *tmp3 ;
/*
 *	Open sockets and make connection.
 */
   if (
      ( ServerSocket = socket ( ServerHost . h_addrtype , SOCK_STREAM , 0 ) )
      == -1 )
   {
      perror ( "unable to open socket" ) ;
      exit ( 1 ) ;
   }
   Addr . sin_family = ServerHost . h_addrtype ;
   Addr . sin_port = SMTPService . s_port ;
   memcpy ( &Addr . sin_addr , ServerAddr , ServerHost . h_length ) ;
   if ( connect ( ServerSocket , (struct sockaddr *) &Addr ,
		  sizeof ( Addr ) ) == -1 )
   {
      perror ( "connect" ) ;
      exit ( 1 ) ;
   }
/*
 *	Signal at the end of specified time.
 */
   (void) alarm ( Seconds ) ;
   signal ( SIGALRM , CatchAlarm ) ;
/*
 *	Determine user and send mail.
 */
   while ( !done )
   {
      if ( !SendMail ( fromUser , toUser , ServerSocket , file1kbuf ) )
      {
	 nMails++ ;
      }
      else
      {
	 fprintf ( stderr , "Cannot send message: %d %d\n" , errno , h_errno ) ;
      }
   }
   printf ( "%d messages sent in %d seconds\n" , nMails , Seconds ) ;
}
/*
 * Send a message on an open socket
 */
int
SendMail ( char *from , char *to , int Socket , char *data )
{
   char
      buf [1024] ;
   static int
      SaidHello = 0 ;

   if ( !SaidHello )
   {
      if ( !Readbuf ( Socket ) ) return -1 ;
      sprintf ( buf , "helo %s\n" , LocalhostName ) ;
      if ( !Writebuf ( Socket , buf ) ) return -1 ;
      if ( !Readbuf ( Socket ) ) return -1 ;
      SaidHello = 1 ;
   }
   sprintf ( buf , "mail from: <%s>\n" , from ) ;
   if ( !Writebuf ( Socket , buf ) ) return -1 ;
   if ( !Readbuf ( Socket ) ) return -1 ;
   sprintf ( buf , "rcpt to: <%s>\n" , to ) ;
   if ( !Writebuf ( Socket , buf ) ) return -1 ;
   if ( !Readbuf ( Socket ) ) return -1 ;
   if ( !Writebuf ( Socket , "data\n" ) ) return -1 ;
   if ( !Readbuf ( Socket ) ) return -1 ;
   if ( !Writebuf ( Socket , data ) ) return -1 ;
   if ( !Writebuf ( Socket , "\r\n.\r\n" ) ) return -1 ;
   if ( !Readbuf ( Socket ) ) return -1 ;
   if ( !Writebuf ( Socket , "rset\n" ) ) return -1 ;
   if ( !Readbuf ( Socket ) ) return -1 ;
   return 0 ;
}
int
Readbuf ( int s )
{
   char
      buf [2048] ;
   PrintTime () ;
   memset ( buf , 0 , sizeof ( buf ) ) ;
   if ( read ( s , buf , sizeof ( buf ) - 1 ) == -1 )
   {
      perror ( "read" ) ;
      return 0 ;
   }
   printf ( "%s" , buf ) ;
   return 1 ;
}
int Writebuf ( int s , char *b )
{
   if ( write ( s , b , strlen ( b ) ) != strlen ( b ) )
   {
      perror ( "write" ) ;
      return 0 ;
   }
   return 1 ;
}
/*
 *	Print the current time string: hh:mm:ss.fff
 */
void
PrintTime ( void )
{
   struct tm
      tm ;
   struct timeval
      tv ;
/*
   static struct timezone
      tz =
   { -330 , DST_NONE } ;
*/

   gettimeofday ( &tv , NULL) ;

   tm = *localtime ( &tv . tv_sec ) ;
   printf ( "%02d:%02d:%02d.%06d: " , tm . tm_hour , tm . tm_min , tm . tm_sec ,
	    tv . tv_usec ) ;
}
