/*
 * SMTP Send Mail Utility.
 */

#define __Program__ "PutMail"
#define __Version__ "1.24"

#include <Defaults.h>
#include <SMTP.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/dir.h>
#include <dos/stdio.h>
#include <dos/dosextens.h>
#include <exec/memory.h>

#define AMITCP_NEW_NAMES
#define _OPTINLINE
#include <LocalInclude:AmiTCP/errno.h>
#include <netdb.h>

BPTR fhIn = NULL, fhOut = NULL;
struct Remember *MemList = NULL;
BPTR Console = NULL, MyConsole = NULL;

#define OPT_TEMPLATE "MAIL=MAILFILE/K,TO=RECIPIENT/K/M,SUB=SUBJECT/K,HOME/K,REPLYTO/K,SMTPHOST/K,NOHEAD/S,NOADDR/S,NOSIG/S,VERBOSE/S"
#define OPT_MAIL 0
#define OPT_TO 1
#define OPT_SUB 2
#define OPT_HOME 3
#define OPT_REPLYTO 4
#define OPT_SMTPHOST 5
#define OPT_NOHEAD 6
#define OPT_NOADDR 7
#define OPT_NOSIG 8
#define OPT_VERBOSE 9
#define OPT_COUNT 10

struct RDArgs *Args;
LONG Options[OPT_COUNT];

STRPTR Mail;               // Mail file name.
STRPTR *To;                // TO Address.
STRPTR Subject;            // Subject text.
STRPTR HomeDir;            // Home directory.
STRPTR ReplyTo;            // E-Mail address to send replies to.
STRPTR SMTPHost;           // SMTP Mail Host.

BOOL NoHead;
BOOL NoAddr;
BOOL NoSig;
BOOL Verbose;

STRPTR Domain;
#define USERID_LEN 16
char UserID[USERID_LEN];
#define USERNAME_LEN 64
char UserName[USERNAME_LEN];
#define HOSTNAME_LEN 256
char HostName[HOSTNAME_LEN];
char MailTemp[MAXNAMLEN + 1];

#define CMDBUF_SIZE 512
#define DATBUF_SIZE 1024

int hSocket = SMTP_NO_SOCKET;
struct sockaddr_in INetSocketAddr;


void __regargs Abort(STRPTR ErrorMsg, BOOL ErrorCR, int ErrorRC, LONG Error2);


void __regargs Message(STRPTR Msg, BOOL CR)
{

if (!Console)

   {
   if (Console = Output())
      MyConsole = NULL;
   else
      Console = MyConsole = Open(STDIO, MODE_READWRITE);
   
   Write(Console, "\n", 1);
   Message(Version, TRUE);
   Message("Written by Martin V Lanza.\n", TRUE);
   }

if (Msg) Write(Console, Msg, strlen(Msg));
if (CR) Write(Console, "\n", 1);

return;
}


void __regargs VerboseMsg(STRPTR Func, STRPTR Name, STRPTR Value)
{
static BOOL DoLF;
static char Msg[DATBUF_SIZE * 2];

if (!Verbose) return;

sprintf(Msg, "%-16s  ", Func);

if (Name) strcat(Msg, Name);
if (Value) strcat(Msg, Value);

if (Msg[strlen(Msg)-1] == '\n')
   DoLF = FALSE;
else
   DoLF = TRUE; 

Message(Msg, DoLF);

return;
}


BOOL __regargs RecvDat(STRPTR DatBuf, int *DatLen)
{
static char Func[] = "RecvDat";

errno = 0;
if (hSocket == SMTP_NO_SOCKET) return(FALSE);
*DatLen = Recv(hSocket, DatBuf, DATBUF_SIZE - 1, 0);
if (*DatLen) DatBuf[*DatLen] = '\0'; else DatBuf[0] = '\0';
VerboseMsg(Func, "Recv() ", DatBuf);

return(TRUE);
}


