/* The outbound mail functions */
extern "C" {
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <pwd.h>
#include <limits.h>
}
#include "mime.h"
#include "terminal.h"
#include "rcfile.h"
#include "tempfile.h"
#include "outgoing.h"
#ifndef MAILER
#define MAILER "/usr/lib/sendmail -t"
#endif
#define EDITOR "vi +%d"
#define SIGFILE ".signature"
extern int verbose;
/* Bare bones mail delivery */
static int SendMail(char *file)
{
char cmdline[2*PATH_MAX];
char *sentpath;
/* Save a copy of the mail, if desired */
sentpath = ExpandPath(GetStartVar("SentFile"));
if ( sentpath ) {
sprintf(cmdline, "echo From you >>%s", sentpath);
system(cmdline);
sprintf(cmdline, "echo Date: `date \"+%%a, %%d %%b %%Y %%H:%%M:%%S\"` >>%s", sentpath);
system(cmdline);
sprintf(cmdline, "cat %s >>%s", file, sentpath);
system(cmdline);
delete[] sentpath;
}
sprintf(cmdline, "%s <%s", MAILER, file);
return(system(cmdline));
}
/***************************************************************************/
/* Helper routines for the mail functions */
static char *LocalAddr(char *addr)
{
struct passwd *pw;
char *fulladdr;
char *domain, domainbuf[BUFSIZ];
/* Inet address: user@host.net */
if ( strchr(addr, '@') != NULL )
return(NULL);
/* Local address, otherwise, so look in password file */
if ( (pw=getpwnam(addr)) == NULL )
return(NULL);
/* Slight optimization :-) */
domainbuf[0] = '@';
if ( (domain=GetStartVar("MailDomain")) == NULL ) {
if ( (getdomainname(&domainbuf[1], BUFSIZ-2) < 0) ||
(strcmp(&domainbuf[1], "(none)") == 0) )
domain = "";
else
domain = domainbuf;
} else {
domainbuf[1] = '\0';
strncat(domainbuf, domain, BUFSIZ-2);
domain = domainbuf;
}
/* Assemble the full name and address */
fulladdr = new char[1+strlen(pw->pw_gecos)+1+1+
strlen(addr)+strlen(domain)+1];
sprintf(fulladdr, "(%s) %s%s", pw->pw_gecos, addr, domain);
return(fulladdr);
}
/* Possible perform line wrapping? */
static int WriteAddrs(char *Field, char *Addrs, FILE *output)
{
MIME_body *aliases = NULL;
char *ptr, *alias;
/* Print the "To: " caption */
fprintf(output, Field);
/* Get any possible aliases we have */
if ( startup )
aliases = startup->ByName("aliases");
/* Run along the line, split it into addresses */
while ( *Addrs && isspace(*Addrs) )
++Addrs;
ptr = Addrs;
while ( *Addrs ) {
if ( ! *ptr || (*ptr == ',') ) {
if ( *ptr ) {
*ptr = '\0';
do {
++ptr;
} while ( *ptr && (isspace(*ptr) || *ptr == ',') );
}
if ( aliases &&
(alias=(char *)aliases->GetField(Addrs)) ) {
if ( fprintf(output, "%s", alias) <= 0 )
return(-1);
} else if ( (alias=LocalAddr(Addrs)) ) {
if ( fprintf(output, "%s", alias) <= 0 ) {
delete[] alias;
return(-1);
}
delete[] alias;
} else {
if ( fprintf(output, "%s", Addrs) <= 0 )
return(-1);
}
if ( *ptr != '\0' )
fprintf(output, ", ");
Addrs = ptr;
} else
++ptr;
}
fprintf(output, "\n");
return(1);
}
/* Add any extra headers to the output */
static int AutoHeader(FILE *output)
{
MIME_body *headers;
char *header_key;
char *header_val;
int written = 0;
if ( ! startup || ((headers=startup->ByName("headers")) == NULL) )
return(0);
headers->GetHeader(NULL);
while ( (header_val=headers->GetHeader(&header_key)) ) {
/* Don't include MIME Content headers */
if (!strncasecmp(header_key, "Content-", strlen("Content-")))
continue;
fprintf(output, "%s: %s\n", header_key, header_val);
++written;
}
return(written);
}
/* Write the signature file to the message */
static void LoadSig(FILE *output)
{
FILE *input;
char buffer[BUFSIZ];
char *home;
char *filename;
if ( (home=getenv("HOME")) == NULL )
return;
/* Open the signature file */
filename = new char[strlen(home)+1+strlen(SIGFILE)+1];
sprintf(filename, "%s/%s", home, SIGFILE);
if ( (input=fopen(filename, "r")) == NULL ) {
delete[] filename;
return;
}
delete[] filename;
/* Copy it to the mail message */
while ( fgets(buffer, BUFSIZ-1, input) )
fputs(buffer, output);
fclose(input);
}
static int AttachFile(char *&message, char *file, int is_mime)
{
IObottle *feeder;
MIME_body *body;
char *endings[] = { NULL }; /* No explicit boundaries */
int okay, olderr;
/* First open an IObottle on the message */
feeder = new IObottle(message);
if ( feeder->fail() || feeder->eof() ) {
delete feeder;
return(-1);
}
/* Now turn the message into a MIME body */
body = new MIME_body(feeder, endings);
/* Try adding the file */
if ( (okay = body->AddPart(file, is_mime)) > -1 ) {
if ( strcmp(message, body->RawPath()) != 0 ) {
/* We no longer need the original message */
feeder->temp(1);
/* Set up the message as the new raw file */
delete[] message;
message = new char[strlen(body->RawPath())+1];
strcpy(message, body->RawPath());
}
}
olderr = errno;
delete body;
delete feeder;
errno = olderr;
return(okay);
}
/* File tab-completion function */
extern char *file_complete(char *sofar); /* From handlemail.cc */
/* We pass in the outgoing file by reference, so that we can modify it */
static int SendMenu(char *&outgoing, char command, int offset, Terminal *tty)
{
char buffer[BUFSIZ];
char *editor;
int done = 0;
int retval = 0;
/* Choose your editor */
if ( ((editor=getenv("EDITOR")) == NULL) &&
((editor=getenv("VISUAL")) == NULL) )
editor = EDITOR;
/* Run the menu loop */
while ( ! done ) {
if ( command == '\0' ) {
command = tty->promptchar(0,
"[S]end, [e]dit, [a]dd attachment, [n]one of these: ");
}
switch (command) {
case 'E':
case 'e':
sprintf(buffer, "%s %s", editor, outgoing);
tty->system(0, buffer, offset);
break;
case 'A':
case 'a':
/* We don't support attachments yet */
tty->fillprompt(buffer, BUFSIZ,
"Enter file to attach: ", NULL, file_complete);
if ( buffer[0] == '\0' ) {
tty->status(0, "Attachment canceled.");
sleep(1);
break;
}
if ( AttachFile(outgoing, buffer, 0) < 0 ) {
tty->status(0, "Attachment failed: %s",
strerror(errno));
tty->waitchar();
}
break;
case 'N':
case 'n':
case 'q':
tty->status(0, "Message cancelled.");
sleep(1);
done = 1;
break;
case 'S':
case 's':
default:
/* Send mail and break out */
tty->status(0, "Sending mail...");
retval = SendMail(outgoing);
tty->status(0, "Mail sent!");
sleep(1);
done = 1;
break;
}
command = '\0';
}
return(retval);
}
/***************************************************************************/
/* Hot potato, we've got mail! */
/* Curses menu mailing */
int NewMail(char *To, char *Cc, const char *InReplyTo, const char *Subject,
int do_edit, FILE *incfile, Terminal *tty, int use_signature)
{
char *outbound;
char temp_name[PATH_MAX];
FILE *output;
int hlen, lines;
int retval = 0;
/* Open a temporary file for processing */
if ( (output=create_tempfile("w", temp_name)) == NULL ) {
tty->status(0, "Couldn't create temp file: %s", strerror(errno));
tty->waitchar();
return(-1);
}
/* Write the header and then one blank line to start */
hlen = 0;
if ( (lines=WriteAddrs("To: ", To, output)) < 0 ) {
tty->status(0, "Write error on tmpfile %s: %s",
temp_name, strerror(errno));
tty->waitchar();
(void) unlink(temp_name);
return(-1);
}
hlen += lines;
if ( Cc ) {
if ( (lines=WriteAddrs("Cc: ", Cc, output)) < 0 ) {
tty->status(0, "Write error on tmpfile %s: %s",
temp_name, strerror(errno));
tty->waitchar();
(void) unlink(temp_name);
return(-1);
}
hlen += lines;
}
if ( InReplyTo ) {
fprintf(output, "In-Reply-To: %s\n", InReplyTo);
++hlen;
}
fprintf(output, "Subject: %s\n", Subject);
++hlen;
hlen += AutoHeader(output);
fprintf(output, "\n");
++hlen;
if ( incfile ) {
char buffer[BUFSIZ];
while ( fgets(buffer, BUFSIZ-1, incfile) ) {
if ( fputs(buffer, output) == EOF ) {
tty->status(0, "Write error on tmpfile %s: %s",
temp_name, strerror(errno));
tty->waitchar();
(void) unlink(temp_name);
return(-1);
}
}
}
/* Print an extra line for the body */
fprintf(output, "\n");
/* Load up a .signature file, if one exists */
if ( use_signature ) {
LoadSig(output);
}
fclose(output);
/* Save the name of the tmp_file for later deletion */
outbound = new char[strlen(temp_name)+1];
strcpy(outbound, temp_name);
/* Send (or abort) the mail */
SendMenu(outbound, (do_edit ? 'e' : '\0'), hlen+1, tty);
/* Clean up! We're done! :) */
(void) unlink(outbound);
delete[] outbound;
return(retval);
}
/* Command-line mailing */
int NewMail(char *ToArray[], const char *Subject)
{
Terminal *tty;
char *To;
int i, len;
int retval;
/* Create the "To: " line */
for ( i=0, len=0; ToArray[i]; ++i ) {
if ( i > 0 )
len += 2;
len += strlen(ToArray[i]);
}
To = new char[len+1];
*To = '\0';
for ( i=0; ToArray[i]; ++i ) {
if ( i > 0 )
strcat(To, ", ");
strcat(To, ToArray[i]);
}
/* Are we sending a file? */
if ( isatty(0) ) {
char subject[BUFSIZ];
tty = new Terminal(1);
if ( Subject == NULL ) {
tty->fillprompt(subject,BUFSIZ,"Subject: ",NULL,NULL);
Subject = subject;
}
retval = NewMail(To, NULL, NULL, Subject, 1, NULL, tty);
delete tty;
} else {
char temp_name[PATH_MAX];
FILE *output;
char line[BUFSIZ];
/* Manually create the message */
if ( (output=create_tempfile("w", temp_name)) == NULL ) {
fprintf(stderr, "Couldn't write to temp file: %s\n", strerror(errno));
return(-1);
}
/* Write the headers */
fprintf(output, "To: %s\n", To);
if ( ! Subject )
Subject = "No subject <file transmission>";
fprintf(output, "Subject: %s\n", Subject);
AutoHeader(output);
fprintf(output, "\n");
/* Write the file */
while ( fgets(line, BUFSIZ-1, stdin) )
fputs(line, output);
fclose(output);
printf("Sending mail...");
fflush(stdout);
retval = SendMail(temp_name);
printf("done.\n");
(void) unlink(temp_name);
}
return(retval);
}
syntax highlighted by Code2HTML, v. 0.9.1