home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *RCS_load_c = "$Id: load.c,v 1.5 90/07/31 11:29:15 rogers Exp $";
- #endif
-
- /* --------------------
- vmail -- load.c
-
- Routines to find folders, find all mail items in folders. Empty
- folders are ignored.
-
- Copyright (C) J. Zobel, University of Melbourne, October 1987.
- -------------------- */
-
- #include "defs.h"
- #include <ctype.h>
-
-
- /* --------------------
- Find all folders in mail directory, set up linked list.
- -------------------- */
- void
- find_folders()
- {
- struct direct *dp;
- struct stat statbuf;
- DIR *dirp;
- int i, max = 0, n = 0, scmp();
- char str[LEN], **fds, **ftmp;
- folder tmp, last = (folder) NULL;
-
- (void)stat(mail_dir, &statbuf);
- /* guess number of folders - 10 is an error bound */
- max = statbuf.st_nlink+10;
- #ifdef sparc
- ftmp = fds = (char **) memalign((unsigned)8, (unsigned)(sizeof(char *) * max));
- #else
- ftmp = fds = (char **) malloc((unsigned)(sizeof(char *) * max));
- #endif
- dirp = opendir(mail_dir);
- for(dp=readdir(dirp) ; dp != (struct direct *)NULL ; dp=readdir(dirp)) {
- if(strcmp(dp->d_name, ".") == 0)
- continue;
- if(strcmp(dp->d_name, "..") == 0)
- continue;
- (void)sprintf(str, "%s/%s", mail_dir, dp->d_name);
- (void)stat(str, &statbuf);
- if(! (statbuf.st_mode & S_IFDIR))
- continue;
- if(! (statbuf.st_mode & S_IREAD) || ! (statbuf.st_mode & S_IWRITE)
- || ! (statbuf.st_mode & S_IEXEC)) {
- (void)printf("Folder %s unreadable.\n", dp->d_name);
- continue;
- }
- if(n == max){
- int offset = ftmp - fds; /* how far into fds */
-
- /*
- * We just overflowed the guessed number of entries
- * Let's try 10 more.
- */
- max += 10;
- fds = (char **)realloc((char *)fds, (unsigned)(sizeof(char *) * max));
- ftmp = fds + offset;
- }
-
- *ftmp = NEWSTR(strlen(dp->d_name)+1);
- (void)strcpy(*ftmp, dp->d_name);
- n++, ftmp++;
- }
- (void)closedir(dirp);
- if(n == 0) {
- (void)printf("No folders.\n");
- exit(1);
- }
- qsort((char *)fds, n, sizeof(char *), scmp);
- for(i=0, ftmp=fds ; i < n ; ftmp++, i++) {
- tmp = NEW(mail_folder);
- tmp->name = *ftmp;
- tmp->last = tmp->mail = (item) NULL;
- tmp->pages = tmp->pagenum = 1;
- tmp->valid = false;
- tmp->prev = last;
- tmp->next = (folder) NULL;
- if(last != (folder) NULL)
- last->next = tmp;
- else
- folders = tmp;
- last = tmp;
- }
- }
-
-
- int
- scmp(p, q)
- char **p, **q;
- {
- return(strcmp(*p, *q));
- }
-
-
- /* --------------------
- Find all mail items in given folder, throw away folder record if no
- mail items. Returns next folder in linked list, adds new folder
- records to linked list if original record overflows.
- -------------------- */
- folder
- find_mail(flr, load_time)
- folder flr;
- int load_time;
- {
- struct direct *dp, *readdir();
- DIR *dirp, *opendir();
- int i, n = 0, items[MAXITEMS], *itmp = items, dcmp();
- char str[LEN];
- item tmp, last = (item) NULL;
- folder new_folder();
-
- (void)sprintf(str, "%s/%s", mail_dir, flr->name);
- dirp = opendir(str);
- if(dirp == (DIR *) NULL) {
- if(load_time)
- (void)printf("%s: strange folder.\n", str);
- } else {
- for(dp=readdir(dirp) ; dp!=(struct direct *) NULL ; dp=readdir(dirp)) {
- /* get numbers of all mail items */
- if(n >= MAXITEMS) {
- no_control();
- (void)printf("\nMore than %d items in folder.\n",MAXITEMS-1);
- exit(1);
- }
- /* ignore anything that is not string of digits */
- if(! digits(dp->d_name))
- continue;
- /* assume any file that is string of digits is a mail
- item and not a directory */
- *itmp = atoi(dp->d_name);
- n++, itmp++;
- }
- (void)closedir(dirp);
- }
- if(n == 0) { /* Empty folder - delete from list */
- flr->valid = EMPTY;
- if(load_time)
- (void)printf("\t%s: empty\n", flr->name);
- if(flr->prev != (folder) NULL)
- flr->prev->next = flr->next;
- else
- folders = flr->next;
- if(flr->next != (folder) NULL)
- flr->next->prev = flr->prev;
- return(flr->next);
- } else
- qsort((char *)items, n, sizeof(int), dcmp);
- if(load_time) /* show status of folder */
- if(n == 1)
- (void)printf("\t%s: %d\n", flr->name, *items);
- else
- (void)printf("\t%s: %d-%d (%d items)\n",flr->name,*items,*(items+n-1),n);
- for(i=0, itmp=items ; i < n ; itmp++, i++) {
- /* add item to list of items in folder */
- tmp = NEW(mail_item);
- get_title(flr, tmp, *itmp);
- if(i % lines == 0 && last != (item) NULL) {
- /* add new record for folder */
- flr->last = last;
- flr = new_folder(flr);
- last = (item) NULL;
- }
- tmp->next = (item) NULL;
- tmp->prev = last;
- if(last != (item) NULL)
- last->next = tmp;
- else
- flr->mail = tmp;
- last = tmp;
- }
- flr->last = last;
- return(flr->next);
- }
-
-
- int
- dcmp(a, b)
- int *a, *b;
- {
- return(*a - *b);
- }
-
-
- /* --------------------
- Return true if string consists only of digits.
- -------------------- */
- int
- digits(str)
- char *str;
- {
- for( ; *str != '\0' ; str++)
- if(! isdigit(*str))
- return(false);
- return(true);
- }
-
-
- /* --------------------
- Make header line from mail item.
- -------------------- */
- void
- get_title(flr, mail, num)
- folder flr;
- item mail;
- int num;
- {
- FILE *fp, *fopen();
- char date[10], str[LEN], subj[42], from[20], to[16], fill[42];
- char repl = ' ', *first(), *s, *fgets();
- int i;
-
- subj[0] = from[0] = to[0] = fill[0] = '\0';
- (void)sprintf(str, "%s/%s/%d", mail_dir, flr->name, num);
- fp = fopen(str, "r");
- while((s=fgets(str, LEN, fp)) != (char *) NULL && *str != '\n') {
- /* while not eof and reading header */
- str[strlen(str)-1] = '\0';
- /* should also check date */
- if(! lstrncmp("date:", str, 5))
- get_date(str+5, date);
- else if(! lstrncmp("subject:", str, 8)) {
- s = first(str+8);
- (void)strncpy(subj, s, 41);
- subj[41] = '\0';
- } else if(! lstrncmp("replied:", str, 8))
- repl = '-';
- else if(! lstrncmp("from:", str, 5)) {
- s = first(str+5);
- if(! isuser(s)) {
- (void)strncpy(from, s, 19);
- from[19] = '\0';
- }
- } else if(! lstrncmp("to:", str, 3)) {
- s = first(str+3);
- (void)strncpy(to, s, 15);
- to[15] = '\0';
- } else if(! lstrncmp("apparently-to:", str, 14)) {
- s = first(str+14);
- (void)strncpy(to, s, 15);
- to[15] = '\0';
- }
- }
- if(s != (char *) NULL) {
- for(i=0 ; i < 42 && fgets(str, LEN, fp) != (char *) NULL ;) {
- str[strlen(str)-1] = ' ';
- (void)strncpy(fill+i, str, 42-i);
- i += strlen(str);
- }
- fill[41] = '\0';
- }
- (void)fclose(fp);
- if(subj[0] == '\0')
- (void)strcpy(subj, "(none)");
- flatten(subj);
- flatten(fill);
- if(from[0] == '\0')
- (void)sprintf(str, " %8s %cTo: %-15s %s << %s",date,repl,to,subj,fill);
- else
- (void)sprintf(str, " %8s %c%-19s %s << %s",date,repl,from,subj,fill);
- str[cols-6] = '\0';
- mail->title = NEWSTR(strlen(str)+1);
- mail->number = num;
- (void)strcpy(mail->title, str);
- }
-
-
- #ifdef USDATE
- #define DAY1 date[3]
- #define DAY2 date[4]
- #define MTH1 date[0]
- #define MTH2 date[1]
- #else
- #define DAY1 date[0]
- #define DAY2 date[1]
- #define MTH1 date[3]
- #define MTH2 date[4]
- #endif
- #define YR1 date[6]
- #define YR2 date[7]
-
- /* --------------------
- Get date from first argument; assumes format is one of
- Date: Fri, 3 Apr 87 ... (a)
- Date: Wed, 17 Jun 87 ... (b)
- Date: 07 Sep 87 ... (c)
- Date: Tue Sep 29 12:27:01 EST 1987 (d)
- Dates are put into Imperial form (dd-mm-yy), or US form (mm-dd-yy)
- if -DUSDATE is set.
-
- This routine should be more flexible re: recognizing date formats.
- -------------------- */
- void
- get_date(str, date)
- char *str, *date;
- {
- int i;
- bool get_month();
- char *next_token();
-
- date[2] = date[5] = '-';
- date[8] = '\0';
- for(; *str == ' ' || *str == '\t' ; str++)
- ;
- if(*str == '\0')
- goto unknown;
- if(! isdigit(*str)) /* day of month not first field */
- str = next_token(str); /* skip day of week */
- if(str == (char *) NULL + 1)
- goto unknown;
-
- if(isdigit(*str)) { /* one of (a), (b) or (c) formats */
- if(isdigit(*(str+1))) /* two-number date */
- #ifdef USDATE
- DAY1 = *str, DAY2 = *(++str);
- else
- DAY1 = '0', DAY2 = *str;
- #else
- DAY1 = (*str == '0') ? ' ' : *str, DAY2 = *(++str);
- else
- DAY1 = ' ', DAY2 = *str;
- #endif
- str = next_token(str); /* go to month */
- if(str == (char *) NULL + 1)
- goto unknown;
- if(! get_month(str, date))
- goto unknown;
- str = next_token(str); /* go to year */
- if(str == (char *) NULL + 1)
- goto unknown;
- if(! isdigit(*str) || ! isdigit(*(str+1)))
- goto unknown;
- YR1 = *str, YR2 = *(str+1);
- } else { /* format (d) */
- if(! get_month(str, date))
- goto unknown;
- str = next_token(str); /* go to day */
- if(str == (char *) NULL + 1)
- goto unknown;
- if(! isdigit(*str) || ! isdigit(*(str+1)))
- goto unknown;
- #ifdef USDATE
- DAY1 = *str, DAY2 = *(++str);
- #else
- DAY1 = (*str == '0') ? ' ' : *str, DAY2 = *(++str);
- #endif
- str += strlen(str) - 2; /* go to year */
- if(! isdigit(*str) || ! isdigit(*(str+1)))
- goto unknown;
- YR1 = *str, YR2 = *(str+1);
- }
- return; /* date is ok */
-
- unknown: /* erase date */
- for(i=0 ; i < 8 ; i++)
- date[i] = ' ';
- }
-
-
- static char *month[] = {
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec"
- };
-
- /* --------------------
- Put the month from the first part of str in date as a number.
- -------------------- */
- bool
- get_month(str, date)
- char *str, *date;
- {
- int i;
-
- for(i=0 ; i < 12 && lstrncmp(month[i], str, 3) != 0 ; i++)
- ;
- if(i == 12) /* string doesn't match month */
- return(false);
- else {
- if(i < 9) /* single digit month */
- #ifdef USDATE
- MTH1 = ' ', MTH2 = i + '0' + 1;
- #else
- MTH1 = '0', MTH2 = i + '0' + 1;
- #endif
- else
- MTH1 = '1', MTH2 = i + '0' - 9;
- return(true);
- }
- }
-
-
- /* --------------------
- Replace tabs and newlines in string by spaces.
- Compress multiple spaces to a single space.
- -------------------- */
- void
- flatten(str)
- char *str;
- {
- char prev = ' ', *s = str;
-
- /* advance str monotonically, copying into s as necessary */
-
- while (*str)
- {
- /* change funny character to space */
- if (!isgraph(*str)) {
- *str = ' ';
- }
-
- /* copy character into new position */
- *s = *str;
-
- /* advance new string pointer, but compress multiple spaces */
- if (isgraph(*str) || prev != ' ') {
- prev = *s;
- s++;
- }
- str++;
- }
- *s = '\0';
- }
-
-
- /* --------------------
- Return pointer to first non-white character in string.
- -------------------- */
- char *
- first(str)
- char *str;
- {
- for(; *str == ' ' || *str == '\t' || *str == '\n' ; str++)
- ;
- return(str);
- }
-
-
- /* --------------------
- Check given string for occurence of user's name.
- -------------------- */
- int
- isuser(str)
- char *str;
- {
- int len = strlen(user);
-
- for(; *str != '\0' ; str++)
- /* assume all chars in all unames alphanumeric */
- if(*str == *user && strncmp(str, user, len) == 0 &&
- (*(str+len) < 'a' || *(str+len) > 'z') &&
- (*(str+len) < 'A' || *(str+len) > 'Z') &&
- (*(str+len) < '0' || *(str+len) > '9'))
- return(true);
- return(false);
- }
-
-
- /* --------------------
- Make a new folder record.
- -------------------- */
- folder
- new_folder(flr)
- folder flr;
- {
- folder f;
-
- f = NEW(mail_folder);
- f->prev = flr;
- f->next = flr->next;
- flr->next = f;
- if(f->next != (folder) NULL)
- f->next->prev = f;
- f->pagenum = f->pages = flr->pages + 1;
- f->name = flr->name;
- f->valid = true;
- f->mail = f->last = (item) NULL;
- flr = f;
- for(f=f->prev; f != (folder) NULL && f->name == flr->name ; f=f->prev)
- f->pages = flr->pages;
- return(flr);
- }
-
-
- /* --------------------
- Find next free slot in directory for mail item (that is, find next
- unused number) -- structures in vmail may not be up to date if user
- has initiated a "send" process.
- -------------------- */
- int
- next_vacant(flr)
- folder flr;
- {
- struct direct *dp, *readdir();
- DIR *dirp, *opendir();
- char str[LEN];
- int i, n = 0;
-
- (void)sprintf(str, "%s/%s", mail_dir, flr->name);
- dirp = opendir(str);
- for(dp=readdir(dirp) ; dp != (struct direct *) NULL ; dp=readdir(dirp)) {
- /* ignore anything that is not string of digits */
- if(! digits(dp->d_name))
- continue;
- if((i = atoi(dp->d_name)) > n)
- n = i;
- }
- (void)closedir(dirp);
- return(n+1);
- }
-