/**---------------------------------------------------------------------------*/
// File: hudmail\smtp.c
// A component of the Workflow system of subsidized contract administration.
// Copyright (c) 2001, Richard Heurtley. All rights reserved.
/**---------------------------------------------------------------------------*/
#include "common.h"
/**---------------------------------------------------------------------------*/
//#define TEST // Richard's office
//#define NOXMITDELETE // don't delete \email\xmit files
#define HTMLMESSAGE // do send HTML format message
/**---------------------------------------------------------------------------*/
typedef struct
{
char *filenamep;
char *postedp;
char *fromp;
char *top;
char *ccp;
char *subjp;
char cno[11+1];
char pna[50+1];
char amount[1+10+1+2+1]; // $-000000005.00~
} XFILE;
/**---------------------------------------------------------------------------*/
void XFileFree(XFILE *xfilep)
{
MemFree(xfilep->filenamep);
MemFree(xfilep->postedp);
MemFree(xfilep->fromp);
MemFree(xfilep->top);
MemFree(xfilep->ccp);
MemFree(xfilep->subjp);
MemFree(xfilep);
RETURNVOID;
}
/**---------------------------------------------------------------------------*/
void detrail(char *p)
{
char *q;
for (q = p; *q; q++); // get end of string
for (q--; q >= p && *q == ' '; q--); // get last significant char
*(q+1) = 0; // delimit string
RETURNVOID;
}
/**---------------------------------------------------------------------------*/
void dezero(char *p)
{
char *q;
if (*p == '-') // if negative
p++; // operate on next character
for (q = p; *q && *q == '0'; q++); // find first non-zero
strcpy(p, q); // move to beginning of string
if (!*p)
strcpy(p, "0");
RETURNVOID;
}
/**---------------------------------------------------------------------------*/
char *Parse(char *p)
{
char *rvp;
for (; *p && !isspace(*p); p++); // find whitespace
rvp = p; // get return value
if (!*p) // if none
goto EGRESS; // return pointer to null
for (; *p && isspace(*p); p++); // find content
rvp = p; // get return value
if (!*p) // if none
goto EGRESS; // return pointer to null
for (; *p; p++); // find terminator
for (p--; isspace(*p); p--); // find content
p++; // get whitespace
*p = 0; // delimit it
EGRESS:
RETURN(rvp);
}
/**---------------------------------------------------------------------------*/
int Expect(char *replyp, int expect)
{
int rv = 0;
int n;
int code;
n = sscanf(replyp, "%d", &code);
if (n != 1)
{
LOGF("Unable to parse reply:");
TextLog(replyp);
rv = 1;
goto EGRESS;
}
if (code != expect)
{
LOGF("Received unexpected reply:");
TextLog(replyp);
LOGF("Expected %d", expect);
rv = 1;
goto EGRESS;
}
EGRESS:
RETURN(rv);
}
/**---------------------------------------------------------------------------*/
int VExpect(XSOCKET *xsp, int expect, char *sendp)
{
int rv = 0;
int nbytes;
static char line[1024];
rv = VLine(xsp, line, &nbytes);
if (rv)
{
LOGF("Timeout waiting for reply to:");
TextLog(sendp);
goto EGRESS;
}
rv = Expect(line, expect);
if (rv)
{
LOGF("Received bad reply to:");
TextLog(sendp);
goto EGRESS;
}
EGRESS:
RETURN(rv);
}
/**---------------------------------------------------------------------------*/
int XVExpect(XSOCKET *xsp, int expect, char *formatp, ...)
{
int rv = 0;
va_list arglist;
static char send[1024];
va_start(arglist, formatp);
vsprintf(send, formatp, arglist);
va_end(arglist);
rv = XLine(xsp, "%s", send);
if (rv)
{
LOGF("Unable to send:");
TextLog(send);
goto EGRESS;
}
rv = VExpect(xsp, expect, send);
if (rv)
{
LOGF("Unexpected reply to:");
TextLog(send);
goto EGRESS;
}
EGRESS:
RETURN(rv);
}
/**---------------------------------------------------------------------------*/
int XVCode(XSOCKET *xsp, int *codep, char *formatp, ...)
{
int rv = 0;
int n;
int code;
int nbytes;
va_list arglist;
static char send[1024];
static char line[1024];
va_start(arglist, formatp);
vsprintf(send, formatp, arglist);
va_end(arglist);
rv = XLine(xsp, "%s", send);
if (rv)
{
LOGF("Unable to send:");
TextLog(send);
goto EGRESS;
}
rv = VLine(xsp, line, &nbytes);
if (rv)
{
LOGF("Timeout waiting for reply to:");
TextLog(send);
goto EGRESS;
}
n = sscanf(line, "%d", &code);
if (n != 1)
{
LOGF("Unable to parse reply:");
TextLog(line);
rv = 1;
goto EGRESS;
}
if (codep)
*codep = code;
EGRESS:
RETURN(rv);
}
/**---------------------------------------------------------------------------*/
char *NBSP(char *p)
{
if (!p || !p[0])
p = " ";
RETURN(p);
}
/**---------------------------------------------------------------------------*/
char *Left(char *srcp, int dstlen)
{
int dst;
int srclen;
char *stringp;
static int string;
static char strings[8][64];
if (string >= 8)
string = 0;
stringp = strings[string];
string++;
srclen = strlen(srcp);
if (srclen > dstlen)
srclen = dstlen;
dst = 0;
memset(stringp, ' ', dstlen);
memcpy(&stringp[dst], srcp, srclen);
stringp[dstlen] = 0;
RETURN(stringp);
}
/**---------------------------------------------------------------------------*/
char *Center(char *srcp, int dstlen)
{
int dst;
int srclen;
char *stringp;
static int string;
static char strings[8][64];
if (string >= 8)
string = 0;
stringp = strings[string];
string++;
srclen = strlen(srcp);
if (srclen > dstlen)
srclen = dstlen;
dst = (dstlen - srclen) / 2;
memset(stringp, ' ', dstlen);
memcpy(&stringp[dst], srcp, srclen);
stringp[dstlen] = 0;
RETURN(stringp);
}
/**---------------------------------------------------------------------------*/
char *Right(char *srcp, int dstlen)
{
int dst;
int srclen;
char *stringp;
static int string;
static char strings[8][64];
if (string >= 8)
string = 0;
stringp = strings[string];
string++;
srclen = strlen(srcp);
if (srclen > dstlen)
srclen = dstlen;
dst = dstlen - srclen;
memset(stringp, ' ', dstlen);
memcpy(&stringp[dst], srcp, srclen);
stringp[dstlen] = 0;
RETURN(stringp);
}
/**---------------------------------------------------------------------------*/
char *Dup(char c, int dstlen)
{
char *stringp;
static int string;
static char strings[8][64];
if (string >= 8)
string = 0;
stringp = strings[string];
string++;
dstlen += 2;
memset(stringp, c, dstlen);
stringp[dstlen] = 0;
RETURN(stringp);
}
/**---------------------------------------------------------------------------*/
char *FileName(int time, int msgseq, int fileseq)
{
int y, m, d, h, n, s;
int md;
int hns;
static char filename[8+1+3 +1];
DateTimeDecompose(time, &y, &m, &d, &h, &n, &s);
y -= 2000;
md = (m-1) * 31 + (d-1);
hns = (h * 60 + n) * 60 + s;
y = y % 26;
d = md % 26; md /= 26;
m = md % 26;
s = hns % 26; hns /= 26;
n = hns % 26; hns /= 26;
h = hns % 26;
filename[0] = 'A' + y;
filename[1] = 'A' + m;
filename[2] = 'A' + d;
filename[3] = 'A' + h;
filename[4] = 'A' + n;
filename[5] = 'A' + s;
filename[6] = 'A' + msgseq;
filename[7] = 'A' + fileseq;
strcpy(&filename[8], ".TXT");
RETURN(filename);
}
/**---------------------------------------------------------------------------*/
// generate the fixed message text
int MessageText
(
XSOCKET *xsp,
LIST *yfilelistp,
int time,
int msgseq,
int fileseq,
int html
)
{
int rv = 0;
LISTLOOP yfileloop;
XFILE *yfilep;
char *contentsp;
char *eolp;
if (html)
eolp = "
\r\n";
else
eolp = "\r\n";
if (html)
{
rv = XLine
(
xsp,
"\r\n"
"
\r\n"
"\r\n"
);
if (rv) goto EGRESS;
}
if (yfilelistp->nnodes > 1)
rv = XLine(xsp, "This message contains %d attached TRACS files as follows:%s", yfilelistp->nnodes, eolp);
else
rv = XLine(xsp, "This message contains the following attached TRACS file:%s", eolp);
if (rv) goto EGRESS;
rv = XLine(xsp, "%s", eolp);
if (rv) goto EGRESS;
if (html)
{
rv = XLine(xsp, "\r\n");
if (rv) goto EGRESS;
}
if (!html)
{
rv = XLine
(
xsp,
"| %s | %s | %s | %s | %s |\r\n",
Center("File", 12), // 12345678.123
Center("Project", 35),
Center("Contract", 11),
Center("Contents", 8),
Center("Amount", 11) // $1222333.00
);
if (rv) goto EGRESS;
rv = XLine
(
xsp,
"+%s+%s+%s+%s+%s+\r\n",
Dup('-', 12), // 12345678.123
Dup('-', 35),
Dup('-', 11),
Dup('-', 8),
Dup('-', 11) // $1222333.00
);
if (rv) goto EGRESS;
}
else
{
rv = XLine
(
xsp,
""
"| File | "
"Project | "
"Contract | "
"Contents | "
"Amount | "
"
\r\n"
);
if (rv) goto EGRESS;
}
LISTLOOPLP(yfile)
{
if (*yfilep->amount)
contentsp = "voucher";
else
contentsp = "cert";
if (!html)
{
rv = XLine
(
xsp,
"| %s | %s | %s | %s | %s |\r\n",
Center(FileName(time, msgseq, fileseq), 12),
Left(yfilep->pna, 35),
Center(yfilep->cno, 11),
Center(contentsp, 8),
Right(yfilep->amount, 11)
);
}
else
{
rv = XLine
(
xsp,
""
"| %s | "
"%s | "
"%s | "
"%s | "
"%s | "
"
\r\n",
FileName(time, msgseq, fileseq),
NBSP(yfilep->pna),
NBSP(yfilep->cno),
contentsp,
NBSP(yfilep->amount)
);
}
if (rv) goto EGRESS;
fileseq++;
}
if (html)
{
rv = XLine
(
xsp,
"
\r\n"
"\r\n"
"\r\n"
);
if (rv) goto EGRESS;
}
EGRESS:
RETURN(rv);
}
/**---------------------------------------------------------------------------*/
int main(int npars, char **pars)
{
int rv = 0;
int boundseq;
int fileseq;
int lasttime;
int line;
int msgseq;
int nbytes;
int nlines;
int port;
int rc;
int time;
int code;
char *postedp;
char *fromp;
char *top;
char *ccp;
char *subjp;
char *bufferp;
char *filenamep;
char *linep;
char *servernamep;
char *subj;
char **lines;
char *usernamep;
char *passwordp;
DIR *dirp;
FILE *filep;
LIST xfilelist;
LIST yfilelist;
LISTLOOP xfileloop;
LISTLOOP yfileloop;
MATFIELD *fieldp;
MATFIELD *fields;
MATRECORD *cursectionp;
MATRECORD *detailp;
MATRECORD *partialp;
MATRECORD *recordp;
VERSION *curversionp;
VERSION *versionp;
XFILE *xfilep;
XFILE *yfilep;
struct dirent *entryp;
struct stat filestat;
static struct utsname utsname;
static XSOCKET xs;
static char string[10+1];
static char inner[80];
static char outer[80];
static char oddpath[256];
static char xmitpath[256];
static char xmitpathfile[256];
static char pendpath[256];
static char pendpathfile[256];
static char sentpath[256];
static char sentpathfile[256];
/**---------------------------------------------------------------------------*/
// initialize
dirp = 0;
filep = 0;
bufferp = 0;
boundseq = 0;
msgseq = 0;
fileseq = 0;
lasttime = 0;
lines = 0;
ListZero(&xfilelist, 8);
ListZero(&yfilelist, 8);
rv = VersionInit();
if (rv)
goto EGRESS;
/**---------------------------------------------------------------------------*/
ConsoleInit();
uname(&utsname); // get this computer's name
/**---------------------------------------------------------------------------*/
#ifdef TEST
usernamep = "idyllic";
servernamep = "sigma";
#else
usernamep = "tracm08941";
servernamep = "tracsmail.hud.gov";
#endif
passwordp = 0;
port = 25;
if (npars >= 2)
passwordp = pars[1];
if (npars >= 3)
{
if (!streq(pars[2], "*"))
usernamep = pars[2];
}
if (npars >= 4)
{
if (!streq(pars[3], "*"))
servernamep = pars[3];
}
if (npars >= 5)
{
if (!streq(pars[4], "*"))
{
rc = sscanf(pars[4], "%d", &port);
if (rc != 1)
{
LOGF("Error: Unable to parse port parameter \"%s\".", pars[4]);
rv = 1;
goto EGRESS;
}
}
}
if (!passwordp)
{
printf("usage: smtp [ [ [ ] ] ]\n");
printf(" default user: %s\n", usernamep);
printf(" default server: %s\n", servernamep);
printf(" default port: %d\n", port);
goto EGRESS;
}
/**---------------------------------------------------------------------------*/
rv = DirectoryVerify(EMAILROOT);
IF(rv,Unable to create directory.);
strbuild(xmitpath, EMAILROOT, SEP, "xmit", 0);
rv = DirectoryVerify(xmitpath);
IF(rv,Unable to create directory.);
strbuild(oddpath, EMAILROOT, SEP, "odd", 0);
rv = DirectoryVerify(oddpath);
IF(rv,Unable to create directory.);
strappend(oddpath, SEP, DateTimeFormat0(TimeStamp()), 0);
strbuild(pendpath, EMAILROOT, SEP, "pend", 0);
rv = DirectoryVerify(pendpath);
IF(rv,Unable to create directory.);
strbuild(sentpath, EMAILROOT, SEP, "sent", 0);
rv = DirectoryVerify(sentpath);
IF(rv,Unable to create directory.);
/**---------------------------------------------------------------------------*/
// scan through files in email\xmit
dirp = opendir(xmitpath);
IF(!dirp,Unable to open directory.);
for (;;) // for each file
{
entryp = readdir(dirp);
if (!entryp)
break;
filenamep = entryp->d_name;
if (filenamep[0] == '.') // if dotted directory entry
continue; // ignore
strbuild(xmitpathfile, xmitpath, SEP, filenamep, 0);
stat(xmitpathfile, &filestat);
if (S_ISDIR(filestat.st_mode)) // if directory
continue; // ignore
/**---------------------------------------------------------------------------*/
// read and parse file
LOGF("Parsing file %s", filenamep);
rv = FileRead2(xmitpathfile, &bufferp, &nbytes);
IF(rv,Unable to read file.);
rv = FileLinesParse
(
bufferp,
nbytes,
&lines,
&nlines
);
IF(rv,Unable to parse file lines.);
/**---------------------------------------------------------------------------*/
// extract header information
postedp = "";
fromp = "";
top = "";
ccp = "";
subjp = "";
for (line = 0; line < nlines; line++)
{
linep = lines[line];
if (strieqz(linep, "posted:"))
{
postedp = Parse(linep);
IF(!postedp,Unable to parse Posted: line.);
}
else
if (strieqz(linep, "from:"))
{
fromp = Parse(linep);
IF(!fromp,Unable to parse From: line.);
}
else
if (strieqz(linep, "to:"))
{
top = Parse(linep);
IF(!top,Unable to parse To: line.);
}
else
if (strieqz(linep, "cc:"))
{
ccp = Parse(linep);
IF(!ccp,Unable to parse CC: line.);
}
else
if (strieqz(linep, "subj:"))
{
subjp = Parse(linep);
IF(!subjp,Unable to parse Subj: line.);
}
} // for (line = 0; line < nlines; line++)
/**---------------------------------------------------------------------------*/
// verify file
if (!top[0])
{
LOGF("File %s has no To: destination. Moving to odd directory.", filenamep);
rv = DirectoryVerify(oddpath);
IF(rv,Unable to create directory.);
rv = FileMove(xmitpath, filenamep, oddpath);
IF(rv,Unable to move file.);
goto FILENEXT;
}
if (streqz(top, "TRACS")) // if SprintMail destination
goto FILENEXT; // ignore file
if // if
(
!( // it is not the case that
streqz(top, "TRACM") // valid prefix
&& // and
( // either
streq(&top[5], "PROD") // HUD production
|| // or
streq(&top[5], "TEST") // HUD test
|| // or
(
strlen(&top[5]) == 5 // string ends with five characters
&& // and
strisdigit(&top[5]) // the characters are all digits
&& // and
!streq(&top[5], "08941") // not sending to EPS
)
)
)
)
{
LOGF("File %s is addressed to \"%s\". Moving to odd directory.", filenamep, top);
rv = DirectoryVerify(oddpath);
IF(rv,Unable to create directory.);
rv = FileMove(xmitpath, filenamep, oddpath);
IF(rv,Unable to move file.);
goto FILENEXT;
}
/**---------------------------------------------------------------------------*/
// queue file for transmission
xfilep = MemGet(sizeof(XFILE));
ListObjAppend(&xfilelist, xfilep);
xfilep->filenamep = StrDup(filenamep);
xfilep->postedp = StrDup(postedp);
xfilep->fromp = StrDup(fromp);
xfilep->top = StrDup(top);
xfilep->ccp = StrDup(ccp);
xfilep->subjp = StrDup(subjp);
/**---------------------------------------------------------------------------*/
// create pending file
strbuild(pendpathfile, pendpath, SEP, xfilep->filenamep, 0);
filep = fopen(pendpathfile, "w");
if (!filep)
{
LOGF("Unable to create file %s", pendpathfile);
rv = 1;
goto EGRESS;
}
for (line = 0; line < nlines; line++)
{
linep = lines[line];
if
(
linep[0] // line has content
&&
(
linep[0] == 0x1a ||
strieqz(linep, "posted:") ||
strieqz(linep, "to:") ||
strieqz(linep, "from:") ||
strieqz(linep, "cc:") ||
strieqz(linep, "subj:") ||
strieqz(linep, "text:")
)
)
continue;
fprintf(filep, "%s\n", linep);
}
fclose(filep);
filep = 0;
/**---------------------------------------------------------------------------*/
// parse file records
curversionp = 0;
cursectionp = 0;
for (line = 0; line < nlines; line++)
{
linep = lines[line];
RecordParse(linep, &versionp, &recordp, &partialp);
if (recordp) // if primary
{
if
(
streq(recordp->recordp, "MAT10")
||
streq(recordp->recordp, "MAT30")
)
{
curversionp = versionp;
cursectionp = recordp;
}
continue;
}
if (partialp) // if partial primary
continue;
if
(
!curversionp
||
!cursectionp
)
continue;
DetailParse(linep, curversionp, cursectionp, &detailp, &partialp);
if (detailp)
{
if
(
streq(detailp->recordp, "MAT10")
&&
streq(detailp->detailp, "2")
)
{
fields = curversionp->mat10_2.fields;
fieldp = &fields[15]; // contract number
memcpyz(xfilep->cno, &linep[fieldp->start], fieldp->len);
fieldp = &fields[13]; // project name
memcpyz(xfilep->pna, &linep[fieldp->start], fieldp->len);
detrail(xfilep->pna);
}
else
if
(
streq(detailp->recordp, "MAT30")
&&
streq(detailp->detailp, "2")
)
{
fields = curversionp->mat30_2.fields;
fieldp = &fields[3]; // contract number
memcpyz(xfilep->cno, &linep[fieldp->start], fieldp->len);
fieldp = &fields[5]; // project name
memcpyz(xfilep->pna, &linep[fieldp->start], fieldp->len);
detrail(xfilep->pna);
fieldp = &fields[35]; // voucher xfilep->amount
memcpyz(string, &linep[fieldp->start], fieldp->len);
dezero(string);
sprintf(xfilep->amount, "$%s.00", string);
}
continue;
}
if (partialp) // if partial detail
continue;
} // for (line = 0; line < nlines; line++)
FILENEXT:;
MemFree(lines);
lines = 0;
MemFree(bufferp);
bufferp = 0;
/**---------------------------------------------------------------------------*/
} // for (;;) // for each file
closedir(dirp);
dirp = 0;
/**---------------------------------------------------------------------------*/
// open connection and initialize socket
#ifndef TEST
LOGF("Connecting to e-mail server.");
rv = PPPOpen("TRACSMail", usernamep, passwordp);
IF(rv,Unable to open PPP connection.);
LOGF("E-mail server connection established.");
#endif
rv = SocketInit(&xs, servernamep, port);
IF(rv,Unable to initialize socket.);
xs.xlog = 0;
xs.vlog = 0;
/**---------------------------------------------------------------------------*/
// dialog
rv = VExpect(&xs, 220, "");
if (rv) goto EGRESS;
rv = XVExpect(&xs, 250, "helo %s\r\n", utsname.nodename);
if (rv) goto EGRESS;
/**---------------------------------------------------------------------------*/
// send files
for (;;)
{
// get up to 26 files with the same header
xfilep = ListFirstObjGet(&xfilelist);
if (!xfilep)
break;
postedp = xfilep->postedp;
fromp = xfilep->fromp;
top = xfilep->top;
ccp = xfilep->ccp;
subj = xfilep->subjp;
LISTLOOPL(xfile)
{
if
(
streq(xfilep->postedp, postedp)
&&
streq(xfilep->fromp, fromp)
&&
streq(xfilep->top, top)
&&
streq(xfilep->ccp, ccp)
&&
streq(xfilep->subjp, subj)
)
{
ListObjAppend(&yfilelist, xfilep);
ListLoopObjDelete(xfile);
if (yfilelist.nnodes == 26)
break;
}
}
/**---------------------------------------------------------------------------*/
// verify mailbox
// HUD sometimes rejects rcpt to: commands with a 550
// complaining about an unavailable account
// but all accounts return 251 in response to a vrfy. Shitheads.
rv = XVCode(&xs, &code, "vrfy %s@tracsmail.hud.gov\r\n", top);
if (rv) goto EGRESS;
if
(
code != 250 // local user
&&
code != 251 // remote user but will forward
)
{
LOGF("Mailbox \"%s\" is unavailable or not found.", top);
if (code != 550)
{
LOGF("Received unexpected reply code %d.", code);
}
LOGF("Moving files to odd directory.");
rv = DirectoryVerify(oddpath);
IF(rv,Unable to create directory.);
LISTLOOPL(yfile)
{
LOGF("%s", yfilep->filenamep);
rv = FileMove(xmitpath, yfilep->filenamep, oddpath);
IF(rv,Unable to move file.);
rv = FileDelete(pendpath, yfilep->filenamep);
IF(rv,Unable to delete file.);
}
goto NOSEND;
}
/**---------------------------------------------------------------------------*/
// wait for the timer to update if we've sent 26 messages this second
for
(
time = TimeStamp();
time == lasttime && msgseq >= 26;
time = TimeStamp()
)
sleep(1);
// reset the sequence counters if the time changed
if (time != lasttime)
{
lasttime = time;
msgseq = 0;
fileseq = 0;
}
// build outer and inner boundary strings
sprintf
(
outer,
"outer-outer-outer-outer-%s-%d",
DateTimeFormat0(time),
boundseq
);
sprintf
(
inner,
"inner-inner-inner-inner-%s-%d",
DateTimeFormat0(time),
boundseq
);
boundseq++;
/**---------------------------------------------------------------------------*/
// begin message
LOGF("%12s: Starting message with %d attachments", top, yfilelist.nnodes);
#ifdef TEST
rv = XVExpect(&xs, 250, "mail from: douglass@beta.dumpnet\r\n");
if (rv) goto EGRESS;
rv = XVExpect(&xs, 250, "rcpt to: idyllic@sigma.dumpnet\r\n");
if (rv) goto EGRESS;
#else
rv = XVExpect(&xs, 250, "mail from: tracm08941@tracsmail.hud.gov\r\n");
if (rv) goto EGRESS;
//rv = XVExpect(&xs, 250, "rcpt to: %s@tracsmail.hud.gov\r\n", top);
//if (rv) goto EGRESS;
rv = XVCode(&xs, &code, "rcpt to: %s@tracsmail.hud.gov\r\n", top);
if (rv) goto EGRESS;
if (code != 250)
{
LOGF("Mailbox \"%s\" is unavailable or not found.", top);
if (code != 550)
{
LOGF("Received unexpected reply code %d.", code);
}
LOGF("Moving files to odd directory.");
rv = DirectoryVerify(oddpath);
IF(rv,Unable to create directory.);
LISTLOOPL(yfile)
{
LOGF("%s", yfilep->filenamep);
rv = FileMove(xmitpath, yfilep->filenamep, oddpath);
IF(rv,Unable to move file.);
rv = FileDelete(pendpath, yfilep->filenamep);
IF(rv,Unable to delete file.);
}
rv = XVExpect(&xs, 250, "rset\r\n"); // undo mail from: command
if (rv) goto EGRESS;
goto NOSEND;
}
#endif
rv = XVExpect(&xs, 354, "data\r\n");
if (rv) goto EGRESS;
#ifdef TEST
rv = XLine(&xs, "From: Douglass \r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "To: Idyllic \r\n");
if (rv) goto EGRESS;
#else
rv = XLine(&xs, "From: \"EPS, Inc.\" \r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "To: %s@tracsmail.hud.gov\r\n", top);
if (rv) goto EGRESS;
if (ccp[0])
{
rv = XLine(&xs, "CC: %s@tracsmail.hud.gov\r\n", ccp);
if (rv) goto EGRESS;
}
#endif
if (*subj)
rv = XLine(&xs, "Subject: %s\r\n", subj);
else
rv = XLine(&xs, "Subject: TRACS files\r\n");
if (rv) goto EGRESS;
/**---------------------------------------------------------------------------*/
// begin outer blocking
rv = XLine(&xs, "MIME-Version: 1.0\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Type: multipart/mixed;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tboundary=\"%s\"\r\n", outer);
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "This is a multi-part message in MIME format.\r\n");
if (rv) goto EGRESS;
// begin inner blocking
#ifdef HTMLMESSAGE
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "--%s\r\n", outer);
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Type: multipart/alternative;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tboundary=\"%s\"\r\n", inner);
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
#endif
// plain text message
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
#ifdef HTMLMESSAGE
rv = XLine(&xs, "--%s\r\n", inner);
#else
rv = XLine(&xs, "--%s\r\n", outer);
#endif
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Type: text/plain;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tcharset=\"us-ascii\"\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Transfer-Encoding: 7bit\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = MessageText(&xs, &yfilelist, time, msgseq, fileseq, 0);
if (rv) goto EGRESS;
// HTML formatted message
#ifdef HTMLMESSAGE
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "--%s\r\n", inner);
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Type: text/html;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tcharset=\"us-ascii\"\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Transfer-Encoding: 7bit\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = MessageText(&xs, &yfilelist, time, msgseq, fileseq, 1);
if (rv) goto EGRESS;
// end of inner blocking
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "--%s--\r\n", inner);
if (rv) goto EGRESS;
#endif
/**---------------------------------------------------------------------------*/
// attach files
LISTLOOPL(yfile)
{
LOGF("%12s: Sending file %s as attachment %s", top, yfilep->filenamep, FileName(time, msgseq, fileseq));
strbuild(pendpathfile, pendpath, SEP, yfilep->filenamep, 0);
rv = FileRead2(pendpathfile, &bufferp, &nbytes);
IF(rv,Unable to read file.);
rv = FileLinesParse(bufferp, nbytes, &lines, &nlines);
IF(rv,Unable to parse file lines.);
// file attachment
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "--%s\r\n", outer);
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Type: text/plain;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tname=\"%s\"\r\n", FileName(time, msgseq, fileseq));
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Transfer-Encoding: 7bit\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "Content-Disposition: attachment;\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "\tfilename=\"%s\"\r\n", FileName(time, msgseq, fileseq));
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
// don't do this, HUD regenerates the Posted: line
#if 0
if (*(yfilep->postedp))
{
rv = XLine(&xs, "Posted: %s\r\n", yfilep->postedp);
if (rv) goto EGRESS;
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
}
#endif
for (line = 0; line < nlines; line++)
{
linep = lines[line];
if (streq(linep, "."))
linep = "..";
rv = XLine(&xs, "%s\r\n", linep);
if (rv) goto EGRESS;
rv = XWait(&xs); // wait for line to be transmitted
if (rv) goto EGRESS;
}
MemFree(lines);
MemFree(bufferp);
fileseq++;
} // LISTLOOPL(yfile)
/**---------------------------------------------------------------------------*/
// end of outer blocking
rv = XLine(&xs, "\r\n");
if (rv) goto EGRESS;
rv = XLine(&xs, "--%s--\r\n", outer);
if (rv) goto EGRESS;
rv = XLine(&xs, ".\r\n"); // end of message
if (rv) goto EGRESS;
rv = VExpect(&xs, 250, "");
if (rv) goto EGRESS;
/**---------------------------------------------------------------------------*/
// at this point the message is sent
LOGF("%12s: Message complete", top);
LISTLOOPL(yfile)
{
strbuild(sentpathfile, sentpath, SEP, yfilep->filenamep, 0);
filep = fopen(sentpathfile, "wb");
if (!filep)
{
LOGF("Unable to create file %s", sentpathfile);
rv = 1;
goto EGRESS;
}
if (*(yfilep->postedp))
fprintf(filep, "Posted: %s\r\n", yfilep->postedp);
if (*(yfilep->fromp))
fprintf(filep, "From: %s\r\n", yfilep->fromp);
if (*(yfilep->top))
fprintf(filep, "To: %s\r\n", yfilep->top);
if (*(yfilep->ccp))
fprintf(filep, "CC: %s\r\n", yfilep->ccp);
if (*(yfilep->subjp))
fprintf(filep, "Subj: %s\r\n", yfilep->subjp);
fprintf(filep, "\r\n");
fclose(filep);
rv = FileCat(pendpath, yfilep->filenamep, sentpath);
IF(rv,Unable to move file.);
#ifndef NOXMITDELETE
rv = FileDelete(xmitpath, yfilep->filenamep);
IF(rv,Unable to delete file.);
#endif
}
NOSEND:
LISTLOOPL(yfile)
XFileFree(yfilep);
ListFree(&yfilelist);
msgseq++;
fileseq = 0;
} // for (;;) message loop
// at this point all messages are sent
/**---------------------------------------------------------------------------*/
// disconnect and exit
rv = XVExpect(&xs, 221, "quit\r\n");
if (rv) goto EGRESS;
/**---------------------------------------------------------------------------*/
// close socket and hang up
EGRESS:
rc = SocketExit(&xs);
if (rc)
{
LOGF("Unable to exit socket.");
}
#ifndef TEST
LOGF("Disconnecting from e-mail server.");
rc = PPPClose();
if (rc)
{
LOGF("Unable to close PPP connection.");
}
#endif
/**---------------------------------------------------------------------------*/
// delete any remaining pending files
dirp = opendir(pendpath);
if (dirp)
{
for (;;) // for each file
{
entryp = readdir(dirp);
if (!entryp)
break;
filenamep = entryp->d_name;
if (filenamep[0] == '.') // if dotted directory entry
continue; // ignore
strbuild(pendpathfile, pendpath, SEP, filenamep, 0);
stat(pendpathfile, &filestat);
if (S_ISDIR(filestat.st_mode)) // if directory
continue; // ignore
FileDelete(pendpath, filenamep); // don't check return code
}
closedir(dirp);
dirp = 0;
}
/**---------------------------------------------------------------------------*/
ConsoleExit();
if (bufferp)
MemFree(bufferp);
if (filep)
fclose(filep);
if (lines)
MemFree(lines);
if (bufferp)
MemFree(bufferp);
if (dirp)
closedir(dirp);
LISTLOOPL(xfile)
XFileFree(xfilep);
ListFree(&xfilelist);
LISTLOOPL(yfile)
XFileFree(yfilep);
ListFree(&yfilelist);
MemVerify();
RETURN(rv);
}