1 |
|
|
/* $OpenBSD: aux.c,v 1.29 2015/10/16 17:56:07 mmcc Exp $ */ |
2 |
|
|
/* $NetBSD: aux.c,v 1.5 1997/05/13 06:15:52 mikel Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1980, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include "rcv.h" |
34 |
|
|
#include <fcntl.h> |
35 |
|
|
#include "extern.h" |
36 |
|
|
|
37 |
|
|
/* |
38 |
|
|
* Mail -- a mail program |
39 |
|
|
* |
40 |
|
|
* Auxiliary functions. |
41 |
|
|
*/ |
42 |
|
|
static char *save2str(char *, char *); |
43 |
|
|
|
44 |
|
|
/* |
45 |
|
|
* Return a pointer to a dynamic copy of the argument. |
46 |
|
|
*/ |
47 |
|
|
char * |
48 |
|
|
savestr(char *str) |
49 |
|
|
{ |
50 |
|
|
char *new; |
51 |
|
|
int size = strlen(str) + 1; |
52 |
|
|
|
53 |
|
|
if ((new = salloc(size)) != NULL) |
54 |
|
|
(void)memcpy(new, str, size); |
55 |
|
|
return(new); |
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
/* |
59 |
|
|
* Make a copy of new argument incorporating old one. |
60 |
|
|
*/ |
61 |
|
|
static char * |
62 |
|
|
save2str(char *str, char *old) |
63 |
|
|
{ |
64 |
|
|
char *new; |
65 |
|
|
int newsize = strlen(str) + 1; |
66 |
|
|
int oldsize = old ? strlen(old) + 1 : 0; |
67 |
|
|
|
68 |
|
|
if ((new = salloc(newsize + oldsize)) != NULL) { |
69 |
|
|
if (oldsize) { |
70 |
|
|
(void)memcpy(new, old, oldsize); |
71 |
|
|
new[oldsize - 1] = ' '; |
72 |
|
|
} |
73 |
|
|
(void)memcpy(new + oldsize, str, newsize); |
74 |
|
|
} |
75 |
|
|
return(new); |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
/* |
79 |
|
|
* Touch the named message by setting its MTOUCH flag. |
80 |
|
|
* Touched messages have the effect of not being sent |
81 |
|
|
* back to the system mailbox on exit. |
82 |
|
|
*/ |
83 |
|
|
void |
84 |
|
|
touch(struct message *mp) |
85 |
|
|
{ |
86 |
|
|
|
87 |
|
|
mp->m_flag |= MTOUCH; |
88 |
|
|
if ((mp->m_flag & MREAD) == 0) |
89 |
|
|
mp->m_flag |= MREAD|MSTATUS; |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
/* |
93 |
|
|
* Test to see if the passed file name is a directory. |
94 |
|
|
* Return true if it is. |
95 |
|
|
*/ |
96 |
|
|
int |
97 |
|
|
isdir(char *name) |
98 |
|
|
{ |
99 |
|
|
struct stat sbuf; |
100 |
|
|
|
101 |
|
|
if (stat(name, &sbuf) < 0) |
102 |
|
|
return(0); |
103 |
|
|
return(S_ISDIR(sbuf.st_mode)); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
/* |
107 |
|
|
* Count the number of arguments in the given string raw list. |
108 |
|
|
*/ |
109 |
|
|
int |
110 |
|
|
argcount(char **argv) |
111 |
|
|
{ |
112 |
|
|
char **ap; |
113 |
|
|
|
114 |
|
|
for (ap = argv; *ap++ != NULL;) |
115 |
|
|
; |
116 |
|
|
return(ap - argv - 1); |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* |
120 |
|
|
* Return the desired header line from the passed message |
121 |
|
|
* pointer (or NULL if the desired header field is not available). |
122 |
|
|
*/ |
123 |
|
|
char * |
124 |
|
|
hfield(char *field, struct message *mp) |
125 |
|
|
{ |
126 |
|
|
FILE *ibuf; |
127 |
|
|
char linebuf[LINESIZE]; |
128 |
|
|
int lc; |
129 |
|
|
char *hfield; |
130 |
|
|
char *colon, *oldhfield = NULL; |
131 |
|
|
|
132 |
|
|
ibuf = setinput(mp); |
133 |
|
|
if ((lc = mp->m_lines - 1) < 0) |
134 |
|
|
return(NULL); |
135 |
|
|
if (readline(ibuf, linebuf, LINESIZE, NULL) < 0) |
136 |
|
|
return(NULL); |
137 |
|
|
while (lc > 0) { |
138 |
|
|
if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) |
139 |
|
|
return(oldhfield); |
140 |
|
|
if ((hfield = ishfield(linebuf, colon, field)) != NULL) |
141 |
|
|
oldhfield = save2str(hfield, oldhfield); |
142 |
|
|
} |
143 |
|
|
return(oldhfield); |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
/* |
147 |
|
|
* Return the next header field found in the given message. |
148 |
|
|
* Return >= 0 if something found, < 0 elsewise. |
149 |
|
|
* "colon" is set to point to the colon in the header. |
150 |
|
|
* Must deal with \ continuations & other such fraud. |
151 |
|
|
*/ |
152 |
|
|
int |
153 |
|
|
gethfield(FILE *f, char *linebuf, int rem, char **colon) |
154 |
|
|
{ |
155 |
|
|
char line2[LINESIZE]; |
156 |
|
|
char *cp, *cp2; |
157 |
|
|
int c; |
158 |
|
|
|
159 |
|
|
for (;;) { |
160 |
|
|
if (--rem < 0) |
161 |
|
|
return(-1); |
162 |
|
|
if ((c = readline(f, linebuf, LINESIZE, NULL)) <= 0) |
163 |
|
|
return(-1); |
164 |
|
|
for (cp = linebuf; |
165 |
|
|
isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; |
166 |
|
|
cp++) |
167 |
|
|
; |
168 |
|
|
if (*cp != ':' || cp == linebuf) |
169 |
|
|
continue; |
170 |
|
|
/* |
171 |
|
|
* I guess we got a headline. |
172 |
|
|
* Handle wraparounding |
173 |
|
|
*/ |
174 |
|
|
*colon = cp; |
175 |
|
|
cp = linebuf + c; |
176 |
|
|
for (;;) { |
177 |
|
|
while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) |
178 |
|
|
; |
179 |
|
|
cp++; |
180 |
|
|
if (rem <= 0) |
181 |
|
|
break; |
182 |
|
|
ungetc(c = getc(f), f); |
183 |
|
|
if (c != ' ' && c != '\t') |
184 |
|
|
break; |
185 |
|
|
if ((c = readline(f, line2, LINESIZE, NULL)) < 0) |
186 |
|
|
break; |
187 |
|
|
rem--; |
188 |
|
|
for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) |
189 |
|
|
; |
190 |
|
|
c -= cp2 - line2; |
191 |
|
|
if (cp + c >= linebuf + LINESIZE - 2) |
192 |
|
|
break; |
193 |
|
|
*cp++ = ' '; |
194 |
|
|
(void)memcpy(cp, cp2, c); |
195 |
|
|
cp += c; |
196 |
|
|
} |
197 |
|
|
*cp = 0; |
198 |
|
|
return(rem); |
199 |
|
|
} |
200 |
|
|
/* NOTREACHED */ |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
/* |
204 |
|
|
* Check whether the passed line is a header line of |
205 |
|
|
* the desired breed. Return the field body, or 0. |
206 |
|
|
*/ |
207 |
|
|
|
208 |
|
|
char* |
209 |
|
|
ishfield(char *linebuf, char *colon, char *field) |
210 |
|
|
{ |
211 |
|
|
char *cp = colon; |
212 |
|
|
|
213 |
|
|
*cp = 0; |
214 |
|
|
if (strcasecmp(linebuf, field) != 0) { |
215 |
|
|
*cp = ':'; |
216 |
|
|
return(0); |
217 |
|
|
} |
218 |
|
|
*cp = ':'; |
219 |
|
|
for (cp++; *cp == ' ' || *cp == '\t'; cp++) |
220 |
|
|
; |
221 |
|
|
return(cp); |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
/* |
225 |
|
|
* Copy a string, lowercasing it as we go. ``dsize'' should be |
226 |
|
|
* the real size (not len) of the dest string (guarantee NUL term). |
227 |
|
|
*/ |
228 |
|
|
size_t |
229 |
|
|
istrlcpy(char *dst, const char *src, size_t dsize) |
230 |
|
|
{ |
231 |
|
|
char *d = dst; |
232 |
|
|
const char *s = src; |
233 |
|
|
size_t n = dsize; |
234 |
|
|
|
235 |
|
|
/* Copy as many bytes as will fit */ |
236 |
|
|
if (n != 0 && --n != 0) { |
237 |
|
|
do { |
238 |
|
|
if ((*d++ = tolower((unsigned char)*s++)) == 0) |
239 |
|
|
break; |
240 |
|
|
} while (--n != 0); |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
/* Not enough room in dst, add NUL and traverse rest of src */ |
244 |
|
|
if (n == 0) { |
245 |
|
|
if (dsize != 0) |
246 |
|
|
*d = '\0'; /* NUL-terminate dst */ |
247 |
|
|
while (*s++) |
248 |
|
|
; |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
return(s - src - 1); /* count does not include NUL */ |
252 |
|
|
} |
253 |
|
|
|
254 |
|
|
/* |
255 |
|
|
* The following code deals with input stacking to do source |
256 |
|
|
* commands. All but the current file pointer are saved on |
257 |
|
|
* the stack. |
258 |
|
|
*/ |
259 |
|
|
static int ssp; /* Top of file stack */ |
260 |
|
|
struct sstack { |
261 |
|
|
FILE *s_file; /* File we were in. */ |
262 |
|
|
int s_cond; /* Saved state of conditionals */ |
263 |
|
|
int s_loading; /* Loading .mailrc, etc. */ |
264 |
|
|
} sstack[OPEN_MAX]; |
265 |
|
|
|
266 |
|
|
/* |
267 |
|
|
* Pushdown current input file and switch to a new one. |
268 |
|
|
* Set the global flag "sourcing" so that others will realize |
269 |
|
|
* that they are no longer reading from a tty (in all probability). |
270 |
|
|
*/ |
271 |
|
|
int |
272 |
|
|
source(void *v) |
273 |
|
|
{ |
274 |
|
|
char **arglist = v; |
275 |
|
|
FILE *fi; |
276 |
|
|
char *cp; |
277 |
|
|
|
278 |
|
|
if ((cp = expand(*arglist)) == NULL) |
279 |
|
|
return(1); |
280 |
|
|
if ((fi = Fopen(cp, "r")) == NULL) { |
281 |
|
|
warn("%s", cp); |
282 |
|
|
return(1); |
283 |
|
|
} |
284 |
|
|
if (ssp >= OPEN_MAX - 1) { |
285 |
|
|
puts("Too much \"sourcing\" going on."); |
286 |
|
|
(void)Fclose(fi); |
287 |
|
|
return(1); |
288 |
|
|
} |
289 |
|
|
sstack[ssp].s_file = input; |
290 |
|
|
sstack[ssp].s_cond = cond; |
291 |
|
|
sstack[ssp].s_loading = loading; |
292 |
|
|
ssp++; |
293 |
|
|
loading = 0; |
294 |
|
|
cond = CANY; |
295 |
|
|
input = fi; |
296 |
|
|
sourcing++; |
297 |
|
|
return(0); |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
/* |
301 |
|
|
* Pop the current input back to the previous level. |
302 |
|
|
* Update the "sourcing" flag as appropriate. |
303 |
|
|
*/ |
304 |
|
|
int |
305 |
|
|
unstack(void) |
306 |
|
|
{ |
307 |
|
|
|
308 |
|
|
if (ssp <= 0) { |
309 |
|
|
puts("\"Source\" stack over-pop."); |
310 |
|
|
sourcing = 0; |
311 |
|
|
return(1); |
312 |
|
|
} |
313 |
|
|
(void)Fclose(input); |
314 |
|
|
if (cond != CANY) |
315 |
|
|
puts("Unmatched \"if\""); |
316 |
|
|
ssp--; |
317 |
|
|
cond = sstack[ssp].s_cond; |
318 |
|
|
loading = sstack[ssp].s_loading; |
319 |
|
|
input = sstack[ssp].s_file; |
320 |
|
|
if (ssp == 0) |
321 |
|
|
sourcing = loading; |
322 |
|
|
return(0); |
323 |
|
|
} |
324 |
|
|
|
325 |
|
|
/* |
326 |
|
|
* Touch the indicated file. |
327 |
|
|
* This is nifty for the shell. |
328 |
|
|
*/ |
329 |
|
|
void |
330 |
|
|
alter(char *name) |
331 |
|
|
{ |
332 |
|
|
struct timespec ts[2]; |
333 |
|
|
|
334 |
|
|
clock_gettime(CLOCK_REALTIME, &ts[0]); |
335 |
|
|
ts[0].tv_sec++; |
336 |
|
|
ts[1].tv_nsec = UTIME_OMIT; |
337 |
|
|
(void)utimensat(AT_FDCWD, name, ts, 0); |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
/* |
341 |
|
|
* Examine the passed line buffer and |
342 |
|
|
* return true if it is all blanks and tabs. |
343 |
|
|
*/ |
344 |
|
|
int |
345 |
|
|
blankline(char *linebuf) |
346 |
|
|
{ |
347 |
|
|
char *cp; |
348 |
|
|
|
349 |
|
|
for (cp = linebuf; *cp; cp++) |
350 |
|
|
if (*cp != ' ' && *cp != '\t') |
351 |
|
|
return(0); |
352 |
|
|
return(1); |
353 |
|
|
} |
354 |
|
|
|
355 |
|
|
/* |
356 |
|
|
* Get sender's name from this message. If the message has |
357 |
|
|
* a bunch of arpanet stuff in it, we may have to skin the name |
358 |
|
|
* before returning it. |
359 |
|
|
*/ |
360 |
|
|
char * |
361 |
|
|
nameof(struct message *mp, int reptype) |
362 |
|
|
{ |
363 |
|
|
char *cp, *cp2; |
364 |
|
|
|
365 |
|
|
cp = skin(name1(mp, reptype)); |
366 |
|
|
if (reptype != 0 || charcount(cp, '!') < 2) |
367 |
|
|
return(cp); |
368 |
|
|
cp2 = strrchr(cp, '!'); |
369 |
|
|
cp2--; |
370 |
|
|
while (cp2 > cp && *cp2 != '!') |
371 |
|
|
cp2--; |
372 |
|
|
if (*cp2 == '!') |
373 |
|
|
return(cp2 + 1); |
374 |
|
|
return(cp); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
/* |
378 |
|
|
* Start of a "comment". |
379 |
|
|
* Ignore it. |
380 |
|
|
*/ |
381 |
|
|
char * |
382 |
|
|
skip_comment(char *cp) |
383 |
|
|
{ |
384 |
|
|
int nesting = 1; |
385 |
|
|
|
386 |
|
|
for (; nesting > 0 && *cp; cp++) { |
387 |
|
|
switch (*cp) { |
388 |
|
|
case '\\': |
389 |
|
|
if (cp[1]) |
390 |
|
|
cp++; |
391 |
|
|
break; |
392 |
|
|
case '(': |
393 |
|
|
nesting++; |
394 |
|
|
break; |
395 |
|
|
case ')': |
396 |
|
|
nesting--; |
397 |
|
|
break; |
398 |
|
|
} |
399 |
|
|
} |
400 |
|
|
return(cp); |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
/* |
404 |
|
|
* Skin an arpa net address according to the RFC 822 interpretation |
405 |
|
|
* of "host-phrase." |
406 |
|
|
*/ |
407 |
|
|
char * |
408 |
|
|
skin(char *name) |
409 |
|
|
{ |
410 |
|
|
char *nbuf, *bufend, *cp, *cp2; |
411 |
|
|
int c, gotlt, lastsp; |
412 |
|
|
|
413 |
|
|
if (name == NULL) |
414 |
|
|
return(NULL); |
415 |
|
|
if (strchr(name, '(') == NULL && strchr(name, '<') == NULL |
416 |
|
|
&& strchr(name, ' ') == NULL) |
417 |
|
|
return(name); |
418 |
|
|
|
419 |
|
|
/* We assume that length(input) <= length(output) */ |
420 |
|
|
if ((nbuf = malloc(strlen(name) + 1)) == NULL) |
421 |
|
|
err(1, "malloc"); |
422 |
|
|
gotlt = 0; |
423 |
|
|
lastsp = 0; |
424 |
|
|
bufend = nbuf; |
425 |
|
|
for (cp = name, cp2 = bufend; (c = (unsigned char)*cp++) != '\0'; ) { |
426 |
|
|
switch (c) { |
427 |
|
|
case '(': |
428 |
|
|
cp = skip_comment(cp); |
429 |
|
|
lastsp = 0; |
430 |
|
|
break; |
431 |
|
|
|
432 |
|
|
case '"': |
433 |
|
|
/* |
434 |
|
|
* Start of a "quoted-string". |
435 |
|
|
* Copy it in its entirety. |
436 |
|
|
*/ |
437 |
|
|
while ((c = (unsigned char)*cp) != '\0') { |
438 |
|
|
cp++; |
439 |
|
|
if (c == '"') |
440 |
|
|
break; |
441 |
|
|
if (c != '\\') |
442 |
|
|
*cp2++ = c; |
443 |
|
|
else if ((c = (unsigned char)*cp) != '\0') { |
444 |
|
|
*cp2++ = c; |
445 |
|
|
cp++; |
446 |
|
|
} |
447 |
|
|
} |
448 |
|
|
lastsp = 0; |
449 |
|
|
break; |
450 |
|
|
|
451 |
|
|
case ' ': |
452 |
|
|
if (strncmp(cp, "at ", 3) == 0) |
453 |
|
|
cp += 3, *cp2++ = '@'; |
454 |
|
|
else |
455 |
|
|
if (strncmp(cp, "@ ", 2) == 0) |
456 |
|
|
cp += 2, *cp2++ = '@'; |
457 |
|
|
else |
458 |
|
|
lastsp = 1; |
459 |
|
|
break; |
460 |
|
|
|
461 |
|
|
case '<': |
462 |
|
|
cp2 = bufend; |
463 |
|
|
gotlt++; |
464 |
|
|
lastsp = 0; |
465 |
|
|
break; |
466 |
|
|
|
467 |
|
|
case '>': |
468 |
|
|
if (gotlt) { |
469 |
|
|
gotlt = 0; |
470 |
|
|
while ((c = (unsigned char)*cp) && c != ',') { |
471 |
|
|
cp++; |
472 |
|
|
if (c == '(') |
473 |
|
|
cp = skip_comment(cp); |
474 |
|
|
else if (c == '"') |
475 |
|
|
while ((c = (unsigned char)*cp) != '\0') { |
476 |
|
|
cp++; |
477 |
|
|
if (c == '"') |
478 |
|
|
break; |
479 |
|
|
if (c == '\\' && *cp) |
480 |
|
|
cp++; |
481 |
|
|
} |
482 |
|
|
} |
483 |
|
|
lastsp = 0; |
484 |
|
|
break; |
485 |
|
|
} |
486 |
|
|
/* Fall into . . . */ |
487 |
|
|
|
488 |
|
|
default: |
489 |
|
|
if (lastsp) { |
490 |
|
|
lastsp = 0; |
491 |
|
|
*cp2++ = ' '; |
492 |
|
|
} |
493 |
|
|
*cp2++ = c; |
494 |
|
|
if (c == ',' && *cp == ' ' && !gotlt) { |
495 |
|
|
*cp2++ = ' '; |
496 |
|
|
while (*++cp == ' ') |
497 |
|
|
; |
498 |
|
|
lastsp = 0; |
499 |
|
|
bufend = cp2; |
500 |
|
|
} |
501 |
|
|
} |
502 |
|
|
} |
503 |
|
|
*cp2 = 0; |
504 |
|
|
|
505 |
|
|
if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) |
506 |
|
|
nbuf = cp; |
507 |
|
|
return(nbuf); |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
/* |
511 |
|
|
* Fetch the sender's name from the passed message. |
512 |
|
|
* Reptype can be |
513 |
|
|
* 0 -- get sender's name for display purposes |
514 |
|
|
* 1 -- get sender's name for reply |
515 |
|
|
* 2 -- get sender's name for Reply |
516 |
|
|
*/ |
517 |
|
|
char * |
518 |
|
|
name1(struct message *mp, int reptype) |
519 |
|
|
{ |
520 |
|
|
char namebuf[LINESIZE]; |
521 |
|
|
char linebuf[LINESIZE]; |
522 |
|
|
char *cp, *cp2; |
523 |
|
|
FILE *ibuf; |
524 |
|
|
int first = 1; |
525 |
|
|
|
526 |
|
|
if ((cp = hfield("from", mp)) != NULL) |
527 |
|
|
return(cp); |
528 |
|
|
if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) |
529 |
|
|
return(cp); |
530 |
|
|
ibuf = setinput(mp); |
531 |
|
|
namebuf[0] = '\0'; |
532 |
|
|
if (readline(ibuf, linebuf, LINESIZE, NULL) < 0) |
533 |
|
|
return(savestr(namebuf)); |
534 |
|
|
newname: |
535 |
|
|
for (cp = linebuf; *cp && *cp != ' '; cp++) |
536 |
|
|
; |
537 |
|
|
for (; *cp == ' ' || *cp == '\t'; cp++) |
538 |
|
|
; |
539 |
|
|
for (cp2 = &namebuf[strlen(namebuf)]; |
540 |
|
|
*cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;) |
541 |
|
|
*cp2++ = *cp++; |
542 |
|
|
*cp2 = '\0'; |
543 |
|
|
if (readline(ibuf, linebuf, LINESIZE, NULL) < 0) |
544 |
|
|
return(savestr(namebuf)); |
545 |
|
|
if ((cp = strchr(linebuf, 'F')) == NULL) |
546 |
|
|
return(savestr(namebuf)); |
547 |
|
|
if (strncmp(cp, "From", 4) != 0) |
548 |
|
|
return(savestr(namebuf)); |
549 |
|
|
while ((cp = strchr(cp, 'r')) != NULL) { |
550 |
|
|
if (strncmp(cp, "remote", 6) == 0) { |
551 |
|
|
if ((cp = strchr(cp, 'f')) == NULL) |
552 |
|
|
break; |
553 |
|
|
if (strncmp(cp, "from", 4) != 0) |
554 |
|
|
break; |
555 |
|
|
if ((cp = strchr(cp, ' ')) == NULL) |
556 |
|
|
break; |
557 |
|
|
cp++; |
558 |
|
|
if (first) { |
559 |
|
|
cp2 = namebuf; |
560 |
|
|
first = 0; |
561 |
|
|
} else |
562 |
|
|
cp2 = strrchr(namebuf, '!') + 1; |
563 |
|
|
strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); |
564 |
|
|
strlcat(namebuf, "!", sizeof(namebuf)); |
565 |
|
|
goto newname; |
566 |
|
|
} |
567 |
|
|
cp++; |
568 |
|
|
} |
569 |
|
|
return(savestr(namebuf)); |
570 |
|
|
} |
571 |
|
|
|
572 |
|
|
/* |
573 |
|
|
* Count the occurances of c in str |
574 |
|
|
*/ |
575 |
|
|
int |
576 |
|
|
charcount(char *str, int c) |
577 |
|
|
{ |
578 |
|
|
char *cp; |
579 |
|
|
int i; |
580 |
|
|
|
581 |
|
|
for (i = 0, cp = str; *cp; cp++) |
582 |
|
|
if (*cp == c) |
583 |
|
|
i++; |
584 |
|
|
return(i); |
585 |
|
|
} |
586 |
|
|
|
587 |
|
|
/* |
588 |
|
|
* Copy s1 to s2, return pointer to null in s2. |
589 |
|
|
*/ |
590 |
|
|
char * |
591 |
|
|
copy(char *s1, char *s2) |
592 |
|
|
{ |
593 |
|
|
|
594 |
|
|
while ((*s2++ = *s1++) != '\0') |
595 |
|
|
; |
596 |
|
|
return(s2 - 1); |
597 |
|
|
} |
598 |
|
|
|
599 |
|
|
/* |
600 |
|
|
* See if the given header field is supposed to be ignored. |
601 |
|
|
*/ |
602 |
|
|
int |
603 |
|
|
isign(char *field, struct ignoretab ignore[2]) |
604 |
|
|
{ |
605 |
|
|
char realfld[LINESIZE]; |
606 |
|
|
|
607 |
|
|
if (ignore == ignoreall) |
608 |
|
|
return(1); |
609 |
|
|
/* |
610 |
|
|
* Lower-case the string, so that "Status" and "status" |
611 |
|
|
* will hash to the same place. |
612 |
|
|
*/ |
613 |
|
|
istrlcpy(realfld, field, sizeof(realfld)); |
614 |
|
|
if (ignore[1].i_count > 0) |
615 |
|
|
return(!member(realfld, ignore + 1)); |
616 |
|
|
else |
617 |
|
|
return(member(realfld, ignore)); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
int |
621 |
|
|
member(char *realfield, struct ignoretab *table) |
622 |
|
|
{ |
623 |
|
|
struct ignore *igp; |
624 |
|
|
|
625 |
|
|
for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link) |
626 |
|
|
if (*igp->i_field == *realfield && |
627 |
|
|
equal(igp->i_field, realfield)) |
628 |
|
|
return(1); |
629 |
|
|
return(0); |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
void |
633 |
|
|
clearnew(void) |
634 |
|
|
{ |
635 |
|
|
struct message *mp; |
636 |
|
|
|
637 |
|
|
for (mp = &message[0]; mp < &message[msgCount]; mp++) { |
638 |
|
|
if (mp->m_flag & MNEW) { |
639 |
|
|
mp->m_flag &= ~MNEW; |
640 |
|
|
mp->m_flag |= MSTATUS; |
641 |
|
|
} |
642 |
|
|
} |
643 |
|
|
} |