home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / fish / telecom / uucp_442 / src / dmail / load_mail.c < prev    next >
C/C++ Source or Header  |  1991-01-06  |  14KB  |  669 lines

  1.  
  2. /*
  3.  *  LOAD_MAIL.C
  4.  *
  5.  *  $Header: Beta:src/uucp/src/dmail/RCS/load_mail.c,v 1.1 90/02/02 12:03:35 dillon Exp Locker: dillon $
  6.  *
  7.  *  (C) Copyright 1985-1990 by Matthew Dillon,  All Rights Reserved.
  8.  *
  9.  *  file-io routines to scan the mail file and load required information.
  10.  *
  11.  *
  12.  *  Global Routines:    HOLD_LOAD()         hold on loading mail after change
  13.  *            NOHOLD_LOAD()       hold off.. load if changes
  14.  *            LOAD_CHANGES()      reload mail if changed
  15.  *            LOAD_MAIL()         load/reload mail
  16.  *            SAVE_FILE()         save mail items back to spool
  17.  *            CHECK_NEW_MAIL()    check for new mail
  18.  *            WRITE_FILE()        append mail items to a file
  19.  *            GET_EXTRA_OVR()     ret index of Field (create if not)
  20.  *            ADD_EXTRA()         add another field (reloads mail)
  21.  *            DELETE_EXTRA()      delete a field
  22.  *            GET_EXTRA()         ret index of Field, or error
  23.  *            M_SELECT()          select on current message list
  24.  *
  25.  *
  26.  *  Static Routines:    LOAD_HASH()         load hash table from fields list
  27.  *            FREE_ENTRY()        unload EVERYTHING
  28.  *            FREE_TABLE()        unload all Fields table
  29.  *            LOAD_FILE()         raw file loading/counting
  30.  *
  31.  *
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <sys/file.h>
  36. #include "dmail.h"
  37.  
  38. void do_flock();
  39. void free_table();
  40. void load_hash();
  41.  
  42. #define NOHOLD    0
  43. #define HOLD    1
  44.  
  45. #define NO_BASE     0
  46. #define NO_FIELDS   1
  47. #define ENTRY_OK    2
  48.  
  49. struct FIND Find[MAXTYPE + 1] = {
  50.     "From:"   , 5, 1, 0,
  51.     "To:"     , 3, 1, 0,
  52.     "Subject:", 8, 1, 0 };
  53.  
  54. static int  File_size;
  55. static int  changed, load_hold;
  56. static int  Hash[256];
  57.  
  58. static char *quo_quo = "";
  59.  
  60. void
  61. hold_load()
  62. {
  63.     load_hold = 1;
  64. }
  65.  
  66. void
  67. nohold_load()
  68. {
  69.     void load_changes();
  70.     load_hold = 0;
  71.     load_changes();
  72. }
  73.  
  74. void
  75. load_changes()
  76. {
  77.     if (changed  &&  !load_hold)
  78.     load_mail(Entries, 1);
  79. }
  80.  
  81. initial_load_mail()
  82. {
  83.     if (load_mail (0, 0) < 0)
  84.     return (-1);
  85.     return ((Entries) ? 1 : -1);
  86. }
  87.  
  88.  
  89. static
  90. load_mail(at, from0)
  91. {
  92.     FILE *fi;
  93.     int i, count, file_size;
  94.  
  95.     if (No_load_mail)
  96.     return (-1);
  97.     push_break();
  98.     load_hash();
  99.     if (from0)
  100.     free_table (0, HOLD);
  101.     else
  102.     free_table (at, NOHOLD);
  103.     fi = fopen (mail_file, "r+");
  104.     if (m_fi != NULL)
  105.     fclose (m_fi);
  106.     m_fi = fopen (mail_file, "r+");
  107.     if (fi == NULL  ||  m_fi == NULL) {
  108.     pop_break();
  109.     return (-1);
  110.     }
  111.     do_flock (fileno(m_fi), LOCK_EX);
  112.     if (at)
  113.     fseek (fi, Entry[at].fpos, 0);
  114.     else
  115.     fseek (fi, 0, 0);
  116.     count = Entries;
  117.     while (search_from(fi))
  118.     ++count;
  119.     if (Entries != count) {
  120.     if (!lmessage_overide)
  121.         printf ("%d Other Items loaded\n", count - Entries);
  122.     lmessage_overide = 0;
  123.     Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry) * (count + 1));
  124.     bzero (&Entry[Entries], sizeof(*Entry) * (count + 1 - Entries));
  125.     }
  126.     Entries = count;
  127.     for (i = at; i < Entries; ++i) {
  128.     Entry[i].no  = 0;
  129.     Entry[i].status = 0;
  130.     }
  131.     Entry[i].fpos = File_size = file_size = ftell (fi);
  132.     fclose (fi);
  133.     load_file ((from0) ? 0 : at);
  134.     if (file_size != File_size) {       /* Last entry incomplete?       */
  135.     free_table (Entries - 1, NOHOLD);
  136.     }
  137.     changed = 0;
  138.     if (SelAll)
  139.     m_select (Nulav, 0);
  140.     flock (fileno(m_fi), LOCK_UN);
  141.     pop_break();
  142.     return (1);
  143. }
  144.  
  145. void
  146. do_flock(fd, stat)
  147. {
  148.     if (flock(fd, stat | LOCK_NB) < 0) {
  149.     puts ("File in use, Waiting for lock");
  150.     flock (fd, stat);
  151.     puts ("Have lock");
  152.     }
  153. }
  154.  
  155. static
  156. load_file(at)
  157. int at;
  158. {
  159.     FILE *fi;
  160.     char *next, *ptr;
  161.     int i, bit, maxbit, len, count, havefrom;
  162.  
  163.     maxbit = 0;
  164.     for (i = 0; Find[i].search != NULL; ++i)
  165.     maxbit = (maxbit << 1) | 1;
  166.     fi = fopen (mail_file, "r");
  167.     count = -1;
  168.     havefrom = 0;
  169.     while (havefrom  ||  search_from (fi)) {
  170.     havefrom = 0;
  171.     if (++count >= Entries)
  172.         break;
  173.     len = strlen(Buf) - 1;
  174.     Buf[len] = '\0';
  175.     next = next_word(Buf);
  176.     len -= next - Buf;
  177.     Entry[count].fpos = ftell (fi);
  178.     Entry[count].from = malloc (len + 1);
  179.     bcopy (next, Entry[count].from, len + 1);
  180.  
  181.     /* SEARCH FIELD LIST */
  182.  
  183.     bit = 0;
  184.     if (XDebug)
  185.         printf ("No %d  ---------------------\n", count + 1);
  186.     while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
  187.         if (Buf[0] == '\n')
  188.         break;
  189.         if (isfrom(Buf)) {
  190.         havefrom = 1;
  191.         break;
  192.         }
  193.         len = strlen(Buf) - 1;
  194.         Buf[len] = '\0';
  195.         if (XDebug)
  196.         printf ("CHECK: %s  ", Buf);
  197.         next = next_word(Buf);
  198.         len -= next - Buf;
  199.         if (XDebug)
  200.         printf("HASH: %d\n", Hash[*(ubyte *)Buf]);
  201.         if (Hash[*(ubyte *)Buf] == 0)
  202.         continue;
  203.         if (Hash[*(ubyte *)Buf] > 0) {
  204.         i = Hash[*(ubyte *)Buf] & 0xff;
  205.         if (strncmp (Find[i].search, Buf, Find[i].len) == 0)
  206.             goto found;
  207.         continue;
  208.         }
  209.         for (i = -Hash[*(ubyte *)Buf] & 0xff; Find[i].search; ++i) {
  210.         if (strncmp (Find[i].search, Buf, Find[i].len) == 0)
  211.             goto found;
  212.         }
  213.         continue;
  214. found:
  215.         if (XDebug)
  216.         printf ("Found: %d %s\n", i, Buf);
  217.         if (Find[i].notnew == 0) {
  218.         Find[i].notnew = 1;
  219.         ptr = Buf;
  220.         while (*ptr  &&  *ptr != ':')
  221.             ++ptr;
  222.         ++ptr;
  223.         Find[i].search =
  224.             realloc (Find[i].search, ptr - Buf + 1);
  225.         strncpy (Find[i].search, Buf, ptr - Buf);
  226.         *(Find[i].search + (ptr - Buf)) = '\0';
  227.         Find[i].len = strlen(Find[i].search);
  228.         }
  229.         compile_field (Buf, fi);
  230.         Entry[count].fields[i] =
  231.             malloc (strlen(next) + 1);
  232.         strcpy (Entry[count].fields[i], next);
  233.         if ((bit |= (1 << i)) == maxbit)
  234.         break;
  235.     }
  236.     if (bit != maxbit) {
  237.         for (i = 0; Find[i].search != NULL; ++i) {
  238.         if (((1 << i) & bit) == 0) {
  239.             Entry[count].fields[i] = quo_quo;
  240.         }
  241.         }
  242.     }
  243.     }
  244.     File_size = ftell (fi);
  245.     fclose (fi);
  246.     return (1);
  247. }
  248.  
  249.  
  250. static void
  251. load_hash()
  252. {
  253.     int i, v, c;
  254.  
  255.     bzero (Hash, sizeof(Hash));
  256.     for (i = 0; Find[i].search; ++i) {
  257.     if (XDebug)
  258.         printf("LOADH %d %s\n", i, Find[i].search);
  259.  
  260.     c = *(ubyte *)Find[i].search;
  261.     v = Hash[c];
  262.  
  263.     if (v == 0) {
  264.         Hash[c] = i | 0x100;
  265.     } else {
  266.         if (v < 0)
  267.         v = -v;
  268.         if (i < (v & 0xFF))
  269.         v = i | 0x100;
  270.         Hash[c] = -v;
  271.     }
  272.     }
  273. }
  274.  
  275.  
  276. void
  277. free_entry()
  278. {
  279.     free_table(0, NOHOLD);
  280.     Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry));
  281.     bzero (Entry[0].fields, sizeof(Entry[0].fields));
  282.     File_size = Entries = 0;
  283.     Entry->status = Entry->no = Entry->fpos = Current = 0;
  284.     Listsize = 3;
  285.     if (m_fi) {
  286.     fclose (m_fi);
  287.     m_fi = NULL;
  288.     }
  289. }
  290.  
  291.  
  292. static void
  293. free_table(at, hold)
  294. {
  295.     int i, j;
  296.  
  297.     for (i = at; i < Entries; ++i) {
  298.     xfree (Entry[i].from);
  299.     for (j = 0; Find[j].search != NULL; ++j) {
  300.         if (Entry[i].fields[j] != quo_quo)
  301.         xfree (Entry[i].fields[j]);
  302.     }
  303.     }
  304.     Entries = (hold == HOLD) ? Entries : at;
  305.     File_size = (at) ? Entry[Entries].fpos : 0;
  306. }
  307.  
  308. static
  309. search_from(fi)
  310. FILE *fi;
  311. {
  312.     while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
  313.     if (isfrom (Buf))
  314.         return (1);
  315.     }
  316.     return (0);
  317. }
  318.  
  319.  
  320. save_file(reload, mark, notmark)
  321. {
  322.     FILE *fiscr;
  323.     int fdscr;
  324.     int i, count;
  325.     char scratch[64];
  326.  
  327.     for (i = 0; i < Entries; ++i) {
  328.     if ((Entry[i].status & mark) != mark  ||
  329.         (~Entry[i].status & notmark) != notmark)
  330.         break;
  331.     }
  332.     if (i == Entries) {
  333.     m_select (Nulav, M_RESET);
  334.     puts ("No Changes Made");
  335.     return (Entries);
  336.     }
  337.     if (m_fi == NULL)
  338.     return (-1);
  339.     count = 0;
  340.     sprintf(scratch, "t:dmail%d", getpid());
  341.     do_flock (fileno(m_fi), LOCK_EX);
  342.     fdscr = open (scratch, O_RDWR | O_CREAT | O_TRUNC, MAILMODE);
  343. #ifdef AMIGA        /*    fix bug in Lattice C fdopen */
  344.     fiscr = fopen("nil:", "w");
  345.     fclose(fiscr);
  346. #endif
  347.     fiscr = fdopen (fdscr, "a+");
  348.     for (i = 0; i < Entries; ++i) {
  349.     if ((Entry[i].status & mark) == mark  &&
  350.         (~Entry[i].status & notmark) == notmark) {
  351.         ++count;
  352.         fputs ("From ", fiscr);
  353.         fputs (Entry[i].from, fiscr);
  354.         putc ('\n', fiscr);
  355.         fseek (m_fi, Entry[i].fpos, 0);
  356.         while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
  357.         if (isfrom(Buf))
  358.             break;
  359.         fputs (Buf, fiscr);
  360.         }
  361.     }
  362.     }
  363.  
  364.     /*
  365.      *    If new mail has come in, append to the scratch file as well.
  366.      *    NOTE: for some machines like the Amiga an already open descriptor
  367.      *          does not know about any new data, thus we cannot simply
  368.      *          use m_fi .
  369.      */
  370.  
  371.     {
  372.     FILE *fi;
  373.  
  374.     if (fi = fopen(mail_file, "r")) {
  375.         fseek(fi, File_size, 0);
  376.         while (fgets(Buf, MAXFIELDSIZE, fi))
  377.         fputs(Buf, fiscr);
  378.         fclose(fi);
  379.     }
  380.     }
  381.  
  382.     /* Write scratch file back to mail file, or try to */
  383.  
  384.     fflush (fiscr);
  385.     fflush (m_fi);
  386.  
  387.     lseek (fdscr, 0 ,0);
  388. #ifdef UNIX
  389.     lseek (fileno(m_fi), 0, 0);
  390.     while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
  391.     write (fileno(m_fi), Buf, i);
  392.     ftruncate (fileno(m_fi), lseek (fileno(m_fi), 0, 1));
  393. #else
  394.     fclose(m_fi);
  395.     if (m_fi = fopen (mail_file, "w")) {
  396.     while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
  397.         write (fileno(m_fi), Buf, i);
  398.     fclose(m_fi);
  399.     m_fi = fopen (mail_file, "r+");
  400.     }
  401.     if (m_fi == NULL) {
  402.     printf("Unable to re-open %s !\n", mail_file);
  403.     return(-1);
  404.     }
  405. #endif
  406.     if (lseek (fileno(m_fi), 0, 2) == 0  &&  !reload) {
  407.     if (Did_cd == 0) {
  408.         fclose(m_fi);
  409.         m_fi = NULL;
  410.         if (unlink (mail_file) == 0)
  411.         printf ("%s  Removed\n", mail_file);
  412.         else
  413.         printf ("0 messages left in %s\n", mail_file);
  414.     }
  415.     }
  416.     fclose (fiscr);
  417.     if (m_fi)
  418.     fclose (m_fi);          /* Effectively unlocks the descriptor */
  419.     m_fi = NULL;
  420.     unlink (scratch);
  421.     if (reload) {
  422.     free_entry();
  423.     load_mail(0, 0);
  424.     }
  425.     m_select (Nulav, M_RESET);
  426.     return (count);
  427. }
  428.  
  429. void
  430. check_new_mail()
  431. {
  432.     FILE *fi;
  433.  
  434.     push_break();
  435.     if (m_fi == NULL) {
  436.     m_fi = fopen (mail_file, "r+");
  437.     if (m_fi == NULL) {
  438.         pop_break();
  439.         return;
  440.     }
  441.     }
  442.     if (fi = fopen(mail_file, "r")) {
  443.     if (fseek(fi, 0, 2) < 0 || ftell(fi) != File_size)
  444.         load_mail(Entries, 1);
  445.     fclose(fi);
  446.     }
  447.     pop_break();
  448. }
  449.  
  450.  
  451. write_file(file, modes, mark, notmark)
  452. char *file;
  453. {
  454.     int i, fd = 1, notopen = 1;
  455.     FILE *fi = NULL;
  456.  
  457.     for (i = 0; i < Entries; ++i) {
  458.     if ((Entry[i].status & mark) == mark  &&
  459.         (~Entry[i].status & notmark) == notmark) {
  460.         if (notopen) {
  461.         notopen = 0;
  462.         fd = open (file, O_APPEND | O_WRONLY | modes, MAILMODE);
  463.         if (fd < 0)
  464.             return (-1);
  465.         do_flock (fd, LOCK_EX);
  466. #ifdef AMIGA        /*    fix bug in Lattice C fdopen */
  467.         fi = fopen("nil:", "w");
  468.         fclose(fi);
  469. #endif
  470.         fi = fdopen (fd, "a");
  471.  
  472. #ifdef NOTDEF
  473.         if (fi) {
  474.             printf("ptr     %08lx\n", fi->_ptr);
  475.             printf("rcnt    %08lx\n", fi->_rcnt);
  476.             printf("wcnt    %08lx\n", fi->_wcnt);
  477.             printf("base    %08lx\n", fi->_base);
  478.             printf("size    %08lx\n", fi->_size);
  479.             printf("flag    %08lx\n", fi->_flag);
  480.             printf("file    %08lx\n", fi->_file);
  481.             return(-1);
  482.         }
  483. #endif
  484.         }
  485.         fputs ("From ", fi);
  486.         fputs (Entry[i].from, fi);
  487.         putc ('\n', fi);
  488.         if (m_fi) {
  489.         fseek (m_fi, Entry[i].fpos, 0);
  490.         while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
  491.             if (isfrom(Buf))
  492.             break;
  493.             fputs (Buf, fi);
  494.         }
  495.         }
  496.     }
  497.     }
  498.     if (!notopen)
  499.     fclose (fi);
  500.     return (1);
  501. }
  502.  
  503. /*
  504.  * Basic scheme: Each entry has a fields list.    Each entry in the fields list
  505.  * is guarenteed to be a valid malloc'd pointer (except some may be set to
  506.  * quo_quo).
  507.  *
  508.  * The find[] struct array holds the field name and length, the index
  509.  * corresponding to the index into the field[] in an Entry.
  510.  *
  511.  * The header and width arrays hold the list format.
  512.  */
  513.  
  514. get_extra_ovr(str)
  515. char *str;
  516. {
  517.     register int i;
  518.  
  519.     i = get_extra (str);
  520.     if (i < 0) {
  521.     i = add_extra (str);
  522.     load_changes();
  523.     }
  524.     return (i);
  525. }
  526.  
  527.  
  528. /*
  529.  * If there's room to add it, append to end.
  530.  * Else Find oldest field which doesn't exist in the setlist and replace it
  531.  *  with the new one.
  532.  */
  533.  
  534. add_extra(str)
  535. char *str;
  536. {
  537.     register int i, j, j_age, k;
  538.  
  539.     for (i = EXSTART; i < MAXTYPE; ++i) {
  540.     if (Find[i].search == NULL)
  541.         break;
  542.     ++Find[i].age;
  543.     }
  544.     if (i == MAXTYPE) {                 /* No room to add onto end */
  545.     j = j_age = -1;
  546.     for (i = EXSTART; i < MAXTYPE; ++i) {
  547.         for (k = 0; k < Listsize; ++k) {
  548.         if (i == header[k])
  549.             break;
  550.         }
  551.         if (k == Listsize  &&  Find[i].age > j_age) {
  552.         j = i;
  553.         j_age = Find[i].age;
  554.         }
  555.     }
  556.     i = j;
  557.     }
  558.     if (i < 0)
  559.     return (-1);
  560.     push_break();
  561.     if (Find[i].search != NULL)
  562.     xfree (Find[i].search);
  563.     Find[i].len = strlen(str);
  564.     Find[i].search = malloc (Find[i].len + 1);
  565.     Find[i].notnew = Find[i].age = 0;
  566.     strcpy (Find[i].search, str);
  567.     changed = 1;
  568.     for (j = 0; j < Entries; ++j) {
  569.     if (Entry[j].fields[i] && Entry[j].fields[i] != quo_quo)
  570.         xfree (Entry[j].fields[i]);
  571.     Entry[j].fields[i] = quo_quo;
  572.     }
  573.     pop_break();
  574.     return (i);
  575. }
  576.  
  577.  
  578. get_extra(str)
  579. char *str;
  580. {
  581.     int i;
  582.  
  583.     for (i = 0; Find[i].search; ++i) {
  584.     if (strncmp (str, Find[i].search, strlen(str)) == 0) {
  585.         Find[i].age = 0;
  586.         return (i);
  587.     }
  588.     }
  589.     return (-1);
  590. }
  591.  
  592.  
  593. m_select(sav, mode)
  594. register char *sav[];
  595. {
  596.     char *ptr, *dest;
  597.     char l_map[256];
  598.     int idx[MAXLIST], ix = 0;
  599.     int ok, not, len, scr;
  600.     register int i, j, avi;
  601.  
  602.     for (i = 0;i < 256; ++i)
  603.     l_map[i] = i;
  604.     for (i = 'A'; i <= 'Z'; ++i)
  605.     l_map[i] += 'a' - 'A';
  606.     hold_load();
  607.     i = 0;
  608.     idx[ix++] = get_extra_ovr (sav[i++]);
  609.     for (; sav[i]; ++i) {
  610.     if (strcmp (sav[i], ",") == 0  &&  sav[i + 1])
  611.         idx[ix++] = get_extra_ovr (sav[++i]);
  612.     }
  613.     idx[ix] = -1;
  614.     nohold_load();
  615.     j = 1;
  616.     push_break();
  617.     for (i = 0; i < Entries; ++i) {
  618.     if (mode == M_CONT  &&  Entry[i].no == 0)
  619.         continue;
  620.     ix = ok = 0;
  621.     avi = 1;
  622.     while ((ptr = sav[avi]) != NULL) {
  623.         if (ptr[0] == ','  &&  ptr[1] == '\0' && sav[avi+1]) {
  624.         ++ix;
  625.         avi += 2;
  626.         continue;
  627.         }
  628.         if (not = (*ptr == '!'))
  629.         ++ptr;
  630.         len = strlen (ptr);
  631.         dest = Entry[i].fields[idx[ix]];
  632.         if (*ptr == '\0') {
  633.         ok = 1;
  634.         goto gotit;
  635.         }
  636.         while (*dest) {
  637.         scr = 0;
  638.         while (l_map[dest[scr]] == l_map[ptr[scr]] && ptr[scr])
  639.             ++scr;
  640.         if (ptr[scr] == '\0') {
  641.             ok = 1;
  642.             goto gotit;
  643.         }
  644.         ++dest;
  645.         }
  646.         ++avi;
  647.     }
  648. gotit:
  649.     Entry[i].no = (ok ^ not) ? j++ : 0;
  650.     }
  651.     pop_break();
  652.     if (Current < 0)
  653.     Current = 0;
  654.     if (Entries) {
  655.     if (Entry[Current].no == 0) {
  656.         Current = indexof (1);
  657.         if (Current < 0) {
  658.          Current = 0;
  659.          return (-1);
  660.         }
  661.     }
  662.     } else {
  663.     Current = -1;
  664.     }
  665.     return (1);
  666. }
  667.  
  668.  
  669.