BOOL __regargs SendDat(STRPTR SendData)
{
static char Func[] = "SendDat";
static char StrBuf[DATBUF_SIZE];

if (hSocket == SMTP_NO_SOCKET) return(FALSE);
if (!SendData) return(TRUE);

// Conform to RFC821.
// This prevents premature message termination by user text.

*StrBuf = '\0';
if (SendData[0] == '.')
   if (SendData[1] == '\r')
      if (SendData[2] == '\n')
            {
            StrBuf[0] = '.';
            StrBuf[1] = '\0';
            }

strcat(StrBuf, SendData);
VerboseMsg(Func, "Send() ", StrBuf);
if (Send(hSocket, StrBuf, strlen(StrBuf), 0) != -1) return(TRUE);
Abort("Socket message send failure.", TRUE, RETURN_FAIL, Errno());
return(FALSE);
}


void __regargs SendCmd(STRPTR CmdText, STRPTR ParmText)
{
static int StrLen;
static char StrBuf[DATBUF_SIZE];

if (hSocket == SMTP_NO_SOCKET) return;

if (!CmdText || !*CmdText)
   *StrBuf = '\0';
else
   if (!ParmText || !*ParmText)
      sprintf(StrBuf, "%s\r\n", CmdText);
   else
      sprintf(StrBuf, "%s %s\r\n", CmdText, ParmText);

if (!SendDat(StrBuf)) return;
if (!RecvDat(StrBuf, &StrLen)) return;

switch (atoi(StrBuf))
   {
   case SMTP_STATUS_REPLY :   break;
   case SMTP_HELP_MESSAGE :   break;
   case SMTP_SERVICE_READY:   break;
   case SMTP_SERVICE_CLOSE:   break;
   case SMTP_OK           :   break;
   case SMTP_OK_FORWARD   :   break;
   case SMTP_SEND_MAIL    :   break;
   
   default:
      {
      char ErrorMsg[256];
      sprintf(ErrorMsg, "Bad %s command response: %s", CmdText, StrBuf);
      Abort(ErrorMsg, TRUE, RETURN_FAIL, ERROR_BAD_NUMBER);
      }
   }

// Extended responce may not fit in the buffer :-(
// Keep reading untill we get it all.
if (StrBuf[3] == '-')
   while (StrBuf[StrLen - 1] != '\n')
      if (!RecvDat(StrBuf, &StrLen)) break;
         
return;
}


void __regargs SocketDisconnect(void)
{
char Func[] = "SocketDisconnect";

if (hSocket != SMTP_NO_SOCKET)
   {
   SendCmd("QUIT", NULL);
   Shutdown(hSocket, 2);
   CloseSocket(hSocket);
   hSocket = SMTP_NO_SOCKET;
   VerboseMsg(Func, "Disconnected from SMTP Host ", SMTPHost);
   }

return;
}


void __regargs CleanUp(void)
{
char Func[] = "CleanUp";

VerboseMsg(Func, "Cleanup in progress.", NULL);

if (fhIn != Input())
   if (fhIn) Close(fhIn);

if (fhOut) Close(fhOut);

if (Args) FreeArgs(Args);

if (MemList) FreeRemember(&MemList, TRUE);

if (MyConsole)
   {
   Message("\nPress RETURN to terminate program: ", FALSE);
   FGetC(MyConsole);
   Close(MyConsole);
   }
   
return;
}


void __regargs Abort(STRPTR ErrorMsg, BOOL ErrorCR, int ErrorRC, LONG Error2)
{
static BOOL Aborting;

if (Aborting) return;
Aborting = TRUE;

if (ErrorMsg)
   {
   Message(__Program__ ": ", FALSE);
   Message(ErrorMsg, ErrorCR);
   }

SendCmd("RSET", NULL);
SocketDisconnect();

CleanUp();

if (Error2) ((struct Process *) FindTask(NULL))->pr_Result2 = Error2;

exit(ErrorRC);
}


