1 /* $NetBSD: cmd1.c,v 1.29 2007/10/29 23:20:37 christos Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
37 __RCSID("$NetBSD: cmd1.c,v 1.29 2007/10/29 23:20:37 christos Exp $");
54 * Mail -- a mail program
62 * Compute screen size.
70 if ((cp
= value(ENAME_SCREEN
)) != NULL
&& (s
= atoi(cp
)) > 0)
72 return screenheight
- 4;
76 * Print out the header of a specific message.
77 * This is a slight improvement to the standard one.
85 fmtstr
= value(ENAME_HEADER_FORMAT
);
87 fmtstr
= DEFAULT_HEADER_FORMAT
;
88 msgline
= smsgprintf(fmtstr
, get_message(mesg
));
90 msgline
[screenwidth
] = '\0';
91 (void)printf("%s\n", msgline
);
96 * Print the current active headings.
97 * Don't change dot if invoker didn't give an argument.
112 screen
= (n
- 1)/size
;
116 if ((mp
= get_message(screen
* size
+ 1)) == NULL
) {
118 msgCount
= get_msgCount();
119 if (screen
* size
+ 1 > msgCount
)
120 mp
= get_message(msgCount
- size
+ 1);
125 if (dot
!= get_message(n
))
127 for (/*EMPTY*/; mp
; mp
= next_message(mp
)) {
128 if (mp
->m_flag
& MDELETED
)
132 printhead(get_msgnum(mp
));
135 (void)printf("No more mail.\n");
142 * Scroll to the next/previous screen
160 if (s
* size
>= get_msgCount()) {
161 (void)printf("On last screenful of messages\n");
169 (void)printf("On first screenful of messages\n");
176 (void)printf("Unrecognized scrolling command \"%s\"\n", arg
);
183 * Print out the headlines for each message
184 * in the passed message list.
193 for (ip
= msgvec
; *ip
!= 0; ip
++)
196 dot
= get_message(*ip
);
201 * Print out the value of dot.
210 dot
= get_message(msgvec
[0]);
212 (void)printf("%d\n", get_msgnum(dot
));
217 * Print out all the possible commands.
221 pcmdlist(void *v __unused
)
223 const struct cmd
*cp
;
226 (void)printf("Commands are:\n");
228 for (cp
= cmdtab
; cp
->c_name
!= NULL
; cp
++) {
229 cc
+= strlen(cp
->c_name
) + 2;
232 cc
= strlen(cp
->c_name
) + 2;
234 if ((cp
+ 1)->c_name
!= NULL
)
235 (void)printf("%s, ", cp
->c_name
);
237 (void)printf("%s\n", cp
->c_name
);
245 sget_msgnum(struct message
*mp
, struct message
*parent
)
249 if (parent
== NULL
|| parent
== mp
) {
250 (void)sasprintf(&p
, "%d", mp
->m_index
);
253 p
= sget_msgnum(mp
->m_plink
, parent
);
255 (void)sasprintf(&p
, "%s.%d", p
, mp
->m_index
);
260 show_msgnum(FILE *obuf
, struct message
*mp
, struct message
*parent
)
263 if (value(ENAME_QUIET
) == NULL
)
264 (void)fprintf(obuf
, "Message %s:\n", sget_msgnum(mp
, parent
));
267 struct type1_core_args_s
{
269 struct message
*parent
;
270 struct ignoretab
*igtab
;
271 struct mime_info
**mip
;
274 type1_core(struct message
*mp
, void *v
)
276 struct type1_core_args_s
*args
;
280 show_msgnum(args
->obuf
, mp
, args
->parent
);
282 if (args
->mip
== NULL
)
283 (void)mime_sendmessage(mp
, args
->obuf
, args
->igtab
, NULL
, NULL
);
285 *args
->mip
= mime_decode_open(mp
);
286 (void)mime_sendmessage(mp
, args
->obuf
, args
->igtab
, NULL
, *args
->mip
);
287 mime_decode_close(*args
->mip
);
290 (void)sendmessage(mp
, args
->obuf
, args
->igtab
, NULL
, NULL
);
297 * Respond to a broken pipe signal --
298 * probably caused by quitting more.
300 static jmp_buf pipestop
;
304 cmd1_brokpipe(int signo __unused
)
307 longjmp(pipestop
, 1);
311 * Type out the messages requested.
314 # define type1(a,b,c) legacy_type1(a,b)
317 type1(int *msgvec
, int doign
, int mime_decode
)
323 * Some volatile variables so longjmp will get the current not
324 * starting values. Note it is the variable that is volatile,
325 * not what it is pointing at!
327 FILE *volatile obuf
; /* avoid longjmp clobbering */
328 sig_t
volatile oldsigpipe
; /* avoid longjmp clobbering? */
330 struct mime_info
*volatile mip
; /* avoid longjmp clobbering? */
335 if ((obuf
= last_registered_file(0)) == NULL
)
339 * Even without MIME_SUPPORT, we need to handle SIGPIPE here
340 * or else the handler in execute() will grab things and our
341 * exit code will never be seen.
344 oldsigpipe
= sig_signal(SIGPIPE
, cmd1_brokpipe
);
345 if (setjmp(pipestop
))
348 msgCount
= get_msgCount();
350 recursive
= do_recursion();
351 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
352 struct type1_core_args_s args
;
355 mp
= get_message(*ip
);
358 args
.parent
= recursive
? mp
: NULL
;
359 args
.igtab
= doign
? ignore
: 0;
361 args
.mip
= mime_decode
? __UNVOLATILE(&mip
) : NULL
;
365 (void)thread_recursion(mp
, type1_core
, &args
);
370 struct sigaction osa
;
374 * Ignore SIGPIPE so it can't cause a duplicate close.
376 (void)sig_ignore(SIGPIPE
, &osa
, &oset
);
377 mime_decode_close(mip
);
378 (void)sig_restore(SIGPIPE
, &osa
, &oset
);
381 (void)sig_signal(SIGPIPE
, oldsigpipe
);
391 return value(ENAME_MIME_DECODE_MSG
) != NULL
;
395 * Identical to type(), but with opposite mime behavior.
403 return type1(msgvec
, 1, !de_mime());
407 * Identical to Type(), but with opposite mime behavior.
415 return type1(msgvec
, 0, !de_mime());
417 #endif /* MIME_SUPPORT */
420 * Type out messages, honor ignored fields.
428 return type1(msgvec
, 1, de_mime());
432 * Type out messages, even printing ignored fields.
440 return type1(msgvec
, 0, de_mime());
444 * Pipe the current message buffer to a command.
450 FILE *volatile obuf
; /* void longjmp clobbering */
451 sig_t
volatile oldsigpipe
; /* XXX - is volatile needed? */
455 warn("pipcmd: no current message");
460 if (setjmp(pipestop
))
464 obuf
= Popen(cmd
, "w");
466 warn("pipecmd: Popen failed: %s", cmd
);
470 oldsigpipe
= sig_signal(SIGPIPE
, cmd1_brokpipe
);
472 (void)sendmessage(dot
, obuf
, ignoreall
, NULL
, NULL
);
475 if (obuf
!= stdout
) {
476 struct sigaction osa
;
479 * Ignore SIGPIPE so it can't cause a duplicate close.
481 (void)sig_ignore(SIGPIPE
, &osa
, &oset
);
483 (void)sig_restore(SIGPIPE
, &osa
, &oset
);
485 (void)sig_signal(SIGPIPE
, oldsigpipe
);
490 struct top_core_args_s
{
493 struct message
*parent
;
496 top_core(struct message
*mp
, void *v
)
498 char buffer
[LINESIZE
];
499 struct top_core_args_s
*args
;
508 show_msgnum(stdout
, mp
, args
->parent
);
511 for (lines
= 0; lines
< c
&& lines
<= args
->topl
; lines
++) {
513 if (readline(ibuf
, buffer
, (int)sizeof(buffer
), 0) < 0)
516 args
->lineb
= blankline(buffer
);
523 * Print the top so many lines of each desired message.
524 * The number of lines is taken from the variable "toplines"
530 struct top_core_args_s args
;
540 valtop
= value(ENAME_TOPLINES
);
541 if (valtop
!= NULL
) {
543 if (topl
< 0 || topl
> 10000)
548 recursive
= do_recursion();
549 msgCount
= get_msgCount();
550 for (ip
= msgvec
; *ip
&& ip
- msgvec
< msgCount
; ip
++) {
553 mp
= get_message(*ip
);
555 args
.parent
= recursive
? mp
: NULL
;
556 (void)thread_recursion(mp
, top_core
, &args
);
562 * Touch all the given messages so that they will
572 for (ip
= msgvec
; *ip
!= 0; ip
++) {
574 dot
= set_m_flag(*ip
, ~(MPRESERVE
| MTOUCH
), MTOUCH
);
580 * Make sure all passed messages get mboxed.
589 for (ip
= msgvec
; *ip
!= 0; ip
++) {
591 dot
= set_m_flag(*ip
,
592 ~(MPRESERVE
| MTOUCH
| MBOX
), MTOUCH
| MBOX
);
598 * List the folders the user currently has.
602 folders(void *v __unused
)
604 char dirname
[PATHSIZE
];
607 if (getfold(dirname
, sizeof(dirname
)) < 0) {
608 (void)printf("No value set for \"folder\"\n");
611 if ((cmd
= value(ENAME_LISTER
)) == NULL
)
613 (void)run_command(cmd
, NULL
, -1, -1, dirname
, NULL
);
618 * Update the mail file with any new messages that have
619 * come in since we started reading mail.
623 inc(void *v __unused
)
631 (void)printf("No new mail.\n");
632 } else if (nmsg
> 0) {
634 mdot
= newfileinfo(get_abs_msgCount() - nmsg
);
635 if ((mp
= get_message(mdot
)) != NULL
)
638 (void)printf("\"inc\" command failed...\n");