Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "common.h"
#include "send.h"

static String* s_parseq(String*, String*);

/* exports */
dest *dlist;

extern dest*
d_new(String *addr)
{
        dest *dp;

        dp = (dest *)mallocz(sizeof(dest), 1);
        if (dp == 0) {
                perror("d_new");
                exit(1);
        }
        dp->same = dp;
        dp->nsame = 1;
        dp->nchar = 0;
        dp->next = dp;
        dp->addr = escapespecial(addr);
        dp->parent = 0;
        dp->repl1 = dp->repl2 = 0;
        dp->status = d_undefined;
        return dp;
}

extern void
d_free(dest *dp)
{
        if (dp != 0) {
                s_free(dp->addr);
                s_free(dp->repl1);
                s_free(dp->repl2);
                free((char *)dp);
        }
}

/* The following routines manipulate an ordered list of items.  Insertions
 * are always to the end of the list.  Deletions are from the beginning.
 *
 * The list are circular witht the `head' of the list being the last item
 * added.
 */

/*  Get first element from a circular list linked via 'next'. */
extern dest *
d_rm(dest **listp)
{
        dest *dp;

        if (*listp == 0)
                return 0;
        dp = (*listp)->next;
        if (dp == *listp)
                *listp = 0;
        else
                (*listp)->next = dp->next;
        dp->next = dp;
        return dp;
}

/*  Insert a new entry at the end of the list linked via 'next'. */
extern void
d_insert(dest **listp, dest *new)
{
        dest *head;

        if (*listp == 0) {
                *listp = new;
                return;
        }
        if (new == 0)
                return;
        head = new->next;
        new->next = (*listp)->next;
        (*listp)->next = head;
        *listp = new;
        return;
}

/*  Get first element from a circular list linked via 'same'. */
extern dest *
d_rm_same(dest **listp)
{
        dest *dp;

        if (*listp == 0)
                return 0;
        dp = (*listp)->same;
        if (dp == *listp)
                *listp = 0;
        else
                (*listp)->same = dp->same;
        dp->same = dp;
        return dp;
}

/* Look for a duplicate on the same list */
int
d_same_dup(dest *dp, dest *new)
{
        dest *first = dp;

        if(new->repl2 == 0)
                return 1;
        do {
                if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0)
                        return 1;
                dp = dp->same;
        } while(dp != first);
        return 0;
}

/* Insert an entry into the corresponding list linked by 'same'.  Note that
 * the basic structure is a list of lists.
 */
extern void
d_same_insert(dest **listp, dest *new)
{
        dest *dp;
        int len;

        if(new->status == d_pipe || new->status == d_cat) {
                len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0;
                if(*listp != 0){
                        dp = (*listp)->next;
                        do {
                                if(dp->status == new->status
                                && strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){
                                        /* remove duplicates */
                                        if(d_same_dup(dp, new))
                                                return;
                                        /* add to chain if chain small enough */
                                        if(dp->nsame < MAXSAME
                                        && dp->nchar + len < MAXSAMECHAR){
                                                new->same = dp->same;
                                                dp->same = new;
                                                dp->nchar += len + 1;
                                                dp->nsame++;
                                                return;
                                        }
                                }
                                dp = dp->next;
                        } while (dp != (*listp)->next);
                }
                new->nchar = strlen(s_to_c(new->repl1)) + len + 1;
        }
        new->next = new;
        d_insert(listp, new);
}

/*
 *  Form a To: if multiple destinations.
 *  The local! and !local! checks are artificial intelligence,
 *  there should be a better way.
 */
extern String*
d_to(dest *list)
{
        dest *np, *sp;
        String *s;
        int i, n;
        char *cp;

        s = s_new();
        s_append(s, "To: ");
        np = list;
        i = n = 0;
        do {
                np = np->next;
                sp = np;
                do {
                        sp = sp->same;
                        cp = s_to_c(sp->addr);

                        /* hack to get local! out of the names */
                        if(strncmp(cp, "local!", 6) == 0)
                                cp += 6;

                        if(n > 20){     /* 20 to appease mailers complaining about long lines */
                                s_append(s, "\n\t");
                                n = 0;
                        }
                        if(i != 0){
                                s_append(s, ", ");
                                n += 2;
                        }
                        s_append(s, cp);
                        n += strlen(cp);
                        i++;
                } while(sp != np);
        } while(np != list);

        return unescapespecial(s);
}

/* expand a String of destinations into a linked list of destiniations */
extern dest *
s_to_dest(String *sp, dest *parent)
{
        String *addr;
        dest *list=0;
        dest *new;

        if (sp == 0)
                return 0;
        addr = s_new();
        while (s_parseq(sp, addr)!=0) {
                addr = escapespecial(addr);
                if(shellchars(s_to_c(addr))){
                        while(new = d_rm(&list))
                                d_free(new);
                        break;
                }
                new = d_new(addr);
                new->parent = parent;
                new->authorized = parent->authorized;
                d_insert(&list, new);
                addr = s_new();
        }
        s_free(addr);
        return list;
}

#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')

/*  Get the next field from a String.  The field is delimited by white space.
 *  Anything delimited by double quotes is included in the string.
 */
static String*
s_parseq(String *from, String *to)
{
        int c;

        if (*from->ptr == '\0')
                return 0;
        if (to == 0)
                to = s_new();
        for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){
                s_putc(to, c);
                if(c == '"'){
                        for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr))
                                s_putc(to, *from->ptr);
                        s_putc(to, '"');
                        if(c == 0)
                                break;
                }
        }
        s_terminate(to);

        /* crunch trailing white */
        while(isspace(*from->ptr))
                from->ptr++;

        return to;
}