home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / msgpst32.zip / mpostp.c < prev    next >
Text File  |  1995-03-06  |  37KB  |  1,187 lines

  1. /****************************************************************************
  2.  ╒═══════════════════════════════════════════════════════════════════════════╕
  3.  │ MsgPost/2 Version 1.10 5th Dec 1992       (C) 1992 by CodeLand Australia, │
  4.  │                                                      All Rights Reserved. │
  5.  │ Written by Colin Wheat of Fidonet 3:690/613                               │
  6.  │ Compiled using C SET/2                                                    │
  7.  │                                                                           │
  8.  │ Modified to use 32-bit Squish API DLL and netmail bug fixed               │
  9.  │ by Wouter Cloetens, 2:292/608.18@fidonet, 81:432/109@os2net               │
  10.  │ 6 march 1995                                                              │
  11.  │                                                                           │
  12.  │            MsgPost uses the Squish Message Base Level 0 MsgAPI            │
  13.  │                  Squish is a trademark of Scott J. Dudley                 │
  14.  │                                                                           │
  15.  │                                                                           │
  16.  │ COMMAND LINE:                                                             │
  17.  │                                                                           │
  18.  │              COMMAND LINE ONLY                                            │
  19.  │ -T<name>     Text source file path & name                                 │
  20.  │ -K           Kill text file after processing                              │
  21.  │ -C<name>     Configuration file path & name                               │
  22.  │ -@<name>     List file name                                               │
  23.  │ -?           Program help screen                                          │
  24.  │                                                                           │
  25.  │              CONFIGURATION OVERRIDES                                      │
  26.  │ -M<name>     Message area path & name                                     │
  27.  │ -N<addr>     Netmail format - send to address                             │
  28.  │ -O<addr>     [Zone:]Net/Node[.Point][@Domain]                             │
  29.  │ -P[cfhdkpru] Message priority flag(s)                                     │
  30.  │ -F<fname>    Message addressed to first name                              │
  31.  │ -L<lname>    Message addressed to last name                               │
  32.  │ -W<name>     Message addressed from name                                  │
  33.  │ -J<subj>     Message subject                                              │
  34.  │ -S<##>       Split long messages to ## Kb size (0-16)                     │
  35.  │                                                                           │
  36.  │                                                                           │
  37.  │ CONFIGURATION FILE:                                                       │
  38.  │                                                                           │
  39.  │ Address:     [Zone:]Net/Node[.Point][@Domain]                             │
  40.  │ Origin:      <Your system echomail identification>                        │
  41.  │ Area:        <Message area path & name>                                   │
  42.  │ Netmail:     [Zone:]Net/Node[.Point][@Domain]                             │
  43.  │ MsgType:     <Echomail | Conference | Local | Matrix>                     │
  44.  │ To:          <Some Name>                                                  │
  45.  │ From:        <Your Name>                                                  │
  46.  │ Subj:        <Your Subject>                                               │
  47.  │ Attr:        <c|f|h|d|k|p|r|u|l>                                          │
  48.  │ FakeNet:     <###>                                                        │
  49.  │ NoSeenBy:                                                                 │
  50.  │ Split:       <###>                                                        │
  51.  │                                                                           │
  52.  │                                                                           │
  53.  │ ERROR LEVELS:                                                             │
  54.  │                                                                           │
  55.  │ 0 - Normal exit                                                           │
  56.  │ 1 - Syntax exit                                                           │
  57.  │ 2 - Out of memory                                                         │
  58.  │ 3 - Configuration or text file not found                                  │
  59.  │ 4 - No system address set                                                 │
  60.  │ 5 - Message base open failed                                              │
  61.  │ 6 - Names list file not found                                             │
  62.  ╘═══════════════════════════════════════════════════════════════════════════╛
  63.  ****************************************************************************/
  64.  
  65. #define INCL_DOSDATETIME
  66. #include <os2.h>
  67.  
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <ctype.h>
  72. #include <time.h>
  73. #include <io.h>
  74. #include <sys\types.h>
  75. #include <sys\stat.h>
  76. #include <fcntl.h>
  77. #include <share.h>
  78. #include "prog.h"               /* Squish API header */
  79. #include "alc.h"                /* Squish API header */
  80. #include "msgapi.h"             /* Squish API header */
  81.  
  82.  
  83. #define VERSION     "1.10"      /* MsgPost version   */
  84. #define SVERSON     "1.1"       /* Short version     */
  85. #define MAX_BLOCK   16000       /* Maximum text size */
  86. #define MAX_LINE    10000       /* Maximum lines     */
  87.  
  88. #define MSGTYP_ECHO 1           /* Echomail msg type */
  89. #define MSGTYP_CONF 2           /* Conf. msg type    */
  90. #define MSGTYP_LOCL 3           /* Local msg type    */
  91. #define MSGTYP_MATX 4           /* Netmail msg type  */
  92.  
  93. /*
  94.     Echomail    - DestAddr=NO  PID=NO  Tear=YES Origin=YES SeenBy=YES
  95.     Conference  - DestAddr=NO  PID=YES Tear=NO  Origin=NO  SeenBy=NO
  96.     Local       - DestAddr=NO  PID=NO  Tear=YES Origin=NO  SeenBy=NO
  97.     Matrix      - DestAddr=YES PID=YES Tear=NO  Origin=NO  SeenBy=NO
  98. */
  99.  
  100. #define DEF_NADDR {0,0,0,0,{0}}
  101.  
  102. typedef struct _naddr {
  103.     word zone;
  104.     word net;
  105.     word node;
  106.     word point;
  107.     char domain[64];
  108. } NADDR;
  109.  
  110. char *def_orig = "^KD <Esc> <F2> ^Z ^C (damnit!) q e quit exit !Q system";
  111.  
  112. NADDR sy_addr=DEF_NADDR;        /* System address    */
  113. NADDR fm_addr=DEF_NADDR;        /* Origin address    */
  114. NADDR to_addr=DEF_NADDR;        /* Destination addr  */
  115. unsigned int fakenet=0;         /* System fakenet    */
  116.  
  117. int listflg=0;                  /* Run in list mode  */
  118. int killtxtflg=0;               /* Txtfile kill flag */
  119. int seenbyflg=1;                /* Seenby line flag  */
  120. int addrflg=0;                  /* Address flag      */
  121. int msgtyp=MSGTYP_ECHO;         /* Message type      */
  122. int split_k=12;                 /* Message split     */
  123. unsigned long seed;             /* MSGID seed        */
  124. time_t time_now;                /* Creation time     */
  125. int mn;                         /* Split unique #    */
  126.  
  127. char exepath[80];               /* Executable path   */
  128. char msgpath[80];               /* Message area name */
  129. char txtpath[80];               /* Import text file  */
  130. char cfgpath[80];               /* MsgPost CFG file  */
  131. char lstpath[80];               /* Names list file   */
  132.  
  133. char str_to[XMSG_TO_SIZE];      /* Message to field  */
  134. char str_from[XMSG_FROM_SIZE];  /* Message from fld  */
  135. char str_subj[XMSG_SUBJ_SIZE];  /* Message subj fld  */
  136. char str_orig[80];              /* Echo origin line  */
  137. dword attr=MSGLOCAL;            /* Message attr      */
  138.  
  139. char *lines[MAX_LINE];          /* Line ptr array    */
  140. int linescount=0;               /* Line ptr count    */
  141. long linesbytes=0L;             /* Total text bytes  */
  142. int linesidx;                   /* Line ptr index    */
  143.  
  144. char *textbuf=NULL;             /* Msg text buffer   */
  145. long textcount;                 /* Msg text length   */
  146.  
  147. static void  Quit (int status);
  148. static int  ReadCfg (void);
  149. static int  ReadTxt (void);
  150. static int  SetMsgCfg (char *s);
  151. static int  Process (MSG *ap);
  152. static void  WriteMsg (MSG *ap);
  153. static int  GetNum (int splitbytes);
  154. static int  BuildText (int limit);
  155. static void  SetAttr (char *p);
  156. static int  ReadOrig (void);
  157. static void  BuildTear (char *s);
  158. static void  BuildHdr (XMSG *x, int num, int maxnum);
  159. static void  BuildCtrl (char *str, int *len, int num, int maxnum);
  160. static char *  AddrToStr (NADDR *addr);
  161. static unsigned long  HsecTime (void);
  162. static void  GetAddr (char *str, NADDR *addr);
  163. static void  AddSlash (char *str);
  164. static void  StripSlash(char *str);
  165. static void  StripCr (char *str);
  166. static void  StrTrim (char *str);
  167. static int  StrBlank (char *str);
  168. static void  CvtUs (char *s);
  169. static int  IsSpace (char c);
  170. static char *  FancyStr (char *string);
  171. static void  MakeExePath (char *pth);
  172. static FILE *  ShFopen (char *name, char *fpmode);
  173. static void  SetUp (int argc, char *argv[]);
  174. static void  GetCmdLine (int argc, char *argv[]);
  175. static void  Usage (void);
  176.  
  177.  
  178. void main (int argc, char *argv[])
  179. {
  180.     int status=0;               /* Exit status                  */
  181.     int areatyp;                /* Message area type            */
  182.     struct _minf mi;            /* API structure                */
  183.     MSG *ap;                    /* API area pointer             */
  184.  
  185.     printf("\nMPost/2 v" VERSION " - the Fidonet/Squish Message Base Writer"
  186.            "\n   (C) Copyright 1992 by CodeLand, All Rights Reserved\n\n");
  187.  
  188.     SetUp(argc,argv);           /* Read initial command line    */
  189.     if(!ReadCfg()) {            /* Read configuration file      */
  190.         printf("\n%cERROR: Configuration file not found!\n\n",0x07);
  191.         Quit(3);
  192.     }
  193.  
  194.     if(!ReadTxt()) {       /* Read the message source text file */
  195.         printf("\n%cERROR: Text file not found!\n\n",0x07);
  196.         Quit(3);
  197.     }
  198.  
  199.     GetCmdLine(argc,argv);      /* Get command line overrides   */
  200.     
  201.     if(!addrflg) {              /* If no system address         */
  202.         printf("\n%cERROR: No address set!\n\n",0x07);
  203.         Quit(4);
  204.     }
  205.  
  206.     /* Setup MsgApi */
  207.     mi.req_version=0;
  208.     mi.def_zone=(msgtyp==MSGTYP_MATX?sy_addr.zone:fm_addr.zone);
  209.  
  210.     /* If no origin set, try from the message area, else use default */
  211.     if(msgtyp==MSGTYP_ECHO)
  212.         if(!*str_orig) if(!ReadOrig()) strcpy(str_orig,def_orig);
  213.  
  214.     MsgOpenApi(&mi); /* Open the MsgApi */
  215.     areatyp=(*msgpath=='$'?MSGTYPE_SQUISH:MSGTYPE_SDM);
  216.     if(areatyp==MSGTYPE_SDM&&msgtyp!=MSGTYP_MATX) areatyp|=MSGTYPE_ECHO;
  217.  
  218.     /* Open the message base */
  219.     if((ap=MsgOpenArea((byte *)msgpath+(*msgpath=='$'),MSGAREA_NORMAL,areatyp)
  220.        )==NULL) {
  221.         printf("\n%cERROR: Message base open failed!\n\n",0x07);
  222.         Quit(5);
  223.     }
  224.  
  225.     MsgLock(ap); /* Lock the base */
  226.  
  227.     /* Write the message(s) */
  228.     if((status=Process(ap))!=0) {
  229.         printf("\n%cERROR: List file not found!\n\n",0x07);
  230.     }
  231.  
  232.     MsgUnlock(ap); MsgCloseArea(ap);    /* Unlock & close the base  */
  233.     MsgCloseApi();                      /* Close the API            */
  234.  
  235.     if(killtxtflg) unlink(txtpath);     /* Delete text source file  */
  236.     Quit(status);
  237. }
  238.  
  239.  
  240. /*
  241. ** Quit ()
  242. ** Exit the program
  243. */
  244.  
  245. static void  Quit (int status)
  246. {
  247.     /* Release allocated memory */
  248.     while(linescount) free(lines[--linescount]);
  249.     if(textbuf) free(textbuf);
  250.  
  251.     if(!status) printf("\nDone! (exit 0)\n");
  252.     exit(status);
  253. }
  254.  
  255.  
  256. /*
  257. ** ReadCfg ()
  258. ** Read configuration file
  259. */
  260.  
  261. static int  ReadCfg (void)
  262. {
  263.     FILE *fp;
  264.     char line[258];
  265.  
  266.     if((fp=ShFopen(cfgpath,"r"))==NULL) return 0;
  267.     while(fgets(line,256,fp)!=NULL) SetMsgCfg(line);
  268.     fclose(fp);
  269.  
  270.     return 1;
  271. }
  272.  
  273.  
  274. /*
  275. ** ReadTxt ()
  276. ** Read complete text file into line pointer array
  277. */
  278.  
  279. static int  ReadTxt (void)
  280. {
  281.     int llen, checkcfg=1, trimleading=1;
  282.     FILE *fp;
  283.     char *fbuf=NULL;
  284.     char line[258];
  285.  
  286.     if(!*txtpath) { /* Allow for a blank msg */
  287.         lines[linescount]=strdup("");
  288.         ++linescount;
  289.         return 1;
  290.     }
  291.  
  292.     printf("Reading %s\n",FancyStr(txtpath));
  293.  
  294.     if((fp=ShFopen(txtpath,"r"))==NULL) return 0;
  295.     fbuf=(char *)malloc(4096); /* Get extended file buffer */
  296.     if(fbuf!=NULL) setvbuf(fp,fbuf,_IOFBF,4096);
  297.  
  298.     while(fgets(line,256,fp)!=NULL) {
  299.  
  300.         if(checkcfg) { /* Check for override configuration */
  301.             if(SetMsgCfg(line)) continue;
  302.             else checkcfg=0;
  303.         }
  304.  
  305.         StripCr(line); StrTrim(line); /* Clean up */
  306.  
  307.         /* Ignore leading blank lines */
  308.         if(trimleading) {
  309.             if(StrBlank(line)) continue;
  310.             else trimleading=0;
  311.         }
  312.  
  313.         strcat(line,"\r"); llen=strlen(line);
  314.         if((lines[linescount]=(char *)malloc(llen+1))==NULL) {
  315.             printf("\n%cERROR: Out of memory!\n\n",0x07);
  316.             fclose(fp);
  317.             Quit(2);
  318.         }
  319.  
  320.         memcpy(lines[linescount],line,llen+1);
  321.         linesbytes+=(long)llen;
  322.         if(++linescount>=MAX_LINE) break;
  323.     }
  324.     
  325.     if(linescount) {
  326.         for(;;) { /* Strip trailing blank lines */
  327.             if(!StrBlank(lines[linescount-1])&&lines[linescount-1][0]!='\r')
  328.                 break;
  329.             linesbytes-=(long)strlen(lines[linescount-1]);
  330.             if(!--linescount) break;
  331.         }
  332.     }
  333.  
  334.     fclose(fp);
  335.     if(fbuf) free(fbuf);
  336.     return 1;
  337. }
  338.  
  339.  
  340. /*
  341. ** SetMsgCfg ()
  342. ** Set message configuration from configuration string
  343. ** Returns TRUE for a valid cfg line processed
  344. */
  345.  
  346. static int  SetMsgCfg (char *s)
  347. {
  348.     char *p, *q, *r, sbuf[258];
  349.  
  350.     strcpy(sbuf,s); /* Clone the line so we don't change the original */
  351.  
  352.     if((p=strtok(sbuf," \t\n\r"))!=NULL) {
  353.         if(*p==';'||*p=='%') return 1;
  354.         if((q=strtok(NULL,"\n\r"))!=NULL) {
  355.             r=q; while(*r==' '||*r=='\t') ++r; /* Strip leading */
  356.             StrTrim(r); /* Strip trailing */
  357.             if(*r) {
  358.                 if(!stricmp(p,"TO:")) {
  359.                     strncpy(str_to,r,XMSG_TO_SIZE-1);
  360.                     str_to[XMSG_TO_SIZE-1]='\0';
  361.                     return 1;
  362.                 }
  363.                 else if(!stricmp(p,"FROM:")) {
  364.                     strncpy(str_from,r,XMSG_FROM_SIZE-1);
  365.                     str_from[XMSG_FROM_SIZE-1]='\0';
  366.                     return 1;
  367.                 }
  368.                 else if(!stricmp(p,"SUBJ:")) {
  369.                     strncpy(str_subj,r,XMSG_SUBJ_SIZE-1);
  370.                     str_subj[XMSG_SUBJ_SIZE-1]='\0';
  371.                     return 1;
  372.                 }
  373.                 else if(!stricmp(p,"ORIGIN:")) {
  374.                     strncpy(str_orig,r,59);
  375.                     str_orig[59]='\0';
  376.                     return 1;
  377.                 }
  378.                 else if(!stricmp(p,"ADDRESS:")) {
  379.                     /* System address */
  380.                     GetAddr(r,&sy_addr); 
  381.                     /* Set default message from address to system address */
  382.                     fm_addr=sy_addr;
  383.                     ++addrflg;
  384.                     return 1;
  385.                 }
  386.                 else if(!stricmp(p,"ATTR:")) {
  387.                     SetAttr(r);
  388.                     return 1;
  389.                 }
  390.                 else if(!stricmp(p,"AREA:")) {
  391.                     strncpy(msgpath,r,78); msgpath[78]='\0';
  392.                     StripSlash(msgpath);
  393.                     return 1;
  394.                 }
  395.                 else if(!stricmp(p,"NETMAIL:")) {
  396.                     GetAddr(r,&to_addr); msgtyp=MSGTYP_MATX;
  397.                     return 1;
  398.                 }
  399.                 else if(!stricmp(p,"MSGTYPE:")) {
  400.                     if(!stricmp(r,"ECHOMAIL")) {
  401.                         msgtyp=MSGTYP_ECHO; return 1;
  402.                     }
  403.                     else if(!stricmp(r,"CONFERENCE")) {
  404.                         msgtyp=MSGTYP_CONF; return 1;
  405.                     }
  406.                     else if(!stricmp(r,"LOCAL")) {
  407.                         msgtyp=MSGTYP_LOCL; return 1;
  408.                     }
  409.                     else if(!stricmp(r,"MATRIX")) {
  410.                         msgtyp=MSGTYP_MATX; return 1;
  411.                     }
  412.                 }
  413.                 else if(!stricmp(p,"FAKENET:")) {
  414.                     fakenet=(unsigned int)atol(r);
  415.                     return 1;
  416.                 }
  417.                 else if(!stricmp(p,"NOSEENBY:")) {
  418.                     seenbyflg=0;
  419.                     return 1;
  420.                 }
  421.                 else if(!stricmp(p,"SPLIT:")) {
  422.                     split_k=atoi(r);
  423.                     if(split_k<0||split_k>16) split_k=12;
  424.                     return 1;
  425.                 }
  426.             }
  427.         }
  428.     }
  429.  
  430.     return 0;
  431. }
  432.  
  433.  
  434. /*
  435. ** Process ()
  436. ** Write out the messages
  437. */
  438.  
  439. static int  Process (MSG *ap)
  440. {
  441.     int i=0, oldmsgtyp;
  442.     FILE *fp;
  443.     char *p, *q, line[258];
  444.  
  445.     if(listflg) { /* List mode */
  446.         printf("Reading %s\n",FancyStr(lstpath));
  447.  
  448.         if((fp=ShFopen(lstpath,"r"))==NULL) return 6; /* Open list file */
  449.         oldmsgtyp=msgtyp;
  450.         for(;;) {
  451.             if(fgets(line,256,fp)==NULL) break;
  452.             p=line; while(*p==' '||*p=='\t') ++p; /* Strip leading */
  453.             if((q=strchr(p,','))!=NULL) { /* Get optional netmail addr */
  454.                 GetAddr(q+1,&to_addr); msgtyp=MSGTYP_MATX;
  455.                 *q='\0';
  456.             }
  457.             else msgtyp=oldmsgtyp;
  458.             StripCr(p); StrTrim(p); /* Strip trailing */
  459.             if(!StrBlank(p)) {
  460.                 strncpy(str_to,p,XMSG_TO_SIZE-1);
  461.                 str_to[XMSG_TO_SIZE-1]='\0';
  462.                 printf("List message %3d to: %s\n",++i,str_to);
  463.                 WriteMsg(ap);
  464.             }
  465.         }
  466.         fclose(fp);
  467.     }
  468.     else WriteMsg(ap); /* Normal mode */
  469.  
  470.     return 0;
  471. }
  472.  
  473.  
  474. /*
  475. ** WriteMsg ()
  476. ** Write message(s)
  477. */
  478.  
  479. static void  WriteMsg (MSG *ap)
  480. {
  481.     int i;
  482.     int split_num=1;                /* How many msgs        */
  483.     int splitbytes;                 /* Split size           */
  484.     MSGH *msg;                      /* Message pointer      */
  485.     XMSG xmsg;                      /* Xmsg structure       */
  486.     int ctrllen;                    /* Control info size    */
  487.     char ctrl[256];                 /* Control info         */
  488.     char tear[256];                 /* Tear line, origin    */
  489.  
  490.     time_now=time(NULL);            /* Get message time     */
  491.     seed=HsecTime();                /* Get MSGID seed       */
  492.  
  493.     linesidx=0;  /* Start loading from start of lines array */
  494.  
  495.     /* Get split messages unique number */
  496.     srand((unsigned)seed); mn=rand(); 
  497.  
  498.     /* Make tear/origin line for echomail/local */
  499.     BuildTear(tear); 
  500.  
  501.     /* Set split message size */
  502.     if(!split_k) splitbytes=MAX_BLOCK;
  503.     else splitbytes=split_k*1024;
  504.     if(splitbytes>MAX_BLOCK) splitbytes=MAX_BLOCK;
  505.  
  506.     /* Adjust for tear and header */
  507.     if(msgtyp==MSGTYP_ECHO||msgtyp==MSGTYP_LOCL) splitbytes-=strlen(tear);
  508.     splitbytes-=250;
  509.  
  510.     /* Split or cut the text */
  511.     if(split_k&&linesbytes>(long)splitbytes) { 
  512.         split_num=GetNum(splitbytes); /* Compute number of messages */
  513.  
  514.         /* Set to average message size */
  515.         splitbytes=(int)(linesbytes/(long)split_num);
  516.  
  517.         for(;;) { /* And adjust size back up so no text is lost */
  518.             if(GetNum(splitbytes)<=split_num) break;
  519.             ++splitbytes;
  520.         }
  521.     }
  522.  
  523.     printf("Writing %s  01/%02u ",FancyStr(msgpath),split_num);
  524.  
  525.     for(i=0;i<split_num;i++) {
  526.         printf("\b\b\b\b\b\b%02u/%02u ",i+1,split_num);
  527.  
  528.         if(!BuildText(splitbytes)) break;
  529.  
  530.         if(msgtyp==MSGTYP_ECHO||msgtyp==MSGTYP_LOCL) {
  531.             strcat(textbuf,tear); textcount+=(long)strlen(tear);
  532.         }
  533.  
  534.         if(i) attr&=~MSGFILE; /* Kill file attaches on 2nd, 3rd, etc */
  535.         BuildHdr(&xmsg,i+1,split_num);
  536.  
  537.         msg=MsgOpenMsg(ap,MOPEN_CREATE,0L); /* Create new message */
  538.         BuildCtrl(ctrl,&ctrllen,i+1,split_num);
  539.         MsgWriteMsg(msg,FALSE,&xmsg,NULL,0L,textcount,ctrllen,(byte *)ctrl);
  540.         MsgWriteMsg(msg,TRUE,NULL,(byte *)textbuf,textcount,textcount,0L,NULL);
  541.         MsgCloseMsg(msg);
  542.     }
  543.  
  544.     printf("\n");
  545. }
  546.  
  547.  
  548. /*
  549. ** GetNum ()
  550. ** Compute how many split messages to generate
  551. */
  552.  
  553. static int  GetNum (int splitbytes)
  554. {
  555.     int i, result=1;
  556.     long len=0L;
  557.  
  558.     for(i=0;i<linescount;i++) { /* Scan through the lines */
  559.         len+=(long)strlen(lines[i]);
  560.         if(len>(long)splitbytes) {
  561.             ++result;
  562.             len=(long)strlen(lines[i]);
  563.         }
  564.     }
  565.     return result;
  566. }
  567.  
  568.  
  569. /*
  570. ** BuildText ()
  571. ** Fill the text buffer from the lines array
  572. */
  573.  
  574. static int  BuildText (int limit)
  575. {
  576.     int len;
  577.     char *p;
  578.  
  579.     if(!linescount) {
  580.         *textbuf='\0'; textcount=1L;
  581.         return 1; /* Allow for blank msg */
  582.     }
  583.     if(linesidx>=linescount) return 0;
  584.  
  585.     p=textbuf; textcount=0L;
  586.  
  587.     for(;;) {
  588.         len=strlen(lines[linesidx]);
  589.         if(textcount+(long)len>limit) break;
  590.         memcpy(p,lines[linesidx],len);
  591.         p+=len; textcount+=(long)len;
  592.         if(++linesidx>=linescount) break;
  593.     }
  594.     *p='\0'; ++textcount;
  595.  
  596.     return 1;
  597. }
  598.  
  599.  
  600. /*
  601. ** SetAttr ()
  602. ** Set message attribute flags
  603. */
  604.  
  605. static void  SetAttr (char *p)
  606. {
  607.     while(*p) {
  608.         *p=tolower(*p);
  609.         switch (*p) {
  610.         case 'p': /* Private */
  611.                   attr|=MSGPRIVATE; break;
  612.         case 'c': /* Crash */
  613.                   attr|=MSGCRASH; attr&=~MSGHOLD;
  614.                   break;
  615.         case 'd': /* Direct */
  616.                   attr|=MSGXX2;
  617.                   break;
  618.         case 'f': /* File attach */
  619.                   attr|=MSGFILE; break;
  620.         case 'h': /* Hold */
  621.                   attr|=MSGHOLD; attr&=~MSGCRASH;
  622.                   break;
  623.         case 'k': /* Kill after sending */
  624.                   attr|=MSGKILL; break;
  625.         case 'r': /* File Request */
  626.                   attr|=MSGFRQ; break;
  627.         case 'u': /* File Update Request */
  628.                   attr|=MSGURQ; break;
  629.         case 'l': /* Local flag */
  630.                   attr&=~MSGLOCAL; /* Turn local flag OFF */
  631.                   break;
  632.         }
  633.         ++p;
  634.     }
  635. }
  636.  
  637.  
  638. /*
  639. ** ReadOrig ()
  640. ** Read message area origin file
  641. */
  642.  
  643. static int  ReadOrig (void)
  644. {
  645.     FILE *fp;
  646.     char *p, buf[128];
  647.  
  648.     if(*msgpath=='$') { strcpy(buf,msgpath+1); strcat(buf,".SQO"); }
  649.     else { strcpy(buf,msgpath); strcat(buf,"\\ORIGIN."); }
  650.     printf("Reading %s\n",FancyStr(buf));
  651.  
  652.     if((fp=ShFopen(buf,"r"))==NULL) return 0;
  653.     fgets(buf,128,fp);
  654.     fclose(fp);
  655.  
  656.     p=buf; while(*p==' '||*p=='\t') ++p; /* Strip leading */
  657.     if(strlen(p)>59) p[59]='\0';
  658.     StripCr(p); StrTrim(p);
  659.     strcpy(str_orig,p);
  660.     return 1;
  661. }
  662.  
  663.  
  664. /*
  665. ** BuildTear ()
  666. ** Make tear, origin, & seenby lines
  667. */
  668.  
  669. static void  BuildTear (char *s)
  670. {
  671.     char line[128];
  672.  
  673.     *s='\0';
  674.     if(msgtyp==MSGTYP_ECHO||msgtyp==MSGTYP_LOCL) {
  675.         strcpy(s,"\r--- MPost/2 v" SVERSON "\r"); /* Tear line */
  676.  
  677.         if(msgtyp==MSGTYP_ECHO) {
  678.             /* Origin line */
  679.             sprintf(line," * Origin: %s (%s)\r",str_orig,AddrToStr(&fm_addr));
  680.             strcat(s,line);
  681.  
  682.             /* Seen-by line */
  683.             if(seenbyflg) {
  684.                 if(fm_addr.point&&fakenet) { /* Use point's fakenet */
  685.                     sprintf(line,"SEEN-BY: %u/%u\r",fakenet,fm_addr.point);
  686.                 }
  687.                 else sprintf(line,"SEEN-BY: %u/%u\r",fm_addr.net,fm_addr.node);
  688.                 strcat(s,line);
  689.             }
  690.         }
  691.     }
  692. }
  693.  
  694.  
  695. /*
  696. ** BuildHdr ()
  697. ** Set message header information
  698. */
  699.  
  700. static void  BuildHdr (XMSG *x, int num, int maxnum)
  701. {
  702.     union stamp_combo combo;
  703.     struct tm *tmdate;
  704.  
  705.     memset(x,'\0',sizeof(XMSG));
  706.  
  707.     x->attr=attr; /* Set message attributes */
  708.  
  709.     /* Set source and destination addresses */
  710.     x->orig=x->dest=*((struct _netaddr *)&fm_addr);
  711.     if(msgtyp==MSGTYP_MATX) x->dest=*((struct _netaddr *)&to_addr);
  712.  
  713.     strcpy((char *)x->to,str_to); strcpy((char *)x->from,str_from);
  714.  
  715.     if(maxnum>1) {
  716.         sprintf((char *)x->subj,"[%d of %d] ",num,maxnum);
  717.         strncat((char *)x->subj,str_subj,
  718.             XMSG_SUBJ_SIZE-1-strlen((char *)x->subj));
  719.         (x->subj)[XMSG_SUBJ_SIZE-1]='\0';
  720.     }
  721.     else strcpy((char *)x->subj,str_subj);
  722.  
  723.     tmdate=localtime(&time_now);
  724.     x->date_written=x->date_arrived=(TmDate_to_DosDate(tmdate,&combo))->msg_st;
  725. }
  726.  
  727.  
  728. /*
  729. ** BuildCtrl ()
  730. ** Set message control information
  731. */
  732.  
  733. static void  BuildCtrl (char *str, int *len, int num, int maxnum)
  734. {
  735.     struct tm *t;
  736.     unsigned long time_new;
  737.     char ubuf[20], sbuf[80];
  738.     char *const Months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  739.                                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  740.  
  741.     *len=0; 
  742.     time_new=HsecTime(); if(seed<time_new) seed=time_new;
  743.  
  744.     sprintf(str,"\01MSGID: %s %08lx",AddrToStr(&fm_addr),seed);
  745.  
  746.     if(msgtyp==MSGTYP_CONF||msgtyp==MSGTYP_MATX) {
  747.         sprintf(sbuf,"\01PID: MPost/2 %s",SVERSON);
  748.         strcat(str,sbuf);
  749.     }
  750.  
  751.     /* ^ASPLIT: 30 Mar 90 11:12:34 @494/4       12345 02/03 +++++++++++ */
  752.     if(maxnum>1) {
  753.         t=localtime(&time_now);
  754.         sprintf(ubuf,"@%u/%u",fm_addr.net,fm_addr.node); ubuf[12]='\0';
  755.         sprintf(sbuf,"\01SPLIT: %02u %s %02u %02u:%02u:%02u %-12s %05u %02u/%02u +++++++++++",
  756.             t->tm_mday,Months[t->tm_mon],t->tm_year,
  757.             t->tm_hour,t->tm_min,t->tm_sec,ubuf,mn,num,maxnum);
  758.         strcat(str,sbuf);
  759.     }
  760.  
  761.     *len=strlen(str)+1; ++seed;
  762. }
  763.  
  764.  
  765. /*
  766. ** AddrToStr ()
  767. ** Build address string
  768. */
  769.  
  770. static char *  AddrToStr (NADDR *addr)
  771. {
  772.     static char str[256];
  773.     char point[20], domain[70];
  774.  
  775.     if(addr->point) sprintf(point,".%u",addr->point);
  776.     else *point='\0';
  777.     if(*(addr->domain)) sprintf(domain,"@%s",addr->domain);
  778.     else *domain='\0';
  779.  
  780.     sprintf(str,"%u:%u/%u%s%s",addr->zone,addr->net,addr->node,point,domain);
  781.     return str;
  782. }
  783.  
  784.  
  785. /*
  786. ** HsecTime ()
  787. ** Get system date/time in hsec's
  788. */
  789.  
  790. static unsigned long  HsecTime (void)
  791. {
  792.     unsigned long i;
  793.     DATETIME dt;
  794.     APIRET rc;
  795.  
  796.     rc = DosGetDateTime(&dt);
  797.     i=((dt.day+(((unsigned)dt.month*3057-3007)/100))*144000L) +
  798.     (dt.hours*360000L) +                             /* hours today: hsec    */
  799.     (dt.minutes*6000L) +                             /* minutes: hsec        */
  800.     (dt.seconds*100L) +                              /* seconds: hsec        */
  801.     dt.hundredths;                                   /* hundreds of seconds  */
  802.  
  803.     return i;
  804. }
  805.  
  806.  
  807. /*
  808. ** GetAddr ()
  809. ** Get command line system address
  810. */
  811.  
  812. static void  GetAddr (char *str, NADDR *addr)
  813. {
  814.     char *p;
  815.  
  816.     /* Zone */
  817.     if((p=strchr(str,':'))!=NULL) {
  818.         addr->zone=(unsigned int)atol(str); str=p+1;
  819.     }
  820.     else addr->zone=sy_addr.zone;
  821.  
  822.     /* Net */
  823.     if((p=strchr(str,'/'))!=NULL) {
  824.         addr->net=(unsigned int)atol(str); str=p+1;
  825.     }
  826.     else addr->net=sy_addr.net;
  827.  
  828.     /* Node */
  829.     addr->node=(unsigned int)atol(str);
  830.  
  831.     /* Point */
  832.     if((p=strchr(str,'.'))!=NULL) {
  833.         str=p+1; addr->point=(unsigned int)atol(str);
  834.     }
  835.     else addr->point=0;
  836.  
  837.     /* Domain */
  838.     if((p=strchr(str,'@'))!=NULL) {
  839.         str=p+1; strcpy(addr->domain,str);
  840.     }
  841.     else *(addr->domain)='\0';
  842. }
  843.  
  844.  
  845. /*
  846. ** AddSlash (char *str)
  847. ** Add trailing back slash
  848. */
  849.  
  850. static void  AddSlash (char *str)
  851. {
  852.     char *p;
  853.  
  854.     p=str; while(*p) ++p;
  855.     if(p!=str) { p--; if(*p!='\\') strcat(str,"\\"); }
  856. }
  857.  
  858.  
  859. /*
  860. ** StripSlash ()
  861. ** Strip trailing back slash
  862. */
  863.  
  864. static void  StripSlash (char *str)
  865. {
  866.     int i;
  867.  
  868.     for(i=strlen(str)-1;(str[i]=='\\')&&i>=0;i--) ;
  869.     str[i+1]='\0';
  870. }
  871.  
  872.  
  873. /*
  874. ** StripCr ()
  875. ** Strip trailing cr/lf
  876. */
  877.  
  878. static void  StripCr (char *str)
  879. {
  880.     int i;
  881.  
  882.     for(i=strlen(str)-1;(str[i]=='\r'||str[i]=='\n')&&i>=0;i--) ;
  883.     str[i+1]='\0';
  884. }
  885.  
  886.  
  887. /*
  888. ** StrTrim ()
  889. ** Strip trailing white space
  890. */
  891.  
  892. static void  StrTrim (char *str)
  893. {
  894.     int i;
  895.  
  896.     for(i=strlen(str)-1;IsSpace(str[i])&&i>=0;i--) ;
  897.     str[i+1]='\0';
  898. }
  899.  
  900.  
  901. /*
  902. ** StrBlank ()
  903. ** Is string blank?
  904. */
  905.  
  906. static int  StrBlank (char *str)
  907. {
  908.     for(;*str;str++) {
  909.         if(!IsSpace(*str)) return 0;
  910.     }
  911.     return 1;
  912. }
  913.  
  914.  
  915. /*
  916. ** CvtUs ()
  917. ** Convert underscore characters to spaces
  918. */
  919.  
  920. static void  CvtUs (char *s)
  921. {
  922.     while(*s) { if(*s=='_') *s=' '; ++s; }
  923. }
  924.  
  925.  
  926. /*
  927. ** IsSpace ()
  928. ** If the character is whitespace
  929. */
  930.  
  931. static int  IsSpace (char c)
  932. {
  933.     if(c==' '||c=='\t') return 1;
  934.     return 0;
  935. }
  936.  
  937.  
  938. /*
  939. ** FancyStr ()
  940. ** Make It Look Like This
  941. */
  942.  
  943. static char *  FancyStr (char *string)
  944. {
  945.     int flag=0;
  946.     char *s;
  947.  
  948.     s=string;
  949.     while(*string) {
  950.         if(isalpha(*string)) {                  /* If alphabetic,     */
  951.             if(flag) *string=tolower(*string);  /* already saw one?   */
  952.             else {
  953.                 flag = 1;                       /* first one, flag it */
  954.                 *string=toupper(*string);       /* Uppercase it       */
  955.             }
  956.         }
  957.         else flag=0;                            /* reset alpha flag   */
  958.         ++string;
  959.     }
  960.     return s;
  961. }
  962.  
  963.  
  964. /*
  965. ** MakeExePath ()
  966. ** Get executable path
  967. */
  968.  
  969. static void  MakeExePath (char *pth)
  970. {
  971.     char drive[_MAX_DRIVE], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
  972.  
  973.     _splitpath(pth,drive,dir,name,ext);
  974.     strcpy(exepath,drive); strcat(exepath,dir);
  975.     AddSlash(exepath);
  976. }
  977.  
  978.  
  979. /*
  980. ** ShFopen ()
  981. ** Share aware fopen function using SH_DENYNONE attribute
  982. */
  983.  
  984. static FILE *  ShFopen (char *name, char *fpmode)
  985. {
  986.     FILE *fp;           /* Temporary stram pointer */
  987.     int fd;             /* Temporary file handle   */
  988.     unsigned access=0;  /* Required access         */
  989.     unsigned mode=0;    /* Required access mode    */
  990.     char *fpm=fpmode;
  991.     char c;
  992.  
  993.     /* Check first mode character */
  994.     if((c=*fpmode++) == 'r') { access=O_RDONLY; }
  995.     else if(c=='w') { access=O_CREAT|O_WRONLY|O_TRUNC; mode=S_IWRITE; }
  996.     else if(c=='a') { access=O_WRONLY|O_CREAT|O_APPEND; mode=S_IWRITE; }
  997.     else return NULL;
  998.  
  999.     /* Check for '+' read/write */
  1000.     c=*fpmode++;
  1001.     if(c=='+'||(*fpmode=='+'&&c=='b')) {
  1002.         if(c=='+') c=*fpmode;
  1003.         /* Same modes, but both read and write */
  1004.         access=(access&~(O_WRONLY|O_RDONLY))|O_RDWR;
  1005.         mode=S_IREAD|S_IWRITE;
  1006.     }
  1007.  
  1008.     /* Set text or binary access */
  1009.     if('b'==c) { access|=O_BINARY; }
  1010.     else { access|=O_TEXT; }
  1011.  
  1012.     /* Open the file */
  1013.     if((fd=sopen(name,access,SH_DENYNONE,mode))==-1) return NULL;
  1014.  
  1015.     /* Open the stream */
  1016.     if((fp=fdopen(fd,fpm))==NULL) close(fd);
  1017.  
  1018.     return fp; /* Return the stream pointer */
  1019. }
  1020.  
  1021.  
  1022. /*
  1023. ** SetUp ()
  1024. ** Initial program setup
  1025. */
  1026.  
  1027. static void  SetUp (int argc, char *argv[])
  1028. {
  1029.     int i;
  1030.     int textflg=0;
  1031.     char *p;
  1032.  
  1033.     if(argc<2) Usage();
  1034.     MakeExePath(argv[0]);
  1035.  
  1036.     *str_orig=*msgpath=*txtpath='\0';
  1037.     sprintf(cfgpath,"%sMPost.Cfg",exepath);
  1038.     sprintf(lstpath,"%sMPost.Lst",exepath);
  1039.     strcpy(str_to,"All");
  1040.     strcpy(str_from,"MPost/2 " SVERSON);
  1041.     strcpy(str_subj,"Automated Posting");
  1042.  
  1043.     /* Get initial command line */
  1044.     for(i=1;i<argc;i++) {
  1045.         p=argv[i];
  1046.         if(*p=='-'||*p=='/') {
  1047.             switch(tolower(*(++p))) {
  1048.                 case 't': strcpy(txtpath,++p);
  1049.                           ++textflg;
  1050.                           break;
  1051.                 case 'c': strcpy(cfgpath,++p);
  1052.                           break;
  1053.                 case 'k': killtxtflg=1;
  1054.                           break;
  1055.                 case '@': listflg=1; if(*++p) strcpy(lstpath,p);
  1056.                           break;
  1057.                 case 'm': /* Process these commands later */
  1058.                 case 'n':
  1059.                 case 'p':
  1060.                 case 'f':
  1061.                 case 'l':
  1062.                 case 'j':
  1063.                 case 'w':
  1064.                 case 'o':
  1065.                 case 's': break;
  1066.                 case '?':
  1067.                 default : Usage();
  1068.             }
  1069.         }
  1070.         else Usage();
  1071.     }
  1072.  
  1073.     if(!textflg) {
  1074.         printf("\n%cERROR: No text file supplied!\n\n",0x07);
  1075.         Quit(3);
  1076.     }
  1077.  
  1078.     /* Get the text storage */
  1079.     if((textbuf=malloc(MAX_BLOCK+1024))==NULL) {
  1080.         printf("\n%cERROR: Out of memory!\n\n",0x07);
  1081.         Quit(2);
  1082.     }
  1083.     memset(textbuf,'\0',MAX_BLOCK+1024);
  1084. }
  1085.  
  1086.  
  1087. /*
  1088. ** GetCmdLine ()
  1089. ** Get command line parameters
  1090. */
  1091.  
  1092. static void  GetCmdLine (int argc, char *argv[])
  1093. {
  1094.     int i, gotsubj=0;
  1095.     char *p, s[60], f[XMSG_TO_SIZE], l[XMSG_TO_SIZE];
  1096.  
  1097.     *f=*l='\0'; /* Clear the name buffers */
  1098.     for(i=1;i<argc;i++) {
  1099.         p=argv[i];
  1100.         if(*p=='-'||*p=='/') {
  1101.             switch(tolower(*(++p))) {
  1102.                 case 'm': strcpy(msgpath,++p); StripSlash(msgpath);
  1103.                           break;
  1104.                 case 'n': strcpy(s,++p); GetAddr(s,&to_addr);
  1105.                           msgtyp=MSGTYP_MATX;
  1106.                           break;
  1107.                 case 'p': attr=MSGLOCAL; SetAttr(++p);
  1108.                           break;
  1109.                 case 'f': strncpy(f,++p,XMSG_TO_SIZE-1);
  1110.                           f[XMSG_TO_SIZE-1]='\0';
  1111.                           CvtUs(f);
  1112.                           break;
  1113.                 case 'l': strncpy(l,++p,XMSG_TO_SIZE-1);
  1114.                           l[XMSG_TO_SIZE-1]='\0';
  1115.                           CvtUs(l);
  1116.                           break;
  1117.                 case 'j': strncpy(str_subj,++p,XMSG_SUBJ_SIZE-1);
  1118.                           str_subj[XMSG_SUBJ_SIZE-1]='\0';
  1119.                           ++gotsubj;
  1120.                           break;
  1121.                 case 'w': strncpy(str_from,++p,XMSG_FROM_SIZE-1);
  1122.                           str_from[XMSG_FROM_SIZE-1]='\0';
  1123.                           CvtUs(str_from);
  1124.                           break;
  1125.                 case 'o': strcpy(s,++p); GetAddr(s,&fm_addr);
  1126.                           if(sy_addr.net==0&&sy_addr.node==0) {
  1127.                               /* Set system address to message from address */
  1128.                               sy_addr=fm_addr; 
  1129.                           }
  1130.                           ++addrflg;
  1131.                           break;
  1132.                 case 's': split_k=atoi(++p);
  1133.                           if(split_k<0||split_k>16) split_k=12;
  1134.                           break;
  1135.             }
  1136.         }
  1137.     }
  1138.  
  1139.     if(gotsubj) {
  1140.         if( (!(attr&MSGFILE)) &&
  1141.             (!(attr&MSGFRQ)) &&
  1142.             (!(attr&MSGURQ))
  1143.         ) CvtUs(str_subj);
  1144.     }
  1145.  
  1146.     if(*f||*l) { /* Load command line name override */
  1147.         strncpy(str_to,f,XMSG_TO_SIZE-1);
  1148.         str_to[XMSG_TO_SIZE-1]='\0';
  1149.         if(*l&&strcmp(l,"NLN")) { /* Use last name if exist & is valid */
  1150.             i=XMSG_TO_SIZE-1-strlen(f);
  1151.             strncat(str_to," ",i); strncat(str_to,l,i-1);
  1152.             str_to[XMSG_TO_SIZE-1]='\0';
  1153.         }
  1154.     }
  1155. }
  1156.  
  1157.  
  1158. /*
  1159. ** Usage ()
  1160. ** Syntax command line display and exit
  1161. */
  1162.  
  1163. static void  Usage (void)
  1164. {
  1165.    puts("    Syntax:  MPostP [-switch -switch ... ]\n\n"
  1166.         "\t                   COMMAND LINE ONLY\n"
  1167.         "\t     -T<name>      Text source file path & name\n"
  1168.         "\t     -K            Kill text file after processing\n"
  1169.         "\t     -C<name>      Configuration file path & name\n"
  1170.         "\t     -@<name>      Names list file mode\n"
  1171.         "\t     -?            Program help screen\n\n"
  1172.         "\t                   CONFIGURATION OVERRIDES\n"
  1173.         "\t     -M<name>      Message area path & name\n"
  1174.         "\t     -N<addr>      Netmail format - send to address\n"
  1175.         "\t     -O<addr>      Message origin address\n"
  1176.         "\t     -P<cfhdkprul> Message priority flag(s)\n"
  1177.         "\t     -F<fname>     Message addressed to first name\n"
  1178.         "\t     -L<lname>     Message addressed to last name\n"
  1179.         "\t     -W<name>      Message addressed from name\n"
  1180.         "\t     -J<subj>      Message subject (NO spaces)\n"
  1181.         "\t     -S<##>        Split long messages to ## Kb size (0-16)"
  1182.     );
  1183.  
  1184.     Quit(1);
  1185. }
  1186.  
  1187.