home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1990 / 12 / ohlsen.asc < prev    next >
Text File  |  1990-11-15  |  23KB  |  917 lines

  1. _A DATABASE SYSTEM FOR AUTOMATING E-MAIL_
  2. by Chris Ohlsen
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* You will need the Paradox Engine to compile this program. If you have   */ 
  8. /* placed directory for Engine in your INCLUDE path and LIBRARY path, the  */
  9. /* modules should compile fine with: tcc -ml mci parse send pxengtcl.lib   */
  10. /* Otherwise, specify where Engine header file and library files are       */
  11. /* using the -I and -L compiler switches.                   */
  12.  
  13. #define MCIMAIN
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <pxengine.h>
  18. #include "mci.h"
  19.  
  20. void closeTables(void);
  21. void getFldNames(void);
  22. void makeTblExist(char *tblName,int nFlds,char **fld,char **types,
  23.                                                                 int keyFields);
  24. void openTables(void);
  25. void shutdownEngine(void);
  26. void startEngine(void);
  27.  
  28. /**** DEFINE HEADER TABLE INFORMATION ****/
  29. char *headerFields[] =
  30. {
  31.   "Date Received","Message#","Subject","From User","From ID"
  32. };
  33. char *headerTypes[] =
  34. {
  35.   "D","N","A40","A20","A8"
  36. };
  37. int headerKeyFields = 2;
  38. #define headerNFields sizeof(headerTypes)/sizeof(char*)
  39.  
  40. /**** DEFINE MESSAGE TABLE INFORMATION ****/
  41. char *msgFields[] =
  42. {
  43.   "Message#","Line#","Text"
  44. };
  45. char *msgTypes[] =
  46. {
  47.   "N","N","A80"
  48. };
  49. int msgKeyFields = 2;
  50. #define msgNFields sizeof(msgTypes)/sizeof(char*)
  51.  
  52. /**** DEFINE ROUTE TABLE INFORMATION ****/
  53. char *routeFields[] =
  54. {
  55.   "Message#","TOorCC","User Name","User ID"
  56. };
  57. char *routeTypes[] =
  58. {
  59.   "N","A5","A20","A8"
  60. };
  61. int routeKeyFields = 3;
  62. #define routeNFields sizeof(routeTypes)/sizeof(char*)
  63.  
  64. int lastPXErr;
  65. FIELDHANDLE fh[] = {1};
  66. TABLEHANDLE headerTbl,msgTbl,routeTbl;
  67.  
  68. int main(int argc,char *argv[])
  69. {
  70.     startEngine();
  71.     openTables();
  72.     getFldNames();
  73.     if (argc > 1)
  74.          parse(argv[1]);    /* only add to tables if filename passed in */
  75.     send();
  76.     closeTables();
  77.     shutdownEngine();
  78.     return 0;
  79. }
  80.  
  81. void startEngine(void)
  82. {
  83.     PXCheck(0x101,PXInit());
  84. }
  85.  
  86. void shutdownEngine(void)
  87. {
  88.     PXCheck(0x110,PXExit());
  89. }
  90.  
  91. void openTables(void)
  92. {
  93.  makeTblExist("Header",headerNFields,headerFields,headerTypes,headerKeyFields);
  94.  makeTblExist("Message",msgNFields,msgFields,msgTypes,msgKeyFields);
  95.  makeTblExist("Route",routeNFields,routeFields,routeTypes,routeKeyFields);
  96.     PXCheck(0x120,PXTblOpen("Header",&headerTbl,0,0));
  97.     PXCheck(0x121,PXTblOpen("Message",&msgTbl,0,0));
  98.     PXCheck(0x122,PXTblOpen("Route",&routeTbl,0,0));
  99.     PXCheck(0x123,PXRecBufOpen(headerTbl,&headerRec));
  100.     PXCheck(0x125,PXRecBufOpen(msgTbl,&msgRec));
  101.     PXCheck(0x126,PXRecBufOpen(routeTbl,&routeRec));
  102. }
  103.  
  104. void closeTables(void)
  105. {
  106.     PXCheck(0x130,PXTblClose(headerTbl));
  107.     PXCheck(0x131,PXTblClose(msgTbl));
  108.     PXCheck(0x132,PXTblClose(routeTbl));
  109. }
  110.  
  111. void getFldNames(void)
  112. {
  113.     PXCheck(0x140,PXFldHandle(headerTbl,"Date Received",&hdrDateFld));
  114.     PXCheck(0x141,PXFldHandle(headerTbl,"Message#",&hdrMsgFld));
  115.     PXCheck(0x142,PXFldHandle(headerTbl,"Subject",&hdrSubjectFld));
  116.     PXCheck(0x143,PXFldHandle(headerTbl,"From User",&hdrUserFld));
  117.     PXCheck(0x144,PXFldHandle(headerTbl,"From ID",&hdrIDFld));
  118.     PXCheck(0x145,PXFldHandle(msgTbl,"Message#",&msgMsgNumFld));
  119.     PXCheck(0x146,PXFldHandle(msgTbl,"Line#",&msgLineFld));
  120.     PXCheck(0x147,PXFldHandle(msgTbl,"Text",&msgTextFld));
  121.     PXCheck(0x148,PXFldHandle(routeTbl,"Message#",&routeMsgFld));
  122.     PXCheck(0x149,PXFldHandle(routeTbl,"ToOrCC",&routeToFld));
  123.     PXCheck(0x14A,PXFldHandle(routeTbl,"User Name",&routeUserFld));
  124.     PXCheck(0x14B,PXFldHandle(routeTbl,"User ID",&routeIDFld));
  125.     return;
  126. }
  127.  
  128. void makeTblExist(char *tblName,int nFlds,char **fld,char **types,
  129.                                                                 int keyFields)
  130. {
  131.     int exist;
  132.     PXCheck(0x150,PXTblExist(tblName,&exist));
  133.     if (!exist)
  134.     {
  135.         PXCheck(0x151,PXTblCreate(tblName,nFlds,fld,types));
  136.         if (keyFields)
  137.             PXCheck(0x152,PXKeyAdd(tblName,keyFields,fh,PRIMARY));
  138.     }
  139.     return;
  140. }
  141.  
  142. void PXCheck(int loc,int errCode)
  143. {
  144.     lastPXErr=errCode;
  145.     if(errCode==PXSUCCESS)
  146.         return;
  147.     switch (loc)
  148.     {
  149.                 case 0x234:
  150.         case 0x237:
  151.         case 0x247:
  152.         case 0x253:
  153.         case 0x254:    return;
  154.         default:  printf("Error '%s' at %04x\n",PXErrMsg(errCode),loc);
  155.                     exit (1);
  156.     }
  157. }
  158.  
  159. int PXLastErr(void)
  160. {
  161.     return lastPXErr;
  162. }
  163.  
  164. [LISTING TWO]
  165.  
  166. #ifdef MCIMAIN
  167. #define extern
  168. #endif
  169.  
  170. #define MESSAGELENGTH 90
  171. #define STARTOFNEWMESSAGE "Date:"
  172. #define ENDOFSCRIPT "Command:"
  173.  
  174. int PXLastErr(void);
  175. void PXCheck(int loc,int errCode);
  176. void send(void);
  177. void parse(char *filename);
  178.  
  179. extern short MessageID;
  180. extern TABLEHANDLE headerTbl,msgTbl,routeTbl;
  181. extern RECORDHANDLE headerRec,msgRec,routeRec;
  182.  
  183. extern FIELDHANDLE hdrDateFld;
  184. extern FIELDHANDLE hdrMsgFld;
  185. extern FIELDHANDLE hdrSubjectFld;
  186. extern FIELDHANDLE hdrUserFld;
  187. extern FIELDHANDLE hdrIDFld;
  188.  
  189. extern FIELDHANDLE msgMsgNumFld;
  190. extern FIELDHANDLE msgLineFld;
  191. extern FIELDHANDLE msgTextFld;
  192.  
  193. extern FIELDHANDLE routeMsgFld;
  194. extern FIELDHANDLE routeToFld;
  195. extern FIELDHANDLE routeUserFld;
  196. extern FIELDHANDLE routeIDFld;
  197.  
  198.  
  199. [LISTING THREE]
  200.  
  201. #include <stdio.h>
  202. #include <stdlib.h>
  203. #include <string.h>
  204. #include <pxengine.h>
  205. #include "mci.h"
  206.  
  207. void getCC(FILE *inMsgFp,char inBuffer[],int msgID);
  208. void getHeaderInfo(FILE *inMsgFp,char inBuffer[],int msgID);
  209. short getNextMsgID(short *MessageID);
  210. void getTo(FILE *inMsgFp,char inBuffer[],int msgID);
  211. void parseAddr(char inBuffer[],char Person[],char ID[]);
  212. void parseDate(char *dateStr);
  213. void whoFrom(FILE *inMsgFp,char inBuffer[],int msgID);
  214. int convertMonth(char *str);
  215.  
  216. void parse(char *filename)
  217. {
  218.     FILE *inMsgFp;
  219.     char inBuffer[MESSAGELENGTH+1];
  220.     short LineNumber;
  221.  
  222.     if ((inMsgFp = fopen(filename,"r")) == NULL)
  223.     {
  224.         perror(filename);
  225.         PXExit();
  226.         return;
  227.     }
  228.  
  229.     /* Parse through text file searching for first MCI message. */
  230.     while (fgets(inBuffer,MESSAGELENGTH,inMsgFp))
  231.         if(strstr(inBuffer,STARTOFNEWMESSAGE) == inBuffer)
  232.             break;
  233.     do
  234.     {
  235.     /* If STARTOFNEWMESSAGE is at beginning of current line, save last  */
  236.         /* message and get remainder of header information for the message. */
  237.     /* Otherwise, keep getting text.                                    */
  238.         if (strstr(inBuffer,ENDOFSCRIPT) == inBuffer)
  239.             break;                   /* Reached end of messages */
  240.         if (strstr(inBuffer,STARTOFNEWMESSAGE) == inBuffer)
  241.         {
  242.             LineNumber = 1;
  243.             getNextMsgID(&MessageID);
  244.             getHeaderInfo(inMsgFp,inBuffer,MessageID);
  245.         }
  246.          if (strlen(inBuffer) > 0 && inBuffer[strlen(inBuffer)-1] == '\n')
  247.             inBuffer[strlen(inBuffer)-1] = '\0';
  248.          PXCheck(0x300,PXPutAlpha(msgRec,msgTextFld,inBuffer));
  249.          PXCheck(0x301,PXPutShort(msgRec,msgLineFld,LineNumber++));
  250.          PXCheck(0x302,PXPutShort(msgRec,msgMsgNumFld,MessageID));
  251.          PXCheck(0x303,PXRecAppend(msgTbl,msgRec));
  252.     }while (fgets(inBuffer,MESSAGELENGTH,inMsgFp));
  253.     fclose(inMsgFp);
  254.     return;
  255. }
  256.  
  257. void getHeaderInfo(FILE *inMsgFp,char inBuffer[],int msgID)
  258. {
  259.     char subject[41],dummy[1];
  260.     parseDate(inBuffer);
  261.     whoFrom(inMsgFp,inBuffer,msgID);
  262.  
  263.     /*Skip the Blank Line*/
  264.     fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  265.  
  266.     /*Skip the First TO: line (ignore address to self) */
  267.     fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  268.  
  269.     getTo(inMsgFp,inBuffer,msgID);
  270.     getCC(inMsgFp,inBuffer,msgID);
  271.  
  272.     parseAddr(inBuffer,subject,dummy);
  273.     PXCheck(0x330,PXPutAlpha(headerRec,hdrSubjectFld,subject));
  274.     PXCheck(0x331,PXRecAppend(headerTbl,headerRec));
  275.  
  276.     /* Skip blank lines */
  277.     fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  278.     fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  279. }
  280.  
  281. void getTo(FILE *inMsgFp,char inBuffer[],int msgID)
  282. {
  283.     char person[MESSAGELENGTH+1];
  284.     char id[MESSAGELENGTH+1];
  285.     while (fgets(inBuffer,MESSAGELENGTH,inMsgFp) &&
  286.            strstr(inBuffer,"TO") || strstr(inBuffer,"EMS"))
  287.     {
  288.         parseAddr(inBuffer,person,id);
  289.         PXCheck(0x310,PXPutAlpha(routeRec,routeUserFld,person));
  290.         PXCheck(0x311,PXPutAlpha(routeRec,routeIDFld,id));
  291.         PXCheck(0x312,PXPutShort(routeRec,msgMsgNumFld,msgID));
  292.         PXCheck(0x313,PXPutAlpha(routeRec,routeToFld,"TO"));
  293.         PXCheck(0x314,PXRecAppend(routeTbl,routeRec));
  294.     }
  295. }
  296.  
  297. void getCC(FILE *inMsgFp,char inBuffer[],int msgID)
  298. {
  299.     char person[MESSAGELENGTH+1];
  300.     char id[MESSAGELENGTH+1];
  301.     while (strstr(inBuffer,"CC"))
  302.     {
  303.         parseAddr(inBuffer,person,id);
  304.         PXCheck(0x320,PXPutAlpha(routeRec,routeUserFld,person));
  305.         PXCheck(0x321,PXPutAlpha(routeRec,routeIDFld,id));
  306.         PXCheck(0x322,PXPutShort(routeRec,msgMsgNumFld,msgID));
  307.         PXCheck(0x323,PXPutAlpha(routeRec,routeToFld,"CC"));
  308.         PXCheck(0x324,PXRecAppend(routeTbl,routeRec));
  309.         fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  310.     }
  311. }
  312.  
  313. void whoFrom(FILE *inMsgFp,char inBuffer[],int msgID)
  314. {
  315.     char person[MESSAGELENGTH+1];
  316.     char id[MESSAGELENGTH+1];
  317.  
  318.     fgets(inBuffer,MESSAGELENGTH,inMsgFp);
  319.     parseAddr(inBuffer,person,id);
  320.     printf("From: %s\n",person);
  321.     printf("MCI ID: %s\n",id);
  322.     PXCheck(0x350,PXPutAlpha(headerRec,hdrIDFld,id));
  323.     PXCheck(0x351,PXPutAlpha(headerRec,hdrUserFld,person));
  324.     PXCheck(0x352,PXPutShort(headerRec,hdrMsgFld,msgID));
  325. }
  326.  
  327. void parseAddr(char *inBuffer,char *person,char *id)
  328. {
  329.     char *p;
  330.     char *s = person;
  331.     if ((p = strchr(inBuffer,':'))!=NULL)
  332.     {
  333.         while (*(++p) == ' ' || *p == '*')
  334.             ;
  335.         while ( (*s++ = *p++) != '/' && *p)
  336.             ;
  337.         *(--s) = '\0';
  338.     }
  339.     s = id;
  340.     if ((p = strchr(p,':'))!=NULL)
  341.     {
  342.         while ( *(++p) == ' ')
  343.             ;
  344.         while ( (*s++ = *p++) != '\n')
  345.             ;
  346.         *(--s) = '\0';
  347.     }
  348. }
  349.  
  350. short getNextMsgID(short *msgID)
  351. {
  352.     RECORDNUMBER nRecs;
  353.     PXCheck(0x360,PXTblNRecs(msgTbl,&nRecs));
  354.     if (nRecs == 0)
  355.         *msgID = 1;
  356.     else
  357.     {
  358.         PXCheck(0x370,PXRecLast(msgTbl));
  359.         PXCheck(0x371,PXRecGet(msgTbl,msgRec));
  360.         PXCheck(0x372,PXGetShort(msgRec,msgMsgNumFld,msgID));
  361.         ++(*msgID);
  362.     }
  363.  
  364.     return(*msgID);
  365. }
  366.  
  367. void parseDate(char *dateStr)
  368. {
  369.     char *mon,*day,*year;
  370.     int iMon,iDay,iYear;
  371.     long engDate;
  372.  
  373.     strtok(dateStr," ");
  374.     strtok(NULL," ");
  375.     mon=strtok(NULL," ");
  376.     day=strtok(NULL," ");
  377.     year=strtok(NULL," ");
  378.     if((iMon=convertMonth(mon))==0)
  379.         PXCheck(0x380,PXERR_INVDATE);
  380.     iDay=atoi(day);
  381.     iYear=atoi(year);
  382.     PXCheck(381,PXRecBufEmpty(headerRec));
  383.     PXCheck(382,PXDateEncode(iMon,iDay,iYear,&engDate));
  384.     PXCheck(383,PXPutDate(headerRec,hdrDateFld,engDate));
  385. }
  386.  
  387. int convertMonth(char *str)
  388. {
  389.     switch (str[0])
  390.     {
  391.         case 'A': switch (str[1])
  392.                 {
  393.                     case 'p': return 4;  /* April */
  394.                     case 'u': return 8;  /* August */
  395.                 }
  396.         case 'D': return 12;                        /* December */
  397.         case 'F': return 2;                         /* February */
  398.         case 'J': switch (str[1])
  399.                 {
  400.                     case 'a': return 1; /* January */
  401.                     case 'u': switch (str[2])
  402.                             {
  403.                     case 'l': return 7; /* July */
  404.                     case 'n': return 6; /* June */
  405.                             }
  406.                 }
  407.         case 'M': switch (str[2])
  408.                 {
  409.                     case 'r': return 3; /* March */
  410.                     case 'y': return 5; /* May */
  411.                 }
  412.         case 'N': return 11;                        /* November */
  413.         case 'S': return 9;                         /* September */
  414.         case 'O': return 10;                        /* October */
  415.     }
  416.     return 0;
  417. }
  418.  
  419.  
  420. [LISTING FOUR]
  421.  
  422. #include <stdio.h>
  423. #include <stdlib.h>
  424. #include <pxengine.h>
  425. #include "mci.h"
  426.  
  427. void createIndex(TABLEHANDLE *tbl,FIELDHANDLE fld[3]);
  428. void processMany(FILE *fp,FIELDHANDLE f[3],TABLEHANDLE t,int pn,char *st);
  429. void processFile(FILE *fp,FIELDHANDLE f[3],TABLEHANDLE t,int pn);
  430. void nextPendNum(TABLEHANDLE t,FIELDHANDLE f,short *pn);
  431.  
  432. #define PENDFIELD 0
  433. #define ACTFIELD  1
  434. #define TEXTFIELD 2
  435.  
  436. void send(void)
  437. {
  438.     TABLEHANDLE tbl;
  439.     FIELDHANDLE flds[3];
  440.     FILE *output;
  441.     int exists;
  442.     short pendNum;
  443.     PXCheck(0x200,PXTblExist("Pending",&exists));
  444.     if(!exists)
  445.         return;
  446.     createIndex(&tbl,flds);
  447.     PXCheck(0x201,PXTblOpen("Pending",&tbl,0,0));
  448.     pendNum=1;
  449.     output=fopen("mci-send.txt","wt");
  450.     if(output==NULL)
  451.     {
  452.         perror("mci-send.txt");
  453.         exit(1);
  454.     }
  455.     do
  456.     {
  457.         fprintf(output,"\ncr\n");
  458.         processMany(output,flds,tbl,pendNum,"TO");
  459.         fputs("\n",output);
  460.         processMany(output,flds,tbl,pendNum,"CC");
  461.         fputs("\n",output);
  462.         processMany(output,flds,tbl,pendNum,"Subject");
  463.         processFile(output,flds,tbl,pendNum);
  464.         fputs("\n/\n\n\Yes\n",output);
  465.         nextPendNum(tbl,flds[PENDFIELD],&pendNum);
  466.     }while(pendNum>0);
  467.  
  468.     fputs("exit\n",output);
  469.     fclose(output);
  470.     PXCheck(0x202,PXTblClose(tbl));
  471.     PXCheck(0x203,PXTblDelete("Pending"));
  472.     return;
  473. }
  474. void createIndex(TABLEHANDLE *tbl,FIELDHANDLE fld[3])
  475. {
  476.     PXCheck(0x210,PXTblOpen("Pending",tbl,0,0));
  477.     PXCheck(0x211,PXFldHandle(*tbl,"Pending#",&fld[PENDFIELD]));
  478.     PXCheck(0x212,PXFldHandle(*tbl,"Action",&fld[ACTFIELD]));
  479.     PXCheck(0x213,PXFldHandle(*tbl,"Text",&fld[TEXTFIELD]));
  480.     PXCheck(0x214,PXTblClose(*tbl));
  481.     PXCheck(0x215,PXKeyAdd("Pending",1,&fld[ACTFIELD],SECONDARY));
  482. }
  483. void processMany(FILE *fp,FIELDHANDLE f[3],TABLEHANDLE t,int pn,char *st)
  484. {
  485.     char txtSt[81];
  486.     RECORDHANDLE srchRec,rec;
  487.  
  488.     PXCheck(0x230,PXRecBufOpen(t,&rec));
  489.     PXCheck(0x231,PXRecBufOpen(t,&srchRec));
  490.     PXCheck(0x232,PXPutShort(srchRec,f[PENDFIELD],pn));
  491.     PXCheck(0x233,PXPutAlpha(srchRec,f[ACTFIELD],st));
  492.     PXCheck(0x234,PXSrchKey(t,srchRec,2,SEARCHFIRST));
  493.  
  494.     while(PXLastErr()==PXSUCCESS)
  495.     {
  496.         PXCheck(0x235,PXRecGet(t,rec));
  497.         PXCheck(0x236,PXGetAlpha(rec,f[TEXTFIELD],sizeof(txtSt),txtSt));
  498.         fprintf(fp,"%s\n",txtSt);
  499.         PXCheck(0x237,PXSrchKey(t,srchRec,2,SEARCHNEXT));
  500.     }
  501.     PXCheck(0x238,PXRecBufClose(rec));
  502.     PXCheck(0x239,PXRecBufClose(srchRec));
  503. }
  504. void processFile(FILE *fp,FIELDHANDLE f[3],TABLEHANDLE t,int pn)
  505. {
  506.     char txtSt[81],fname[21];
  507.     FILE *inFp;
  508.     RECORDHANDLE srchRec,rec;
  509.  
  510.     PXCheck(0x240,PXRecBufOpen(t,&rec));
  511.     PXCheck(0x241,PXRecBufOpen(t,&srchRec));
  512.     PXCheck(0x242,PXPutShort(srchRec,f[PENDFIELD],pn));
  513.     PXCheck(0x243,PXPutAlpha(srchRec,f[ACTFIELD],"Filename"));
  514.     PXCheck(0x244,PXSrchKey(t,srchRec,2,SEARCHFIRST));
  515.  
  516.     while(PXLastErr()==PXSUCCESS)
  517.     {
  518.            PXCheck(0x245,PXRecGet(t,rec));
  519.                PXCheck(0x246,PXGetAlpha(rec,f[TEXTFIELD],sizeof(fname),fname));
  520.         if((inFp=fopen(fname,"rt"))==NULL)
  521.         {
  522.             perror(fname);
  523.             exit(1);
  524.         }
  525.         while(fgets(txtSt,80,inFp)!=NULL)
  526.             fputs(txtSt,fp);
  527.         fclose(inFp);
  528.         unlink(fname);
  529.  
  530.         PXCheck(0x247,PXSrchKey(t,srchRec,2,SEARCHNEXT));
  531.     }
  532.     PXCheck(0x248,PXRecBufClose(rec));
  533.     PXCheck(0x249,PXRecBufClose(srchRec));
  534. }
  535. void nextPendNum(TABLEHANDLE t,FIELDHANDLE f,short *pn)
  536. {
  537.     RECORDHANDLE r;
  538.  
  539.     PXCheck(0x250,PXRecBufOpen(t,&r));
  540.     PXCheck(0x251,PXPutShort(r,f,*pn));
  541.     PXCheck(0x252,PXSrchKey(t,r,1,SEARCHFIRST));
  542.     while(PXLastErr()==PXSUCCESS)
  543.         PXCheck(0x253,PXSrchKey(t,r,1,SEARCHNEXT));
  544.     PXCheck(0x254,PXRecNext(t));
  545.     if(PXLastErr()==PXSUCCESS)
  546.     {
  547.         PXCheck(0x255,PXRecGet(t,r));
  548.         PXCheck(0x256,PXGetShort(r,f,pn));
  549.         PXCheck(0x257,PXRecBufClose(r));
  550.     }
  551.     else
  552.         *pn=0;
  553. }
  554.  
  555.  
  556. [LISTING FIVE]
  557.  
  558. editor = "ED"  ; Change this to your word processor
  559.  
  560. PROC BuildHdrForm()
  561.   {Forms} {Design} {Header} {2} {Brief Header}     ; Design form for HEADER
  562.   " Date Recvd      From                  Subject" ; Place text...
  563.   Enter
  564.   " ----------- -------------------- ----------------------------------------"
  565.   Enter
  566.   " "
  567.   Menu {Field} {Place} {Regular} {Date Received}   ; Place DATE field
  568.   Enter Enter Right
  569.   Menu {Field} {Place} {Regular} {From User}       ; Place FROM USER field
  570.   Enter Enter Right
  571.   Menu {Field} {Place} {Regular} {Subject}         ; Place SUBJECT field
  572.   Enter Enter CtrlHome
  573.   Menu {Multi} {Records} {Define}                  ; Define as MultiRecord
  574.   Enter Left Enter Down Down Down Down Down Down Down Enter
  575.   Do_It!                                           ; Save this form
  576. ENDPROC ; BuildHdrForm
  577.  
  578. PROC BuildMsgForms()
  579.   {Forms} {Design} {Message} {1} {Message Body} ; Design form for MESSAGE
  580.   MENU {Field} {Place} {Regular} {Line#}        ; Place LINE# field
  581.   ENTER LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT; Truncate field size
  582.   LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT LEFT ENTER
  583.  
  584.   MENU {Field} {Place} {Regular} {Text}         ; Place TEXT field
  585.   RIGHT ENTER ENTER
  586.  
  587.   MENU {Multi} {Records} {Define}               ; Define as MultiRecord fields
  588.   ENTER LEFT ENTER DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN ENTER
  589.  
  590.   ; The next four lines set up the position and color for hiding the line#
  591.   ; field. It currently sets the color to a light grey on light grey.
  592.   HOME CTRLHOME
  593.   MENU {Style} {Color} {Area}
  594.   ENTER DOWN DOWN DOWN DOWN DOWN DOWN DOWN DOWN ENTER
  595.   RIGHT RIGHT RIGHT RIGHT RIGHT RIGHT RIGHT ENTER
  596.  
  597.   DO_IT!                                        ; Save this form
  598.  
  599.   {Forms} {Design} {Header} {1} {Message}       ; Design for for HEADER table
  600.   ENTER "  Date Received "                      ; Set up position and text
  601.   MENU {Field} {Place} {Regular} {Date Received} ; Place DATE RECEIVED field
  602.  
  603.   ENTER ENTER ENTER  "  Subject ..... "         ; Set up position and text
  604.   MENU {Field} {Place} {Regular} {Subject}      ; Place SUBJECT field
  605.  
  606.   ENTER ENTER ENTER  "  From ........ "         ; Set up position and text
  607.   MENU {Field} {Place} {Regular} {From User}    ; Place FROM USER field
  608.   ENTER ENTER
  609.  
  610.   MENU {Multi} {Tables} {Place}       ; Place MultiTable Linked Form from
  611.   {Linked} {Message} {1} {Message#}   ; MESSAGE table.
  612.   UP UP UP UP UP UP UP UP UP ENTER    ; Position the field
  613.  
  614.   DO_IT!                              ; Save this form
  615. ENDPROC ; BuildMsgForms
  616.  
  617. PROC MenuScrn()
  618.   CANVAS OFF
  619.   @4,0
  620.   SETMARGIN 25
  621.  
  622.   PAINTCANVAS ATTRIBUTE 31 2,0,24,79 ; Fill Background w/White on Blue
  623.   PAINTCANVAS ATTRIBUTE 0 5,27,8,54  ; Shadow Box in Black
  624.   STYLE ATTRIBUTE 7
  625.   TEXT
  626. ----------------------------
  627. |    MCI Message System    |
  628. |                          |
  629. ----------------------------
  630.   ENDTEXT
  631.  
  632.   SETMARGIN 0
  633.   @22,0
  634.  
  635.   TEXT
  636.  ----------------------------------------------------------------------------
  637.      Use Cursor Keys <- -> To Move Between Menu Choices, or 1st Character
  638.  ----------------------------------------------------------------------------
  639.   ENDTEXT
  640.   PAINTCANVAS ATTRIBUTE 31 22,0,24,79
  641.   CANVAS ON
  642. ENDPROC ; MenuScrn
  643.  
  644. PROC Inbox()
  645.   IF ( ISEMPTY("Header") ) THEN
  646.     @ 20,27
  647.     ?? "No messages to be viewed"
  648.     RETURN
  649.   ENDIF
  650.   VIEW "Header"
  651.   PICKFORM 2
  652.   WAIT TABLE
  653.     PROMPT "Arrow to message, press RETURN to view.",
  654.            "ESC aborts to main menu."
  655.   UNTIL "Enter", "Esc"
  656.  
  657.   SWITCH
  658.     CASE retval = "Enter" :
  659.       ViewMessage()
  660.     CASE retval = "Esc" :
  661.       CLEAR
  662.       CLEARALL
  663.       RETURN
  664.   ENDSWITCH
  665. ENDPROC ; Inbox
  666.  
  667. PROC ViewMessage()
  668.   PICKFORM 1
  669.   DOWNIMAGE
  670.   WHILE (TRUE)
  671.     WAIT TABLE
  672.       PROMPT "F3/F4 move to Previous/Next message. INS responds to message.",
  673.              "Arrow keys scroll the current message. ESC aborts to main menu."
  674.     UNTIL "Esc", "F3", "F4", "Ins"
  675.  
  676.     SWITCH
  677.       CASE retval = "Ins":
  678.         Respond();
  679.         PICKFORM 1
  680.         DOWNIMAGE
  681.       CASE retval = "F3":
  682.         UPIMAGE
  683.         PGUP
  684.         DOWNIMAGE
  685.       CASE retval = "F4":
  686.         UPIMAGE
  687.         PGDN
  688.         DOWNIMAGE
  689.       CASE retval = "Esc":
  690.         QUITLOOP
  691.     ENDSWITCH
  692.   ENDWHILE
  693.   CLEAR
  694.   CLEARALL
  695. ENDPROC ; ViewMessage
  696.  
  697. PROC CheckPending()
  698.   IF ( NOT ISTABLE("Pending") ) THEN
  699.     CREATE "Pending"
  700.       "Pending#" : "N*",
  701.       "Action"   : "A8*",
  702.       "Text"     : "A40*"
  703.     RETURN 1
  704.   ELSE
  705.     IF ( ISEMPTY("Pending") ) THEN
  706.       RETURN 1
  707.     ELSE
  708.       RETURN CMAX("Pending","Pending#") + 1
  709.     ENDIF
  710.   ENDIF
  711. ENDPROC ; CheckPending
  712.  
  713. PROC Respond()
  714.   UPIMAGE
  715.   mnum    = [Message#]
  716.   subject = [Subject]
  717.   from    = [From ID]
  718.   pnum    = CheckPending()
  719.  
  720.   QUERY
  721.   Route | Message# | TOorCC | User Name | User ID |
  722.         | ~mnum    | Check  |           | Check   |
  723.         |          |        |           |         |
  724.         |          |        |           |         |
  725.  
  726.   ENDQUERY
  727.   DO_IT!
  728.  
  729.   VIEW "Answer"
  730.   IF ( ISEMPTY("Answer") ) THEN
  731.     answerTable=TRUE
  732.   ELSE
  733.     answerTable=FALSE
  734.   ENDIF
  735.   VIEW "Pending"
  736.   EDIT "Pending"
  737.   END
  738.   DOWN
  739.   [Pending#] = pnum
  740.   [Action]   = "Filename"
  741.   [Text]     = "Pending." + STRVAL(pnum)
  742.   DOWN
  743.   [Pending#] = pnum
  744.   [Action]   = "Subject"
  745.   [Text]     = "RE:" + subject
  746.   DOWN
  747.   [Pending#] = pnum
  748.   [Action]   = "TO"
  749.   [Text]     = from
  750.   DOWN
  751.   UPIMAGE
  752.  
  753.   IF ( NOT answerTable ) THEN
  754.     WHILE ( TRUE )
  755.       to_cc = [TOorCC]
  756.       uid   = [User ID]
  757.  
  758.       DOWNIMAGE
  759.       [Pending#] = pnum
  760.       [Action]   = to_cc
  761.       [Text]     = uid
  762.       DOWN
  763.  
  764.       UPIMAGE
  765.       IF ( ATLAST() ) THEN
  766.         QUITLOOP
  767.       ENDIF
  768.       DOWN
  769.     ENDWHILE
  770.   ENDIF
  771.  
  772.   DO_IT!
  773.  
  774.   RUN BIG editor + " Pending." + STRVAL(pnum)
  775.   CLEAR
  776.   CLEARIMAGE          ; Close the Pending Table
  777.   CLEARIMAGE          ; Close the Answer Table
  778.   UPIMAGE
  779.   CLEARIMAGE          ; Close Route Query Table
  780. ENDPROC ; Respond()
  781.  
  782. PROC Compose()
  783.   pnum = CheckPending()
  784.  
  785.   VIEW "Pending"
  786.   EDIT "Pending"
  787.   END
  788.   DOWN
  789.  
  790.   [Pending#] = pnum
  791.   [Action]   = "Filename"
  792.   [Text]     = "Pending." + STRVAL(pnum)
  793.   DOWN
  794.  
  795.   CLEAR
  796.   @ 0,0
  797.   GetMultiple("TO",TRUE);
  798.   IF ( NOT retval ) THEN
  799.     CANCELEDIT
  800.     CLEAR
  801.     CLEARALL
  802.     RETURN
  803.   ENDIF
  804.   GetMultiple("CC",FALSE);
  805.   IF ( NOT retval ) THEN
  806.     CANCELEDIT
  807.     CLEAR
  808.     CLEARALL
  809.     RETURN
  810.   ENDIF
  811.  
  812.   sub = ""
  813.   WHILE( LEN(sub) = 0 )
  814.     ? "Subject: "
  815.     ACCEPT "A40" to sub
  816.     IF ( NOT retval ) THEN
  817.       CANCELEDIT
  818.       CLEAR
  819.       CLEARALL
  820.       RETURN
  821.     ENDIF
  822.   ENDWHILE
  823.   [Pending#] = pnum
  824.   [Action]   = "Subject"
  825.   [Text]     = sub
  826.  
  827.   DO_IT!
  828.  
  829.   RUN BIG editor + " Pending." + STRVAL(pnum)
  830.   CLEAR
  831.   CLEARALL
  832. ENDPROC ; Compose
  833.  
  834. PROC GetMultiple(where,one)
  835.   IF (one) THEN
  836.     name = ""
  837.     WHILE ( LEN(name) = 0 )         ; Loop until at least one [where] field
  838.       ? where + ": "                ; has been input.
  839.       ACCEPT "A20" TO name
  840.       IF ( NOT retval ) THEN        ; Esc was pressed
  841.         RETURN FALSE
  842.       ENDIF
  843.     ENDWHILE
  844.     [Pending#] = pnum
  845.     [Action]   = where
  846.     [Text]     = name
  847.     DOWN
  848.   ENDIF
  849.  
  850.   WHILE (TRUE)
  851.     ? where + ": "
  852.     ACCEPT "A20" TO name
  853.     IF ( NOT retval ) THEN          ; Esc was pressed
  854.       RETURN FALSE
  855.     ENDIF
  856.     IF ( LEN(name) = 0 ) THEN
  857.       QUITLOOP
  858.     ENDIF
  859.     [Pending#] = pnum
  860.     [Action]   = where
  861.     [Text]     = name
  862.     DOWN
  863.   ENDWHILE
  864.   RETURN TRUE
  865. ENDPROC ; GetMultiple
  866.  
  867. PROC Main()
  868.   WHILE (TRUE)
  869.     Menuscrn()
  870.  
  871.     SHOWMENU
  872.       "Inbox"  : "View Current Messages",
  873.       "Compose": "Compose a new Message",
  874.       "Quit"   : "Quit the MCI Message System"
  875.       TO choice
  876.  
  877.     SWITCH
  878.       CASE choice = "Inbox" :
  879.         Inbox()
  880.       CASE choice = "Compose" :
  881.         Compose()
  882.       CASE choice = "Quit" :
  883.         SHOWMENU
  884.           "No"  : "Do NOT Quit The Application.",
  885.           "Yes" : "Quit The Application."
  886.           TO theexit
  887.         IF ( theexit = "Yes" ) THEN
  888.           MENU {Exit} {Yes}
  889.         ENDIF
  890.     ENDSWITCH
  891.   ENDWHILE
  892. ENDPROC ; Main
  893.  
  894. ;**** Mainline ****
  895. RESET
  896. CLEAR
  897. CLEARALL
  898.  
  899. IF ( NOT ISTABLE("Message") ) OR ( NOT ISTABLE("Header") ) OR
  900.    ( NOT ISTABLE("Route") ) THEN
  901.   @ 12,17
  902.   ?? "You must run MCI.EXE before running this script"
  903.   SLEEP 5000
  904.   RETURN
  905. ENDIF
  906.  
  907. IF ( NOT ISFILE("Header.F1") ) OR ( NOT ISFILE("Message.F1") ) THEN
  908.   BuildMsgForms();
  909. ENDIF
  910.  
  911. IF ( NOT ISFILE("Header.F2") ) THEN
  912.   BuildHdrForm();
  913. ENDIF
  914.  
  915. Main()
  916.  
  917.