4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
45 * mailx -- a modified version of a University of California at Berkeley
48 * Message list handling.
51 static int check(int mesg
, int f
);
52 static int evalcol(int col
);
53 static int isinteger(char *buf
);
54 static void mark(int mesg
);
55 static int markall(char buf
[], int f
);
56 static int matchsubj(char *str
, int mesg
);
57 static int metamess(int meta
, int f
);
58 static void regret(int token
);
59 static int scan(char **sp
);
60 static void scaninit(void);
61 static int sender(char *str
, int mesg
);
62 static void unmark(int mesg
);
65 * Process message operand list.
66 * Convert the user string of message numbers and
67 * store the numbers into vector.
69 * Returns the count of messages picked up or -1 on error.
72 getmessage(char *buf
, int *vector
, int flags
)
75 register struct message
*mp
;
77 char delims
[] = "\t- ";
80 if (markall(buf
, flags
) < 0)
85 * Check for first message number and make sure it is
86 * at the beginning of the vector.
88 result
= strtok(buf
, delims
);
89 if (result
!= NULL
&& isinteger(result
)) {
90 firstmsg
= atoi(result
);
95 * Add marked messages to vector and skip first
96 * message number because it is already at the
97 * beginning of the vector
99 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++) {
100 if (firstmsg
== mp
- &message
[0] + 1)
102 if (mp
->m_flag
& MMARK
)
103 *ip
++ = mp
- &message
[0] + 1;
106 return (ip
- vector
);
110 * Check to see if string is an integer
112 * Returns 1 if is an integer and 0 if it is not
119 /* check for empty string */
120 if (strcmp(buf
, "") == 0) {
126 while (buf
[i
] != '\0') {
127 if (!isdigit(buf
[i
])) {
137 * Process msglist operand list.
138 * Convert the user string of message numbers and
139 * store the numbers into vector.
141 * Returns the count of messages picked up or -1 on error.
145 getmsglist(char *buf
, int *vector
, int flags
)
148 register struct message
*mp
;
150 if (markall(buf
, flags
) < 0)
153 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
154 if (mp
->m_flag
& MMARK
)
155 *ip
++ = mp
- &message
[0] + 1;
157 return (ip
- vector
);
162 * Mark all messages that the user wanted from the command
163 * line in the message structure. Return 0 on success, -1
168 * Bit values for colon modifiers.
171 #define CMNEW 01 /* New messages */
172 #define CMOLD 02 /* Old messages */
173 #define CMUNREAD 04 /* Unread messages */
174 #define CMDELETED 010 /* Deleted messages */
175 #define CMREAD 020 /* Read messages */
178 * The following table describes the letters which can follow
179 * the colon and gives the corresponding modifier bit.
182 static struct coltab
{
183 char co_char
; /* What to find past : */
184 int co_bit
; /* Associated modifier bit */
185 int co_mask
; /* m_status bits to mask */
186 int co_equal
; /* ... must equal this */
188 'n', CMNEW
, MNEW
, MNEW
,
190 'u', CMUNREAD
, MREAD
, 0,
191 'd', CMDELETED
, MDELETED
, MDELETED
,
192 'r', CMREAD
, MREAD
, MREAD
,
196 static int lastcolmod
;
199 markall(char buf
[], int f
)
203 register struct message
*mp
;
204 char *namelist
[NMLSIZE
], *bufp
;
205 int tok
, beg
, mc
, star
, other
, colmod
, colresult
;
208 for (i
= 1; i
<= msgCount
; i
++)
218 while (tok
!= TEOL
) {
223 printf(gettext("No numbers mixed with *\n"));
229 if (check(lexnumber
, f
))
231 for (i
= beg
; i
<= lexnumber
; i
++)
232 if ((message
[i
-1].m_flag
&MDELETED
) == f
)
251 "Non-numeric second argument\n"));
255 if (lexstring
[0] == ':') {
256 colresult
= evalcol(lexstring
[1]);
257 if (colresult
== 0) {
259 "Unknown colon modifier \"%s\"\n"),
266 *np
++ = savestr(lexstring
);
274 lexnumber
= metamess(lexstring
[0], f
);
282 "Can't mix \"*\" with anything\n"));
294 for (i
= 0; i
< msgCount
; i
++)
295 if ((message
[i
].m_flag
& MDELETED
) == f
) {
300 printf(gettext("No applicable messages\n"));
307 * If no numbers were given, mark all of the messages,
308 * so that we can unmark any whose sender was not selected
309 * if any user names were given.
312 if ((np
> namelist
|| colmod
!= 0) && mc
== 0)
313 for (i
= 1; i
<= msgCount
; i
++)
314 if ((message
[i
-1].m_flag
& MDELETED
) == f
)
318 * If any names were given, go through and eliminate any
319 * messages whose senders were not requested.
323 for (i
= 1; i
<= msgCount
; i
++) {
324 for (mc
= 0, np
= &namelist
[0]; *np
!= NOSTR
; np
++)
326 if (matchsubj(*np
, i
)) {
331 if (sender(*np
, i
)) {
341 * Make sure we got some decent messages.
345 for (i
= 1; i
<= msgCount
; i
++)
346 if (message
[i
-1].m_flag
& MMARK
) {
351 printf(gettext("No applicable messages from {%s"),
353 for (np
= &namelist
[1]; *np
!= NOSTR
; np
++)
361 * If any colon modifiers were given, go through and
362 * unmark any messages which do not satisfy the modifiers.
366 for (i
= 1; i
<= msgCount
; i
++) {
367 register struct coltab
*colp
;
369 mp
= &message
[i
- 1];
370 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
371 if (colp
->co_bit
& colmod
)
372 if ((mp
->m_flag
& colp
->co_mask
)
377 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
378 if (mp
->m_flag
& MMARK
)
380 if (mp
>= &message
[msgCount
]) {
381 register struct coltab
*colp
;
383 printf(gettext("No messages satisfy"));
384 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
385 if (colp
->co_bit
& colmod
)
386 printf(" :%c", colp
->co_char
);
395 * Turn the character after a colon modifier into a bit
401 register struct coltab
*colp
;
405 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
406 if (colp
->co_char
== col
)
407 return (colp
->co_bit
);
412 * Check the passed message number for legality and proper flags.
415 check(int mesg
, int f
)
417 register struct message
*mp
;
419 if (mesg
< 1 || mesg
> msgCount
) {
420 printf(gettext("%d: Invalid message number\n"), mesg
);
423 mp
= &message
[mesg
-1];
424 if ((mp
->m_flag
& MDELETED
) != f
) {
425 printf(gettext("%d: Inappropriate message\n"), mesg
);
432 * Scan out the list of string arguments, shell style
437 getrawlist(char line
[], char **argv
, int argc
)
439 register char **ap
, *cp
, *cp2
;
440 char linebuf
[LINESIZE
], quotec
;
441 register char **last
;
445 last
= argv
+ argc
- 1;
446 while (*cp
!= '\0') {
447 while (any(*cp
, " \t"))
451 while (*cp
!= '\0') {
460 if (*(cp
+1) != '\0') {
465 "Trailing \\; ignoring\n"));
481 printf(gettext("Too many elements in the list;"
482 " excess discarded\n"));
485 *ap
++ = savestr(linebuf
);
492 * scan out a single lexical item and return its token number,
493 * updating the string pointer passed **p. Also, store the value
494 * of the number or string scanned in lexnumber or lexstring as
495 * appropriate. In any event, store the scanned `thing' in lexstring.
516 register char *cp
, *cp2
;
518 register struct lex
*lp
;
522 copy(stringstack
[regretp
], lexstring
);
523 lexnumber
= numberstack
[regretp
];
524 return (regretstack
[regretp
--]);
531 * strip away leading white space.
534 while (any(c
, " \t"))
538 * If no characters remain, we are at end of line,
548 * If the leading character is a digit, scan
549 * the number and convert it on the fly.
550 * Return TNUMBER when done.
556 lexnumber
= lexnumber
*10 + c
- '0';
566 * Check for single character tokens; return such
570 for (lp
= &singles
[0]; lp
->l_char
!= 0; lp
++)
571 if (c
== lp
->l_char
) {
575 return (lp
->l_token
);
579 * We've got a string! Copy all the characters
580 * of the string into lexstring, until we see
581 * a null, space, or tab.
582 * If the lead character is a " or ', save it
583 * and scan until you get another.
592 if (quotec
== 0 && c
== '\\') {
596 fprintf(stderr
, gettext("Trailing \\; "
604 if (quotec
== 0 && any(c
, " \t"))
606 if (cp2
- lexstring
< STRINGLEN
-1)
610 if (quotec
&& c
== 0)
611 fprintf(stderr
, gettext("Missing %c\n"), quotec
);
618 * Unscan the named token by pushing it onto the regret stack.
624 if (++regretp
>= REGDEP
)
625 panic("Too many regrets");
626 regretstack
[regretp
] = token
;
627 lexstring
[STRINGLEN
-1] = '\0';
628 stringstack
[regretp
] = savestr(lexstring
);
629 numberstack
[regretp
] = lexnumber
;
633 * Reset all the scanner global variables.
643 * Find the first message whose flags & m == f and return
644 * its message number.
651 register struct message
*mp
;
653 mesg
= dot
- &message
[0] + 1;
656 for (mp
= dot
; mp
< &message
[msgCount
]; mp
++) {
657 if ((mp
->m_flag
& m
) == f
)
661 mesg
= dot
- &message
[0];
662 for (mp
= dot
-1; mp
>= &message
[0]; mp
--) {
663 if ((mp
->m_flag
& m
) == f
)
671 * See if the passed name sent the passed message number. Return true
675 sender(char *str
, int mesg
)
677 return (samebody(str
, skin(nameof(&message
[mesg
-1])), TRUE
));
681 * See if the given string matches inside the subject field of the
682 * given message. For the purpose of the scan, we ignore case differences.
683 * If it does, return true. The string search argument is assumed to
684 * have the form "/search-string." If it is of the form "/," we use the
685 * previous search string.
688 static char lastscan
[128];
691 matchsubj(char *str
, int mesg
)
693 register struct message
*mp
;
694 register char *cp
, *cp2
, *backup
;
697 if (strlen(str
) == 0)
700 nstrcpy(lastscan
, sizeof (lastscan
), str
);
701 mp
= &message
[mesg
-1];
704 * Now look, ignoring case, for the word in the string.
708 cp2
= hfield("subject", mp
, addone
);
715 if (toupper(*cp
++) != toupper(*cp2
++)) {
724 * Mark the named message by setting its mark bit.
733 if (i
< 1 || i
> msgCount
)
734 panic("Bad message number to mark");
735 message
[i
-1].m_flag
|= MMARK
;
739 * Unmark the named message.
748 if (i
< 1 || i
> msgCount
)
749 panic("Bad message number to unmark");
750 message
[i
-1].m_flag
&= ~MMARK
;
754 * Return the message number corresponding to the passed meta character.
757 metamess(int meta
, int f
)
760 register struct message
*mp
;
766 * First 'good' message left.
768 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
769 if ((mp
->m_flag
& MDELETED
) == f
)
770 return (mp
- &message
[0] + 1);
771 printf(gettext("No applicable messages\n"));
776 * Next 'good' message left.
778 for (mp
= dot
+ 1; mp
< &message
[msgCount
]; mp
++)
779 if ((mp
->m_flag
& MDELETED
) == f
)
780 return (mp
- &message
[0] + 1);
781 printf(gettext("Referencing beyond last message\n"));
786 * Previous 'good' message.
788 for (mp
= dot
- 1; mp
>= &message
[0]; mp
--)
789 if ((mp
->m_flag
& MDELETED
) == f
)
790 return (mp
- &message
[0] + 1);
791 printf(gettext("Referencing before first message\n"));
796 * Last 'good message left.
798 for (mp
= &message
[msgCount
-1]; mp
>= &message
[0]; mp
--)
799 if ((mp
->m_flag
& MDELETED
) == f
)
800 return (mp
- &message
[0] + 1);
801 printf(gettext("No applicable messages\n"));
808 m
= dot
- &message
[0] + 1;
809 if ((dot
->m_flag
& MDELETED
) != f
) {
810 printf(gettext("%d: Inappropriate message\n"), m
);
816 printf(gettext("Unknown metachar (%c)\n"), c
);