void __regargs SocketConnect(void)
{
struct hostent *HostAddr;
char Func[] = "SocketConnect";

HostAddr = GetHostByName(SMTPHost);
if (!HostAddr)
   {
   VerboseMsg(Func, "GetHostByName() ", SMTPHost);
   if (h_errno == TRY_AGAIN)
      Abort("Unable to locate the SMTP Host, try again later.", TRUE, RETURN_FAIL, h_errno);
   else
      Abort("The SMTP Host is invalid.", TRUE, RETURN_FAIL, h_errno);
   }

INetSocketAddr.sin_len = sizeof(INetSocketAddr);
INetSocketAddr.sin_family = AF_INET;
INetSocketAddr.sin_port = 25; // SMTP
INetSocketAddr.sin_addr.s_addr = 0;

memcpy(&INetSocketAddr.sin_addr, HostAddr->h_addr, HostAddr->h_length);

hSocket = Socket(HostAddr->h_addrtype, SOCK_STREAM, 0);
if (hSocket == SMTP_NO_SOCKET)
   {
   VerboseMsg(Func, "Socket() Failed!", NULL);
   Abort("Socket allocation failed.", TRUE, RETURN_FAIL, Errno());
   }

if (Connect(hSocket, (struct sockaddr *) &INetSocketAddr, sizeof(INetSocketAddr)) == -1)
   {
   VerboseMsg(Func, "Connect() Failed!", NULL);
   Abort("Socket connection failed.", TRUE, RETURN_FAIL, Errno());
   }

VerboseMsg(Func, "Connected to SMTP Host ", SMTPHost);

SendCmd(NULL, NULL);       // Check for the Welcome... message.
SendCmd("HELO", HostName); // Say HELLO, Receive HELLO.
   
return;
}


BOOL __regargs GetEnvVar(STRPTR Name, STRPTR Buffer, long Len)
{
static int BufLen, EnvLen;

BufLen = GetVar(Name, Buffer, Len - 1, GVF_GLOBAL_ONLY);
EnvLen = IoErr();
SetIoErr(NULL);

if (BufLen <= NULL) return(FALSE);
if (BufLen != EnvLen) return(FALSE);

return(TRUE);
}


BOOL __regargs GetEMailAddr(void)
{
int Len;
BPTR fhFile;
char strName[MAXNAMLEN + 1];
char Func[] = "GetEMailAddr";

strcpy(strName, HomeDir);
AddPart(strName, ".EMailAddr", MAXNAMLEN);

if (!(fhFile = Open(strName, MODE_OLDFILE)))
   {
   VerboseMsg(Func, strName, " could not be opened.");
   return(FALSE);
   }

VerboseMsg(Func, strName, " successfully opened.");
FGets(fhFile, ReplyTo, USERID_LEN + HOSTNAME_LEN);

if (IoErr())
   {
   VerboseMsg(Func, "Read failure on ", strName);
   Close(fhFile);
   return(FALSE);
   }

Close(fhFile);

Len = strlen(ReplyTo);
if (!Len) return(FALSE);

while (--Len)
   {
   if (ReplyTo[Len] != ' ')
      if (ReplyTo[Len] != '\r')
         if (ReplyTo[Len] != '\n')
            break;
            
   ReplyTo[Len] = '\0';
   }

return(TRUE);
}


