Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/mailx/names.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the BSD package *
4
*Copyright (c) 1978-2010 The Regents of the University of California an*
5
* *
6
* Redistribution and use in source and binary forms, with or *
7
* without modification, are permitted provided that the following *
8
* conditions are met: *
9
* *
10
* 1. Redistributions of source code must retain the above *
11
* copyright notice, this list of conditions and the *
12
* following disclaimer. *
13
* *
14
* 2. Redistributions in binary form must reproduce the above *
15
* copyright notice, this list of conditions and the *
16
* following disclaimer in the documentation and/or other *
17
* materials provided with the distribution. *
18
* *
19
* 3. Neither the name of The Regents of the University of California*
20
* names of its contributors may be used to endorse or *
21
* promote products derived from this software without *
22
* specific prior written permission. *
23
* *
24
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
25
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
26
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
27
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
28
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS *
29
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
30
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED *
31
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
32
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *
33
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
34
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
35
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
36
* POSSIBILITY OF SUCH DAMAGE. *
37
* *
38
* Redistribution and use in source and binary forms, with or without *
39
* modification, are permitted provided that the following conditions *
40
* are met: *
41
* 1. Redistributions of source code must retain the above copyright *
42
* notice, this list of conditions and the following disclaimer. *
43
* 2. Redistributions in binary form must reproduce the above copyright *
44
* notice, this list of conditions and the following disclaimer in *
45
* the documentation and/or other materials provided with the *
46
* distribution. *
47
* 3. Neither the name of the University nor the names of its *
48
* contributors may be used to endorse or promote products derived *
49
* from this software without specific prior written permission. *
50
* *
51
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" *
52
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
53
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
54
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS *
55
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
56
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
57
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *
58
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
59
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
60
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *
61
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
62
* SUCH DAMAGE. *
63
* *
64
* Kurt Shoens (UCB) *
65
* gsf *
66
* *
67
***********************************************************************/
68
#pragma prototyped
69
/*
70
* Mail -- a mail program
71
*
72
* Handle name lists.
73
*/
74
75
#include "mailx.h"
76
77
/*
78
* Grab a single word (liberal word)
79
* Throw away things between ()'s, and take anything between <>.
80
*/
81
char*
82
yankword(char* ap, char* wbuf)
83
{
84
register char* cp;
85
register char* cp2;
86
87
cp = ap;
88
for (;;) {
89
if (*cp == 0)
90
return 0;
91
if (*cp == '(') {
92
register int nesting = 0;
93
94
while (*cp != 0) {
95
switch (*cp++) {
96
case '(':
97
nesting++;
98
break;
99
case ')':
100
--nesting;
101
break;
102
}
103
if (nesting <= 0)
104
break;
105
}
106
}
107
else if (*cp == ' ' || *cp == '\t' || *cp == ',')
108
cp++;
109
else
110
break;
111
}
112
if (*cp == '<')
113
for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
114
;
115
else
116
for (cp2 = wbuf; *cp && !strchr(" \t,(", *cp); *cp2++ = *cp++)
117
;
118
*cp2 = 0;
119
return *wbuf ? cp : (char*)0;
120
}
121
122
/*
123
* Clear flags.
124
*/
125
static int
126
clear(Dt_t* dt, void* object, void* context)
127
{
128
if (!(((struct name*)object)->flags &= ~(*(unsigned long*)context)))
129
((struct name*)object)->flags |= GDONE;
130
return 0;
131
}
132
133
/*
134
* Clear items from header.
135
*/
136
void
137
headclear(struct header* hp, unsigned long flags)
138
{
139
hp->h_clear &= ~flags;
140
if (flags & GSUB) {
141
hp->h_flags &= ~GSUB;
142
hp->h_subject = 0;
143
}
144
if (flags & GMISC) {
145
hp->h_clear &= ~GMISC;
146
hp->h_misc.head = hp->h_misc.tail = 0;
147
}
148
if (flags &= (GNAME|GMETOO)) {
149
hp->h_clear &= ~(flags|GFIRST);
150
hp->h_first = 0;
151
dictwalk(&hp->h_names, clear, &flags);
152
}
153
}
154
155
/*
156
* Extract a list of names from a line,
157
* and make a list of names from it.
158
*/
159
void
160
extract(struct header* hp, unsigned long flags, register char* s)
161
{
162
register struct name* np;
163
register int n;
164
register struct list* x;
165
char buf[LINESIZE];
166
167
if (s) {
168
note(DEBUG, "extract type=0x%08x data=\"%s\"%s", flags, s, (hp->h_clear & flags) ? " [clear]" : "");
169
if (flags & GNAME) {
170
if (hp->h_clear & flags) {
171
hp->h_clear &= ~flags;
172
dictwalk(&hp->h_names, clear, &flags);
173
}
174
while (s = yankword(s, buf))
175
if (np = dictsearch(&hp->h_names, buf, INSERT|IGNORECASE|STACK)) {
176
np->flags = flags;
177
hp->h_flags |= flags;
178
if (!hp->h_first && (flags & GTO) || (flags & GFIRST)) {
179
flags &= ~GFIRST;
180
hp->h_first = np->name;
181
}
182
}
183
}
184
else if (flags & GSUB) {
185
hp->h_clear &= ~flags;
186
if (!*s) {
187
hp->h_flags &= ~flags;
188
hp->h_subject = 0;
189
}
190
else if (!hp->h_subject || !streq(hp->h_subject, s)) {
191
hp->h_flags |= flags;
192
hp->h_subject = savestr(s);
193
}
194
}
195
else if (flags & GMISC) {
196
if (hp->h_clear & flags) {
197
hp->h_clear &= ~flags;
198
hp->h_misc.head = hp->h_misc.tail = 0;
199
}
200
if (*s) {
201
if ((n = strlen(s)) > 0 && s[n - 1] == '\n')
202
s[--n] = 0;
203
for (x = hp->h_misc.head; x; x = x->next)
204
if (streq(x->name, s))
205
return;
206
hp->h_flags |= flags;
207
x = (struct list*)salloc(sizeof(struct list) + n + 1);
208
strcpy(x->name, s);
209
x->next = 0;
210
if (hp->h_misc.tail)
211
hp->h_misc.tail->next = x;
212
else
213
hp->h_misc.head = x;
214
hp->h_misc.tail = x;
215
}
216
}
217
}
218
}
219
220
/*
221
* Low level for detract().
222
*/
223
224
typedef struct
225
{
226
size_t count;
227
int flags;
228
int sep;
229
char* base;
230
char* next;
231
} Walk_str_t;
232
233
static int
234
stringize(Dt_t* dt, void* object, void* context)
235
{
236
register struct name* np = (struct name*)object;
237
register Walk_str_t* ws = (Walk_str_t*)context;
238
register char* s;
239
register char* t;
240
241
if (!ws->flags || ws->flags == (np->flags & GMASK)) {
242
if (s = ws->next) {
243
if (s > ws->base) {
244
if (ws->sep)
245
*s++ = ',';
246
*s++ = ' ';
247
}
248
for (t = np->name; *s = *t++; s++);
249
ws->next = s;
250
np->flags |= GDONE;
251
}
252
else
253
ws->count += strlen(np->name) + ws->sep;
254
}
255
return 0;
256
}
257
258
/*
259
* Turn a list of names into a string of the same names.
260
*/
261
char*
262
detract(struct header* hp, unsigned long flags)
263
{
264
Walk_str_t ws;
265
266
if (flags & GNAME) {
267
if (hp->h_names) {
268
if (flags & GCOMMA)
269
note(DEBUG, "detract asked to insert commas");
270
ws.sep = (flags & GCOMMA) ? 2 : 1;
271
ws.flags = flags &= ~GCOMMA;
272
ws.count = 0;
273
ws.base = ws.next = 0;
274
dictwalk(&hp->h_names, stringize, &ws);
275
if (ws.count) {
276
ws.base = ws.next = salloc(ws.count + 2);
277
ws.sep--;
278
dictwalk(&hp->h_names, stringize, &ws);
279
return ws.base;
280
}
281
}
282
}
283
else if (flags & GSUB)
284
return hp->h_subject;
285
return 0;
286
}
287
288
typedef struct {
289
int more;
290
int show;
291
Dt_t* seen;
292
Dt_t* prev;
293
Dt_t* next;
294
} Walk_map_t;
295
296
/*
297
* Add name,flags to the next map level.
298
*/
299
static void
300
mapadd(register Walk_map_t* wm, register struct name* np, char* name, unsigned long flags)
301
{
302
if (wm->show)
303
note(0, "\"%s\" -> \"%s\"", np->name, name);
304
if (!dictsearch(&wm->prev, name, LOOKUP)) {
305
np = dictsearch(&wm->next, name, INSERT|IGNORECASE|STACK);
306
np->flags = flags;
307
if (dictsearch(&wm->seen, name, CREATE|IGNORECASE|STACK)) {
308
wm->more = 1;
309
}
310
else {
311
np->flags |= GMAP;
312
note(0, "\"%s\": alias loop", name);
313
}
314
}
315
}
316
317
/*
318
* Map all of the aliased users in the invoker's mailrc
319
* file and insert them into the list.
320
* Changed after all these months of service to recursively
321
* expand names (2/14/80).
322
* And changed after all these years to weed out state.var.user
323
* in one place (8/11/96).
324
*/
325
static int
326
mapuser(Dt_t* dt, void* object, void* context)
327
{
328
register struct name* np = (struct name*)object;
329
register Walk_map_t* wm = (Walk_map_t*)context;
330
struct name* ap;
331
struct list* mp;
332
char* s;
333
334
if (np->flags & GDONE)
335
return 0;
336
if (!(np->flags & GMAP)) {
337
np->flags |= GMAP;
338
dictsearch(&wm->seen, np->name, INSERT|IGNORECASE|STACK);
339
if (*np->name != '\\' && (ap = dictsearch(&state.aliases, np->name, LOOKUP))) {
340
for (mp = (struct list*)ap->value; mp; mp = mp->next)
341
mapadd(wm, np, mp->name, np->flags & ~(GMAP|GMETOO));
342
return 0;
343
}
344
if (s = normalize(np->name, GCOMPARE, state.path.path, sizeof(state.path.path))) {
345
mapadd(wm, np, s, np->flags & ~GMAP);
346
return 0;
347
}
348
if (!(np->flags & GMETOO) && !state.var.metoo && streq(np->name, state.var.user) && (np->flags & (GCC|GBCC))) {
349
if (wm->show)
350
note(0, "\"%s\" -> DELETE", np->name);
351
return 0;
352
}
353
}
354
if (!dictsearch(&state.aliases, np->name, LOOKUP))
355
dictsearch(&wm->next, (char*)np, INSERT|IGNORECASE|STACK|OBJECT|COPY);
356
return 0;
357
}
358
359
int
360
usermap(struct header* hp, int show)
361
{
362
struct name* np;
363
Walk_map_t wm;
364
365
wm.seen = 0;
366
wm.prev = 0;
367
do {
368
wm.more = 0;
369
wm.next = wm.prev;
370
wm.prev = hp->h_names;
371
dictclear(&wm.next);
372
wm.show = show;
373
dictwalk(&hp->h_names, mapuser, &wm);
374
hp->h_names = wm.next;
375
} while (wm.more);
376
if (!hp->h_names &&
377
hp->h_first &&
378
(np = dictsearch(&wm.prev, hp->h_first, LOOKUP)) &&
379
((np->flags & GMETOO) || streq(np->name, state.var.user))) {
380
if (wm.show)
381
note(0, "\"%s\" -> ADD", np->name);
382
dictsearch(&hp->h_names, (char*)np, INSERT|IGNORECASE|OBJECT);
383
}
384
return hp->h_names != 0;
385
}
386
387
/*
388
* Return path of file to record outgoing messages.
389
*/
390
char*
391
record(char* author, unsigned long flags)
392
{
393
register int c;
394
register char* ap;
395
register char* rp;
396
register char* ep;
397
register char* tp;
398
399
rp = state.path.path;
400
ep = rp + sizeof(state.path.path) - 1;
401
if ((flags & FOLLOWUP) && (ap = author)) {
402
if (tp = state.var.followup) {
403
if (state.var.outfolder && !strchr(METAFILE, *tp) && rp < ep)
404
*rp++ = '+';
405
while ((*rp = *tp++) && rp < ep)
406
rp++;
407
if (*(rp - 1) != '/' && rp < ep)
408
*rp++ = '/';
409
}
410
else if (state.var.outfolder && rp < ep)
411
*rp++ = '+';
412
tp = rp;
413
ap = author;
414
for (;;) {
415
switch (c = *ap++) {
416
case 0:
417
break;
418
case '@':
419
break;
420
case '!':
421
rp = tp;
422
continue;
423
default:
424
if (rp < ep)
425
*rp++ = c;
426
continue;
427
}
428
break;
429
}
430
tp = state.path.path;
431
*rp = 0;
432
}
433
else if (!(tp = state.var.log))
434
*rp = 0;
435
else if (state.var.outfolder && !strchr(METAFILE, *tp)) {
436
if (rp < ep)
437
*rp++ = '+';
438
strncopy(rp, tp, ep - rp);
439
}
440
return tp && *tp ? expand(tp, 1) : (char*)0;
441
}
442
443