home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / msq31004.zip / MSG.C < prev    next >
C/C++ Source or Header  |  1995-07-06  |  32KB  |  990 lines

  1. /*  msg.c
  2.  
  3. released into the PUBLIC DOMAIN 10 jul 1994 by John Dennis
  4.  
  5. NOTE:
  6. Because the SDM routines are NOT the same (the Msgn are the same as
  7. the UIDs, so the Msgn's are not contiguous), I basically had to create
  8. my own API to distance my code from the real API.  (Making it easy to
  9. integrate other message types).  All msgbase specific stuff should be
  10. kept within the module that handles it.
  11.  
  12. History:
  13.  
  14.  18/11/91 first gleamings in my eye (after long sleep; about april).
  15.  20/11/91 basic version, reads/writes but not smart.
  16.  26/11/91 complete versiom, reads/writes/etc, no crashes (?).
  17.  01/12/91 complete conversion to the MSGAPI for squish.
  18.           (Previously used own code).
  19.  02/12/91 cleaned up code a bit, fixed bug where it would always
  20.           write a non-new msg as SCANNED whether it was or not.
  21.           Aslo cleaned up returns from errors.
  22.  05/12/91 Cleaned up some cases where it was passing NULL to a
  23.           msgapi function (certain crash). Also cleaned up the
  24.           ctrlinfo routines for extraction and writes.
  25.           Made *dead* sure a NULL is never passed to msgapi func.
  26.           Fixed it so proper zone & point info is stored in
  27.           msgbase.
  28.  06/12/91 Neatened up the code, added in a few extra checks I
  29.           missed before.
  30.  13/12/91 Added locking code to *.sql file bits.
  31.  08/01/92 Fixed logic in squish_writmsg() & fixed the
  32.           conversion of UID to MsgNm to do exact conversions.
  33.  10/01/92 Made new msgs kill the MSGSCANNED bit.
  34.  23/02/92 Removed locking routines on lastread files.  Also changed way
  35.           of obtaining lastread pointer: now uses API to locate it.
  36.  20/06/92 Made the code completey compliant with API v1
  37.  13/07/92 changed name to msg.c and made it do other message types.
  38. */
  39.  
  40. #define NO_STDLIB       /* causes conflicts with errno.h in MSC */
  41. #define DEBUG 0
  42.  
  43. #include <msgapi.h>
  44. #include <time.h>
  45. #include "msged.h"
  46. #include "date.h"
  47. #include <errno.h>
  48. #include <sys/types.h>
  49. #include <sys/stat.h>
  50. #include <fcntl.h>
  51. #ifdef __MSC__
  52.   #include <sys/locking.h>
  53. #endif
  54. #include <share.h>
  55. #include <progprot.h>
  56. #if DEBUG
  57. #include <assert.h>
  58. #endif
  59.  
  60. #define CHUNKSZ         10         /* size of chunk to allocate as extra */
  61.  
  62. /* ------------------------------------------------------------------*/
  63. /*                          prototypes                               */
  64. /*-------------------------------------------------------------------*/
  65.  
  66. #include "normal.h"
  67.  
  68. time_t stampToTimeT(struct _stamp *st);
  69. static struct _stamp *timeTToStamp(time_t);
  70.  
  71. /* ------------------------------------------------------------------*/
  72. /*                   typedefs and global vars                        */
  73. /*-------------------------------------------------------------------*/
  74.  
  75. extern struct _minf minf;
  76. extern word _stdc msgapierr;
  77.  
  78. MSG  *Ahandle        = NULL;   /* area handle           */
  79. static MSGH *mh      = NULL;   /* message handle        */
  80. static XMSG xmsg;              /* squish message header */
  81.  
  82. char msgbuf[BUFLEN];           /* message text buffer   */
  83. char cinfbuf[BUFLEN];          /* control info buffer   */
  84.  
  85. static UMSGID replyto = 0;     /* to ensure correct uplinks when $mxx is used */
  86.  
  87. static unsigned long num_msgs,  /*  number of messages in msgbase */
  88.            new = 0;            /* if msg being written is new                 */
  89.  
  90.  
  91. /*-------------------------------------------------------------------*/
  92. /*                                                                   */
  93. /* open_sqbase(char *path);                                          */
  94. /*                                                                   */
  95. /*  opens the msgbase at path, creating if it doesn't exist.         */
  96. /*                                                                   */
  97. /*-------------------------------------------------------------------*/
  98.  
  99. int open_sqbase(char *path, word type)
  100. {
  101. #if DEBUG
  102.     assert(mh==NULL);
  103. #endif
  104.     if (mh != NULL) {        /* if we didn't close it for whatever reason... */
  105.         MsgCloseMsg(mh);
  106.         mh = NULL;
  107.     }
  108. #if DEBUG
  109.     assert(Ahandle==NULL);
  110. #endif
  111.     if (Ahandle != NULL) {   /* if we didn't close it for whatever reason... */
  112.         if (MsgCloseArea(Ahandle) == -1) {
  113.             return (-1);     /* urg, this should *not* happen */
  114.         }
  115.     }
  116.     if ((Ahandle=MsgOpenArea((unsigned char *)path, 
  117.                              MSGAREA_CRIFNEC, 
  118.                              type))==NULL) {
  119.         return (-1);         /* create if not already there */
  120.     }
  121.     return TRUE;
  122. }
  123.  
  124.  
  125.  
  126. /*-------------------------------------------------------------------*/
  127. /*                                                                   */
  128. /* squish_scan(AREA *a);                                             */
  129. /*                                                                   */
  130. /*  scans an area for messages, opening the msgbase and filling      */
  131. /*  the message[] array.                                             */
  132. /*                                                                   */
  133. /*-------------------------------------------------------------------*/
  134.  
  135. long SquishMsgAreaOpen(AREA *a)
  136. {
  137.     struct stat b;               /* stats for sql file */
  138.     unsigned long  lastread;             /* lastread record    */
  139.     char   work[256];            /* path to sql file   */
  140.     int    sql;                  /* file handle        */
  141.     unsigned long  k = 0;                /* counter            */
  142.  
  143.     a->last     = a->first   = 1;
  144.     a->lastread = a->current = 1;
  145.  
  146.     a->status   = 0;             /* not open currently */
  147.  
  148.     if (a->msgtype == FIDO)      /* open the msgbase   */
  149.     {
  150.         if (open_sqbase(a->path, MSGTYPE_SDM) == -1)
  151.         {
  152.             return 0;
  153.         }
  154.     }
  155.     else
  156.         if (open_sqbase(a->path, MSGTYPE_SQUISH) == -1)
  157.             return 0;
  158.  
  159.     sprintf(work,"%s.SQL", a->path);
  160.     sql = sopen(work, O_BINARY|O_RDWR, SH_DENYNO, S_IWRITE|S_IREAD);
  161.     if (sql != -1)
  162.     {
  163.         fstat(sql, &b);
  164.                                  /* we make it big enough          */
  165.         if (b.st_size < (SW->useroffset * sizeof(long)))
  166.         {
  167.             lastread    = 0;
  168.             k           = b.st_size / sizeof(long);
  169.             lseek(sql, 0L, SEEK_END);
  170.             while (SW->useroffset > k) {
  171.                 write(sql, &lastread, sizeof(long));
  172.                 k++;
  173.             }
  174.         }
  175.         else
  176.         {                   /* we read the data in             */
  177.             lseek(sql, SW->useroffset * sizeof(long), SEEK_SET);
  178.             if (read(sql, &lastread, sizeof(UMSGID)) == sizeof(long))
  179.             {
  180.                 if (CurArea.netmail)
  181.                     a->lastread = a->current = MsgUidToMsgn(Ahandle, lastread, UID_PREV);
  182.                 else
  183.                     a->lastread = a->current = MsgUidToMsgn(Ahandle, lastread, UID_NEXT);
  184.             }
  185.  
  186.         }
  187.         close(sql);
  188.     }
  189.  
  190.     a->last   = MsgHighMsg(Ahandle);
  191.     a->status = 1;
  192.  
  193.     if (a->last >= 1 && a->current == 0)
  194.     {
  195.         a->lastread = 1;
  196.         a->current  = 1;
  197.     }
  198.  
  199.     return a->last;
  200. }
  201.  
  202.  
  203.  
  204. /*-------------------------------------------------------------------*/
  205. /*                                                                   */
  206. /* squish_readheader(unsigned long n);                                       */
  207. /*                                                                   */
  208. /*  reads in the message header and control info for the message.    */
  209. /*                                                                   */
  210. /*-------------------------------------------------------------------*/
  211.  
  212. msg *SquishMsgReadHeader(unsigned long n, int type)
  213. {
  214.     char      path[PATHLEN];
  215.     msg      *m;
  216.     int       i = 0;
  217.  
  218. #if DEBUG
  219.     assert(mh==NULL);
  220.     assert(Ahandle!=NULL);
  221. #endif
  222.  
  223.     if (!Ahandle)
  224.     {
  225.         return NULL;
  226.     }
  227.  
  228.     if (mh != NULL)              /* if open, close it                   */
  229.     {            
  230.         MsgCloseMsg(mh);
  231.     }
  232.                                  /* open msg we want to open            */
  233.     if ((mh=MsgOpenMsg(Ahandle, MOPEN_READ, n)) == NULL)
  234.     {
  235.         return NULL;
  236.     }
  237.                                  
  238.     if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, BUFLEN, 
  239.                                       (unsigned char *)cinfbuf) == (dword)-1)
  240.     {
  241.         MsgCloseMsg(mh);        /* no message header or control info! */
  242.         mh = NULL;
  243.         return NULL;
  244.     }
  245.  
  246.     if ((m = (msg *) calloc(1, sizeof(msg))) == NULL)
  247.     {
  248.         outamemory();
  249.     }
  250.                                  /* basically copy info across to msg   */
  251.     m->msgnum     = MsgMsgnToUid(Ahandle, n);
  252.     m->from.zone  = xmsg.orig.zone;
  253.     m->from.net   = xmsg.orig.net;
  254.     m->from.node  = xmsg.orig.node;
  255.     m->from.point = xmsg.orig.point;
  256.  
  257.     m->to.zone    = xmsg.dest.zone;
  258.     m->to.net     = xmsg.dest.net;
  259.     m->to.node    = xmsg.dest.node;
  260.     m->to.point   = xmsg.dest.point;
  261.  
  262.     m->from.domain = NULL;
  263.     m->to.domain   = NULL;
  264.  
  265.     if (xmsg.date_written.date.yr != 0)
  266.     {
  267.         m->timestamp = stampToTimeT(&xmsg.date_written);
  268.         m->time_arvd = stampToTimeT(&xmsg.date_arrived);
  269.     }
  270.     else                           /* only use this when necesary */
  271.     {                              
  272.         memset(path, 0, sizeof path);
  273.         memcpy(path, xmsg.__ftsc_date ,sizeof xmsg.__ftsc_date);
  274.         m->timestamp = parsedate(path);
  275.     }
  276.  
  277.     if ((m->isto   = (char *) calloc(1,sizeof xmsg.to + 1))   == NULL) outamemory();
  278.     if ((m->isfrom = (char *) calloc(1,sizeof xmsg.from + 1)) == NULL) outamemory();
  279.     if ((m->subj   = (char *) calloc(1,sizeof xmsg.subj + 1)) == NULL) outamemory();
  280.  
  281.     memcpy(m->isto,   xmsg.to,   sizeof xmsg.to);
  282.     memcpy(m->isfrom, xmsg.from, sizeof xmsg.from);
  283.     memcpy(m->subj,   xmsg.subj, sizeof xmsg.subj);
  284.  
  285.     m->attrib.private = (xmsg.attr & MSGPRIVATE) != 0;
  286.     m->attrib.crash = (xmsg.attr & MSGCRASH) != 0;
  287.     m->attrib.recvd = (xmsg.attr & MSGREAD) != 0;
  288.     m->attrib.sent = (xmsg.attr & MSGSENT) != 0;
  289.     m->attrib.attached = (xmsg.attr & MSGFILE) != 0;
  290.     m->attrib.forward = (xmsg.attr & MSGFWD) != 0;
  291.     m->attrib.orphan = (xmsg.attr & MSGORPHAN) != 0;
  292.     m->attrib.killsent = (xmsg.attr & MSGKILL) != 0;
  293.     m->attrib.local = (xmsg.attr & MSGLOCAL) != 0;
  294.     m->attrib.hold = (xmsg.attr & MSGHOLD) != 0;
  295.     m->attrib.direct = (xmsg.attr & MSGXX2) != 0;
  296.     m->attrib.freq = (xmsg.attr & MSGFRQ) != 0;
  297.     m->attrib.rreq = (xmsg.attr & MSGRRQ) != 0;
  298.     m->attrib.rcpt = (xmsg.attr & MSGCPT) != 0;
  299.     m->attrib.areq = (xmsg.attr & MSGARQ) != 0;
  300.     m->attrib.ureq = (xmsg.attr & MSGURQ) != 0;
  301.  
  302.     if (xmsg.attr & MSGSCANNED)  /*?*/
  303.         m->scanned = 1;
  304.  
  305.     m->replyto = MsgUidToMsgn(Ahandle, xmsg.replyto, UID_EXACT);
  306.  
  307.     while (i < 9)
  308.     {
  309.         if (xmsg.replies[i] != 0)
  310.         {
  311.             m->replies[i] = MsgUidToMsgn(Ahandle, xmsg.replies[i], UID_EXACT);
  312.         }
  313.         else
  314.         {
  315.             m->replies[i] = 0;
  316.         }
  317.         i++;
  318.     }
  319.     m->replies[9] = 0;
  320.  
  321.     m->cost         = 0;
  322.     m->times_read   = 0;
  323.     m->text         = NULL;
  324.     m->to.fidonet   = m->from.fidonet = 1;
  325.  
  326.     if (type == RD_HEADER)
  327.     {
  328.         MsgCloseMsg(mh);
  329.         mh = NULL;
  330.     }
  331.     return m;
  332. }
  333.  
  334.  
  335.  
  336. /*-------------------------------------------------------------------*/
  337. /*                                                                   */
  338. /* squish_readtext(unsigned long n);                                         */
  339. /*                                                                   */
  340. /*  reads in the entire message, adds the control info to the        */
  341. /*  beginning of the message and continues to return the message     */
  342. /*  to the caller line by line (at each subsequent call).            */
  343. /*  basically a conversion of the corresponding fido funtion.        */
  344. /*                                                                   */
  345. /*-------------------------------------------------------------------*/
  346.  
  347. char *SquishMsgReadText(unsigned long n)
  348. {
  349.     static char *next = NULL;
  350.     static char *end  = NULL;
  351.     char *t    = NULL;
  352.     char *text = NULL;
  353.     char eol = '\0';
  354.     unsigned long i, l;
  355.     static unsigned long ofs = 0, s = 0;
  356.  
  357. #if DEBUG
  358.     assert(Ahandle!=NULL);
  359.     assert(n>0);
  360.     assert(mh!=NULL);
  361. #else
  362.     unused(n);    
  363. #endif
  364.  
  365.     if (!Ahandle)
  366.     {
  367.         return NULL;
  368.     }
  369.  
  370.     if (next == NULL && s != 0)               /* we are finished          */
  371.     {            
  372.         s    = ofs = 0;
  373.         return NULL;
  374.     }
  375.     if (s == 0)                               /* ready to read in new msg */
  376.     {                            
  377.         memset(msgbuf, 0, BUFLEN-1);
  378.         next = msgbuf;
  379.         if (MsgGetCtrlLen(mh) > 0)              /* copy control info from   */
  380.         {            
  381.             t = cinfbuf;                        /* insert /r's  */
  382.             *(t + (size_t)MsgGetCtrlLen(mh) + 1) = '\0';
  383.             if (*t != '\0')
  384.             {
  385.                 *next++ = *t++;
  386.                 while (*t != '\0')
  387.                 {
  388.                     if (*t == '\01')
  389.                     {
  390.                         *next++ = '\r';         /* add a \r to the text     */
  391.                     }
  392.                     *next++ = *t++;
  393.                 }
  394.                 if (*(next - 1) == '\01')
  395.                 {
  396.                     next--;
  397.                     *(next) = '\0';
  398.                 }
  399.                 else
  400.                 {
  401.                     *next++ = '\r';
  402.                     *next   = '\0';             /* terminate string         */
  403.                 }
  404.             }
  405.             next = msgbuf;
  406.             end  = msgbuf + strlen(msgbuf);
  407.             normalize(msgbuf);
  408.         }
  409.         else
  410.             next = NULL;
  411.  
  412.         s = BUFLEN;
  413.     }                                           /* return msg a line at a   */
  414.                                                 /* time                     */
  415.     if (next == NULL)
  416.     {
  417.         i = MsgReadMsg(mh, NULL, ofs, s - 1, 
  418.                                 (unsigned char *)msgbuf, 0L, NULL);
  419.         ofs += i;
  420.         if (i < 1)
  421.         {
  422.             s    = ofs = 0;
  423.             next = NULL;
  424.             return NULL;
  425.         }
  426.         next = msgbuf;
  427.         while (i && (*next == '\0'))
  428.         {
  429.             i--; next++;
  430.         }
  431.         normalize(next);
  432.         end = msgbuf + strlen(msgbuf);
  433.         if (end < next)
  434.             next = end;
  435.     }
  436.  
  437.     if ((end - next) == 0) t = NULL;
  438.     else t = memchr(next,'\n',(int) (end - next));
  439.  
  440.     if (t == NULL) {
  441.         l = strlen(next);
  442.         memmove(msgbuf, next, (size_t)(l+1));
  443.         i = MsgReadMsg(mh, NULL, ofs, s - l - 1, 
  444.                        (unsigned char *)(msgbuf + (size_t)l), 0L, NULL);
  445.         ofs += i;
  446.         if (i < 1)
  447.         {
  448.             next = NULL;
  449.             return(strdup(msgbuf));
  450.         }
  451.         *(msgbuf + (size_t)l + (size_t)i) = '\0';
  452.         normalize(msgbuf+(size_t)l);
  453.         end  = msgbuf + strlen(msgbuf);
  454.         next = msgbuf;
  455.         t    = strchr(next, '\n');
  456.     }
  457.  
  458.     if (t != NULL)
  459.     {
  460.         eol = *(t+1);
  461.         *(t+1) = '\0';
  462.     }
  463.  
  464.     text = strdup(next);
  465.  
  466.     if (t != NULL)
  467.     {
  468.         *(t+1) = eol;
  469.         next = t+1;
  470.     }
  471.     else
  472.         next = NULL;
  473.  
  474.     return text;
  475. }
  476.  
  477.  
  478. /*-------------------------------------------------------------------*/
  479. /*                                                                   */
  480. /* squish_writeheader(msg *m);                                       */
  481. /*                                                                   */
  482. /*  writes msg header to the msgbase, creates new frame if new msg,  */
  483. /*  and makes sure links are correct.                                */
  484. /*                                                                   */
  485. /*-------------------------------------------------------------------*/
  486.  
  487. int SquishMsgWriteHeader(msg *m, int type)
  488. {
  489.     unsigned long  n = MsgUidToMsgn(Ahandle, m->msgnum, UID_EXACT);
  490.     int    i = 0;
  491.  
  492. #if DEBUG
  493.     assert(Ahandle!=NULL);
  494.     assert(mh==NULL);
  495. #endif
  496.  
  497.     if (!Ahandle)
  498.     {
  499.         return FALSE;
  500.     }
  501.  
  502.     if (mh != NULL)            /* close old msg, if left open */
  503.     {         
  504.         MsgCloseMsg(mh);
  505.     }
  506.  
  507. /*    if (n < 0)
  508.         return ERR_OPEN_MSG; */
  509.  
  510.     if (m->new) {             /* if new, store current number of msgs */
  511.                               /* (for use in squish_writetext()), and */
  512.                               /* create a new frame for the new msg   */
  513.         num_msgs = MsgGetNumMsg(Ahandle);
  514.         if ((mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, 0L))==NULL)
  515.         {
  516.             return ERR_OPEN_MSG;
  517.         }
  518.         new = TRUE;
  519.     }
  520.     else
  521.     {                    /* else we open the msg to be changed   */
  522.         if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL)
  523.         {
  524.             return ERR_OPEN_MSG;
  525.         }
  526.         new = FALSE;
  527.     }
  528.  
  529.     memset(&xmsg, 0, sizeof xmsg);
  530.     
  531.     xmsg.attr = 0;
  532.     if (m->attrib.private) xmsg.attr |= MSGPRIVATE;
  533.     if (m->attrib.crash) xmsg.attr |= MSGCRASH;
  534.     if (m->attrib.recvd) xmsg.attr |= MSGREAD;
  535.     if (m->attrib.sent) xmsg.attr |= MSGSENT;
  536.     if (m->attrib.attached) xmsg.attr |= MSGFILE;
  537.     if (m->attrib.forward) xmsg.attr |= MSGFWD;
  538.     if (m->attrib.orphan) xmsg.attr |= MSGORPHAN;
  539.     if (m->attrib.killsent) xmsg.attr |= MSGKILL;
  540.     if (m->attrib.local) xmsg.attr |= MSGLOCAL;
  541.     if (m->attrib.hold) xmsg.attr |= MSGHOLD;
  542.     if (m->attrib.direct) xmsg.attr |= MSGXX2;
  543.     if (m->attrib.freq) xmsg.attr |= MSGFRQ;
  544.     if (m->attrib.rreq) xmsg.attr |= MSGRRQ;
  545.     if (m->attrib.rcpt) xmsg.attr |= MSGCPT;
  546.     if (m->attrib.areq) xmsg.attr |= MSGARQ;
  547.     if (m->attrib.ureq) xmsg.attr |= MSGURQ;
  548.  
  549.     if (new == FALSE) {       /* if the old msg had been scanned,      */
  550.                               /* then we make sure that the MSGSCANNED */
  551.                               /* bit is set on the way out. new msgs   */
  552.                               /*  get this bit stripped.               */
  553.         if (m->scanned && !m->new)  {
  554.             xmsg.attr |= MSGSCANNED;
  555.         }
  556.     }
  557.  
  558.     if (m->replyto != 0)      /* get the links for replies             */
  559.         xmsg.replyto = MsgMsgnToUid(Ahandle, m->replyto);
  560.  
  561.     for (i = 0; i < 9; i++)
  562.     {
  563.         if (m->replies[i]  != 0)
  564.         {
  565.             xmsg.replies[i] = MsgMsgnToUid(Ahandle, m->replies[i]);
  566.         }
  567.     }
  568.  
  569.     i = 0;
  570.  
  571.     while (m->replies[i] != 0 && i < 9) i++;
  572.  
  573.     if (i == 9) i = 8;
  574.  
  575.     if (!m->new && replyto != 0)
  576.     {
  577.         xmsg.replies[i] = replyto;
  578.         replyto         = 0;
  579.     }
  580.  
  581.     xmsg.dest.zone  = (word)m->to.zone;
  582.     xmsg.dest.net   = (word)m->to.net;
  583.     xmsg.dest.node  = (word)m->to.node;
  584.     xmsg.dest.point = (word)m->to.point;
  585.  
  586.     xmsg.orig.zone  = (word)m->from.zone;
  587.     xmsg.orig.net   = (word)m->from.net;
  588.     xmsg.orig.node  = (word)m->from.node;
  589.     xmsg.orig.point = (word)m->from.point;
  590.  
  591.     if (m->isto)
  592.         memcpy(xmsg.to,   m->isto,   min(sizeof xmsg.to,   strlen(m->isto)));
  593.  
  594.     if (m->isfrom)
  595.         memcpy(xmsg.from, m->isfrom, min(sizeof xmsg.from, strlen(m->isfrom)));
  596.  
  597.     if (m->subj)
  598.         memcpy(xmsg.subj, m->subj,   min(sizeof xmsg.subj, strlen(m->subj)));
  599.  
  600.     memcpy(xmsg.__ftsc_date, mtime(m->timestamp), 20);
  601.  
  602.     xmsg.date_written = *timeTToStamp(m->timestamp);
  603.  
  604.     if (m->time_arvd != 0)
  605.     {
  606.         xmsg.date_arrived = *timeTToStamp(m->time_arvd);
  607.     }
  608.     else
  609.         xmsg.date_arrived = xmsg.date_written;
  610.  
  611.     if (type == WR_HEADER || !new)
  612.     {
  613.         MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, 0L, 0L, NULL);
  614.         MsgCloseMsg(mh);
  615.         mh = NULL;
  616.     }
  617.     return TRUE;
  618. }
  619.  
  620.  
  621.  
  622. /*-------------------------------------------------------------------*/
  623. /*                                                                   */
  624. /* strip_whitel(void)                                                */
  625. /*                                                                   */
  626. /*  strips the white spaces from the control info, copying it to     */
  627. /*  the msgbuf array while it's at it.  returns new length.          */
  628. /*                                                                   */
  629. /*-------------------------------------------------------------------*/
  630.  
  631. dword strip_whitel(void)
  632. {
  633.     char *s, *c, *cptr;
  634.  
  635.     cptr = cinfbuf;            /* we put it in the cinfbuf, killing  */
  636.     s    = msgbuf;             /* any \r & \n's in the process       */
  637.     c = s + (strlen(s)) + 1;
  638.     while (s != c) {           /* copy buffer across, ignoring any   */
  639.         switch (*s) {          /* fluff in the src buffer            */
  640.             case '\r' :
  641.             case '\n' : s++; break;
  642.             default   : *cptr++ = *s++;
  643.         }
  644.     }
  645.     *cptr = '\0';
  646.     return cptr - cinfbuf;
  647. }
  648.  
  649.  
  650. /*-------------------------------------------------------------------*/
  651. /*                                                                   */
  652. /* squish_writetext(char *text, int n);                              */
  653. /*                                                                   */
  654. /*  writes msg text (and header if new msg), to the msgbase.  if     */
  655. /*  msg is not new and new text is larger, then it creates a new     */
  656. /*  frame, while keeping the same position in the index.             */
  657. /*                                                                   */
  658. /*-------------------------------------------------------------------*/
  659.  
  660. int SquishMsgWriteText(char *text, unsigned long msgn, unsigned long mlen)
  661. {
  662.     static char *tptr, *c;
  663.     static int   ready = FALSE, ctrl = TRUE;
  664.     static unsigned long  n     = 0;
  665.     char         cz    = 0;
  666.     unsigned long clen;
  667.  
  668.     if (!Ahandle)
  669.     {
  670.         return FALSE;
  671.     }
  672.  
  673.     if (ready == FALSE) {              /* starting on new msg; reset pntrs   */
  674.         ready = TRUE;
  675.         tptr  = msgbuf;
  676.         n     = MsgUidToMsgn(Ahandle, msgn, UID_EXACT);
  677.     }
  678.  
  679.     if (text == NULL)
  680.     {
  681.         if (ctrl) {                      /* no body in the msg        */
  682.             if (new)
  683.             {
  684.                 clen = strip_whitel();
  685.                 MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, clen, 
  686.                             (unsigned char *)cinfbuf);
  687.                 MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)&cz, 
  688.                             sizeof(char), mlen, 0L, NULL);
  689.             }
  690.             else
  691.             {
  692.                 if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL)
  693.                 {
  694.                     ready = FALSE;
  695.                     ctrl  = TRUE;
  696.                     new   = FALSE;       /* we only change the header */
  697.                     return FALSE;
  698.                 }
  699.                 MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, 0L, NULL);
  700.             }
  701.         }
  702.         else
  703.             MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)&cz, 
  704.                         sizeof(char), mlen, 0L, NULL);
  705.  
  706.         if (new) {                   /* msg is a reply - save new number so */
  707.                                      /* next header written can use it for  */
  708.                                      /* the uplink number                   */
  709.             if (xmsg.replyto) {
  710.                 replyto = MsgMsgnToUid(Ahandle, MsgGetNumMsg(Ahandle));
  711.             }
  712.             if (num_msgs == MsgGetNumMsg(Ahandle)) {
  713.                 CurArea.messages--;
  714.             }
  715.         }
  716.  
  717.         new  = ready = FALSE;
  718.         ctrl = TRUE;
  719.         return TRUE;
  720.     }
  721.     if (*text == '\01' && ctrl)
  722.     {
  723.         c = text;
  724.         while (*c != '\0') {           /* store the ctrl info */
  725.             *tptr++ = *c++;
  726.         }
  727.         *tptr = '\0';
  728.     }
  729.     else
  730.     {
  731.         if (*text != '\01' && ctrl)
  732.         {
  733.             ctrl = FALSE;
  734.             clen = strip_whitel();
  735.             if (!new) {                 /* we are modifying a non-new msg   */
  736.                 if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL) {
  737.                     ready = FALSE;
  738.                     ctrl  = TRUE;
  739.                     new   = FALSE;
  740.                     return FALSE;
  741.                 }
  742.  
  743.                 if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, 0L, NULL) == (dword)-1)
  744.                 {
  745.                     new   = FALSE;
  746.                     ready = FALSE;
  747.                     ctrl  = TRUE;
  748.                     return FALSE;
  749.                 }
  750.  
  751.                 MsgCloseMsg(mh);         /* copy xmsg info across */
  752.  
  753.                 if ((mh=MsgOpenMsg(Ahandle, MOPEN_CREATE, n))==NULL)
  754.                 {
  755.                     ready = FALSE;
  756.                     ctrl  = TRUE;
  757.                     new   = FALSE;
  758.                     return FALSE;
  759.                 }
  760.                                          /* messy, but it works           */
  761.                 MsgWriteMsg(mh, FALSE, &xmsg, (unsigned char *)text, 
  762.                            strlen(text), mlen, 
  763.                            clen, (unsigned char *)cinfbuf);
  764.             }
  765.             else
  766.                 MsgWriteMsg(mh, FALSE, &xmsg, (unsigned char *)text, 
  767.                             strlen(text), mlen, clen, 
  768.                             (unsigned char *)cinfbuf);
  769.         }
  770.         else
  771.             MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)text, 
  772.                         strlen(text), mlen, 0L, NULL);
  773.     }
  774.     return TRUE;
  775. }
  776.  
  777.  
  778. /*---------------------------------------------------------*/
  779. /* MsgClose()                                              */
  780. /*                                                         */
  781. /* closes the message currently opened.                    */
  782. /*                                                         */
  783. /*---------------------------------------------------------*/
  784.  
  785. int SquishMsgClose(void)
  786. {
  787.     word i;
  788.  
  789. #if DEBUG
  790.     assert(Ahandle!=NULL);
  791.     assert(mh!=NULL);
  792. #endif
  793.  
  794.     if (MsgCloseMsg(mh) == -1) {
  795.         i = msgapierr;      /* debug purposes */
  796.         printf("\n!ERROR: message didn't close, error %ud", i);
  797.         exit(-1);
  798.         return ERR_CLOSE_MSG;
  799.     }
  800.     else {
  801.         mh = NULL;
  802.         return TRUE;
  803.     }
  804. }
  805.  
  806. /*---------------------------------------------------------*/
  807. /* MsgAreaClose()                                          */
  808. /*                                                         */
  809. /* closes the area currently opened.                       */
  810. /*                                                         */
  811. /*---------------------------------------------------------*/
  812.  
  813. int SquishMsgAreaClose(void)
  814. {
  815.     word i;
  816.  
  817.     if (!Ahandle)
  818.         return TRUE;
  819.  
  820.     if (MsgCloseArea(Ahandle) == -1)
  821.     {
  822.         i = msgapierr;  /* debug purposes */
  823.         printf("\n!ERROR: area didn't close, error %ud", i);
  824.         exit(-1);
  825.         return ERR_CLOSE_AREA;
  826.     }
  827.     else
  828.     {
  829.         CurArea.status = 0;
  830.         Ahandle               = NULL;
  831.         return TRUE;
  832.     }
  833. }
  834.  
  835.  
  836. /*---------------------------------------------------------*/
  837. /* SquishUidToMsgn()                                       */
  838. /*                                                         */
  839. /* Returns the msg# of a UID.                              */
  840. /*                                                         */
  841. /*---------------------------------------------------------*/
  842.  
  843. unsigned long SquishUidToMsgn(unsigned long n)
  844. {
  845. #if DEBUG
  846.     assert(Ahandle!=NULL);
  847. #endif
  848.     return MsgUidToMsgn(Ahandle, n, UID_EXACT);
  849. }
  850.  
  851.  
  852. /*---------------------------------------------------------*/
  853. /* SquishMsgnToUid()                                       */
  854. /*                                                         */
  855. /* Returns the UID of a squish message.                    */
  856. /*                                                         */
  857. /*---------------------------------------------------------*/
  858.  
  859.  
  860. unsigned long SquishMsgnToUid(unsigned long n)
  861. {
  862. #if DEBUG
  863.     assert(Ahandle!=NULL);
  864. #endif
  865.     return MsgMsgnToUid(Ahandle, n);
  866. }
  867.  
  868. /*-------------------------------------------------------------------*/
  869. /*                                                                   */
  870. /* squish_setlast(AREA a);                                           */
  871. /*                                                                   */
  872. /*  sets the last message read in the *.sql file & closes the msg    */
  873. /*  area; if *.sql file doesn't exist, create it.                    */
  874. /*                                                                   */
  875. /*-------------------------------------------------------------------*/
  876.  
  877. int SquishAreaSetLast(AREA *a)
  878. {
  879.     char work[255];
  880.     long i = 1, k = 0;
  881.     int ret = TRUE;
  882.     int sql;
  883.  
  884.     if (mh != NULL)
  885.     {
  886.         MsgCloseMsg(mh);
  887.         mh = NULL;
  888.     }
  889.     if (Ahandle != NULL)    /* don't do this on closed area! */
  890.     {  
  891.         sprintf(work,"%s.SQL",a->path);
  892.  
  893.         sql = sopen(work, O_BINARY|O_RDWR, SH_DENYNO, S_IWRITE|S_IREAD);
  894.         if (sql == -1)
  895.         {
  896.             if (errno != EACCES && errno != EMFILE)
  897.             {
  898.                 sql = sopen(work, O_BINARY|O_WRONLY|O_CREAT, SH_DENYNO, S_IWRITE|S_IREAD);
  899.                 if (sql == -1)
  900.                     ret = FALSE;
  901.                 else
  902.                 {
  903.                     lseek(sql, 0L, SEEK_SET);
  904.  
  905.                     for (i = 0; SW->useroffset > (int) i; i++)
  906.                     {
  907.                         write(sql, &k, sizeof(k));
  908.                     }
  909.                     i = MsgMsgnToUid(Ahandle, CurArea.lastread);
  910.                     write(sql, (char *) &i, sizeof(long));
  911.                     close(sql);
  912.                 }
  913.             }
  914.             else
  915.                 ret = FALSE;
  916.         }
  917.         else
  918.         {
  919.             lseek(sql, SW->useroffset * sizeof(long), SEEK_SET);
  920.  
  921.             if (SW->use_lastr)
  922.                 i = MsgMsgnToUid(Ahandle, CurArea.lastread);
  923.             else
  924.                 i = MsgMsgnToUid(Ahandle, CurArea.current);
  925.  
  926.             write(sql, (char *) &i, sizeof(long));
  927.             close(sql);
  928.         }
  929.     }
  930.     return ret;
  931. }
  932.  
  933.  
  934. /*-------------------------------------------------------------------*/
  935. /*                                                                   */
  936. /*  MsgDelete()                                                      */
  937. /*                                                                   */
  938. /*  kills a message in the current area, specified by the passed     */
  939. /*  index.                                                           */
  940. /*                                                                   */
  941. /*-------------------------------------------------------------------*/
  942.  
  943. int SquishMsgDelete(unsigned long n)
  944. {
  945.     unsigned long msgn;
  946.  
  947. #if DEBUG
  948.     assert(Ahandle!=NULL);
  949. #endif
  950.     msgn = MsgUidToMsgn(Ahandle, n, UID_EXACT);
  951.  
  952.     if (MsgKillMsg(Ahandle, msgn) == -1)
  953.         return FALSE;
  954.  
  955.     return TRUE;
  956. }
  957.  
  958. time_t stampToTimeT(struct _stamp *st)
  959. {
  960.     struct tm tms;
  961.     time_t tt;
  962.     
  963.     tms.tm_sec = st->time.ss << 1;
  964.     tms.tm_min = st->time.mm;
  965.     tms.tm_hour = st->time.hh;
  966.     tms.tm_mday = st->date.da;
  967.     tms.tm_mon = st->date.mo - 1;
  968.     tms.tm_year = st->date.yr + 80;
  969.     tms.tm_isdst = -1;
  970.     tt = mktime(&tms);
  971.     return (tt);
  972. }
  973.  
  974. static struct _stamp *timeTToStamp(time_t tt)
  975. {
  976.     static struct _stamp st;
  977.     struct tm *tms;
  978.     
  979.     tms = localtime(&tt);
  980.     st.time.ss = tms->tm_sec >> 1;
  981.     st.time.mm = tms->tm_min;
  982.     st.time.hh = tms->tm_hour;
  983.     st.date.da = tms->tm_mday;
  984.     st.date.mo = tms->tm_mon + 1;
  985.     st.date.yr = tms->tm_year - 80;
  986.     return (&st);
  987. }
  988.  
  989. /*-- end --*/
  990.