
/*
 * m_readfolder.c -- initialize folder structure and read folder
 *
 * $Id$
 */

#include <h/mh.h>

/* We allocate the `info' struct 500 at a time */
#define	NINFO  500

/*
 * We create an array of these structures so we have
 * a place to initially put message stats before
 * we copy them into the message/folder structure
 */
struct info {
    int msgno;
    int stats;
};

static int len = 0;
static struct info *head;

/*
 * 1) Create the folder/message structure
 * 2) Read the directory (folder) and setup
 *    initial information
 */

struct msgs *
m_readfolder (char *name)
{
    int i, j;
    struct info *rover, *tail;
    struct msgs *mp;
    struct stat st;
    struct dirent *dp;
    DIR *dd;

    name = m_mailpath (name);
    if (!(dd = opendir (name))) {
	free (name);
	return NULL;
    }

    if (stat (name, &st) == -1) {
	free (name);
	return NULL;
    }

    if (!(mp = (struct msgs *) malloc (MHSIZE (mp, 0, 0))))
	adios (NULL, "unable to allocate folder storage");
    mp->lowmsg = 0;
    mp->hghmsg = 0;
    mp->nummsg = 0;
    mp->curmsg = 0;
    mp->lowsel = 0;
    mp->hghsel = 0;
    mp->numsel = 0;
    mp->msgflags = 0;
    mp->foldpath = name;
    if (st.st_uid != getuid () || access (name, W_OK) == NOTOK)
	mp->msgflags |= READONLY;
    j = strlen(BACKUP_PREFIX);
    if (!head) {
	len = NINFO;
	if (!(head = (struct info *) malloc ((size_t) (len * sizeof(*head)))))
	    adios (NULL, "unable to allocate info storage");
    }

    rover = head;
    tail  = head + len;

    while ((dp = readdir (dd))) {
	if ((i = m_atoi (dp->d_name))) {
	    if (rover >= tail) {
		register int curlen = tail - head;

		if (!(tail = (struct info *) realloc ((char *) head,
                             (size_t) ((len += NINFO) * sizeof(*head))))) {
		    adios (NULL, "unable to allocate info storage");
		} else {
		    rover = tail + curlen;
		    head  = tail;
		    tail += len;
		}
	    }
	    if (i > mp->hghmsg)
		mp->hghmsg = i;
	    mp->nummsg++;
	    if (mp->lowmsg == 0 || i < mp->lowmsg)
		mp->lowmsg = i;
	    rover->msgno = i;
	    rover->stats = EXISTS;
#if 0
	    rover->stats &= ~DELETED;
#endif
	    rover++;
	} else {
	    switch (dp->d_name[0]) {
		case '.': 
		    continue;

		case ',': 
#if 0
		    if ((i = m_atoi (dp->d_name + 1)) {
			register struct info *l;

			for (l = head; l < rover; l++)
			    if (l->msgno == i) {
				if (!(l->stats & EXISTS))
				    l->stats |= DELETED;
				break;
			    }
		    }
#endif
		    continue;

#ifdef MHE
		case '+': 
		    continue;
#endif /* MHE */

#ifdef UCI
		case '_': 
		case '#': 
		    continue;
#endif /* UCI */

		default: 
		    if (strcmp(dp->d_name, LINK) == 0
			    || strncmp(dp->d_name, BACKUP_PREFIX, j) == 0)
			continue;
		    mp->msgflags |= OTHERS;
		    continue;
	    }
	}
    }

    closedir (dd);

#ifndef	MTR
    mp->lowoff = 1;
#else /* MTR */
    mp->lowoff = mp->lowmsg;
#endif /* MTR */
    mp->hghoff = mp->hghmsg + 1;	/* for "new" in m_convert */

    mp = (struct msgs *) realloc (mp, MHSIZE (mp, mp->lowoff, mp->hghoff));
    if (mp == NULL)
	adios (NULL, "unable to allocate folder storage");

#ifndef	MTR
    for (i = mp->lowmsg; i <= mp->hghmsg; i++)
	mp->msgstats[i] = 0;
#else /* MTR */
    mp->msgstats = (int *)
		calloc ((size_t) 1, MHSIZEX (mp, mp->lowmsg, mp->hghmsg));
    if (mp->msgstats == NULL)
	adios (NULL, "unable to allocate messages storage");
    mp->msgstats = (mp->msgbase = mp->msgstats) - mp->lowoff;
    if (mp->msgstats < (int *)0)	/* non portable */
	adios (NULL, "m_readfolder() botch -- you lose big");
#endif /* MTR */

    /*
     * Interate through the array of info structures and copy
     * the stats to the newly allocated mp->msgstats area.
     */
    tail = rover;
    for (rover = head; rover < tail; rover++)
	mp->msgstats[rover->msgno] = rover->stats;

    /*
     * read and initialize the sequence information
     */
    seq_read (mp);
    return mp;
}
