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