home *** CD-ROM | disk | FTP | other *** search
- /*
- 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);
- }
-