home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / SQDEV200.ZIP / SRC / API_SDM.C < prev    next >
C/C++ Source or Header  |  1994-05-23  |  28KB  |  1,214 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *  Squish Developers Kit Source, Version 2.00                             *
  4.  *  Copyright 1989-1994 by SCI Communications.  All rights reserved.       *
  5.  *                                                                         *
  6.  *  USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE       *
  7.  *  SQUISH DEVELOPERS KIT LICENSING AGREEMENT IN SQDEV.PRN.  IF YOU DO NOT *
  8.  *  FIND THE TEXT OF THIS AGREEMENT IN THE AFOREMENTIONED FILE, OR IF YOU  *
  9.  *  DO NOT HAVE THIS FILE, YOU SHOULD IMMEDIATELY CONTACT THE AUTHOR AT    *
  10.  *  ONE OF THE ADDRESSES LISTED BELOW.  IN NO EVENT SHOULD YOU PROCEED TO  *
  11.  *  USE THIS FILE WITHOUT HAVING ACCEPTED THE TERMS OF THE SQUISH          *
  12.  *  DEVELOPERS KIT LICENSING AGREEMENT, OR SUCH OTHER AGREEMENT AS YOU ARE *
  13.  *  ABLE TO REACH WITH THE AUTHOR.                                         *
  14.  *                                                                         *
  15.  *  You can contact the author at one of the address listed below:         *
  16.  *                                                                         *
  17.  *  Scott Dudley       FidoNet     1:249/106                               *
  18.  *  777 Downing St.    Internet    sjd@f106.n249.z1.fidonet.org            *
  19.  *  Kingston, Ont.     CompuServe  >INTERNET:sjd@f106.n249.z1.fidonet.org  *
  20.  *  Canada  K7M 5N3    BBS         1-613-634-3058, V.32bis                 *
  21.  *                                                                         *
  22.  ***************************************************************************/
  23.  
  24. #pragma off(unreferenced)
  25. static char rcs_id[]="$Id: API_SDM.C 1.2 1993/12/30 00:46:52 sjd Exp $";
  26. #pragma on(unreferenced)
  27.  
  28. #define MSGAPI_HANDLERS
  29. #define MSGAPI_NO_OLD_TYPES
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <io.h>
  36. #include <fcntl.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <share.h>
  40. #include "prog.h"
  41. #include "dr.h"
  42. #include "alc.h"
  43. #include "max.h"
  44. #include "old_msg.h"
  45. #include "msgapi.h"
  46. #include "api_sdm.h"
  47. #include "api_sdmp.h"
  48. #include "apidebug.h"
  49.  
  50. #define SDM_BLOCK 256
  51. #define Mhd ((struct _sdmdata *)(mh->apidata))
  52. #define MsghMhd ((struct _sdmdata *)(((HMSG)msgh)->ha->apidata))
  53.  
  54.  
  55. static byte *hwm_from="-=| SquishMail |=-";
  56.  
  57.  
  58. extern void far pascal DosSleep(dword);
  59.  
  60. HAREA MSGAPI SdmOpenArea(byte OS2FAR *name, word mode, word type)
  61. {
  62.   HAREA mh;
  63. #ifdef __TURBOC__
  64.   NW(_junksqd); /* to shut up tc */
  65. #endif
  66.   if ((mh=palloc(sizeof(*mh)))==NULL)
  67.   {
  68.     msgapierr=MERR_NOMEM;
  69.     goto ErrOpen;
  70.   }
  71.  
  72.   (void)memset(mh, '\0', sizeof(*mh));
  73.  
  74.   mh->id=MSGAPI_ID;
  75.  
  76.   if (type & MSGTYPE_ECHO)
  77.     mh->isecho=TRUE;
  78.  
  79.   if ((mh->api=(struct _apifuncs *)palloc(sizeof(struct _apifuncs)))==NULL)
  80.   {
  81.     msgapierr=MERR_NOMEM;
  82.     goto ErrOpen;
  83.   }
  84.  
  85.   (void)memset(mh->api, '\0', sizeof(struct _apifuncs));
  86.  
  87.   if ((mh->apidata=(void *)palloc(sizeof(struct _sdmdata)))==NULL)
  88.   {
  89.     msgapierr=MERR_NOMEM;
  90.     goto ErrOpen;
  91.   }
  92.  
  93.   (void)memset((byte *)mh->apidata, '\0', sizeof(struct _sdmdata));
  94.   
  95.   (void)strcpy(Mhd->base,name);
  96.   (void)Add_Trailing(Mhd->base, '\\');
  97.   Mhd->hwm=(dword)-1L;
  98.   
  99.   mh->len=sizeof(*mh);
  100.   mh->num_msg=0;
  101.   mh->high_msg=0;
  102.   mh->high_water=(dword)-1L;
  103.  
  104.  
  105.   if (! direxist(name) && (mode==MSGAREA_NORMAL || mkdir(name)==-1))
  106.   {
  107.     msgapierr=MERR_NOENT;
  108.     goto ErrOpen;
  109.   }
  110.  
  111.   if (! _SdmRescanArea(mh))
  112.     goto ErrOpen;
  113.  
  114.   mh->type &= ~MSGTYPE_ECHO;
  115.  
  116.   *mh->api=sdm_funcs;
  117.   mh->sz_xmsg=sizeof(XMSG);
  118.  
  119.   msgapierr=0;
  120.   return mh;
  121.  
  122. ErrOpen:
  123.  
  124.   if (mh)
  125.   {
  126.     if (mh->api)
  127.     {
  128.       if (mh->apidata)
  129.         pfree((char *)mh->apidata);
  130.  
  131.       pfree(mh->api);
  132.     }
  133.  
  134.     pfree(mh);
  135.   }
  136.  
  137.   return NULL;
  138. }
  139.  
  140.  
  141.  
  142. static sword MAPIENTRY SdmCloseArea(HAREA mh)
  143. {
  144.   static byte *msgbody="NOECHO\r\rPlease ignore.  This message is only used "
  145.                        "by the SquishMail system to store\r"
  146.                        "the high water mark for each conference area.\r\r"
  147.                        "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"
  148.                        "(Elvis was here!)\r\r\r";
  149.   XMSG msg;
  150.   HMSG msgh;
  151.   
  152.  
  153.   
  154.   if (InvalidMh(mh))
  155.     return -1;
  156.   
  157.   if (Mhd->hwm_chgd)
  158.     if ((msgh=SdmOpenMsg(mh, MOPEN_CREATE, 1L)) != NULL)
  159.     {
  160.       Init_Xmsg(&msg);
  161.  
  162.       (void)Get_Dos_Date((union stamp_combo *)&msg.date_arrived);
  163.       (void)Get_Dos_Date((union stamp_combo *)&msg.date_written);
  164.       
  165.       /* Use high-bit chars in the to/from field, so that (l)users          *
  166.        * can't log on as this userid and delete the HWM.                    */
  167.  
  168.       (void)strcpy(msg.from, hwm_from);
  169.       (void)strcpy(msg.to, msg.from);
  170.       (void)strcpy(msg.subj, "High wadda' mark");
  171.  
  172.       /* To prevent "intl 0:0/0 0:0/0" kludges */
  173.       msg.orig.zone=msg.dest.zone=mi.def_zone;
  174.  
  175.       msg.replyto=mh->high_water;
  176.       msg.attr=MSGPRIVATE | MSGREAD | MSGLOCAL | MSGSENT;
  177.       
  178.       (void)SdmWriteMsg(msgh, FALSE, &msg, msgbody, strlen(msgbody)+1,
  179.                         strlen(msgbody)+1, 0L, NULL);
  180.                     
  181.       (void)SdmCloseMsg(msgh);
  182.     }
  183.  
  184.   if (Mhd->msgs_open)
  185.   {
  186.     msgapierr=MERR_EOPEN;
  187.     return -1;
  188.   }
  189.  
  190.   if (Mhd->msgnum)
  191.     pfree(Mhd->msgnum);
  192.  
  193.   pfree((char *)mh->apidata);
  194.   pfree(mh->api);
  195.  
  196.   mh->id=0L;
  197.   pfree(mh);
  198.  
  199.   msgapierr=MERR_NONE;
  200.   return 0;
  201. }
  202.  
  203.  
  204. static UMSGID MAPIENTRY SdmGetNextUid(HAREA ha)
  205. {
  206.   if (InvalidMh(ha))
  207.     return 0L;
  208.  
  209.   if (!ha->locked)
  210.   {
  211.     msgapierr=MERR_NOLOCK;
  212.     return 0L;
  213.   }
  214.  
  215.   return ha->high_msg+1;
  216. }
  217.  
  218.  
  219. static HMSG  MAPIENTRY SdmOpenMsg(HAREA mh, word mode, dword msgnum)
  220. {
  221.   extern char _stdc _nopen_cheat;
  222.   byte msgname[PATHLEN];
  223.  
  224.   int handle;
  225.   int filemode;
  226.   unsigned mn, owrite=FALSE;
  227.  
  228.   HMSG msgh;
  229.  
  230.  
  231.   if (InvalidMh(mh))
  232.     return NULL;
  233.   
  234.   if (msgnum==MSGNUM_CUR)
  235.     msgnum=mh->cur_msg;
  236.   else if (msgnum==MSGNUM_PREV)
  237.   {
  238.     for (mn=(unsigned)mh->num_msg-1; (int)mn < (int)mh->high_msg; mn--)
  239.       if (Mhd->msgnum[mn] < (unsigned)mh->cur_msg)
  240.       {
  241.         msgnum=mh->cur_msg=(dword)Mhd->msgnum[mn];
  242.         break;
  243.       }
  244.  
  245.     /* If mn==-1, no message to go to */
  246.  
  247.     if (mn==(unsigned)-1)
  248.     {
  249.       msgapierr=MERR_NOENT;
  250.       return NULL;
  251.     }
  252.   }
  253.   else if (msgnum==MSGNUM_NEXT)
  254.   {
  255.     for (mn=0; mn < (unsigned)mh->num_msg; mn++)
  256.       if (Mhd->msgnum[mn] > (unsigned)mh->cur_msg)
  257.       {
  258.         msgnum=mh->cur_msg=(dword)Mhd->msgnum[mn];
  259.         break;
  260.       }
  261.  
  262.     /* If mn==Mhd->msgnum_len, we can't go to any message */
  263.  
  264.     if (mn==(unsigned)mh->num_msg)
  265.     {
  266.       msgapierr=MERR_NOENT;
  267.       return NULL;
  268.     }
  269.   }
  270.   else if (mode != MOPEN_CREATE)
  271.   {
  272.     /* If we're not creating, make sure that the specified msg# can         *
  273.      * be found.                                                            */
  274.  
  275.     for (mn=0; mn < (unsigned)mh->num_msg; mn++)
  276.       if (msgnum==Mhd->msgnum[mn])
  277.         break;
  278.  
  279.     if (mn==(unsigned)mh->num_msg)
  280.     {
  281.       msgapierr=MERR_NOENT;
  282.       return NULL;
  283.     }
  284.   }
  285.  
  286.  
  287.   if (mode==MOPEN_CREATE)
  288.   {
  289.     /* If we're creating a new message... */
  290.  
  291.     if (msgnum==0L)
  292.     {
  293.       /* If the base isn't locked, make sure that we avoid conflicts... */
  294.  
  295.       if (! mh->locked)
  296.       {
  297.         /* Check to see if the msg we're writing already exists */
  298.  
  299.         (void)sprintf(msgname, sd_msg, Mhd->base, (int)mh->high_msg+1);
  300.  
  301.         if (fexist(msgname))
  302.         {
  303.           /* If so, rescan the base, to find out which msg# it is. */
  304.  
  305.           if (Mhd->msgnum && Mhd->msgnum_len)
  306.             pfree(Mhd->msgnum);
  307.  
  308.           if (!_SdmRescanArea(mh))
  309.             return NULL;
  310.         }
  311.       }
  312.  
  313.       msgnum=++mh->high_msg;
  314.       
  315.       /* Make sure that we don't overwrite the high-water mark, unless      *
  316.        * we call with msgnum != 0L (a specific number).                     */
  317.          
  318.       if (mh->isecho && msgnum==1)
  319.         msgnum=mh->high_msg=2;
  320.     }
  321.     else
  322.     {
  323.       /* Otherwise, we're overwriting an existing msg */
  324.  
  325.       owrite=TRUE;
  326.     }
  327.  
  328.     filemode=O_CREAT | O_TRUNC | O_RDWR;
  329.   }
  330.   else if (mode==MOPEN_READ)
  331.     filemode=O_RDONLY;
  332.   else if (mode==MOPEN_WRITE)
  333.     filemode=O_WRONLY;
  334.   else filemode=O_RDWR;
  335.  
  336.   (void)sprintf(msgname, sd_msg, Mhd->base, (unsigned)msgnum);
  337.  
  338.   _nopen_cheat=TRUE;  /* Use fast "cheat" mode for creating msgs */
  339.  
  340.   if ((handle=sopen(msgname, filemode | O_BINARY | O_NOINHERIT, SH_DENYNONE,
  341.                     S_IREAD | S_IWRITE))==-1)
  342.   {
  343.     if (filemode & O_CREAT)
  344.       msgapierr=MERR_BADF;
  345.     else msgapierr=MERR_NOENT;
  346.     
  347.     _nopen_cheat=FALSE;
  348.     return NULL;
  349.   }
  350.  
  351.   _nopen_cheat=FALSE;
  352.  
  353.   mh->cur_msg=msgnum;
  354.  
  355.   if ((msgh=palloc(sizeof(*msgh)))==NULL)
  356.   {
  357.     (void)close(handle);
  358.     msgapierr=MERR_NOMEM;
  359.     return NULL;
  360.   }
  361.  
  362.   (void)memset(msgh, '\0', sizeof(*msgh));
  363.   msgh->fd=handle;
  364.  
  365.   if (mode==MOPEN_CREATE)
  366.   {
  367.     if (mh->num_msg+1 >= Mhd->msgnum_len)
  368.     {
  369.       Mhd->msgnum=repalloc(Mhd->msgnum,
  370.                            (Mhd->msgnum_len += SDM_BLOCK)*sizeof(unsigned));
  371.  
  372.       if (!Mhd->msgnum)
  373.       {
  374.         pfree(msgh);
  375.         (void)close(handle);
  376.         msgapierr=MERR_NOMEM;
  377.         return NULL;
  378.       }
  379.     }
  380.  
  381.     /* If we're writing a new msg, this is easy -- just add to end of list */
  382.  
  383.     if (!owrite /*msgnum==mh->high_msg || mh->num_msg==0*/)
  384.       Mhd->msgnum[(size_t)(mh->num_msg++)]=(unsigned)msgnum;
  385.     else
  386.     {
  387.       for (mn=0; mn < (unsigned)mh->num_msg; mn++)
  388.         if (Mhd->msgnum[mn] >= (unsigned)msgnum)
  389.           break;
  390.  
  391.       /* If this message is already in the list then do nothing -- simply   *
  392.        * overwrite it, keeping the same message number, so no action is     *
  393.        * required.                                                          */
  394.  
  395.       if (Mhd->msgnum[mn]==(unsigned)msgnum)
  396.         ;
  397.       else
  398.       {
  399.         /* Otherwise, we have to shift everything up by one since we're     *
  400.          * adding this new message inbetween two others.                    */
  401.  
  402.         (void)memmove(Mhd->msgnum+mn+1,
  403.                       Mhd->msgnum+mn,
  404.                       (size_t)((int)mh->num_msg-(int)mn) * sizeof(unsigned));
  405.               
  406.         Mhd->msgnum[mn]=(unsigned)msgnum;
  407.         mh->num_msg++;
  408.       }
  409.     }
  410.   }
  411.   
  412.   msgh->cur_pos=0L;
  413.   
  414.   if (mode==MOPEN_CREATE)
  415.     msgh->msg_len=0;
  416.   else msgh->msg_len=(dword)-1;
  417.   
  418.   msgh->ha=mh;
  419.   msgh->id=MSGH_ID;
  420.   msgh->ctrl=NULL;
  421.   msgh->clen=-1;
  422.   msgh->zplen=0;
  423.  
  424.   msgapierr=MERR_NONE;
  425.   
  426.   /* Keep track of how many messages were opened for this area */
  427.  
  428.   MsghMhd->msgs_open++;
  429.   
  430.   return msgh;
  431. }
  432.  
  433.  
  434.  
  435.  
  436.  
  437. static sword MAPIENTRY SdmCloseMsg(HMSG msgh)
  438. {
  439.   if (InvalidMsgh(msgh))
  440.     return -1;
  441.   
  442.   MsghMhd->msgs_open--;
  443.   
  444.   if (msgh->ctrl)
  445.   {
  446.     pfree(msgh->ctrl);
  447.     msgh->ctrl=NULL;
  448.   }
  449.   
  450.   (void)close(msgh->fd);
  451.   
  452.   msgh->id=0L;
  453.   pfree(msgh);
  454.   
  455.   msgapierr=MERR_NONE;
  456.   return 0;
  457. }
  458.  
  459.  
  460.  
  461.  
  462. static dword MAPIENTRY SdmReadMsg(HMSG msgh, PXMSG msg, dword offset, dword bytes, byte *text, dword clen, byte *ctxt)
  463. {
  464.   NETADDR *orig,
  465.           *dest;
  466.  
  467.   byte *fake_msgbuf=NULL;
  468.   byte *newtext;
  469.  
  470.   unsigned len;
  471.   struct _omsg fmsg;
  472.   dword realbytes;
  473.   unsigned need_ctrl;
  474.   int got;
  475.   
  476.   if (InvalidMsgh(msgh))
  477.     return (dword)-1L;
  478.   
  479.   if (! (clen && ctxt))
  480.   {
  481.     clen=0L;
  482.     ctxt=NULL;
  483.   }
  484.   
  485.   if (! (text && bytes))
  486.   {
  487.     bytes=0L;
  488.     text=NULL;
  489.   }
  490.  
  491.   orig=&msg->orig;
  492.   dest=&msg->dest;
  493.  
  494.   if (msg)
  495.   {
  496.     (void)lseek(msgh->fd, 0L, SEEK_SET);
  497.  
  498.     if (farread(msgh->fd, (char *)&fmsg,
  499.              sizeof(struct _omsg)) != (int)sizeof(struct _omsg))
  500.     {
  501.       msgapierr=MERR_BADF;
  502.       return (dword)-1L;
  503.     }
  504.  
  505.     fmsg.to[sizeof(fmsg.to)-1]='\0';
  506.     fmsg.from[sizeof(fmsg.from)-1]='\0';
  507.     fmsg.subj[sizeof(fmsg.subj)-1]='\0';
  508.     fmsg.date[sizeof(fmsg.date)-1]='\0';
  509.  
  510.     Convert_Fmsg_To_Xmsg(&fmsg, msg, mi.def_zone);
  511.  
  512.     (void)StripNasties(msg->from);
  513.     (void)StripNasties(msg->to);
  514.     (void)StripNasties(msg->subj);
  515.   }
  516.  
  517.  
  518.   /* If we weren't instructed to read some message text (ie. only the     *
  519.    * header, read a block anyway.  We need to scan for kludge lines,      *
  520.    * to pick out the appropriate zone/point info.)                        */
  521.  
  522.   if (msgh->ctrl==NULL && ((msg || ctxt || text) || !(msg || ctxt || text)))
  523.     need_ctrl=TRUE;
  524.   else need_ctrl=FALSE;
  525.   
  526.   realbytes=bytes;
  527.   NW(realbytes);
  528.  
  529.  
  530.   /* If we need to read the control information, and the user hasn't      *
  531.    * requested a read operation, we'll need to do one anyway.             */
  532.      
  533.   if (need_ctrl && (text==NULL || bytes < MAX_SDM_CLEN))
  534.   {
  535.     if ((text=fake_msgbuf=palloc(MAX_SDM_CLEN+1))==NULL)
  536.     {
  537.       msgapierr=MERR_NOMEM;
  538.       return (dword)-1;
  539.     }
  540.  
  541.     text[MAX_SDM_CLEN]='\0';
  542.     bytes=MAX_SDM_CLEN;
  543.   }
  544.  
  545.  
  546.  
  547.   /* If we need to read in some text... */
  548.   
  549.   if (text)
  550.   {
  551.     /* Seek is superfluous if we just read msg header */
  552.  
  553.     if (!msg || msgh->msgtxt_start != 0)
  554.     {
  555.       (void)lseek(msgh->fd, (long)sizeof(struct _omsg) +
  556.                     (long)msgh->msgtxt_start + (long)offset,
  557.                   SEEK_SET);
  558.  
  559.       msgh->cur_pos=offset;
  560.     }
  561.  
  562.     got=farread(msgh->fd, text, (unsigned)bytes);
  563.     
  564.     /* Update counter only if we got some text, and only if we're doing     *
  565.      * a read requested by the user (as opposed to reading ahead to find    *
  566.      * kludge lines).                                                       */
  567.  
  568.     if (got > 0 && !fake_msgbuf)
  569.       msgh->cur_pos += (unsigned)got;
  570.   }
  571.   else got=0;
  572.  
  573.  
  574.   /* Convert the kludges into 'ctxt' format */
  575.   
  576.   if (need_ctrl && got > 0 && offset==0L)
  577.   {
  578.     len=(unsigned)got;
  579.     
  580.     if ((msgh->ctrl=CopyToControlBuf(text, &newtext, &len)) != NULL)
  581.     {
  582.       msgh->clen=(sdword)strlen(msgh->ctrl)+1;
  583.       msgh->msgtxt_start=(dword)(newtext-text);
  584.  
  585.       /* Shift back the text buffer to counter absence of ^a strings */
  586.  
  587.       (void)memmove(text,newtext, (size_t)(bytes-(dword)(newtext-text)));
  588.  
  589.       got -= (int)(msgh->clen-1u);
  590.     }
  591.   }
  592.   
  593.  
  594.   /* Scan the ctxt ourselves to find zone/point info */
  595.  
  596.   if (msg && msgh->ctrl)
  597.     ConvertControlInfo(msgh->ctrl, orig, dest);
  598.   
  599.  
  600.   /* And if the app requested ctrlinfo, put it in its place. */
  601.       
  602.   if (ctxt && msgh->ctrl)
  603.     (void)memmove(ctxt, msgh->ctrl, min(strlen(msgh->ctrl)+1, (size_t)clen));
  604.  
  605.   if (fake_msgbuf)
  606.   {
  607.     pfree(fake_msgbuf);
  608.     got=0;
  609.   }
  610.  
  611.   msgapierr=MERR_NONE;
  612.   return (dword)got;
  613. }
  614.  
  615.  
  616.  
  617.  
  618. static sword MAPIENTRY SdmWriteMsg(HMSG msgh, word append, PXMSG msg, byte *text, dword textlen, dword totlen, dword clen, byte *ctxt)
  619. {
  620.   struct _omsg fmsg;
  621.   byte *s;
  622.   
  623.   NW(totlen);
  624.  
  625.   if (clen==0L || ctxt==NULL)
  626.   {
  627.     ctxt=NULL;
  628.     clen=0L;
  629.   }
  630.   
  631.   if (InvalidMsgh(msgh))
  632.     return -1;
  633.  
  634.   (void)lseek(msgh->fd, 0L, SEEK_SET);
  635.  
  636.   if (msg)
  637.   {
  638.     Convert_Xmsg_To_Fmsg(msg, &fmsg);
  639.     
  640.     if (farwrite(msgh->fd, (char *)&fmsg,
  641.               sizeof(struct _omsg)) != (int)sizeof(struct _omsg))
  642.     {
  643.       msgapierr=MERR_NODS;
  644.       return -1;
  645.     }
  646.  
  647.     if (!append && msgh->clen <= 0 && msgh->zplen==0)
  648.     {
  649.       statfd=msgh->fd;
  650.       msgh->zplen=(word)WriteZPInfo(msg, WriteToFd, NULL);
  651.     }
  652.   }
  653.   else if (!append || ctxt) /* Skip over old message header */
  654.   {
  655.     (void)lseek(msgh->fd, (long)sizeof(struct _omsg) + (long)msgh->zplen,
  656.                 SEEK_SET);
  657.   }
  658.  
  659.   /* Now write the control info / kludges */
  660.  
  661.   if (clen && ctxt)
  662.   {
  663.  
  664.     if (!msg)
  665.       (void)lseek(msgh->fd,
  666.                   (long)sizeof(struct _omsg) + (long)msgh->zplen,
  667.                   SEEK_SET);
  668.  
  669.     s=CvtCtrlToKludge(ctxt);
  670.  
  671.     if (s)
  672.     {
  673.       unsigned sl_s=(unsigned)strlen(s);
  674.       int ret;
  675.  
  676.       ret=farwrite(msgh->fd, s, sl_s);
  677.       MsgFreeCtrlToken(s);
  678.  
  679.       if (ret != (int)sl_s)
  680.       {
  681.         msgapierr=MERR_NODS;
  682.         return -1;
  683.       }
  684.     }
  685.   }
  686.  
  687.   if (append)
  688.     (void)lseek(msgh->fd, 0L, SEEK_END);
  689.  
  690.   if (text)
  691.     if (farwrite(msgh->fd, text, (unsigned)textlen) != (int)textlen)
  692.     {
  693.       msgapierr=MERR_NODS;
  694.       return -1;
  695.     }
  696.  
  697.   msgapierr=MERR_NONE;
  698.   return 0;
  699. }
  700.  
  701.  
  702.  
  703.  
  704. static sword MAPIENTRY SdmKillMsg(HAREA mh, dword msgnum)
  705. {
  706.   dword hwm;
  707.   byte temp[PATHLEN];
  708.   unsigned mn;
  709.   
  710.   if (InvalidMh(mh))
  711.     return -1;
  712.  
  713.  
  714.   /* Remove the message number from our private index */
  715.  
  716.   for (mn=0; mn < (unsigned)mh->num_msg; mn++)
  717.     if (Mhd->msgnum[mn]==(unsigned)msgnum)
  718.     {
  719.       (void)memmove(Mhd->msgnum+mn,
  720.                     Mhd->msgnum+mn+1,
  721.                     (size_t)((unsigned)mh->num_msg - mn - 1) * sizeof(unsigned));
  722.       break;
  723.     }
  724.  
  725.   /* If we couldn't find it, return an error message */
  726.  
  727.   if (mn==(unsigned)mh->num_msg)
  728.   {
  729.     msgapierr=MERR_NOENT;
  730.     return -1;
  731.   }
  732.  
  733.   (void)sprintf(temp, sd_msg, Mhd->base, (unsigned)msgnum);
  734.  
  735.   if (unlink(temp)==-1)
  736.   {
  737.     msgapierr=MERR_NOENT;
  738.     return -1;
  739.   }
  740.  
  741.   mh->num_msg--;
  742.  
  743.  
  744.   /* Adjust the high message number */
  745.  
  746.   if (msgnum==mh->high_msg)
  747.   {
  748.     if (mh->num_msg)
  749.       mh->high_msg=(dword)Mhd->msgnum[(unsigned)mh->num_msg - 1];
  750.     else mh->high_msg=0;
  751.   }
  752.  
  753.  
  754.   /* Now adjust the high-water mark, if necessary */
  755.  
  756.   hwm=SdmGetHighWater(mh);
  757.  
  758.   if (hwm != (dword)-1 && hwm > 0 && hwm == msgnum) /*SJD Fri  01-24-1992  21:38:37 */
  759.     (void)SdmSetHighWater(mh, msgnum-1);
  760.  
  761.   msgapierr=MERR_NONE;
  762.   return 0;
  763. }
  764.  
  765.  
  766.  
  767. static sword MAPIENTRY SdmLock(HAREA mh)
  768. {
  769.   if (InvalidMh(mh))
  770.     return -1;
  771.  
  772.   msgapierr=MERR_NONE;
  773.   return 0;
  774. }
  775.  
  776. static sword MAPIENTRY SdmUnlock(HAREA mh)
  777. {
  778.   if (InvalidMh(mh))
  779.     return -1;
  780.  
  781.   msgapierr=MERR_NONE;
  782.   return 0;
  783. }
  784.  
  785.  
  786.  
  787.  
  788. sword MSGAPI SdmValidate(byte OS2FAR *name)
  789. {
  790.   msgapierr=MERR_NONE;
  791.   return (direxist(name) != FALSE);
  792. }
  793.  
  794.  
  795.  
  796.  
  797. static sword MAPIENTRY SdmSetCurPos(HMSG msgh, dword pos)
  798. {
  799.   if (InvalidMsgh(msgh))
  800.     return 0;
  801.  
  802.   (void)lseek(msgh->fd, (long)(msgh->cur_pos=pos), SEEK_SET);
  803.   msgapierr=MERR_NONE;
  804.   return 0;
  805. }
  806.  
  807.  
  808.  
  809. static dword MAPIENTRY SdmGetCurPos(HMSG msgh)
  810. {
  811.   if (InvalidMsgh(msgh))
  812.     return (dword)-1L;
  813.  
  814.   msgapierr=MERR_NONE;
  815.   return msgh->cur_pos;
  816. }
  817.  
  818.  
  819.  
  820.  
  821. static UMSGID MAPIENTRY SdmMsgnToUid(HAREA mh, dword msgnum)
  822. {
  823.   if (InvalidMh(mh))
  824.     return (UMSGID)-1;
  825.  
  826.   msgapierr=MERR_NONE;
  827.   return (UMSGID)msgnum;
  828. }
  829.  
  830.  
  831.  
  832. static dword MAPIENTRY SdmUidToMsgn(HAREA mh, UMSGID umsgid, word type)
  833. {
  834.   unsigned wmsgid, mn;
  835.   
  836.   if (InvalidMh(mh))
  837.     return (dword)-1L;
  838.  
  839.   msgapierr=MERR_NONE;
  840.   wmsgid=(unsigned)umsgid;
  841.   
  842.   for (mn=0; mn < (unsigned)mh->num_msg; mn++)
  843.     if (Mhd->msgnum[mn]==wmsgid ||
  844.         (type==UID_NEXT && Mhd->msgnum[mn] >= wmsgid) ||
  845.         (type==UID_PREV && Mhd->msgnum[mn] <= wmsgid &&
  846.         ((mn+1) >= (unsigned)mh->num_msg || Mhd->msgnum[mn+1] > wmsgid)))
  847.       return ((dword)Mhd->msgnum[mn]);
  848.  
  849.   msgapierr=MERR_NOENT;
  850.   return 0L;
  851. }
  852.  
  853.  
  854. static dword MAPIENTRY SdmGetHighWater(HAREA mh)
  855. {
  856.   HMSG msgh;
  857.   XMSG msg;
  858.   
  859.   if (InvalidMh(mh))
  860.     return (dword)-1;
  861.   
  862.   /* If we've already fetched the highwater mark... */
  863.   
  864.   if (mh->high_water != (dword)-1L)
  865.     return (mh->high_water);
  866.   
  867.   if ((msgh=SdmOpenMsg(mh, MOPEN_READ, 1L))==NULL)
  868.     return 0L;
  869.   
  870.   if (SdmReadMsg(msgh, &msg, 0L, 0L, NULL, 0L, NULL)==(dword)-1 ||
  871.       !eqstr(msg.from, hwm_from))
  872.   {
  873.     mh->high_water=0L;
  874.   }
  875.   else mh->high_water=(dword)msg.replyto;
  876.   
  877.   (void)SdmCloseMsg(msgh);
  878.   
  879.   return (mh->high_water);
  880. }
  881.  
  882.  
  883. static sword MAPIENTRY SdmSetHighWater(HAREA mh,dword hwm)
  884. {
  885.   if (InvalidMh(mh))
  886.     return -1;
  887.   
  888.   /* Only write it to memory for now.  We'll do a complete update of        *
  889.    * the real HWM in 1.MSG only when doing a MsgCloseArea(), to save        *
  890.    * time.                                                                  */
  891.  
  892.   if (hwm != mh->high_water)
  893.     Mhd->hwm_chgd=TRUE;
  894.   
  895.   mh->high_water=hwm;
  896.   return 0;
  897. }
  898.  
  899.  
  900.  
  901. static dword MAPIENTRY SdmGetTextLen(HMSG msgh)
  902. {
  903.   dword pos;
  904.   dword end;
  905.   
  906.   /* Figure out the physical length of the message */
  907.  
  908.   if (msgh->msg_len==(dword)-1)
  909.   {
  910.     pos=(dword)tell(msgh->fd);
  911.     end=(dword)lseek(msgh->fd, 0L, SEEK_END);
  912.  
  913.     msgh->msg_len=(end < sizeof(struct _omsg))
  914.                     ? 0L : (unsigned long)(end-(dword)sizeof(struct _omsg));
  915.  
  916.     (void)lseek(msgh->fd, (long)pos, SEEK_SET);
  917.   }
  918.   
  919.   /* If we've already figured out the length of the control info */
  920.   
  921.   if (msgh->clen == (sdword)-1 && _Grab_Clen(msgh)==-1)
  922.     return 0;
  923.   else return (dword)(msgh->msg_len - msgh->msgtxt_start);
  924. }
  925.  
  926.  
  927.  
  928. static dword MAPIENTRY SdmGetCtrlLen(HMSG msgh)
  929. {
  930.   /* If we've already figured out the length of the control info */
  931.   
  932.   if (msgh->clen==-1 && _Grab_Clen(msgh)==-1)
  933.     return 0;
  934.   else return (dword)msgh->clen;
  935. }
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942.  
  943.  
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954. static sword near _Grab_Clen(HMSG msgh)
  955. {
  956.   return ((sdword)SdmReadMsg(msgh,NULL,0L,0L,NULL,0L,NULL) < (sdword)0
  957.                         ? -1 : 0);
  958. }
  959.  
  960.  
  961.  
  962. /* Rescan *.MSG area to find the number of messages contained therein */
  963.  
  964. static sword near _SdmRescanArea(HAREA mh)
  965. {
  966.   FFIND *ff;
  967.   byte temp[PATHLEN];
  968.   unsigned mn, thismsg;
  969.  
  970.   mh->num_msg=0;
  971.  
  972.   if ((Mhd->msgnum=palloc(SDM_BLOCK * sizeof(unsigned)))==NULL)
  973.   {
  974.     msgapierr=MERR_NOMEM;
  975.     return FALSE;
  976.   }
  977.  
  978.   Mhd->msgnum_len=SDM_BLOCK;
  979.  
  980.   (void)sprintf(temp, "%s*.msg", Mhd->base);
  981.  
  982.   if ((ff=FindOpen(temp, 0)) != 0)
  983.   {
  984.     mn=0;
  985.  
  986.     do
  987.     {
  988.       /* Don't count zero-length or invalid messages */
  989.  
  990.       if (ff->ulSize < sizeof(struct _omsg))
  991.         continue;
  992.  
  993.       if (mn >= Mhd->msgnum_len)
  994.       {
  995.         Mhd->msgnum=repalloc(Mhd->msgnum,
  996.                              (Mhd->msgnum_len += SDM_BLOCK) * sizeof(unsigned));
  997.  
  998.         if (!Mhd->msgnum)
  999.         {
  1000.           msgapierr=MERR_NOMEM;
  1001.           return FALSE;
  1002.         }
  1003.       }
  1004.  
  1005.       if ((thismsg=(unsigned)atoi(ff->szName)) != 0)
  1006.       {
  1007.         Mhd->msgnum[mn++]=thismsg;
  1008.  
  1009.         if ((dword)thismsg > mh->high_msg)
  1010.           mh->high_msg=(dword)thismsg;
  1011.         
  1012.         mh->num_msg=(dword)mn;
  1013.       }
  1014.  
  1015.       #ifdef OS_2
  1016.       if((mn % 128)==127)
  1017.         DosSleep(1L);
  1018.       #endif
  1019.     }
  1020.     while (FindNext(ff)==0);
  1021.  
  1022.     FindClose(ff);
  1023.  
  1024.     /* Now sort the list of messages */
  1025.  
  1026.     qksort((int *)Mhd->msgnum, (unsigned)mh->num_msg);
  1027.   }
  1028.   
  1029.   return TRUE;
  1030. }
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036. static void MSGAPI Init_Xmsg(PXMSG msg)
  1037. {
  1038.   (void)memset(msg, '\0', sizeof(XMSG));
  1039. }
  1040.  
  1041. static void MSGAPI Convert_Fmsg_To_Xmsg(struct _omsg *fmsg, PXMSG msg, word def_zone)
  1042. {
  1043.   NETADDR *orig, *dest;
  1044.  
  1045.   Init_Xmsg(msg);
  1046.  
  1047.   orig=&msg->orig;
  1048.   dest=&msg->dest;
  1049.  
  1050.   fmsg->to[sizeof(fmsg->to)-1]='\0';
  1051.   fmsg->from[sizeof(fmsg->from)-1]='\0';
  1052.   fmsg->subj[sizeof(fmsg->subj)-1]='\0';
  1053.   fmsg->date[sizeof(fmsg->date)-1]='\0';
  1054.  
  1055.   (void)strcpy(msg->from, fmsg->from);
  1056.   (void)strcpy(msg->to  , fmsg->to  );
  1057.   (void)strcpy(msg->subj, fmsg->subj);
  1058.  
  1059.   orig->zone=dest->zone=def_zone;
  1060.   orig->point=dest->point=0;
  1061.  
  1062.   orig->net=(word)fmsg->orig_net;
  1063.   orig->node=(word)fmsg->orig;
  1064.  
  1065.   dest->net=(word)fmsg->dest_net;
  1066.   dest->node=(word)fmsg->dest;
  1067.  
  1068.   Get_Binary_Date(&msg->date_written, &fmsg->date_written, fmsg->date);
  1069.   Get_Binary_Date(&msg->date_arrived, &fmsg->date_arrived, fmsg->date);
  1070.  
  1071.   (void)strcpy(msg->__ftsc_date, fmsg->date);
  1072.  
  1073.   msg->utc_ofs=0;
  1074.  
  1075.   msg->replyto=fmsg->reply;
  1076.   msg->replies[0]=fmsg->up;
  1077.   msg->attr=(dword)fmsg->attr;
  1078.  
  1079.   /*
  1080.   sprintf(orig->ascii,sqaddr_fmt,orig->zone,orig->net,orig->node,orig->point);
  1081.   sprintf(dest->ascii,sqaddr_fmt,dest->zone,dest->net,dest->node,dest->point);
  1082.   */
  1083.   
  1084.   /* Convert 4d pointnets */
  1085.  
  1086.   if (fmsg->times==~fmsg->cost && fmsg->times)
  1087.     msg->orig.point=fmsg->times;
  1088. }
  1089.  
  1090. static void MSGAPI Convert_Xmsg_To_Fmsg(PXMSG msg,struct _omsg *fmsg)
  1091. {
  1092.   NETADDR *orig, *dest;
  1093.         
  1094.   (void)memset(fmsg, '\0', sizeof(struct _omsg));
  1095.  
  1096.   orig=&msg->orig;
  1097.   dest=&msg->dest;
  1098.  
  1099.   (void)strncpy(fmsg->from, msg->from, sizeof(fmsg->from));
  1100.   (void)strncpy(fmsg->to  , msg->to  , sizeof(fmsg->to));
  1101.   (void)strncpy(fmsg->subj, msg->subj, sizeof(fmsg->subj));
  1102.  
  1103.   fmsg->from[sizeof(fmsg->from)-1]='\0';
  1104.   fmsg->to  [sizeof(fmsg->to  )-1]='\0';
  1105.   fmsg->subj[sizeof(fmsg->subj)-1]='\0';
  1106.  
  1107.   fmsg->orig_net=(sword)orig->net;
  1108.   fmsg->orig=(sword)orig->node;
  1109.  
  1110.   fmsg->dest_net=(sword)dest->net;
  1111.   fmsg->dest=(sword)dest->node;
  1112.   
  1113.   if (*msg->__ftsc_date)
  1114.   {
  1115.     (void)strncpy(fmsg->date, msg->__ftsc_date, sizeof(fmsg->date));
  1116.     fmsg->date[sizeof(fmsg->date)-1]='\0';
  1117.   }
  1118.   else (void)sprintf(fmsg->date, "%02d %s %02d  %02d:%02d:%02d",
  1119.                      msg->date_written.date.da ? msg->date_written.date.da : 1,
  1120.                      months_ab[msg->date_written.date.mo
  1121.                                  ? msg->date_written.date.mo-1
  1122.                                  : 0],
  1123.                      (msg->date_written.date.yr+80) % 100,
  1124.                      msg->date_written.time.hh,
  1125.                      msg->date_written.time.mm,
  1126.                      msg->date_written.time.ss << 1);
  1127.              
  1128.   fmsg->date_written=msg->date_written;
  1129.   fmsg->date_arrived=msg->date_arrived;
  1130.  
  1131.   fmsg->reply=(word)msg->replyto;
  1132.   fmsg->up=(word)msg->replies[0];
  1133.   fmsg->attr=(word)(msg->attr & 0xffffL);
  1134.  
  1135.  
  1136.   /* Non-standard point kludge to ensure that 4D pointmail works correctly */
  1137.  
  1138.   if (orig->point)
  1139.   {
  1140.     fmsg->times=orig->point;
  1141.     fmsg->cost=~fmsg->times;
  1142.   }
  1143. }
  1144.  
  1145.  
  1146. int MAPIENTRY WriteZPInfo(PXMSG msg, void (MAPIENTRY *wfunc)(byte OS2FAR *str), byte OS2FAR *kludges)
  1147. {
  1148.   byte temp[PATHLEN];
  1149.   byte *null="";
  1150.   int bytes=0;
  1151.  
  1152.   if (!kludges)
  1153.     kludges=null;
  1154.  
  1155.   if ((msg->dest.zone != mi.def_zone || msg->orig.zone != mi.def_zone) &&
  1156.       !stristr(kludges, "\x01INTL"))
  1157.   {
  1158.     (void)sprintf(temp, "\x01INTL %u:%u/%u %u:%u/%u\r",
  1159.                   (unsigned)msg->dest.zone, (unsigned)msg->dest.net,
  1160.                   (unsigned)msg->dest.node, (unsigned)msg->orig.zone,
  1161.                   (unsigned)msg->orig.net, (unsigned)msg->orig.node);
  1162.  
  1163.     (*wfunc)(temp);
  1164.     bytes += (int)strlen(temp);
  1165.   }
  1166.  
  1167.   if (msg->orig.point && !strstr(kludges, "\x01""FMPT"))
  1168.   {
  1169.     (void)sprintf(temp, "\x01""FMPT %u\r", (unsigned)msg->orig.point);
  1170.     (*wfunc)(temp);
  1171.     bytes += (int)strlen(temp);
  1172.   }
  1173.  
  1174.   if (msg->dest.point && !strstr(kludges, "\x01""TOPT"))
  1175.   {
  1176.     (void)sprintf(temp, "\x01""TOPT %u\r", (unsigned)msg->dest.point);
  1177.     (*wfunc)(temp);
  1178.     bytes += (int)strlen(temp);
  1179.   }
  1180.  
  1181.   return bytes;
  1182. }
  1183.  
  1184.  
  1185. static void MAPIENTRY WriteToFd(byte OS2FAR *str)
  1186. {
  1187.   (void)farwrite(statfd, str, strlen(str));
  1188. }
  1189.  
  1190.   
  1191. static void near Get_Binary_Date(struct _stamp *todate, struct _stamp *fromdate, byte *asciidate)
  1192. {
  1193. #ifdef HCC
  1194.   /* If compiling for the HCC, use the ASCII message date only, not         *
  1195.    * the binary dates.  This breaks MR, but Max doesn't mind.               */
  1196.  
  1197.   ASCII_Date_To_Binary(asciidate, (union stamp_combo *)todate);
  1198. #else
  1199.   if (fromdate->date.da==0 ||
  1200.       fromdate->date.da > 31 ||
  1201.       fromdate->date.yr > 50 ||
  1202.       fromdate->date.yr < 7  ||
  1203.       fromdate->time.hh > 23 ||
  1204.       fromdate->time.mm > 59 ||
  1205.       /*fromdate->time.ss > 59 ||*/ /* lint: constant out of range */
  1206.       ((union stamp_combo *)&fromdate)->ldate==0)
  1207.   {
  1208.     ASCII_Date_To_Binary(asciidate,(union stamp_combo *)todate);
  1209.   }
  1210.   else *todate=*fromdate;
  1211. #endif
  1212. }
  1213.  
  1214.