void __regargs InitProg(void)
{
struct passwd *UserList;
char Func[] = "InitProg";
struct DateStamp TheDateStamp;

memset(Options, NULL, sizeof(LONG) * OPT_COUNT);
Args = ReadArgs(OPT_TEMPLATE, Options, NULL);
if (!Args)
   {
   PrintFault(IoErr(), NULL);
   Abort("Argument Template is " OPT_TEMPLATE, TRUE, RETURN_FAIL, ERROR_BAD_TEMPLATE);
   }

Mail = (STRPTR) Options[OPT_MAIL];
To = (STRPTR *) Options[OPT_TO];
Subject = (STRPTR) Options[OPT_SUB];
HomeDir = (STRPTR) Options[OPT_HOME];
ReplyTo = (STRPTR) Options[OPT_REPLYTO];
SMTPHost = (STRPTR) Options[OPT_SMTPHOST];
NoHead = Options[OPT_NOHEAD];
NoAddr = Options[OPT_NOADDR];
NoSig = Options[OPT_NOSIG];
Verbose = Options[OPT_VERBOSE];

DateStamp(&TheDateStamp);
sprintf(MailTemp, "T:PutMail.%ld@%ld", FindTask(NULL), TheDateStamp.ds_Minute);

if (!GetEnvVar("USER", UserID, USERID_LEN))
   Abort("ENV variable 'USER' not found.", TRUE, RETURN_FAIL, NULL);
   
if ((UserList = getpwnam(UserID)))
   strcpy(UserName, UserList->pw_gecos);
else
   *UserName = '\0';


if (!HomeDir)
   {
   HomeDir = AllocRemember(&MemList, MAXNAMLEN + 1, MEMF_ANY | MEMF_CLEAR);
   if (!HomeDir) Abort("Not enough free memory.", TRUE, RETURN_FAIL, ERROR_NO_FREE_STORE);
   if (!GetEnvVar("HOME", HomeDir, MAXNAMLEN))
      Abort("'HOME' not found.", TRUE, RETURN_FAIL, NULL);
   }
   
if (!GetEnvVar("HOSTNAME", HostName, HOSTNAME_LEN))
   Abort("ENV variable 'HOSTNAME' not found.", TRUE, RETURN_FAIL, NULL);

Domain = HostName;
while (*Domain && *Domain != '.') Domain++;
if (*Domain) Domain++;

if (!SMTPHost)
   {
   SMTPHost = AllocRemember(&MemList, HOSTNAME_LEN, MEMF_ANY | MEMF_CLEAR);
   if (!SMTPHost) Abort("Not enough free memory.", TRUE, RETURN_FAIL, ERROR_NO_FREE_STORE);
   if (!GetEnvVar("SMTPHOST", SMTPHost, HOSTNAME_LEN))
      {
      struct hostent *HostAddr;
      if (HostAddr = GetHostByName("SMTPHOST"))
         strcpy(SMTPHost, HostAddr->h_name);
      else
         {
         strcpy(SMTPHost, Domain);
         VerboseMsg(Func, "SMTPHost name not provided, assumed ", SMTPHost);
         }
      }
   }
      
if (!ReplyTo)
   {
   ReplyTo = AllocRemember(&MemList, USERID_LEN + HOSTNAME_LEN, MEMF_ANY | MEMF_CLEAR);
   if (!ReplyTo) Abort("Not enough free memory.", TRUE, RETURN_FAIL, ERROR_NO_FREE_STORE);
   if (!GetEnvVar("EMAILADDR", ReplyTo, USERID_LEN + HOSTNAME_LEN))
      if (!GetEMailAddr())
         {
         sprintf(ReplyTo, "%s@%s", UserID, SMTPHost);
         VerboseMsg(Func, "ReplyTo & EMAILADDR not provided, assumed ", ReplyTo);
         }
   }

if (Verbose)
   {
   if (Mail) VerboseMsg(Func, "MailFile=", Mail);
   if (Subject) VerboseMsg(Func, "Subject=", Subject);
   VerboseMsg(Func, "Home=", HomeDir);
   VerboseMsg(Func, "ReplyTo=", ReplyTo);
   VerboseMsg(Func, "SMTPHost=", SMTPHost);
   NoHead ? VerboseMsg(Func, "NoHead=", "TRUE") : VerboseMsg(Func, "NoHead=", "FALSE");
   NoAddr ? VerboseMsg(Func, "NoAddr=", "TRUE") : VerboseMsg(Func, "NoAddr=", "FALSE");
   NoSig ? VerboseMsg(Func, "NoSig=", "TRUE") : VerboseMsg(Func, "NoSig=", "FALSE");
   Verbose ? VerboseMsg(Func, "Verbose=", "TRUE") : VerboseMsg(Func, "Verbose=", "FALSE");
   }

return;
}


