home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 3
/
Meeting_Pearls_III.iso
/
Pearls
/
tcp
/
Networking
/
TCP
/
Mail
/
mail
/
mail.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-06
|
10KB
|
468 lines
/*
Simple SMTP mail sender.
Copyright 1993 Stephen Norris.
$Revision: 1.21 $
$Log: mail.c,v $
* Revision 1.21 1994/03/06 10:17:03 srn
* Extended messages are broken - temporary fix.
*
* Revision 1.20 1994/02/19 22:33:41 srn
* Now added: If invoked as sendmail, set NoEd, NoSubj, NoHead.
*
* Revision 1.19 1993/12/12 14:20:28 srn
* Minor changes...
*
* Revision 1.18 1993/12/01 09:38:38 srn
* Checked in for beginning 1.7 release.
*
* Revision 1.17 1993/11/30 08:52:02 srn
* Split up code.
* Added Reply-To: and MessageId: headers.
* Tidied up a bit.
*
* Revision 1.16 1993/11/24 23:07:23 srn
* SOrted out NOSIG stuff.
*
* Revision 1.15 1993/11/24 22:50:27 srn
* Removed all SMTPSERVER references.
*
* Revision 1.14 1993/11/24 09:53:44 srn
* Now appends .sig before editing.
*
* Revision 1.13 1993/11/22 21:59:53 srn
* Added editor support.
*
* Revision 1.13 1993/11/22 21:59:53 srn
* Added editor support.
*
* Revision 1.12 1993/11/22 19:29:36 srn
* Added code for sig files.
*
* Revision 1.11 1993/11/21 18:04:32 srn
* Added SIGFILE argument. Generally tidied up the argument handling.
*
* Revision 1.11 1993/11/21 18:04:32 srn
* Added SIGFILE argument. Generally tidied up the argument handling.
*
* Revision 1.10 1993/11/21 16:48:17 srn
* Changed multiple destination code.
*
* Revision 1.9 1993/11/19 22:20:26 srn
* Changed order of sender/receiver SMTP messages; hosts
* require them in a set order.
* Added a HELO to the start, some smtp demons need it.
*
* Revision 1.8 1993/11/17 20:58:36 srn
* Changed To: lines.
*
* Revision 1.7 1993/10/30 09:48:55 srn
* Copes with multiline responces.
*
* Revision 1.6 1993/10/24 11:03:48 srn
* Does multiple destinations, added date header.
*
* Revision 1.6 1993/10/24 11:03:48 srn
* Does multiple destinations, added date header.
*
* Revision 1.5 1993/10/20 22:37:46 srn
* Working for multiple destinations.
* Needs to clean up (unlink) the temporary file...
*
* Revision 1.4 1993/10/20 20:27:09 srn
* Got error checking working.
*
* Revision 1.3 1993/10/16 11:25:44 srn
* Compiles.
*
* Revision 1.2 1993/10/16 11:19:10 srn
* Move includes, defines etc. into mail.h
*
*/
#include "mail.h"
#include "mail_proto.h"
static char *VERSION = "$VER: Mail 1.8 " __AMIGADATE__;
int s;
struct sockaddr_in Address;
struct hostent *Hostaddr;
char *Hostname;
int Mode; /* VERBOSE or not. */
char Name[20]; /* Name of the temporary file. */
FILE *TempMail; /* The mail is written here, then sent. */
char *ReplyTo; /* Address to set replies to. */
char *SigFile; /* Pathname of .sig file. */
/* Flags controlling header generation. */
int NoSubj, NoHead, NoEd, NoSig; /* No subject line, no headers, no editor, no signature file. */
/* Command line options. */
static char Template[] = "RCPT=RECIPIENT/M/A,REPLYTO,SMTPHOST/K,NOSIG/S,VERBOSE/S,NOSUBJ/S,NOHEAD/S,NOED/S";
extern int errno;
extern void _STDcloseSockets();
/* Edit a file for mail. */
void
Edit (char *FileName)
{
char Command[150];
sprintf(Command, "%s %s", GetEditor(), FileName);
system(Command);
}
/* Handle various mailer errors. */
void
MailError(int Type)
{
if (TempMail){
/* Should check for existence of t:dead.letter and use a different
name if it is there. */
char *Fname = "t:dead.letter";
if (rename(Name, Fname) == 0)
printf("Mail saved in %.\n", Fname);
}
switch (Type){
case 0: /* Look in errno. */
PrintNetFault(errno, "mail");
break;
case BAD_RESPONCE: /* The server indicated an error.*/
printf("Error trying to transmit.\n");
break;
case NOTEMP: /* Couldn't open the temporary file. */
printf("Unable to open the temporary file.\n");
break;
}
exit(30);
}
/* Now append a signature file, if required and available. */
void
AppendSig(FILE *ReadFile, char *SigFile)
{
FILE *Sig;
int ch;
char *SigName;
if (!NoSig){
if ((SigName = GetSigName()) != NULL){
if (Sig = fopen (SigName, "r")){
while ((ch = fgetc(Sig)) != EOF){
fputc(ch, ReadFile);
}
} else
printf("Unable to open signature file.\n");
}
}
}
/* Read the mail into a temporary file. */
FILE *
ReadMail ()
{
char Buffer[256];
FILE *ReadFile;
/* Generate a unique name. */
sprintf(Name, "t:mail.%ld", FindTask(NULL));
if (!(ReadFile = fopen(Name, "w+"))){
MailError(NOTEMP);
}
if (!NoSubj && !NoHead){
printf("Subject: ");
fgets(Buffer, 255, stdin);
Buffer[strlen(Buffer) - 1] = (char) 0;
fputs("Subject: ", ReadFile);
fputs(Buffer, ReadFile);
fputs("\n\n", ReadFile);
}
if (NoEd){
printf("Now type the text, terminate with EOF or .\n\n");
/* Read in the body of the mail, and store it in the temporary file. */
while(!feof(stdin)){
if (fgets(Buffer, 255, stdin) == NULL)
break;
Buffer[strlen(Buffer) - 1] = (char) 0;
if (!strcmp(Buffer, "."))
break;
fputs(Buffer, ReadFile);
fputs("\r\n", ReadFile);
}
AppendSig (ReadFile, SigFile);
} else {
/* Edit the mail. */
AppendSig (ReadFile, SigFile);
fclose(ReadFile);
Edit (Name);
if (!(ReadFile = fopen(Name, "r+"))){
MailError(NOTEMP);
}
fseek(ReadFile, 0L, SEEK_END); /* Go to EOF. */
}
fclose(ReadFile);
printf("[EOT]\n");
if (!(ReadFile = fopen(Name, "r"))){
MailError(NOTEMP);
}
return ReadFile;
}
/* Simply send some text down the socket; check the write succeeds, but don't
check for any responce. */
int
SendText(char *Text)
{
if (write(s, Text, strlen(Text)) != strlen(Text)){
MailError(0);
}
return 1;
}
/* Similar to SendText excepting that responces are checked by comparing them with Expect. */
int
SendTextCheck(char *Text, int Expect)
{
char Buffer[256];
int i;
if ((i = write(s, Text, strlen(Text))) != strlen(Text)){
MailError(0);
}
if (read (s, Buffer, 255) <= 5){
MailError(0);
}
if (atoi(Buffer) != Expect){
if (Mode == VERBOSE){
printf("Got %d, expected %d responce from server.\n", atoi(Buffer), Expect);
printf("Full text was: %s.\n", Buffer);
printf("Text sent was: %s.\n", Text);
}
MailError(BAD_RESPONCE);
}
/* Check for, and handle extended messages. */
/*
while (Buffer[3] == '-'){
if (read (s, Buffer, 255) <= 5)
MailError(0);
}
*/
return 1;
}
/* Send the mail to the recipients. Send one MAIL FROM:<> and multiple
RCPT TO: messages, followed by DATA.
*/
int
SendMail(char *Recipients[])
{
char *Buffer[BUFSIZE];
register int i;
rewind(TempMail);
sprintf(Buffer, "MAIL FROM:<%s>\r\n", GetSender());
SendTextCheck(Buffer, 250);
for (i = 0; Recipients[i] != NULL; i++){
sprintf(Buffer, "RCPT TO:<%s>\r\n", Recipients[i]);
SendTextCheck(Buffer, 250);
if (Mode == VERBOSE)
printf("Mail being sent to %s.\n", Recipients[i]);
}
sprintf(Buffer, "DATA\r\n");
SendTextCheck(Buffer, 354);
/* Produce headers. */
/* At present there are the following headers:
Message-Id:
Reply-To:
From:
To:
Date:
Subject:
*/
if (!NoHead){
int i;
sprintf(Buffer, "Message-Id: <%s.AA%d@%s>\r\n", GetDateId(), FindTask(NULL), GetHostName());
SendText(Buffer);
sprintf(Buffer, "Reply-To: %s\r\n", ReplyTo);
SendText(Buffer);
sprintf(Buffer, "From: %s (%s)\r\n", GetSender(), GetRealName());
SendText(Buffer);
sprintf(Buffer, "Date: %s", GetDate());
SendText(Buffer);
SendText("To: ");
for (i = 0; Recipients[i] != NULL; i++){
sprintf(Buffer,"%s", Recipients[i]);
if (Recipients[i+1] != NULL)
strcat (Buffer, ", ");
SendText(Buffer);
}
SendText("\r\n");
}
fgets(Buffer, BUFSIZE - 1, TempMail);
SendText(Buffer);
while (fgets(Buffer, BUFSIZE - 1, TempMail))
SendText(Buffer);
/* Expecting a "I got that one thanks." type message. */
SendTextCheck(".\r\n", 250);
if (Mode == VERBOSE)
printf("Mail is now sent.\n");
}
void
main(int argc, char *argv[])
{
register char *SMTPHost;
struct RDArgs *Args;
long ArgRes[ARGCOUNT] = {0, 0, 0};
register int i = 0;
/* Look at command line arguments. */
if (!(Args = ReadArgs((UBYTE *)Template, ArgRes, NULL))){
printf("Usage: %s\n", Template);
exit(30);
}
if (ArgRes[VERBOSE]){
Mode = VERBOSE;
}
if (ArgRes[REPLYTO]){
ReplyTo = (char *) ArgRes[1];
} else {
ReplyTo = GetSender();
}
if (ArgRes[SMTPHOST]){
SMTPHost = (char *) ArgRes[2];
} else {
SMTPHost = GetSMTPHost();
}
NoSig = ArgRes[NOSIG];
NoSubj = ArgRes[NOSUBJ];
NoHead = ArgRes[NOHEAD];
NoEd = ArgRes[NOED];
if (strcmp (argv[0], "sendmail") == 0){
NoSubj = 1;
NoHead = 1;
NoEd = 1;
}
/* Open up the socket. Pretty standard stuff, cribbed from letnet. */
_STIopenSockets();
atexit (_STDcloseSockets);
Address.sin_len = sizeof(Address);
Address.sin_family = AF_INET;
Address.sin_port = 25; /* SMTP */
Address.sin_addr.s_addr = 0;
if (!(Hostaddr = gethostbyname(SMTPHost))){
printf("Unknown host.\n");
exit(30);
}
bcopy (Hostaddr->h_addr, (char *) &Address.sin_addr, Hostaddr->h_length);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
PrintNetFault(errno, "socket");
exit(30);
}
if (connect (s, (struct sockaddr *) &Address, sizeof(Address)) == -1){
PrintNetFault(errno, "connect");
exit(30);
}
if (Mode == VERBOSE){
printf("Connected to %s.\n", SMTPHost);
}
/* Check we got the "Welcome blah blah" message. */
SendTextCheck("", 220);
/* Now say HELO like a nice program. */
{
char Temp[108];
if (Mode == VERBOSE){
printf("HELO\n");
}
sprintf(Temp, "HELO %s\r\n", GetHostName());
SendTextCheck(Temp, 250);
}
TempMail = ReadMail();
/* Dispatch the mail. */
SendMail ((char **)ArgRes[0]);
/* Clean up and exit. */
fclose(TempMail);
unlink(Name);
SendTextCheck("QUIT\r\n", 221);
shutdown(s, 2);
CloseSocket(s);
FreeArgs(Args);
exit (0);
}