Blob


1 #include "common.h"
2 #include "send.h"
4 static String* s_parseq(String*, String*);
6 /* exports */
7 dest *dlist;
9 extern dest*
10 d_new(String *addr)
11 {
12 dest *dp;
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 }
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 }
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 */
48 /* Get first element from a circular list linked via 'next'. */
49 extern dest *
50 d_rm(dest **listp)
51 {
52 dest *dp;
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 }
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;
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 }
84 /* Get first element from a circular list linked via 'same'. */
85 extern dest *
86 d_rm_same(dest **listp)
87 {
88 dest *dp;
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 }
101 /* Look for a duplicate on the same list */
102 int
103 d_same_dup(dest *dp, dest *new)
105 dest *first = dp;
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;
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)
123 dest *dp;
124 int len;
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;
146 dp = dp->next;
147 } while (dp != (*listp)->next);
149 new->nchar = strlen(s_to_c(new->repl1)) + len + 1;
151 new->next = new;
152 d_insert(listp, new);
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)
163 dest *np, *sp;
164 String *s;
165 int i, n;
166 char *cp;
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);
179 /* hack to get local! out of the names */
180 if(strncmp(cp, "local!", 6) == 0)
181 cp += 6;
183 if(n > 20){ /* 20 to appease mailers complaining about long lines */
184 s_append(s, "\n\t");
185 n = 0;
187 if(i != 0){
188 s_append(s, ", ");
189 n += 2;
191 s_append(s, cp);
192 n += strlen(cp);
193 i++;
194 } while(sp != np);
195 } while(np != list);
197 return unescapespecial(s);
200 /* expand a String of destinations into a linked list of destiniations */
201 extern dest *
202 s_to_dest(String *sp, dest *parent)
204 String *addr;
205 dest *list=0;
206 dest *new;
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;
218 new = d_new(addr);
219 new->parent = parent;
220 new->authorized = parent->authorized;
221 d_insert(&list, new);
222 addr = s_new();
224 s_free(addr);
225 return list;
228 #undef isspace
229 #define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
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)
237 int c;
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;
253 s_terminate(to);
255 /* crunch trailing white */
256 while(isspace(*from->ptr))
257 from->ptr++;
259 return to;