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
39 #pragma ident "%Z%%M% %I% %E% SMI"
47 * mailx -- a modified version of a University of California at Berkeley
50 * Message list handling.
53 static int check(int mesg
, int f
);
54 static int evalcol(int col
);
55 static int isinteger(char *buf
);
56 static void mark(int mesg
);
57 static int markall(char buf
[], int f
);
58 static int matchsubj(char *str
, int mesg
);
59 static int metamess(int meta
, int f
);
60 static void regret(int token
);
61 static int scan(char **sp
);
62 static void scaninit(void);
63 static int sender(char *str
, int mesg
);
64 static void unmark(int mesg
);
67 * Process message operand list.
68 * Convert the user string of message numbers and
69 * store the numbers into vector.
71 * Returns the count of messages picked up or -1 on error.
74 getmessage(char *buf
, int *vector
, int flags
)
77 register struct message
*mp
;
79 char delims
[] = "\t- ";
82 if (markall(buf
, flags
) < 0)
87 * Check for first message number and make sure it is
88 * at the beginning of the vector.
90 result
= strtok(buf
, delims
);
91 if (result
!= NULL
&& isinteger(result
)) {
92 firstmsg
= atoi(result
);
97 * Add marked messages to vector and skip first
98 * message number because it is already at the
99 * beginning of the vector
101 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++) {
102 if (firstmsg
== mp
- &message
[0] + 1)
104 if (mp
->m_flag
& MMARK
)
105 *ip
++ = mp
- &message
[0] + 1;
108 return (ip
- vector
);
112 * Check to see if string is an integer
114 * Returns 1 if is an integer and 0 if it is not
121 /* check for empty string */
122 if (strcmp(buf
, "") == 0) {
128 while (buf
[i
] != '\0') {
129 if (!isdigit(buf
[i
])) {
139 * Process msglist operand list.
140 * Convert the user string of message numbers and
141 * store the numbers into vector.
143 * Returns the count of messages picked up or -1 on error.
147 getmsglist(char *buf
, int *vector
, int flags
)
150 register struct message
*mp
;
152 if (markall(buf
, flags
) < 0)
155 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
156 if (mp
->m_flag
& MMARK
)
157 *ip
++ = mp
- &message
[0] + 1;
159 return (ip
- vector
);
164 * Mark all messages that the user wanted from the command
165 * line in the message structure. Return 0 on success, -1
170 * Bit values for colon modifiers.
173 #define CMNEW 01 /* New messages */
174 #define CMOLD 02 /* Old messages */
175 #define CMUNREAD 04 /* Unread messages */
176 #define CMDELETED 010 /* Deleted messages */
177 #define CMREAD 020 /* Read messages */
180 * The following table describes the letters which can follow
181 * the colon and gives the corresponding modifier bit.
184 static struct coltab
{
185 char co_char
; /* What to find past : */
186 int co_bit
; /* Associated modifier bit */
187 int co_mask
; /* m_status bits to mask */
188 int co_equal
; /* ... must equal this */
190 'n', CMNEW
, MNEW
, MNEW
,
192 'u', CMUNREAD
, MREAD
, 0,
193 'd', CMDELETED
, MDELETED
, MDELETED
,
194 'r', CMREAD
, MREAD
, MREAD
,
198 static int lastcolmod
;
201 markall(char buf
[], int f
)
205 register struct message
*mp
;
206 char *namelist
[NMLSIZE
], *bufp
;
207 int tok
, beg
, mc
, star
, other
, colmod
, colresult
;
210 for (i
= 1; i
<= msgCount
; i
++)
220 while (tok
!= TEOL
) {
225 printf(gettext("No numbers mixed with *\n"));
231 if (check(lexnumber
, f
))
233 for (i
= beg
; i
<= lexnumber
; i
++)
234 if ((message
[i
-1].m_flag
&MDELETED
) == f
)
253 "Non-numeric second argument\n"));
257 if (lexstring
[0] == ':') {
258 colresult
= evalcol(lexstring
[1]);
259 if (colresult
== 0) {
261 "Unknown colon modifier \"%s\"\n"),
268 *np
++ = savestr(lexstring
);
276 lexnumber
= metamess(lexstring
[0], f
);
284 "Can't mix \"*\" with anything\n"));
296 for (i
= 0; i
< msgCount
; i
++)
297 if ((message
[i
].m_flag
& MDELETED
) == f
) {
302 printf(gettext("No applicable messages\n"));
309 * If no numbers were given, mark all of the messages,
310 * so that we can unmark any whose sender was not selected
311 * if any user names were given.
314 if ((np
> namelist
|| colmod
!= 0) && mc
== 0)
315 for (i
= 1; i
<= msgCount
; i
++)
316 if ((message
[i
-1].m_flag
& MDELETED
) == f
)
320 * If any names were given, go through and eliminate any
321 * messages whose senders were not requested.
325 for (i
= 1; i
<= msgCount
; i
++) {
326 for (mc
= 0, np
= &namelist
[0]; *np
!= NOSTR
; np
++)
328 if (matchsubj(*np
, i
)) {
333 if (sender(*np
, i
)) {
343 * Make sure we got some decent messages.
347 for (i
= 1; i
<= msgCount
; i
++)
348 if (message
[i
-1].m_flag
& MMARK
) {
353 printf(gettext("No applicable messages from {%s"),
355 for (np
= &namelist
[1]; *np
!= NOSTR
; np
++)
363 * If any colon modifiers were given, go through and
364 * unmark any messages which do not satisfy the modifiers.
368 for (i
= 1; i
<= msgCount
; i
++) {
369 register struct coltab
*colp
;
371 mp
= &message
[i
- 1];
372 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
373 if (colp
->co_bit
& colmod
)
374 if ((mp
->m_flag
& colp
->co_mask
)
379 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
380 if (mp
->m_flag
& MMARK
)
382 if (mp
>= &message
[msgCount
]) {
383 register struct coltab
*colp
;
385 printf(gettext("No messages satisfy"));
386 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
387 if (colp
->co_bit
& colmod
)
388 printf(" :%c", colp
->co_char
);
397 * Turn the character after a colon modifier into a bit
403 register struct coltab
*colp
;
407 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
408 if (colp
->co_char
== col
)
409 return (colp
->co_bit
);
414 * Check the passed message number for legality and proper flags.
417 check(int mesg
, int f
)
419 register struct message
*mp
;
421 if (mesg
< 1 || mesg
> msgCount
) {
422 printf(gettext("%d: Invalid message number\n"), mesg
);
425 mp
= &message
[mesg
-1];
426 if ((mp
->m_flag
& MDELETED
) != f
) {
427 printf(gettext("%d: Inappropriate message\n"), mesg
);
434 * Scan out the list of string arguments, shell style
439 getrawlist(char line
[], char **argv
, int argc
)
441 register char **ap
, *cp
, *cp2
;
442 char linebuf
[LINESIZE
], quotec
;
443 register char **last
;
447 last
= argv
+ argc
- 1;
448 while (*cp
!= '\0') {
449 while (any(*cp
, " \t"))
453 while (*cp
!= '\0') {
462 if (*(cp
+1) != '\0') {
467 "Trailing \\; ignoring\n"));
483 printf(gettext("Too many elements in the list;"
484 " excess discarded\n"));
487 *ap
++ = savestr(linebuf
);
494 * scan out a single lexical item and return its token number,
495 * updating the string pointer passed **p. Also, store the value
496 * of the number or string scanned in lexnumber or lexstring as
497 * appropriate. In any event, store the scanned `thing' in lexstring.
518 register char *cp
, *cp2
;
520 register struct lex
*lp
;
524 copy(stringstack
[regretp
], lexstring
);
525 lexnumber
= numberstack
[regretp
];
526 return (regretstack
[regretp
--]);
533 * strip away leading white space.
536 while (any(c
, " \t"))
540 * If no characters remain, we are at end of line,
550 * If the leading character is a digit, scan
551 * the number and convert it on the fly.
552 * Return TNUMBER when done.
558 lexnumber
= lexnumber
*10 + c
- '0';
568 * Check for single character tokens; return such
572 for (lp
= &singles
[0]; lp
->l_char
!= 0; lp
++)
573 if (c
== lp
->l_char
) {
577 return (lp
->l_token
);
581 * We've got a string! Copy all the characters
582 * of the string into lexstring, until we see
583 * a null, space, or tab.
584 * If the lead character is a " or ', save it
585 * and scan until you get another.
594 if (quotec
== 0 && c
== '\\') {
598 fprintf(stderr
, gettext("Trailing \\; "
606 if (quotec
== 0 && any(c
, " \t"))
608 if (cp2
- lexstring
< STRINGLEN
-1)
612 if (quotec
&& c
== 0)
613 fprintf(stderr
, gettext("Missing %c\n"), quotec
);
620 * Unscan the named token by pushing it onto the regret stack.
626 if (++regretp
>= REGDEP
)
627 panic("Too many regrets");
628 regretstack
[regretp
] = token
;
629 lexstring
[STRINGLEN
-1] = '\0';
630 stringstack
[regretp
] = savestr(lexstring
);
631 numberstack
[regretp
] = lexnumber
;
635 * Reset all the scanner global variables.
645 * Find the first message whose flags & m == f and return
646 * its message number.
653 register struct message
*mp
;
655 mesg
= dot
- &message
[0] + 1;
658 for (mp
= dot
; mp
< &message
[msgCount
]; mp
++) {
659 if ((mp
->m_flag
& m
) == f
)
663 mesg
= dot
- &message
[0];
664 for (mp
= dot
-1; mp
>= &message
[0]; mp
--) {
665 if ((mp
->m_flag
& m
) == f
)
673 * See if the passed name sent the passed message number. Return true
677 sender(char *str
, int mesg
)
679 return (samebody(str
, skin(nameof(&message
[mesg
-1])), TRUE
));
683 * See if the given string matches inside the subject field of the
684 * given message. For the purpose of the scan, we ignore case differences.
685 * If it does, return true. The string search argument is assumed to
686 * have the form "/search-string." If it is of the form "/," we use the
687 * previous search string.
690 static char lastscan
[128];
693 matchsubj(char *str
, int mesg
)
695 register struct message
*mp
;
696 register char *cp
, *cp2
, *backup
;
699 if (strlen(str
) == 0)
702 nstrcpy(lastscan
, sizeof (lastscan
), str
);
703 mp
= &message
[mesg
-1];
706 * Now look, ignoring case, for the word in the string.
710 cp2
= hfield("subject", mp
, addone
);
717 if (toupper(*cp
++) != toupper(*cp2
++)) {
726 * Mark the named message by setting its mark bit.
735 if (i
< 1 || i
> msgCount
)
736 panic("Bad message number to mark");
737 message
[i
-1].m_flag
|= MMARK
;
741 * Unmark the named message.
750 if (i
< 1 || i
> msgCount
)
751 panic("Bad message number to unmark");
752 message
[i
-1].m_flag
&= ~MMARK
;
756 * Return the message number corresponding to the passed meta character.
759 metamess(int meta
, int f
)
762 register struct message
*mp
;
768 * First 'good' message left.
770 for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
771 if ((mp
->m_flag
& MDELETED
) == f
)
772 return (mp
- &message
[0] + 1);
773 printf(gettext("No applicable messages\n"));
778 * Next 'good' message left.
780 for (mp
= dot
+ 1; mp
< &message
[msgCount
]; mp
++)
781 if ((mp
->m_flag
& MDELETED
) == f
)
782 return (mp
- &message
[0] + 1);
783 printf(gettext("Referencing beyond last message\n"));
788 * Previous 'good' message.
790 for (mp
= dot
- 1; mp
>= &message
[0]; mp
--)
791 if ((mp
->m_flag
& MDELETED
) == f
)
792 return (mp
- &message
[0] + 1);
793 printf(gettext("Referencing before first message\n"));
798 * Last 'good message left.
800 for (mp
= &message
[msgCount
-1]; mp
>= &message
[0]; mp
--)
801 if ((mp
->m_flag
& MDELETED
) == f
)
802 return (mp
- &message
[0] + 1);
803 printf(gettext("No applicable messages\n"));
810 m
= dot
- &message
[0] + 1;
811 if ((dot
->m_flag
& MDELETED
) != f
) {
812 printf(gettext("%d: Inappropriate message\n"), m
);
818 printf(gettext("Unknown metachar (%c)\n"), c
);