Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 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
#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
229
 
230
/*  Get the next field from a String.  The field is delimited by white space.
231
 *  Anything delimited by double quotes is included in the string.
232
 */
233
static String*
234
s_parseq(String *from, String *to)
235
{
236
	int c;
237
 
238
	if (*from->ptr == '\0')
239
		return 0;
240
	if (to == 0)
241
		to = s_new();
242
	for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){
243
		s_putc(to, c);
244
		if(c == '"'){
245
			for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr))
246
				s_putc(to, *from->ptr);
247
			s_putc(to, '"');
248
			if(c == 0)
249
				break;
250
		}
251
	}
252
	s_terminate(to);
253
 
254
	/* crunch trailing white */
255
	while(isspace(*from->ptr))
256
		from->ptr++;
257
 
258
	return to;
259
}