home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / fido / pup_v2b.zip / MSGBASE.C < prev    next >
C/C++ Source or Header  |  1988-01-28  |  7KB  |  289 lines

  1. #include <puppy.h>
  2. #include <pupmem.h>
  3. #include <ascii.h>
  4.  
  5. /*
  6.     Message Base functions
  7.  
  8.     Tom Jennings
  9.     20 Sept 87
  10.  
  11.  
  12. This is the message base (its too crude to be called a "database") for
  13. Puppy. 
  14.  
  15. To the user, it appears to be a Pile of messages of fixed length. You
  16. start at the top of the pile, and read messages one by one until you
  17. hit the bottom. When a new message is enter, it goes on the Top of the
  18. pile and the oldest one falls off the bottom.
  19.  
  20. Physically this is of course a linear file, and is implemented as a
  21. "ring buffer". There is a "place keeper" counter called the "top". 
  22. Initially, the message base is empty, and the top is the beginning
  23. of the file. 
  24.  
  25. It is the nature of this ring buffer that since the "top" points to 
  26. the newest record, (top - 1) is therefore the oldest record. This is
  27. the feature the whole thing is based on. (top - 1) is called the "bottom".
  28.  
  29. (When Top excrements beyond the end or beginning of the physical file,
  30. it is wrapped to the opposite end as you might expect.)
  31.  
  32. When a new message is entered, it is stored at the bottom, ie. in the
  33. oldest record. The top is then decremented so that it points to the
  34. new record; this was the oldest, and now is the newest. The previous
  35. newest is now 2nd newest, etc.
  36.  
  37.  
  38. The interface to this module is the "message number". Message numbers
  39. run 1 (newest, Top of the pile) to N (oldest, bottom of the pile.)
  40.  
  41.  
  42. Internally of course we gotta deal in records, which get converted
  43. into a byte file position. Conversion from MessageNumber to Record is:
  44.  
  45.     recd= (MessageNumber + Top) % pup.Messages
  46.  
  47. */
  48.  
  49. int msgfile;        /* message index file */
  50. int txtfile;        /* message text file */
  51.  
  52. /*
  53.  
  54. openmsg()    Open/start the message base.
  55. closemsg()    Close the message base.
  56.  
  57. Frequently used message base primitives
  58.  
  59. recd(n)        Converts message number into record number.
  60. getmsg(n)    Returns a pointer to message header #n.
  61. ismsg(n,t)    Returns true if the specified message number exists and
  62.         matches the selected topics.
  63. alltopics()    Returns all possible message topic bits.
  64.  
  65. Various message characteristic routines
  66.  
  67. oldest_msg()    Returns the oldest (highest) message number.
  68. newest_msg()    Returns the newest (lowest) message number.
  69. newmsg()    Returns a pointer to the next free message
  70.         header structure.
  71. killmsg(n)    Marks a message as deleted.
  72.  
  73. Message data manipulation routines
  74.  
  75. savemsg(lines)    Add the message in memory to the file.
  76. loadmsg(n)    Load message #n into the text buffer.
  77.  
  78. Message display routines
  79.  
  80. topics(t)    List the topics specified in the bit field.
  81. listhdr(n)    Displays the contents of message header #N.
  82. listmsg(n)    Displays the contents of the message body.
  83. */
  84.  
  85. /* Open the message base; open both files, load the index. */
  86.  
  87. openmsg() {
  88.  
  89.     msgfile= open("puppy.idx",2);        /* open the msg base */
  90.     txtfile= open("puppy.dat",2);
  91.     if ((msgfile < 0) || (txtfile < 0)) {
  92.         printf("Message base file(s) missing!\r\n");
  93.  
  94.     } else read(msgfile,msg,pup.messages * sizeof(struct _msg));
  95. }
  96.  
  97. /* Close the message base. */
  98.  
  99. closemsg() {
  100.  
  101.     if (msgfile != -1) close(msgfile);
  102.     if (txtfile != -1) close(txtfile);
  103.     msgfile= txtfile= -1;
  104. }
  105.  
  106. /* Expand the topics bit field into topic names. Handle the special
  107. case NONE. */
  108.  
  109. topics(t)
  110. WORD t;
  111. {
  112. int i,n;
  113.  
  114.     n= 0;
  115.     for (i= 0; i < 16; i++) {
  116.         if ((t & (1 << i)) && *pup.topic[i].name) {
  117.             mprintf(" %s",pup.topic[i].name);
  118.             ++n;
  119.         }
  120.     }
  121.     if (! n) mputs(" NONE");
  122. }
  123.  
  124. /* List message header #n. */
  125.  
  126. listhdr(n)
  127. int n;
  128. {
  129. struct _msg *t;
  130. char *sep;
  131.  
  132.     sep= ", ";                    /* assume wide screen */
  133.     if (caller.cols < 80) sep= "\r\n";        /* if not, break into 5 lines */
  134.     t= getmsg(n);                    /* ptr to this message */
  135.  
  136.     mputs(str_date(t-> date)); mputs(sep); 
  137.     mputs("TOPIC:"); topics(t-> topic); mputs("\r\n");
  138.     mprintf("FROM: %s%s",t-> from,sep);        /* FROM name, space or CR */
  139.     mprintf("TO: %s%s",t-> to,sep);            /* TO name, space or CR */
  140.     mprintf("TITLE: %s\r\n",t-> subj);
  141. }
  142.  
  143. /* Display the body of a message. This just seeks to the right
  144. place in the file and dumps the text. */
  145.  
  146. listmsg(n)
  147. int n;
  148. {
  149. long l;
  150.  
  151.     l= 0L + pup.msgsize;
  152.     l *= (long) recd(n);
  153.     lseek(txtfile,l,0);
  154.     dumptext(txtfile);
  155. }
  156.  
  157. /* ---------------------------------------------------------------- */
  158.  
  159. /* Return true if this message number exists and is part of 
  160. the selected topic(s). */
  161.  
  162. ismsg(n,t)
  163. int n;
  164. {
  165.     if (n > oldest_msg()) return(0);    /* too high! */
  166.     if (n < newest_msg()) return(0);    /* too low! */
  167.  
  168.     return(getmsg(n)-> topic & t);        /* and topics match */
  169. }
  170.  
  171. /* Mark this message as deleted. */
  172.  
  173. killmsg(n)
  174. int n;
  175. {
  176.     if (ismsg(n,alltopics())) getmsg(n)-> topic= 0;
  177. }
  178.  
  179. /* Return all possible topic bits set. */
  180.  
  181. alltopics() {
  182. int i;
  183. WORD t;
  184.     
  185.     for (t= i= 0; i < BITSWORD; i++) 
  186.         if (*pup.topic[i].name) t |= (1 << i);
  187.     return(t);
  188. }
  189.  
  190. /* Convert message number (1 - N) into record number (0 - N). */
  191.  
  192. recd(n)
  193. int n;
  194. {
  195. int i;
  196.     i= ((n - 1 + pup.top) % pup.messages);
  197.     return(i);
  198. }
  199.  
  200. /* Return the oldest (highest) message number. (They run 1 - N) */
  201.  
  202. oldest_msg() {
  203.  
  204.     return(pup.messages);
  205. }
  206.  
  207. /* Return the newest message number. This is always the logical top
  208. of the pile, or 1. */
  209.  
  210. newest_msg() {
  211.  
  212.     return(1);
  213. }
  214.  
  215. /* Return a pointer to message header #n. */
  216.  
  217. struct _msg *getmsg(n)
  218. {
  219.     return(&msg[recd(n)]);
  220. }
  221.  
  222. /* Return a pointer to the next free message header. */
  223.  
  224. struct _msg *newmsg() {
  225.  
  226.     return(getmsg(oldest_msg()));
  227. }
  228.  
  229. /* Add this message to the message file. Since the message header is
  230. created in the bottom message header in the array, advancing it is the
  231. same as saving it. The message body must be written out however. Since 
  232. the file is preallocated, we dont have to check for write errors. (right) */
  233.  
  234. savemsg(lines)
  235. int lines;
  236. {
  237. int n,i;
  238. char *cp;
  239. long o;
  240.  
  241.     if (--pup.top < 0) 
  242.         pup.top= pup.messages - 1;    /* next message ... */
  243.     ++pup.msgnbr;                /* another message ... */
  244.  
  245.     msg[pup.top].topic_map= 0;        /* clear the map */
  246.     writehdr(pup.top);            /* write out the msg header, */
  247.  
  248. /* We must write out exactly (msgsize) bytes. */
  249.  
  250.     o= 0L + pup.top;
  251.     o *= pup.msgsize;
  252.     lseek(txtfile,o,0);
  253.     for (n= i= 0; i < lines; i++) {
  254.         cp= &text[i * caller.cols];    /* write each line of text */
  255.         write(txtfile,cp,strlen(cp));
  256.         n += strlen(cp);        /* bozo check: dont exceed max */
  257.         if (n >= pup.msgsize - 1) break;/* plus room for a terminator */
  258.     }
  259.  
  260.     n= pup.msgsize - n;            /* amt we need to fill out msg */
  261.     cp= text; for (i= n; i--;) *cp++= SUB;    /* fill with ^Zs */
  262.     write(txtfile,text,n);            /* pad it out */
  263. }
  264.  
  265. /* Write out the specified message header record. */
  266.  
  267. writehdr(n)
  268. int n;
  269. {
  270. long o;
  271.     o= 0L + n;
  272.     o *= sizeof(struct _msg);
  273.     lseek(msgfile,o,0);
  274.     write(msgfile,&msg[n],sizeof(struct _msg));
  275. }
  276.  
  277. /* Load message body #n into the text buffer. */
  278.  
  279. loadmsg(n)
  280. int n;
  281. {
  282. long o;
  283.  
  284.     o= 0L + recd(n);
  285.     o *= pup.msgsize;
  286.     lseek(txtfile,o,0);
  287.     read(txtfile,text,pup.msgsize);
  288. }
  289.