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