plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dest.c (4804B)


      1 #include "common.h"
      2 #include "send.h"
      3 
      4 static String* s_parseq(String*, String*);
      5 
      6 /* exports */
      7 dest *dlist;
      8 
      9 extern dest*
     10 d_new(String *addr)
     11 {
     12 	dest *dp;
     13 
     14 	dp = (dest *)mallocz(sizeof(dest), 1);
     15 	if (dp == 0) {
     16 		perror("d_new");
     17 		exit(1);
     18 	}
     19 	dp->same = dp;
     20 	dp->nsame = 1;
     21 	dp->nchar = 0;
     22 	dp->next = dp;
     23 	dp->addr = escapespecial(addr);
     24 	dp->parent = 0;
     25 	dp->repl1 = dp->repl2 = 0;
     26 	dp->status = d_undefined;
     27 	return dp;
     28 }
     29 
     30 extern void
     31 d_free(dest *dp)
     32 {
     33 	if (dp != 0) {
     34 		s_free(dp->addr);
     35 		s_free(dp->repl1);
     36 		s_free(dp->repl2);
     37 		free((char *)dp);
     38 	}
     39 }
     40 
     41 /* The following routines manipulate an ordered list of items.  Insertions
     42  * are always to the end of the list.  Deletions are from the beginning.
     43  *
     44  * The list are circular witht the `head' of the list being the last item
     45  * added.
     46  */
     47 
     48 /*  Get first element from a circular list linked via 'next'. */
     49 extern dest *
     50 d_rm(dest **listp)
     51 {
     52 	dest *dp;
     53 
     54 	if (*listp == 0)
     55 		return 0;
     56 	dp = (*listp)->next;
     57 	if (dp == *listp)
     58 		*listp = 0;
     59 	else
     60 		(*listp)->next = dp->next;
     61 	dp->next = dp;
     62 	return dp;
     63 }
     64 
     65 /*  Insert a new entry at the end of the list linked via 'next'. */
     66 extern void
     67 d_insert(dest **listp, dest *new)
     68 {
     69 	dest *head;
     70 
     71 	if (*listp == 0) {
     72 		*listp = new;
     73 		return;
     74 	}
     75 	if (new == 0)
     76 		return;
     77 	head = new->next;
     78 	new->next = (*listp)->next;
     79 	(*listp)->next = head;
     80 	*listp = new;
     81 	return;
     82 }
     83 
     84 /*  Get first element from a circular list linked via 'same'. */
     85 extern dest *
     86 d_rm_same(dest **listp)
     87 {
     88 	dest *dp;
     89 
     90 	if (*listp == 0)
     91 		return 0;
     92 	dp = (*listp)->same;
     93 	if (dp == *listp)
     94 		*listp = 0;
     95 	else
     96 		(*listp)->same = dp->same;
     97 	dp->same = dp;
     98 	return dp;
     99 }
    100 
    101 /* Look for a duplicate on the same list */
    102 int
    103 d_same_dup(dest *dp, dest *new)
    104 {
    105 	dest *first = dp;
    106 
    107 	if(new->repl2 == 0)
    108 		return 1;
    109 	do {
    110 		if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0)
    111 			return 1;
    112 		dp = dp->same;
    113 	} while(dp != first);
    114 	return 0;
    115 }
    116 
    117 /* Insert an entry into the corresponding list linked by 'same'.  Note that
    118  * the basic structure is a list of lists.
    119  */
    120 extern void
    121 d_same_insert(dest **listp, dest *new)
    122 {
    123 	dest *dp;
    124 	int len;
    125 
    126 	if(new->status == d_pipe || new->status == d_cat) {
    127 		len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0;
    128 		if(*listp != 0){
    129 			dp = (*listp)->next;
    130 			do {
    131 				if(dp->status == new->status
    132 				&& strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){
    133 					/* remove duplicates */
    134 					if(d_same_dup(dp, new))
    135 						return;
    136 					/* add to chain if chain small enough */
    137 					if(dp->nsame < MAXSAME
    138 					&& dp->nchar + len < MAXSAMECHAR){
    139 						new->same = dp->same;
    140 						dp->same = new;
    141 						dp->nchar += len + 1;
    142 						dp->nsame++;
    143 						return;
    144 					}
    145 				}
    146 				dp = dp->next;
    147 			} while (dp != (*listp)->next);
    148 		}
    149 		new->nchar = strlen(s_to_c(new->repl1)) + len + 1;
    150 	}
    151 	new->next = new;
    152 	d_insert(listp, new);
    153 }
    154 
    155 /*
    156  *  Form a To: if multiple destinations.
    157  *  The local! and !local! checks are artificial intelligence,
    158  *  there should be a better way.
    159  */
    160 extern String*
    161 d_to(dest *list)
    162 {
    163 	dest *np, *sp;
    164 	String *s;
    165 	int i, n;
    166 	char *cp;
    167 
    168 	s = s_new();
    169 	s_append(s, "To: ");
    170 	np = list;
    171 	i = n = 0;
    172 	do {
    173 		np = np->next;
    174 		sp = np;
    175 		do {
    176 			sp = sp->same;
    177 			cp = s_to_c(sp->addr);
    178 
    179 			/* hack to get local! out of the names */
    180 			if(strncmp(cp, "local!", 6) == 0)
    181 				cp += 6;
    182 
    183 			if(n > 20){	/* 20 to appease mailers complaining about long lines */
    184 				s_append(s, "\n\t");
    185 				n = 0;
    186 			}
    187 			if(i != 0){
    188 				s_append(s, ", ");
    189 				n += 2;
    190 			}
    191 			s_append(s, cp);
    192 			n += strlen(cp);
    193 			i++;
    194 		} while(sp != np);
    195 	} while(np != list);
    196 
    197 	return unescapespecial(s);
    198 }
    199 
    200 /* expand a String of destinations into a linked list of destiniations */
    201 extern dest *
    202 s_to_dest(String *sp, dest *parent)
    203 {
    204 	String *addr;
    205 	dest *list=0;
    206 	dest *new;
    207 
    208 	if (sp == 0)
    209 		return 0;
    210 	addr = s_new();
    211 	while (s_parseq(sp, addr)!=0) {
    212 		addr = escapespecial(addr);
    213 		if(shellchars(s_to_c(addr))){
    214 			while(new = d_rm(&list))
    215 				d_free(new);
    216 			break;
    217 		}
    218 		new = d_new(addr);
    219 		new->parent = parent;
    220 		new->authorized = parent->authorized;
    221 		d_insert(&list, new);
    222 		addr = s_new();
    223 	}
    224 	s_free(addr);
    225 	return list;
    226 }
    227 
    228 #undef isspace
    229 #define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
    230 
    231 /*  Get the next field from a String.  The field is delimited by white space.
    232  *  Anything delimited by double quotes is included in the string.
    233  */
    234 static String*
    235 s_parseq(String *from, String *to)
    236 {
    237 	int c;
    238 
    239 	if (*from->ptr == '\0')
    240 		return 0;
    241 	if (to == 0)
    242 		to = s_new();
    243 	for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){
    244 		s_putc(to, c);
    245 		if(c == '"'){
    246 			for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr))
    247 				s_putc(to, *from->ptr);
    248 			s_putc(to, '"');
    249 			if(c == 0)
    250 				break;
    251 		}
    252 	}
    253 	s_terminate(to);
    254 
    255 	/* crunch trailing white */
    256 	while(isspace(*from->ptr))
    257 		from->ptr++;
    258 
    259 	return to;
    260 }