void __regargs CopyFile(int NoBlankLines, STRPTR ErrText)
{
static char StrBuf[DATBUF_SIZE];

while(FGets(fhIn, StrBuf, DATBUF_SIZE))
   {
   int register i;
   i = strlen(StrBuf) - 1;

   //Strip CR & LF to avoid Amiga/IBM differences.
   if (i >= 0 && StrBuf[i] == '\n') StrBuf[i--] = '\0';
   if (i >= 0 && StrBuf[i] == '\r') StrBuf[i--] = '\0';

   while (i >= 0 && StrBuf[i] == ' ') i--;
   if (i < 0 && NoBlankLines) continue;

   //Put standard CR LF on end of line.
   StrBuf[++i] = '\r';
   StrBuf[++i] = '\n';
   StrBuf[++i] = '\0';

   if (FPuts(fhOut, StrBuf))
      if (IoErr()) Abort("Write Error on temporary mail file.", TRUE, RETURN_FAIL, NULL);
   }

if (IoErr()) Abort(ErrText, TRUE, RETURN_FAIL, NULL);

if (fhIn != Input()) Close(fhIn);

fhIn = NULL;

return;
}


BPTR __regargs OpenFile(STRPTR Path, STRPTR Name, LONG Mode)
{
static BPTR fhFile;
static char strMode[33];
static char strName[MAXNAMLEN + 1];
static char Func[] = "OpenFile";

switch (Mode)
   {
   case MODE_OLDFILE:
      strcpy(strMode, " opened for Input."); break;
   case MODE_NEWFILE:
      strcpy(strMode, " opened for Output.");   break;      
   case MODE_READWRITE:
      strcpy(strMode, " opened for Input & Output."); break;      
   }

strcpy(strName, Path);
AddPart(strName, Name, MAXNAMLEN);

fhFile = Open(strName, Mode);

if (fhFile)
   {
   VerboseMsg(Func, strName, strMode);
   //The AmigaDOS buffered IO does NOT work !
   //if (!SetVBuf(fhFile, NULL, BUF_FULL, 4096))
   //   VerboseMsg(Func, strName, " will be buffered.");
   }
else
   VerboseMsg(Func, "Unable to open ", strName);
   
return(fhFile);
}


