do case insensitive comparison on domain name
[unix-history] / usr / src / usr.bin / mail / cmd2.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
acfc7e9b
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
d0aeaf5a
DF
16 */
17
acfc7e9b 18#ifndef lint
470c33f3 19static char sccsid[] = "@(#)cmd2.c 5.10 (Berkeley) %G%";
acfc7e9b 20#endif /* not lint */
a13d1f28
KS
21
22#include "rcv.h"
828615a1 23#include <sys/wait.h>
a13d1f28
KS
24
25/*
26 * Mail -- a mail program
27 *
28 * More user commands.
29 */
30
a13d1f28
KS
31/*
32 * If any arguments were given, go to the next applicable argument
33 * following dot, otherwise, go to the next applicable message.
34 * If given as first command with no arguments, print first message.
35 */
36
37next(msgvec)
38 int *msgvec;
39{
40 register struct message *mp;
41 register int *ip, *ip2;
42 int list[2], mdot;
43
44 if (*msgvec != NULL) {
45
46 /*
47 * If some messages were supplied, find the
48 * first applicable one following dot using
49 * wrap around.
50 */
51
52 mdot = dot - &message[0] + 1;
30629819
KS
53
54 /*
55 * Find the first message in the supplied
56 * message list which follows dot.
57 */
58
a13d1f28
KS
59 for (ip = msgvec; *ip != NULL; ip++)
60 if (*ip > mdot)
61 break;
62 if (*ip == NULL)
63 ip = msgvec;
64 ip2 = ip;
65 do {
a13d1f28
KS
66 mp = &message[*ip2 - 1];
67 if ((mp->m_flag & MDELETED) == 0) {
68 dot = mp;
69 goto hitit;
70 }
30629819
KS
71 if (*ip2 != NULL)
72 ip2++;
73 if (*ip2 == NULL)
74 ip2 = msgvec;
a13d1f28
KS
75 } while (ip2 != ip);
76 printf("No messages applicable\n");
77 return(1);
78 }
79
80 /*
81 * If this is the first command, select message 1.
82 * Note that this must exist for us to get here at all.
83 */
84
799afc8f 85 if (!sawcom)
a13d1f28 86 goto hitit;
a13d1f28
KS
87
88 /*
89 * Just find the next good message after dot, no
90 * wraparound.
91 */
92
93 for (mp = dot+1; mp < &message[msgCount]; mp++)
94 if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
95 break;
96 if (mp >= &message[msgCount]) {
97 printf("At EOF\n");
98 return(0);
99 }
100 dot = mp;
101hitit:
102 /*
103 * Print dot.
104 */
105
106 list[0] = dot - &message[0] + 1;
107 list[1] = NULL;
108 return(type(list));
109}
110
111/*
c7db23a4
KS
112 * Save a message in a file. Mark the message as saved
113 * so we can discard when the user quits.
a13d1f28 114 */
a13d1f28
KS
115save(str)
116 char str[];
117{
c7db23a4 118
2de8fc95 119 return save1(str, 1, "save", saveignore);
c7db23a4
KS
120}
121
122/*
123 * Copy a message to a file without affected its saved-ness
124 */
125copycmd(str)
126 char str[];
127{
128
2de8fc95 129 return save1(str, 0, "copy", saveignore);
c7db23a4
KS
130}
131
132/*
133 * Save/copy the indicated messages at the end of the passed file name.
134 * If mark is true, mark the message "saved."
135 */
2de8fc95 136save1(str, mark, cmd, ignore)
c7db23a4 137 char str[];
2de8fc95
EW
138 char *cmd;
139 struct ignoretab *ignore;
c7db23a4 140{
470c33f3 141 register int *ip;
a13d1f28 142 register struct message *mp;
2de8fc95
EW
143 char *file, *disp;
144 int f, *msgvec;
a13d1f28 145 FILE *obuf;
a13d1f28
KS
146
147 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
148 if ((file = snarf(str, &f)) == NOSTR)
149 return(1);
150 if (!f) {
151 *msgvec = first(0, MMNORM);
152 if (*msgvec == NULL) {
c7db23a4 153 printf("No messages to %s.\n", cmd);
a13d1f28
KS
154 return(1);
155 }
156 msgvec[1] = NULL;
157 }
158 if (f && getmsglist(str, msgvec, 0) < 0)
159 return(1);
160 if ((file = expand(file)) == NOSTR)
161 return(1);
162 printf("\"%s\" ", file);
80187484 163 fflush(stdout);
2de8fc95 164 if (access(file, 0) >= 0)
a13d1f28
KS
165 disp = "[Appended]";
166 else
167 disp = "[New file]";
168 if ((obuf = fopen(file, "a")) == NULL) {
169 perror(NOSTR);
170 return(1);
171 }
a13d1f28 172 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
470c33f3
EW
173 mp = &message[*ip - 1];
174 touch(mp);
2de8fc95 175 if (send(mp, obuf, ignore, NOSTR) < 0) {
a13d1f28
KS
176 perror(file);
177 fclose(obuf);
178 return(1);
179 }
c7db23a4
KS
180 if (mark)
181 mp->m_flag |= MSAVED;
a13d1f28
KS
182 }
183 fflush(obuf);
184 if (ferror(obuf))
185 perror(file);
186 fclose(obuf);
2de8fc95 187 printf("%s\n", disp);
a13d1f28
KS
188 return(0);
189}
190
191/*
192 * Write the indicated messages at the end of the passed
193 * file name, minus header and trailing blank line.
194 */
195
196swrite(str)
197 char str[];
198{
a13d1f28 199
2de8fc95 200 return save1(str, 1, "write", ignoreall);
a13d1f28
KS
201}
202
203/*
204 * Snarf the file from the end of the command line and
205 * return a pointer to it. If there is no file attached,
206 * just return NOSTR. Put a null in front of the file
207 * name so that the message list processing won't see it,
208 * unless the file name is the only thing on the line, in
209 * which case, return 0 in the reference flag variable.
210 */
211
212char *
213snarf(linebuf, flag)
214 char linebuf[];
215 int *flag;
216{
217 register char *cp;
218
219 *flag = 1;
220 cp = strlen(linebuf) + linebuf - 1;
221
222 /*
223 * Strip away trailing blanks.
224 */
225
828615a1 226 while (cp > linebuf && isspace(*cp))
a13d1f28
KS
227 cp--;
228 *++cp = 0;
229
230 /*
231 * Now search for the beginning of the file name.
232 */
233
828615a1 234 while (cp > linebuf && !isspace(*cp))
a13d1f28
KS
235 cp--;
236 if (*cp == '\0') {
237 printf("No file specified.\n");
238 return(NOSTR);
239 }
828615a1 240 if (isspace(*cp))
a13d1f28
KS
241 *cp++ = 0;
242 else
243 *flag = 0;
244 return(cp);
245}
246
247/*
248 * Delete messages.
249 */
250
251delete(msgvec)
252 int msgvec[];
253{
254 return(delm(msgvec));
255}
256
257/*
258 * Delete messages, then type the new dot.
259 */
260
261deltype(msgvec)
262 int msgvec[];
263{
264 int list[2];
12c002da 265 int lastdot;
a13d1f28 266
12c002da 267 lastdot = dot - &message[0] + 1;
a13d1f28 268 if (delm(msgvec) >= 0) {
470c33f3 269 list[0] = dot - &message[0] + 1;
12c002da 270 if (list[0] > lastdot) {
470c33f3 271 touch(dot);
12c002da
KS
272 list[1] = NULL;
273 return(type(list));
274 }
275 printf("At EOF\n");
276 return(0);
a13d1f28
KS
277 }
278 else {
279 printf("No more messages\n");
280 return(0);
281 }
282}
283
284/*
285 * Delete the indicated messages.
286 * Set dot to some nice place afterwards.
287 * Internal interface.
288 */
289
290delm(msgvec)
291 int *msgvec;
292{
293 register struct message *mp;
470c33f3 294 register *ip;
a13d1f28
KS
295 int last;
296
297 last = NULL;
298 for (ip = msgvec; *ip != NULL; ip++) {
470c33f3
EW
299 mp = &message[*ip - 1];
300 touch(mp);
3c139aaf
KS
301 mp->m_flag |= MDELETED|MTOUCH;
302 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
470c33f3 303 last = *ip;
a13d1f28
KS
304 }
305 if (last != NULL) {
306 dot = &message[last-1];
307 last = first(0, MDELETED);
308 if (last != NULL) {
309 dot = &message[last-1];
310 return(0);
311 }
312 else {
313 dot = &message[0];
314 return(-1);
315 }
316 }
317
318 /*
319 * Following can't happen -- it keeps lint happy
320 */
321
322 return(-1);
323}
324
325/*
326 * Undelete the indicated messages.
327 */
328
329undelete(msgvec)
330 int *msgvec;
331{
332 register struct message *mp;
470c33f3
EW
333 register *ip;
334
335 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
336 mp = &message[*ip - 1];
337 touch(mp);
a13d1f28
KS
338 dot = mp;
339 mp->m_flag &= ~MDELETED;
340 }
341}
342
343/*
344 * Interactively dump core on "core"
345 */
346
347core()
348{
322c8626
EW
349 int pid;
350 extern union wait wait_status;
a13d1f28 351
322c8626
EW
352 switch (pid = vfork()) {
353 case -1:
a13d1f28
KS
354 perror("fork");
355 return(1);
322c8626 356 case 0:
a13d1f28
KS
357 abort();
358 _exit(1);
359 }
360 printf("Okie dokie");
361 fflush(stdout);
322c8626
EW
362 wait_child(pid);
363 if (wait_status.w_coredump)
364 printf(" -- Core dumped.\n");
a13d1f28 365 else
322c8626 366 printf(" -- Can't dump core.\n");
828615a1 367 return 0;
a13d1f28 368}
47e37b8b
KS
369
370/*
371 * Clobber as many bytes of stack as the user requests.
372 */
373clobber(argv)
374 char **argv;
375{
376 register int times;
377
378 if (argv[0] == 0)
379 times = 1;
380 else
381 times = (atoi(argv[0]) + 511) / 512;
ab61fde0 382 clob1(times);
47e37b8b
KS
383}
384
385/*
386 * Clobber the stack.
387 */
ab61fde0 388clob1(n)
47e37b8b
KS
389{
390 char buf[512];
391 register char *cp;
392
393 if (n <= 0)
394 return;
395 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
396 ;
ab61fde0 397 clob1(n - 1);
47e37b8b 398}
eed74ec1 399
46053c99
S
400/*
401 * Add the given header fields to the retained list.
402 * If no arguments, print the current list of retained fields.
403 */
404retfield(list)
405 char *list[];
406{
46053c99 407
887efe38 408 return ignore1(list, ignore + 1, "retained");
46053c99
S
409}
410
411/*
887efe38
EW
412 * Add the given header fields to the ignored list.
413 * If no arguments, print the current list of ignored fields.
46053c99 414 */
887efe38
EW
415igfield(list)
416 char *list[];
46053c99 417{
46053c99 418
887efe38 419 return ignore1(list, ignore, "ignored");
46053c99
S
420}
421
887efe38
EW
422saveretfield(list)
423 char *list[];
424{
425
426 return ignore1(list, saveignore + 1, "retained");
427}
428
429saveigfield(list)
eed74ec1
KS
430 char *list[];
431{
887efe38
EW
432
433 return ignore1(list, saveignore, "ignored");
434}
435
436ignore1(list, tab, which)
437 char *list[];
438 struct ignoretab *tab;
439 char *which;
440{
eed74ec1
KS
441 char field[BUFSIZ];
442 register int h;
443 register struct ignore *igp;
444 char **ap;
445
470c33f3 446 if (*list == NOSTR)
887efe38 447 return igshow(tab, which);
eed74ec1
KS
448 for (ap = list; *ap != 0; ap++) {
449 istrcpy(field, *ap);
887efe38
EW
450 if (member(field, tab))
451 continue;
eed74ec1
KS
452 h = hash(field);
453 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
828615a1
EW
454 igp->i_field = calloc((unsigned) strlen(field) + 1,
455 sizeof (char));
eed74ec1 456 strcpy(igp->i_field, field);
887efe38
EW
457 igp->i_link = tab->i_head[h];
458 tab->i_head[h] = igp;
459 tab->i_count++;
eed74ec1 460 }
887efe38 461 return 0;
eed74ec1
KS
462}
463
464/*
887efe38 465 * Print out all currently retained fields.
eed74ec1 466 */
887efe38
EW
467igshow(tab, which)
468 struct ignoretab *tab;
469 char *which;
eed74ec1 470{
887efe38 471 register int h;
eed74ec1 472 struct ignore *igp;
93be40ac
KS
473 char **ap, **ring;
474 int igcomp();
eed74ec1 475
887efe38
EW
476 if (tab->i_count == 0) {
477 printf("No fields currently being %s.\n", which);
478 return 0;
93be40ac 479 }
887efe38 480 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
93be40ac
KS
481 ap = ring;
482 for (h = 0; h < HSHSIZE; h++)
887efe38 483 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
93be40ac
KS
484 *ap++ = igp->i_field;
485 *ap = 0;
887efe38 486 qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
93be40ac
KS
487 for (ap = ring; *ap != 0; ap++)
488 printf("%s\n", *ap);
887efe38 489 return 0;
eed74ec1 490}
93be40ac
KS
491
492/*
493 * Compare two names for sorting ignored field list.
494 */
495igcomp(l, r)
496 char **l, **r;
497{
498
887efe38 499 return strcmp(*l, *r);
93be40ac 500}