/**---------------------------------------------------------------------------*/ // File: hudmail\imap.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 /**---------------------------------------------------------------------------*/ int Expect(char *replyp, int seq) { int rv = 0; int n; int code; char reply[3+1]; if (seq < 0) { if (streqz(replyp, "* OK")) goto EGRESS; LOGF("Error: Received unexpected reply:"); TextLog(replyp); rv = 1; goto EGRESS; } n = sscanf(replyp, "%d %3s", &code, reply); if (n != 2) { LOGF("Error: Unable to parse reply:"); TextLog(replyp); rv = 1; goto EGRESS; } if ( code != seq || !streq(reply, "OK") ) { LOGF("Error: Received unexpected reply:"); TextLog(replyp); rv = 1; goto EGRESS; } EGRESS: RETURN(rv); } /**---------------------------------------------------------------------------*/ int VExpect(XSOCKET *xsp, int seq, char *sendp) { int rv = 0; int replylen; static char reply[1024]; for (;;) // skip star replys { rv = VLine(xsp, reply, &replylen); if (rv) { LOGF("Error: Timeout waiting for reply to:"); TextLog(sendp); goto EGRESS; } if // if ( seq == -1 // expecting a star reply || // or (skipping star replys and) reply[0] != '*' // this isn't a star reply ) break; // break out of loop } rv = Expect(reply, seq); if (rv) { LOGF("Error: Received unexpected reply to:"); TextLog(sendp); goto EGRESS; } EGRESS: RETURN(rv); } /**---------------------------------------------------------------------------*/ int XVExpect(XSOCKET *xsp, int seq, 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, "%d %s", seq, send); if (rv) { LOGF("Error: Unable to send:"); TextLog(send); goto EGRESS; } rv = VExpect(xsp, seq, send); if (rv) goto EGRESS; EGRESS: RETURN(rv); } /**---------------------------------------------------------------------------*/ int main(int npars, char **pars) { int rv = 0; int rc; int port; int seq; char *usernamep; char *passwordp; char *servernamep; char *sendp; int bytes; int nbytes; int replylen; int n; int message; int nmessages; int lo, mi, hi; int ascnum; int txtnum; char *p; FILE *filep; LIST linelist; LISTLOOP lineloop; char *linep; char filename[8+1+3 +1]; static XSOCKET xs; static char recvpath[256]; static char inboxpath[256]; static char msgpath[256]; static char inboxpathfile[256]; static char msgpathfile[256]; static char send[1024]; static char reply[1024]; /**---------------------------------------------------------------------------*/ filep = 0; ListZero(&linelist, 8); ConsoleInit(); #ifdef TEST usernamep = "idyllic"; servernamep = "sigma"; #else usernamep = "tracm08941"; servernamep = "tracsmail.hud.gov"; #endif passwordp = 0; port = 143; 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: imap [ [ [ ] ] ]\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(recvpath, EMAILROOT, SEP, "recv", 0); rv = DirectoryVerify(recvpath); IF(rv,Unable to create directory.); strbuild(inboxpath, SPRMAILROOT, SEP, "in.box", 0); rv = DirectoryVerify(inboxpath); IF(rv,Unable to create directory.); strbuild(msgpath, EMAILROOT, SEP, "msg", 0); rv = DirectoryVerify(msgpath); IF(rv,Unable to create directory.); /**---------------------------------------------------------------------------*/ #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.); /**---------------------------------------------------------------------------*/ // dialog xs.xlog = 0; xs.vlog = 0; seq = 0; rv = VExpect(&xs, -1, ""); if (rv) goto EGRESS; rv = XVExpect(&xs, ++seq, "login %s %s\r\n", usernamep, passwordp); if (rv) goto EGRESS; /**---------------------------------------------------------------------------*/ // select inbox and get number of messages nmessages = -1; sendp = "select inbox\r\n"; rv = XLine(&xs, "%d %s", ++seq, sendp); if (rv) { LOGF("Error: Unable to send:"); TextLog(sendp); goto EGRESS; } for (;;) { rv = VLine(&xs, reply, &replylen); if (rv) { LOGF("Error: Timeout waiting for reply to:"); TextLog(sendp); goto EGRESS; } if (reply[0] != '*') // non-star reply { rv = Expect(reply, seq); if (rv) { LOGF("Error: Received unexpected reply to:"); TextLog(sendp); goto EGRESS; } break; } else // star reply { if (strstr(reply, "EXISTS")) { n = sscanf(reply, "* %d EXISTS", &nmessages); if (n != 1) { LOGF("Error: Unable to parse nmessages from:"); TextLog(reply); LOGF("Received unexpected reply to:"); TextLog(sendp); rv = 1; goto EGRESS; } } } } if (nmessages == -1) { LOGF("Error: Failed to extract number of messages from:"); TextLog(sendp); rv = 1; goto EGRESS; } LOGF("%d messages in inbox.", nmessages); if (!nmessages) goto CLOSE; /**---------------------------------------------------------------------------*/ // determine the highest existing .ASC file number lo = 0; hi = 99999; for (;;) { if (hi - lo <= 1) break; mi = (lo + hi) / 2; sprintf(filename, "i%5.5d.ASC", mi); strbuild(inboxpathfile, inboxpath, SEP, filename, 0); if (FileExist(inboxpathfile)) lo = mi; else hi = mi; } ascnum = -1; if (ascnum == -1) { sprintf(filename, "i%5.5d.ASC", hi); strbuild(inboxpathfile, inboxpath, SEP, filename, 0); if (FileExist(inboxpathfile)) ascnum = hi; } if (ascnum == -1) { sprintf(filename, "i%5.5d.ASC", lo); strbuild(inboxpathfile, inboxpath, SEP, filename, 0); if (FileExist(inboxpathfile)) ascnum = lo; } ascnum++; LOGF("Next available file is i%5.5d.ASC.", ascnum); /**---------------------------------------------------------------------------*/ // determine the highest existing .TXT file number lo = 0; hi = 99999999; for (;;) { if (hi - lo <= 1) break; mi = (lo + hi) / 2; sprintf(filename, "%8.8d.txt", mi); strbuild(msgpathfile, msgpath, SEP, filename, 0); if (FileExist(msgpathfile)) lo = mi; else hi = mi; } txtnum = -1; if (txtnum == -1) { sprintf(filename, "%8.8d.txt", hi); strbuild(msgpathfile, msgpath, SEP, filename, 0); if (FileExist(msgpathfile)) txtnum = hi; } if (txtnum == -1) { sprintf(filename, "%8.8d.txt", lo); strbuild(msgpathfile, msgpath, SEP, filename, 0); if (FileExist(msgpathfile)) txtnum = lo; } txtnum++; LOGF("Next available file is %8.8d.txt.", txtnum); /**---------------------------------------------------------------------------*/ // get the messages for (message = 1; message <= nmessages; message++) { // get message LOGF("Fetching message %d.", message); sprintf(send, "fetch %d rfc822\r\n", message); rv = XLine(&xs, "%d %s", ++seq, send); if (rv) { LOGF("Error: Unable to send:"); TextLog(send); goto EGRESS; } // get message size rv = VLine(&xs, reply, &replylen); if (rv) { LOGF("Error: Timeout waiting for reply to:"); TextLog(send); goto EGRESS; } p = strstr(reply, "RFC822"); if (!p) { LOGF("Error: Unable to parse message size from:"); TextLog(reply); rv = 1; goto EGRESS; } n = sscanf(p, "RFC822 {%d}", &nbytes); if (n != 1) { LOGF("Error: Unable to parse message size from:"); TextLog(reply); rv = 1; goto EGRESS; } LOGF("%d bytes in message body.", nbytes); // get message body for (bytes = 0; bytes < nbytes;) { rv = VLine(&xs, reply, &replylen); IF(rv,Error: Timeout waiting for message body.); linep = StrDup(reply); for (p = linep; *p; p++) // determinate the line { if (*p == '\r' && *(p+1) == '\n') { *p = 0; break; } } ListObjAppend(&linelist, linep); bytes += strlen(reply); } // write message to a file for (;;) // get the next filename { sprintf(filename, "%8.8d.txt", txtnum); strbuild(msgpathfile, msgpath, SEP, filename, 0); txtnum++; if (txtnum >= 100000000) txtnum = 0; if (!FileExist(msgpathfile)) break; } filep = fopen(msgpathfile, "wb"); IF(!filep,Unable to create file.); LISTLOOPL(line) fprintf(filep, "%s\r\n", linep); fclose(filep); filep = 0; // get end-of-message stuff rv = VLine(&xs, reply, &replylen); IF(rv,Error: Timeout waiting for closing paren.); if (!streqz(reply, ")")) { LOGF("Error: Missing closing paren in:"); TextLog(reply); rv = 1; goto EGRESS; } rv = VExpect(&xs, seq, send); if (rv) goto EGRESS; /**---------------------------------------------------------------------------*/ // process message, decode attachments and write to files ListFirstObjGet(&linelist); rv = MIMEParse(&linelist, 0, 0, inboxpath, recvpath, &ascnum); if (rv) goto EGRESS; ListMetaFree(&linelist); /**---------------------------------------------------------------------------*/ // delete message rv = XVExpect(&xs, ++seq, "store %d +flags (\\deleted)\r\n", message); if (rv) goto EGRESS; } // for (message = 1; message <= nmessages; message++) // expunge deleted messages if (nmessages) { rv = XVExpect(&xs, ++seq, "expunge\r\n"); if (rv) goto EGRESS; } /**---------------------------------------------------------------------------*/ // close inbox and logout CLOSE: rv = XVExpect(&xs, ++seq, "close\r\n"); if (rv) goto EGRESS; rv = XVExpect(&xs, ++seq, "logout\r\n"); if (rv) goto EGRESS; /**---------------------------------------------------------------------------*/ EGRESS: if (filep) fclose(filep); rc = SocketExit(&xs); if (rc) { LOGF("Error: Unable to exit socket."); } #ifndef TEST LOGF("Disconnecting from e-mail server."); rc = PPPClose(); if (rc) { LOGF("Unable to close PPP connection."); } #endif /**---------------------------------------------------------------------------*/ ConsoleExit(); ListMetaFree(&linelist); MemVerify(); RETURN(rv); }