void __regargs CreateMail(void)
{
char Advert[DATBUF_SIZE];
char StrBuf[DATBUF_SIZE];
char StrDay[LEN_DATSTRING];
char StrDate[LEN_DATSTRING];
char StrTime[LEN_DATSTRING];
struct DateTime TheDateTime;


// Advertisement :-)
sprintf(Advert, "X-SMTP-Client: Amiga %s %s by Martin Lanza.\r\n", __Program__, __Version__);
   
if (!(fhOut = OpenFile("", MailTemp, MODE_NEWFILE)))
   Abort("Unable to create temporary mail file.", TRUE, RETURN_FAIL, IoErr());

if (NoHead && NoAddr) FPuts(fhOut, Advert);
 
if (!NoHead)
   {
   if (fhIn = OpenFile(HomeDir, ".header", MODE_OLDFILE))
      CopyFile(TRUE, "Error reading '.header' file.");
   if (NoAddr) FPuts(fhOut, Advert);
   }

   
if (!NoAddr)
   {
   // From:
   if (*UserName)
      sprintf(StrBuf, "From: %s@%s (%s)\r\n", UserID, HostName, UserName);
   else
      sprintf(StrBuf, "From: %s@%s\r\n", UserID, HostName);

   FPuts(fhOut, StrBuf);

   // X-SMTP-Client:
   FPuts(fhOut, Advert);
             
   // Date:
   DateStamp(&TheDateTime.dat_Stamp);
   TheDateTime.dat_Format = FORMAT_DOS;
   TheDateTime.dat_Flags = NULL;
   TheDateTime.dat_StrDay = StrDay;
   TheDateTime.dat_StrDate = StrDate;
   TheDateTime.dat_StrTime = StrTime;
   DateToStr(&TheDateTime);
   StrDate[2] = ' '; StrDate[6] = ' ';
   sprintf(StrBuf, "Date: %3.3s, %s %s\r\n", StrDay, StrDate, StrTime);
   FPuts(fhOut, StrBuf);
             
   // Reply-To:
   if (ReplyTo)
      {
      sprintf(StrBuf, "Reply-To: %s\r\n", ReplyTo);
      FPuts(fhOut, StrBuf);
      }

   // To:
   if (To)
      {
      int i;
      char Desc[] = "To:";
      
      for (i=0; To[i]; i++)
         {
         sprintf(StrBuf, "%3.3s %s \r\n", Desc, To[i]);
         if (To[i+1]) StrBuf[strlen(StrBuf) - 3] = ',';
         strcpy(Desc, "   ");
         FPuts(fhOut, StrBuf);
         }
      }
                       
   // Subject:
   if (Subject)
      {
      sprintf(StrBuf, "Subject: %s\r\n", Subject);
      FPuts(fhOut, StrBuf);
      }
   
   if (To)
      if(To[0])   
         {
         sprintf(StrBuf, "\r\n");
         FPuts(fhOut, StrBuf);
         }
   }

if (!Mail)
   {
   fhIn = Input();
   CopyFile(FALSE, "Error reading from Standard Input.");
   }
else
   if (fhIn = OpenFile("", Mail, MODE_OLDFILE))
      CopyFile(FALSE, "Error reading Mail file.");
   else
      Abort("Unable to process Mail input file.", TRUE, RETURN_FAIL, IoErr());


if (!NoSig)
   if (fhIn = OpenFile(HomeDir, ".signature", MODE_OLDFILE))
      CopyFile(FALSE, "Error reading '.signature' file.");

Close(fhOut);
fhOut = NULL;

return;
}


void __regargs FilteredAppend(STRPTR Srce, STRPTR Dest)
{
int register i=0, j=0;
int max = DATBUF_SIZE * 2;

// Find end of Dest.
while(Dest[j]) j++;

while(Srce[i])
   {
   
   // Filter these.
   if (Srce[i] != '\t')
      if (Srce[i] != '\r')
         if (Srce[i] != '\n')
            // Copy char.
            Dest[j++] = Srce[i];

   i++;
   
   if (j >= max)
      Abort("'To:' string exceeds buffer size or is illegal.", TRUE, RETURN_FAIL, NULL);
   }

Dest[j] = '\0';

return;
}


