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 >
Wrap
C/C++ Source or Header
|
1991-01-06
|
14KB
|
669 lines
/*
* LOAD_MAIL.C
*
* $Header: Beta:src/uucp/src/dmail/RCS/load_mail.c,v 1.1 90/02/02 12:03:35 dillon Exp Locker: dillon $
*
* (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 <sys/file.h>
#include "dmail.h"
void do_flock();
void free_table();
void load_hash();
#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 };
static int File_size;
static int changed, load_hold;
static int Hash[256];
static char *quo_quo = "";
void
hold_load()
{
load_hold = 1;
}
void
nohold_load()
{
void load_changes();
load_hold = 0;
load_changes();
}
void
load_changes()
{
if (changed && !load_hold)
load_mail(Entries, 1);
}
initial_load_mail()
{
if (load_mail (0, 0) < 0)
return (-1);
return ((Entries) ? 1 : -1);
}
static
load_mail(at, from0)
{
FILE *fi;
int i, count, file_size;
if (No_load_mail)
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 != NULL)
fclose (m_fi);
m_fi = fopen (mail_file, "r+");
if (fi == NULL || m_fi == NULL) {
pop_break();
return (-1);
}
do_flock (fileno(m_fi), LOCK_EX);
if (at)
fseek (fi, Entry[at].fpos, 0);
else
fseek (fi, 0, 0);
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);
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();
return (1);
}
void
do_flock(fd, stat)
{
if (flock(fd, stat | LOCK_NB) < 0) {
puts ("File in use, Waiting for lock");
flock (fd, stat);
puts ("Have lock");
}
}
static
load_file(at)
int at;
{
FILE *fi;
char *next, *ptr;
int i, bit, maxbit, len, count, havefrom;
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 = malloc (len + 1);
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] =
malloc (strlen(next) + 1);
strcpy (Entry[count].fields[i], next);
if ((bit |= (1 << i)) == maxbit)
break;
}
if (bit != maxbit) {
for (i = 0; Find[i].search != NULL; ++i) {
if (((1 << i) & bit) == 0) {
Entry[count].fields[i] = quo_quo;
}
}
}
}
File_size = ftell (fi);
fclose (fi);
return (1);
}
static void
load_hash()
{
int i, v, c;
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;
}
}
}
void
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;
}
}
static void
free_table(at, hold)
{
int i, j;
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;
}
static
search_from(fi)
FILE *fi;
{
while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
if (isfrom (Buf))
return (1);
}
return (0);
}
save_file(reload, mark, notmark)
{
FILE *fiscr;
int fdscr;
int i, count;
char scratch[64];
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);
puts ("No Changes Made");
return (Entries);
}
if (m_fi == NULL)
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);
#ifdef AMIGA /* fix bug in Lattice C fdopen */
fiscr = fopen("nil:", "w");
fclose(fiscr);
#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);
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")) {
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);
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);
return(-1);
}
#endif
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);
return (count);
}
void
check_new_mail()
{
FILE *fi;
push_break();
if (m_fi == NULL) {
m_fi = fopen (mail_file, "r+");
if (m_fi == NULL) {
pop_break();
return;
}
}
if (fi = fopen(mail_file, "r")) {
if (fseek(fi, 0, 2) < 0 || ftell(fi) != File_size)
load_mail(Entries, 1);
fclose(fi);
}
pop_break();
}
write_file(file, modes, mark, notmark)
char *file;
{
int i, fd = 1, notopen = 1;
FILE *fi = NULL;
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)
return (-1);
do_flock (fd, LOCK_EX);
#ifdef AMIGA /* fix bug in Lattice C fdopen */
fi = fopen("nil:", "w");
fclose(fi);
#endif
fi = fdopen (fd, "a");
#ifdef NOTDEF
if (fi) {
printf("ptr %08lx\n", fi->_ptr);
printf("rcnt %08lx\n", fi->_rcnt);
printf("wcnt %08lx\n", fi->_wcnt);
printf("base %08lx\n", fi->_base);
printf("size %08lx\n", fi->_size);
printf("flag %08lx\n", fi->_flag);
printf("file %08lx\n", fi->_file);
return(-1);
}
#endif
}
fputs ("From ", fi);
fputs (Entry[i].from, fi);
putc ('\n', fi);
if (m_fi) {
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);
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.
*/
get_extra_ovr(str)
char *str;
{
register int i;
i = get_extra (str);
if (i < 0) {
i = add_extra (str);
load_changes();
}
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.
*/
add_extra(str)
char *str;
{
register int i, j, j_age, k;
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)
return (-1);
push_break();
if (Find[i].search != NULL)
xfree (Find[i].search);
Find[i].len = strlen(str);
Find[i].search = malloc (Find[i].len + 1);
Find[i].notnew = Find[i].age = 0;
strcpy (Find[i].search, str);
changed = 1;
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();
return (i);
}
get_extra(str)
char *str;
{
int i;
for (i = 0; Find[i].search; ++i) {
if (strncmp (str, Find[i].search, strlen(str)) == 0) {
Find[i].age = 0;
return (i);
}
}
return (-1);
}
m_select(sav, mode)
register char *sav[];
{
char *ptr, *dest;
char l_map[256];
int idx[MAXLIST], ix = 0;
int ok, not, len, scr;
register int i, j, avi;
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;
return (-1);
}
}
} else {
Current = -1;
}
return (1);
}