home *** CD-ROM | disk | FTP | other *** search
- /*#define PROCDEBUG*/
- /*
- * LOAD_MAIL.C
- *
- * (C) Copyright 1985-1990 by Matthew Dillon, All Rights Reserved.
- *
- * file-io routines to scan the mail file and load required information.
- *
- *
- * Global Routines: HOLD_LOAD() hold on loading mail after change
- * NOHOLD_LOAD() hold off.. load if changes
- * LOAD_CHANGES() reload mail if changed
- * LOAD_MAIL() load/reload mail
- * SAVE_FILE() save mail items back to spool
- * CHECK_NEW_MAIL() check for new mail
- * WRITE_FILE() append mail items to a file
- * GET_EXTRA_OVR() ret index of Field (create if not)
- * ADD_EXTRA() add another field (reloads mail)
- * DELETE_EXTRA() delete a field
- * GET_EXTRA() ret index of Field, or error
- * M_SELECT() select on current message list
- *
- *
- * Static Routines: LOAD_HASH() load hash table from fields list
- * FREE_ENTRY() unload EVERYTHING
- * FREE_TABLE() unload all Fields table
- * LOAD_FILE() raw file loading/counting
- *
- *
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <sys/file.h>
- #include <time.h>
- #include "dmail.h"
-
- #ifdef PROCDEBUG
- #define PROC(x) static const char _proc [] = { x }; static const time_t _tt; time (&_tt); printf ("%s: enter\n", _proc)
- #define D(x) printf ("%s: ", _proc); printf x
- #define EXIT(x) printf ("%s: exit (elapsed %ld) ", _proc, (time (NULL) - _tt)); printf x
- #else
- #define PROC(x)
- #define D(x)
- #define EXIT(x)
- #endif
-
- #ifndef LOCK_EX
- #define LOCK_SH 0x01 /* shared file lock */
- #define LOCK_EX 0x02 /* exclusive file lock */
- #define LOCK_NB 0x04 /* don't block when locking */
- #define LOCK_UN 0x08 /* unlock file */
- #endif
-
- Prototype void hold_load (void);
- Prototype void nohold_load (void);
- Prototype void load_changes (void);
- Prototype int initial_load_mail (void);
- Prototype void do_flock (int, int);
- Prototype void free_entry (void);
- Prototype int save_file (int, int, int);
- Prototype void check_new_mail (void);
- Prototype int write_file (char *, int, int, int);
- Prototype int get_extra_ovr (char *);
- Prototype int add_extra (char *);
- Prototype int get_extra (char *);
- Prototype int m_select (register char **, int);
-
- static int load_mail (int at, int from0);
- static int load_file (int at);
- static void load_hash (void);
- static void free_table (int at, int hold);
- static int search_from (FILE *fi);
-
- #define NOHOLD 0
- #define HOLD 1
-
- #define NO_BASE 0
- #define NO_FIELDS 1
- #define ENTRY_OK 2
-
- struct FIND
- Find [MAXTYPE + 1] = {
- "From:" , 5, 1, 0,
- "To:" , 3, 1, 0,
- "Subject:", 8, 1, 0,
- "Cc:" , 3, 1, 0,
- "Date:" , 5, 1, 0
- };
-
- static int
- File_size = 0,
- changed = 0,
- load_hold = 0,
- Hash [256] = { 0 };
-
- static char
- *quo_quo = "";
-
- void
- hold_load (void)
- {
- PROC ("hold_load");
-
- load_hold = 1;
-
- EXIT (("\n"));
- return;
- }
-
- void
- nohold_load (void)
- {
- PROC ("nohold_load");
-
- load_hold = 0;
- load_changes ();
-
- EXIT (("\n"));
- return;
- }
-
- void
- load_changes (void)
- {
- PROC ("load_changes");
-
- if (changed && !load_hold)
- load_mail (Entries, 1);
-
- EXIT (("\n"));
- return;
- }
-
- int
- initial_load_mail (void)
- {
- PROC ("initial_load_mail");
-
- if (load_mail (0, 0) < 0) {
- EXIT (("-1, load_mail (0, 0) < 0\n"));
- return -1;
- }
-
- EXIT (("%ld, Entries %ld\n", Entries ? 1 : -1, Entries));
- return Entries ? 1 : -1;
- }
-
- static int
- load_mail (int at, int from0)
- {
- FILE
- *fi;
- int
- i,
- count,
- file_size;
-
- PROC ("load_mail");
- D (("at %ld, from0 %ld\n", at, from0));
-
- if (No_load_mail) {
- EXIT (("-1, NoLoadMail\n"));
- return -1;
- }
- push_break ();
-
- load_hash ();
- if (from0)
- free_table (0, HOLD);
- else
- free_table (at, NOHOLD);
-
- fi = fopen (mail_file, "r+");
-
- if (m_fi)
- fclose (m_fi);
- m_fi = fopen (mail_file, "r+");
-
- if (fi == NULL || m_fi == NULL) {
- pop_break ();
- EXIT (("-1, fi 0x%lx m_fi 0x%lx\n", fi, m_fi));
- return -1;
- }
-
- do_flock (fileno (m_fi), LOCK_EX);
- if (at) {
- D (("fseek (0x%lx, %ld, 0)\n", fi, Entry [at].fpos));
- fseek (fi, Entry [at].fpos, 0);
- }
- #if 0
- else {
- D (("fseek (0x%lx, 0, 0)\n", fi, 0, 0));
- fseek (fi, 0, 0);
- }
- #endif
-
- count = Entries;
- while (search_from (fi))
- ++count;
-
- if (Entries != count) {
- if (!lmessage_overide)
- printf ("%d Other Items loaded\n", count - Entries);
- lmessage_overide = 0;
- Entry = (struct ENTRY *) realloc (Entry, sizeof (*Entry) * (count + 1));
- bzero (&Entry [Entries], sizeof (*Entry) * (count + 1 - Entries));
- }
- Entries = count;
-
- for (i = at; i < Entries; ++i) {
- Entry [i].no = 0;
- Entry [i].status = 0;
- }
- Entry [i].fpos = File_size = file_size = ftell (fi);
- D (("ftell (0x%lx) == %ld\n", fi, File_size));
- fclose (fi);
-
- load_file ((from0) ? 0 : at);
- if (file_size != File_size) { /* Last entry incomplete? */
- free_table (Entries - 1, NOHOLD);
- }
- changed = 0;
- if (SelAll)
- m_select (Nulav, 0);
- flock (fileno (m_fi), LOCK_UN);
- pop_break ();
-
- EXIT (("1\n"));
- return 1;
- }
-
- void
- do_flock (int fd, int stat)
- {
- PROC ("do_flock");
-
- #ifdef AMIGA
- /* FIXME - use OwnDevUnit */
- #else
- if (flock (fd, stat | LOCK_NB) < 0) {
- puts ("File in use, Waiting for lock");
- flock (fd, stat);
- puts ("Have lock");
- }
- #endif
- EXIT (("\n"));
- return;
- }
-
- static int
- load_file (int at)
- {
- FILE
- *fi;
- char
- *next,
- *ptr;
- int
- i,
- bit,
- maxbit,
- len,
- count,
- havefrom;
- extern int
- _bufsiz;
-
- PROC ("load_file");
- D (("at %ld _bufsiz %ld\n", at, _bufsiz));
-
- maxbit = 0;
- for (i = 0; Find [i].search != NULL; ++i)
- maxbit = (maxbit << 1) | 1;
- fi = fopen (mail_file, "r");
- count = -1;
- havefrom = 0;
- while (havefrom || search_from (fi)) {
- havefrom = 0;
- if (++count >= Entries)
- break;
- len = strlen (Buf) - 1;
- Buf [len] = '\0';
- next = next_word (Buf);
- len -= next - Buf;
- Entry [count].fpos = ftell (fi);
- Entry [count].from = xmalloc (len + 1);
- /*D (("ftell (0x%lx) == %ld\n", fi, Entry [count].fpos));*/
- bcopy (next, Entry [count].from, len + 1);
-
- /* SEARCH FIELD LIST */
-
- bit = 0;
- if (XDebug)
- printf ("No %d ---------------------\n", count + 1);
- while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
- if (Buf [0] == '\n')
- break;
- if (isfrom (Buf)) {
- havefrom = 1;
- break;
- }
- len = strlen (Buf) - 1;
- Buf [len] = '\0';
- if (XDebug)
- printf ("CHECK: %s ", Buf);
- next = next_word (Buf);
- len -= next - Buf;
- if (XDebug)
- printf ("HASH: %d\n", Hash [*(ubyte *) Buf]);
- if (Hash [*(ubyte *) Buf] == 0)
- continue;
- if (Hash [*(ubyte *) Buf] > 0) {
- i = Hash [*(ubyte *) Buf] & 0xff;
- if (strncmp (Find [i].search, Buf, Find [i].len) == 0)
- goto found;
- continue;
- }
- for (i = -Hash [*(ubyte *) Buf] & 0xff; Find [i].search; ++i) {
- if (strncmp (Find [i].search, Buf, Find [i].len) == 0)
- goto found;
- }
- continue;
- found:
- if (XDebug)
- printf ("Found: %d %s\n", i, Buf);
- if (Find [i].notnew == 0) {
- Find [i].notnew = 1;
- ptr = Buf;
- while (*ptr && *ptr != ':')
- ++ptr;
- ++ptr;
- Find [i].search =
- realloc (Find [i].search, ptr - Buf + 1);
- strncpy (Find [i].search, Buf, ptr - Buf);
- *(Find [i].search + (ptr - Buf)) = '\0';
- Find [i].len = strlen (Find [i].search);
- }
- compile_field (Buf, fi);
- Entry [count].fields [i] =
- xmalloc (strlen (next) + 1);
- strcpy (Entry [count].fields [i], next);
- if ((bit |= (1 << i)) == maxbit)
- break;
- }
- if (bit != maxbit) {
- for (i = 0; Find [i].search; ++i) {
- if (((1 << i) & bit) == 0) {
- Entry [count].fields [i] = quo_quo;
- }
- }
- }
- }
-
- File_size = ftell (fi);
- D (("ftell (0x%lx) == %ld\n", fi, File_size));
- fclose (fi);
-
- EXIT (("1\n"));
- return 1;
- }
-
- static void
- load_hash (void)
- {
- int
- i,
- v,
- c;
-
- PROC ("load_hash");
-
- bzero (Hash, sizeof (Hash));
- for (i = 0; Find [i].search; ++i) {
- if (XDebug)
- printf ("LOADH %d %s\n", i, Find [i].search);
-
- c = *(ubyte *) Find [i].search;
- v = Hash[c];
-
- if (v == 0) {
- Hash [c] = i | 0x100;
- }
- else {
- if (v < 0)
- v = -v;
- if (i < (v & 0xFF))
- v = i | 0x100;
- Hash [c] = -v;
- }
- }
-
- EXIT (("\n"));
- return;
- }
-
- void
- free_entry (void)
- {
- /*PROC ("free_entry");*/
-
- free_table (0, NOHOLD);
- Entry = (struct ENTRY *) realloc (Entry, sizeof (*Entry));
- bzero (Entry[0].fields, sizeof (Entry [0].fields));
- File_size = Entries = 0;
- Entry->status = Entry->no = Entry->fpos = Current = 0;
- Listsize = 3;
- if (m_fi) {
- fclose (m_fi);
- m_fi = NULL;
- }
- /*EXIT (("\n"));*/
- return;
- }
-
- static void
- free_table (int at, int hold)
- {
- int
- i,
- j;
- /*PROC ("free_table");*/
-
- for (i = at; i < Entries; ++i) {
- xfree (Entry [i].from);
- for (j = 0; Find [j].search != NULL; ++j) {
- if (Entry [i].fields [j] != quo_quo)
- xfree (Entry [i].fields [j]);
- }
- }
- Entries = (hold == HOLD) ? Entries : at;
- File_size = at ? Entry [Entries].fpos : 0;
-
- /*EXIT (("\n"));*/
- return;
- }
-
- static int
- search_from (FILE *fi)
- {
- while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
- if (isfrom (Buf)) {
- return 1;
- }
- }
-
- return 0;
- }
-
- int
- save_file (int reload, int mark, int notmark)
- {
- FILE
- *fiscr;
- int
- fdscr,
- i,
- count;
- char
- scratch [64];
-
- PROC ("save_file");
- D (("reload %ld, mark %ld, notmark %ld\n", reload, mark, notmark));
-
- for (i = 0; i < Entries; ++i) {
- if ((Entry[i].status & mark) != mark || (~Entry[i].status & notmark) != notmark)
- break;
- }
- if (i == Entries) {
- m_select (Nulav, M_RESET);
- printf ("No Changes Made\n");
- return Entries;
- }
-
- if (m_fi == NULL) {
- EXIT (("-1, no open m_fi\n"));
- return -1;
- }
-
- count = 0;
- sprintf (scratch, "t:dmail%d", getpid());
- do_flock (fileno (m_fi), LOCK_EX);
- fdscr = open (scratch, O_RDWR | O_CREAT | O_TRUNC, MAILMODE);
- #ifndef _DCC
- #ifdef AMIGA /* fix bug in Lattice C fdopen */
- fiscr = fopen ("nil:", "w");
- fclose (fiscr);
- #endif
- #endif
- fiscr = fdopen (fdscr, "a+");
- for (i = 0; i < Entries; ++i) {
- if ((Entry[i].status & mark) == mark &&
- (~Entry[i].status & notmark) == notmark) {
- ++count;
- fputs ("From ", fiscr);
- fputs (Entry[i].from, fiscr);
- putc ('\n', fiscr);
- D (("fseek (0x%lx, %ld, 0)\n", m_fi, Entry [i].fpos));
- fseek (m_fi, Entry [i].fpos, 0);
- while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
- if (isfrom (Buf))
- break;
- fputs (Buf, fiscr);
- }
- }
- }
-
- /*
- * If new mail has come in, append to the scratch file as well.
- * NOTE: for some machines like the Amiga an already open descriptor
- * does not know about any new data, thus we cannot simply
- * use m_fi .
- */
-
- {
- FILE
- *fi;
-
- if (fi = fopen (mail_file, "r")) {
- D (("fseek (0x%lx, %ld, 0)\n", fi, File_size));
- fseek (fi, File_size, 0);
- while (fgets (Buf, MAXFIELDSIZE, fi))
- fputs (Buf, fiscr);
- fclose (fi);
- }
- }
-
- /* Write scratch file back to mail file, or try to */
-
- fflush (fiscr);
- fflush (m_fi);
-
- D (("lseek (%ld, 0, 0)\n", fdscr));
- lseek (fdscr, 0 ,0);
- #ifdef UNIX
- lseek (fileno(m_fi), 0, 0);
- while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
- write (fileno(m_fi), Buf, i);
- ftruncate (fileno(m_fi), lseek (fileno(m_fi), 0, 1));
- #else
- fclose (m_fi);
- if (m_fi = fopen (mail_file, "w")) {
- while ((i = read (fdscr, Buf, MAXFIELDSIZE)) > 0)
- write (fileno (m_fi), Buf, i);
- fclose (m_fi);
- m_fi = fopen (mail_file, "r+");
- }
- if (m_fi == NULL) {
- printf ("Unable to re-open %s !\n", mail_file);
- EXIT (("-1, can't reopen %s\n", mail_file));
- return -1;
- }
- #endif
- D (("lseek (fileno (0x%lx), 0, 2)\n", m_fi));
- if (lseek (fileno (m_fi), 0, 2) == 0 && !reload) {
- if (Did_cd == 0) {
- fclose(m_fi);
- m_fi = NULL;
- if (unlink (mail_file) == 0)
- printf ("%s Removed\n", mail_file);
- else
- printf ("0 messages left in %s\n", mail_file);
- }
- }
- fclose (fiscr);
-
- if (m_fi)
- fclose (m_fi); /* Effectively unlocks the descriptor */
- m_fi = NULL;
-
- unlink (scratch);
-
- if (reload) {
- free_entry ();
- load_mail (0, 0);
- }
- m_select (Nulav, M_RESET);
-
- EXIT (("%ld\n", count));
- return (count);
- }
-
- void
- check_new_mail (void)
- {
- FILE
- *fi;
-
- PROC ("check_new_mail");
-
- push_break ();
-
- if (m_fi == NULL) {
- m_fi = fopen (mail_file, "r+");
- if (m_fi == NULL) {
- pop_break ();
- EXIT (("no m_fi\n"));
- return;
- }
- }
-
- if (fi = fopen (mail_file, "r")) {
- D (("fseek (0x%lx, 0, 2), ftell (0x%lx) == %ld\n", fi, fi, ftell (fi)));
- if (fseek (fi, 0, 2) < 0 || ftell (fi) != File_size)
- load_mail (Entries, 1);
- fclose (fi);
- }
-
- pop_break ();
-
- EXIT (("\n"));
- return;
- }
-
- int
- write_file (char *file, int modes, int mark, int notmark)
- {
- int
- i,
- fd = 1,
- notopen = 1;
- FILE
- *fi = NULL;
-
- PROC ("write_file");
- D (("file %s, modes 0%o, mark %ld, notmark %ld\n",
- file, modes, mark, notmark));
-
- for (i = 0; i < Entries; ++i) {
- if ((Entry[i].status & mark) == mark &&
- (~Entry[i].status & notmark) == notmark) {
- if (notopen) {
- notopen = 0;
- fd = open (file, O_APPEND | O_WRONLY | modes, MAILMODE);
- if (fd < 0) {
- EXIT (("-1, can't open %s\n", file));
- return -1;
- }
- do_flock (fd, LOCK_EX);
- #ifndef _DCC
- #ifdef AMIGA /* fix bug in Lattice C fdopen */
- fi = fopen ("nil:", "w");
- fclose (fi);
- #endif
- #endif
- fi = fdopen (fd, "a");
- }
- fputs ("From ", fi);
- fputs (Entry [i].from, fi);
- putc ('\n', fi);
- if (m_fi) {
- D (("fseek (0x%lx, %ld, 0)\n", m_fi, Entry [i].fpos));
- fseek (m_fi, Entry [i].fpos, 0);
- while (fgets (Buf, MAXFIELDSIZE, m_fi) != NULL) {
- if (isfrom (Buf))
- break;
- fputs (Buf, fi);
- }
- }
- }
- }
-
- if (!notopen)
- fclose (fi);
-
- EXIT (("1\n"));
- return 1;
- }
-
- /*
- * Basic scheme: Each entry has a fields list. Each entry in the fields list
- * is guarenteed to be a valid malloc'd pointer (except some may be set to
- * quo_quo).
- *
- * The find[] struct array holds the field name and length, the index
- * corresponding to the index into the field[] in an Entry.
- *
- * The header and width arrays hold the list format.
- */
-
- int
- get_extra_ovr (char *str)
- {
- register int
- i;
-
- PROC ("get_extra_ovr");
-
- i = get_extra (str);
- if (i < 0) {
- i = add_extra (str);
- load_changes ();
- }
-
- EXIT (("\n"));
- return i;
- }
-
- /*
- * If there's room to add it, append to end.
- * Else Find oldest field which doesn't exist in the setlist and replace it
- * with the new one.
- */
-
- int
- add_extra (char *str)
- {
- register int
- i,
- j,
- j_age,
- k;
-
- PROC ("add_extra");
-
- for (i = EXSTART; i < MAXTYPE; ++i) {
- if (Find [i].search == NULL)
- break;
- ++Find [i].age;
- }
- if (i == MAXTYPE) { /* No room to add onto end */
- j = j_age = -1;
- for (i = EXSTART; i < MAXTYPE; ++i) {
- for (k = 0; k < Listsize; ++k) {
- if (i == header [k])
- break;
- }
- if (k == Listsize && Find [i].age > j_age) {
- j = i;
- j_age = Find [i].age;
- }
- }
- i = j;
- }
- if (i < 0) {
- EXIT (("-1\n"));
- return -1;
- }
-
- push_break ();
-
- if (Find [i].search)
- xfree (Find [i].search);
- Find [i].len = strlen (str);
- Find [i].search = xmalloc (Find [i].len + 1);
- Find [i].notnew = Find [i].age = 0;
- strcpy (Find [i].search, str);
- changed = 1;
- D (("set changed = 1\n"));
- for (j = 0; j < Entries; ++j) {
- if (Entry [j].fields [i] && Entry [j].fields [i] != quo_quo)
- xfree (Entry [j].fields [i]);
- Entry [j].fields [i] = quo_quo;
- }
-
- pop_break ();
-
- EXIT (("%ld\n", i));
- return i;
- }
-
- int
- get_extra (char *str)
- {
- int
- len = strlen (str),
- i;
-
- PROC ("get_extra");
- D (("string '%s' (len %ld)\n", str, len));
-
- for (i = 0; Find [i].search; ++i) {
- if (strncmp (str, Find [i].search, len) == 0) {
- Find [i].age = 0;
-
- EXIT (("%ld (found '%s')\n", i, str));
- return i;
- }
- }
-
- EXIT (("-1 (not found '%s')\n", str));
- return -1;
- }
-
- int
- m_select (register char **sav, int mode)
- {
- char
- *ptr,
- *dest,
- l_map [256];
- int
- idx [MAXLIST],
- ix = 0,
- ok,
- not,
- len,
- scr;
- register int
- i,
- j,
- avi;
-
- PROC ("m_select");
-
- for (i = 0;i < 256; ++i)
- l_map[i] = i;
- for (i = 'A'; i <= 'Z'; ++i)
- l_map[i] += 'a' - 'A';
-
- hold_load ();
- i = 0;
- idx [ix++] = get_extra_ovr (sav [i++]);
- for (; sav[i]; ++i) {
- if (strcmp (sav [i], ",") == 0 && sav [i + 1])
- idx [ix++] = get_extra_ovr (sav [++i]);
- }
- idx [ix] = -1;
- nohold_load ();
-
- j = 1;
- push_break ();
- for (i = 0; i < Entries; ++i) {
- if (mode == M_CONT && Entry [i].no == 0)
- continue;
- ix = ok = 0;
- avi = 1;
- while ((ptr = sav [avi]) != NULL) {
- if (ptr [0] == ',' && ptr [1] == '\0' && sav [avi + 1]) {
- ++ix;
- avi += 2;
- continue;
- }
- if (not = (*ptr == '!'))
- ++ptr;
- len = strlen (ptr);
- dest = Entry [i].fields [idx [ix]];
- if (*ptr == '\0') {
- ok = 1;
- goto gotit;
- }
- while (*dest) {
- scr = 0;
- while (l_map [dest [scr]] == l_map [ptr [scr]] && ptr [scr])
- ++scr;
- if (ptr [scr] == '\0') {
- ok = 1;
- goto gotit;
- }
- ++dest;
- }
- ++avi;
- }
- gotit:
- Entry [i].no = (ok ^ not) ? j++ : 0;
- }
-
- pop_break ();
-
- if (Current < 0)
- Current = 0;
- if (Entries) {
- if (Entry [Current].no == 0) {
- Current = indexof (1);
- if (Current < 0) {
- Current = 0;
-
- EXIT (("-1\n"));
- return -1;
- }
- }
- }
- else {
- Current = -1;
- }
-
- EXIT (("1\n"));
- return 1;
- }
-