void __regargs LocateTo(void)
{
int i;
STRPTR ToData;
STRPTR *ToArray;
char Desc[] = "To: ";
char StrBuf[DATBUF_SIZE];
char Func[] = "LocateTo";

if (To)
   if (To[0])
      return;

ToData = AllocRemember(&MemList, DATBUF_SIZE * 2, MEMF_ANY | MEMF_CLEAR);
if (!ToData) Abort("Not enough free memory.", TRUE, RETURN_FAIL, ERROR_NO_FREE_STORE);
ToArray = AllocRemember(&MemList, sizeof(STRPTR) * 64, MEMF_ANY | MEMF_CLEAR);
if (!ToArray) Abort("Not enough free memory.", TRUE, RETURN_FAIL, ERROR_NO_FREE_STORE);

if (!(fhIn = OpenFile("", MailTemp, MODE_OLDFILE)))
   Abort("Unable to open temporary mail file.", TRUE, RETURN_FAIL, IoErr());
   
VerboseMsg(Func, "Scanning temporary mail file for 'To:'.", NULL);

while(FGets(fhIn, StrBuf, DATBUF_SIZE))
      {
      if (*StrBuf == '\r')
         // This must mean we are past the message header.
         Abort("Unable to locate 'To:' address.", TRUE, RETURN_FAIL, NULL);

      if (!strnicmp(StrBuf, "To: ", 4)) break;
      }

if (IoErr()) Abort("Read Error on temporary mail file.", TRUE, RETURN_FAIL, IoErr());

FilteredAppend(&StrBuf[4], ToData);

while (FGets(fhIn, StrBuf, DATBUF_SIZE))
   {
   if (StrBuf[0] != ' ' && StrBuf[0] != '\t') break;
   FilteredAppend(StrBuf, ToData);
   }
                     
if (IoErr()) Abort("Read Error on temporary mail file.", TRUE, RETURN_FAIL, IoErr());

Close(fhIn);
fhIn = NULL;

i=0;
ToArray[i++] = ToData;
while(*ToData && i < 63)
   {
   if (*ToData == ',')
      {
      *ToData = '\0';
      ToArray[i++] = ToData + 1;
      }

   ToData++;
   }

To = ToArray;

for (i=0; To[i]; i++)
   {
   // Ignore leading spaces.
   while(To[i] && *To[i] == ' ') To[i]++;

   VerboseMsg(Func, Desc, To[i]);
   strcpy(Desc, " &  ");
   }
   
return;
}


void __regargs MailInit(void)
{
int i;
STRPTR ToAddr, RouteAddr[2];
char ToStr[USERID_LEN + HOSTNAME_LEN + 10];
char FromStr[USERID_LEN + HOSTNAME_LEN + 10];

sprintf(FromStr, "FROM:<%s@%s>", UserID, HostName);
SendCmd("MAIL", FromStr);

for (i = 0; To[i]; i++)
   {
   RouteAddr[0] = strchr(To[i], '<');
   RouteAddr[1] = strchr(To[i], '>');
   if (RouteAddr[0] && RouteAddr[1])
      {
      strcpy(ToStr, "To:");
      strncat(ToStr, RouteAddr[0], 1 + RouteAddr[1] - RouteAddr[0]);
      }
   else
      {
      // Ignore leading spaces.
      while(To[i] && *To[i] == ' ') To[i]++;
      
      // Ignore trailing spaces.
      ToAddr = To[i] + strlen(To[i]) - 1;
      while (*ToAddr == ' ' && ToAddr > To[i]) 
         *(ToAddr--) = '\0';
            
      sprintf(ToStr, "To:<%s>", To[i]);
      }
      
   SendCmd("RCPT", ToStr);
   }

SendCmd("DATA", NULL);

return;
}


void __regargs MailSend(void)
{
char strBuf[DATBUF_SIZE];

if (!(fhIn = OpenFile("", MailTemp, MODE_OLDFILE)))
   Abort("Unable to open temporary mail file.", TRUE, RETURN_FAIL, IoErr());
   
while(FGets(fhIn, strBuf, DATBUF_SIZE)) SendDat(strBuf);

if (IoErr()) Abort("Read Error on temporary mail file.", TRUE, RETURN_FAIL, IoErr());

Close(fhIn);
fhIn = NULL;

return;
}


void __regargs MailEnd(void)
{
char Func[] = "MailEnd";

SendCmd("\r\n.", NULL);

VerboseMsg(Func, "Mail successfully sent.", NULL);

return;
}


int __regargs main(int argc, char **argv)
{

if (!argc) exit(RETURN_FAIL);

InitProg();

CreateMail();

LocateTo();

SocketConnect();

MailInit();

MailSend();

MailEnd();

SocketDisconnect();

CleanUp();

DeleteFile(MailTemp);

return(RETURN_OK);
}
