4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright 1985-2002 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
41 #pragma ident "%Z%%M% %I% %E% SMI"
47 * mailx -- a modified version of a University of California at Berkeley
50 * Auxiliary functions.
53 static char *phrase(char *name
, int token
, int comma
);
54 static char *ripoff(register char *buf
);
57 * Return a pointer to a dynamic copy of the argument.
63 register char *cp
, *cp2
, *top
;
65 for (cp
= str
; *cp
; cp
++)
67 top
= (char *)salloc((unsigned)(cp
-str
+ 1));
70 for (cp
= str
, cp2
= top
; *cp
; cp
++)
77 * Announce a fatal error and die.
83 fprintf(stderr
, gettext("mailx: Panic - %s\n"), str
);
89 * Touch the named message by setting its MTOUCH flag.
90 * Touched messages have the effect of not being sent
91 * back to the system mailbox on exit.
97 register struct message
*mp
;
99 if (mesg
< 1 || mesg
> msgCount
)
101 mp
= &message
[mesg
-1];
102 mp
->m_flag
|= MTOUCH
;
103 if ((mp
->m_flag
& MREAD
) == 0)
104 mp
->m_flag
|= MREAD
|MSTATUS
;
108 * Test to see if the passed file name is a directory.
109 * Return true if it is.
117 if (stat(name
, &sbuf
) < 0)
119 return((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
);
123 * Count the number of arguments in the given string raw list.
127 argcount(char **argv
)
131 for (ap
= argv
; *ap
!= NOSTR
; ap
++)
137 * Return the desired header line from the passed message
138 * pointer (or NOSTR if the desired header field is not available).
139 * Read all the header lines and concatenate multiple instances of
140 * the requested header.
144 hfield(char field
[], struct message
*mp
, char *(*add
)(char *, char *))
147 char linebuf
[LINESIZE
];
152 if ((lc
= mp
->m_lines
) <= 0)
154 if (readline(ibuf
, linebuf
) < 0)
157 while ((lc
= gethfield(ibuf
, linebuf
, lc
)) >= 0)
158 if (ishfield(linebuf
, field
))
159 r
= (*add
)(r
, hcontents(linebuf
));
164 * Return the next header field found in the given message.
165 * Return > 0 if something found, <= 0 elsewise.
166 * Must deal with \ continuations & other such fraud.
175 char line2
[LINESIZE
];
176 register char *cp
, *cp2
;
182 if (readline(f
, linebuf
) < 0)
185 if (strlen(linebuf
) == 0)
187 if (isspace(linebuf
[0]))
189 if (!headerp(linebuf
))
193 * I guess we got a headline.
194 * Handle wraparounding
202 if (!isspace(c
) || c
== '\n')
204 if (readline(f
, line2
) < 0)
208 for (cp2
= line2
; *cp2
!= 0 && isspace(*cp2
); cp2
++)
210 if (strlen(linebuf
) + strlen(cp2
) >=
211 (unsigned)LINESIZE
-2)
213 cp
= &linebuf
[strlen(linebuf
)];
214 while (cp
> linebuf
&&
215 (isspace(cp
[-1]) || cp
[-1] == '\\'))
218 for (cp2
= line2
; *cp2
!= 0 && isspace(*cp2
); cp2
++)
220 nstrcpy(cp
, LINESIZE
- (cp
- linebuf
), cp2
);
222 if ((c
= strlen(linebuf
)) > 0) {
224 while (cp
> linebuf
&& isspace(*cp
))
234 * Check whether the passed line is a header line of
239 ishfield(char linebuf
[], char field
[])
243 if ((cp
= strchr(linebuf
, ':')) == NOSTR
)
248 if (icequal(linebuf
, field
)) {
257 * Extract the non label information from the given header field
262 hcontents(char hfield
[])
266 if ((cp
= strchr(hfield
, ':')) == NOSTR
)
269 while (*cp
&& isspace(*cp
))
275 * Compare two strings, ignoring case.
279 icequal(register char *s1
, register char *s2
)
282 while (toupper(*s1
++) == toupper(*s2
))
289 * Copy a string, lowercasing it as we go. Here dstsize is the size of
290 * the destination buffer dst.
293 istrcpy(char *dst
, int dstsize
, char *src
)
295 register char *cp
, *cp2
;
300 while (--dstsize
> 0 && *cp
!= '\0')
301 *cp2
++ = tolower(*cp
++);
306 * The following code deals with input stacking to do source
307 * commands. All but the current file pointer are saved on
311 static int ssp
= -1; /* Top of file stack */
312 static struct sstack
{
313 FILE *s_file
; /* File we were in. */
314 int s_cond
; /* Saved state of conditionals */
315 int s_loading
; /* Loading .mailrc, etc. */
319 * Pushdown current input file and switch to a new one.
320 * Set the global flag "sourcing" so that others will realize
321 * that they are no longer reading from a tty (in all probability).
330 if ((cp
= expand(name
)) == NOSTR
)
332 if ((fi
= fopen(cp
, "r")) == NULL
) {
333 printf(gettext("Unable to open %s\n"), cp
);
338 if ((maxfiles
= (int)ulimit(4, 0)) < 0)
343 sstack
= (struct sstack
*)calloc(maxfiles
, sizeof(struct sstack
));
344 if (sstack
== NULL
) {
346 "Couldn't allocate memory for sourcing stack\n"));
352 sstack
[++ssp
].s_file
= input
;
353 sstack
[ssp
].s_cond
= cond
;
354 sstack
[ssp
].s_loading
= loading
;
363 * Pop the current input back to the previous level.
364 * Update the "sourcing" flag as appropriate.
371 printf(gettext("\"Source\" stack over-pop.\n"));
377 printf(gettext("Unmatched \"if\"\n"));
378 cond
= sstack
[ssp
].s_cond
;
379 loading
= sstack
[ssp
].s_loading
;
380 input
= sstack
[ssp
--].s_file
;
387 * Touch the indicated file.
388 * This is nifty for the shell.
389 * If we have the utime() system call, this is better served
390 * by using that, since it will work for empty files.
391 * On non-utime systems, we must sleep a second, then read.
397 int rc
= utime(name
, utimep
);
401 fprintf(stderr
, gettext("Cannot utime %s in aux:alter\n"),
403 fprintf(stderr
, gettext("Errno: %d\n"), errno
);
408 * Examine the passed line buffer and
409 * return true if it is all blanks and tabs.
413 blankline(const char linebuf
[])
415 register const char *cp
;
417 for (cp
= linebuf
; *cp
; cp
++)
418 if (!any(*cp
, " \t"))
424 * Skin an arpa net address according to the RFC 822 interpretation
428 phrase(char *name
, int token
, int comma
)
431 register char *cp
, *cp2
;
432 char *bufend
, *nbufp
;
433 int gotlt
, lastsp
, didq
;
439 if (strlen(name
) >= (unsigned)LINESIZE
)
440 nbufp
= (char *)salloc(strlen(name
));
446 for (cp
= name
, cp2
= bufend
; (c
= *cp
++) != 0;) {
450 Start of a comment, ignore it.
453 while ((c
= *cp
) != 0) {
457 if (*cp
== 0) goto outcm
;
467 if (nesting
<= 0) break;
474 Start a quoted string.
475 Copy it in its entirety.
478 while ((c
= *cp
) != 0) {
482 if ((c
= *cp
) == 0) goto outqs
;
488 if (gotlt
== 0 || gotlt
== '<') {
509 if (token
&& (!comma
|| c
== '\n')) {
539 /* FALLTHROUGH . . . */
542 if (gotlt
== 0 || gotlt
== '<') {
553 return (token
? --cp
: equal(name
, nbufp
) ? name
:
554 nbufp
== nbuf
? savestr(nbuf
) : nbufp
);
560 return phrase(name
, 0, 0);
564 * Here sz is the buffer size of word.
567 yankword(char *name
, char *word
, int sz
, int comma
)
573 while (isspace(*name
))
577 cp
= phrase(name
, 1, comma
);
578 nstrcpy(word
, sz
, name
);
585 return s
&& strpbrk(s
, "(<,");
589 * Fetch the sender's name from the passed message.
593 nameof(register struct message
*mp
)
595 char namebuf
[LINESIZE
];
596 char linebuf
[LINESIZE
];
597 register char *cp
, *cp2
;
599 int first
= 1, wint
= 0;
602 if (value("from") && (cp
= hfield("from", mp
, addto
)) != NOSTR
)
606 if (readline(ibuf
, linebuf
) <= 0)
607 return(savestr(namebuf
));
609 for (cp
= linebuf
; *cp
!= ' '; cp
++)
611 while (any(*cp
, " \t"))
613 for (cp2
= &namebuf
[strlen(namebuf
)]; *cp
&& !any(*cp
, " \t") &&
614 cp2
-namebuf
< LINESIZE
-1; *cp2
++ = *cp
++)
618 if (readline(ibuf
, linebuf
) <= 0)
620 if (substr(linebuf
,"forwarded by ") != -1)
622 if (linebuf
[0] == 'F')
624 else if (linebuf
[0] == '>')
628 if (strncmp(cp
, "From ", 5) != 0)
630 if ((wint
= substr(cp
, "remote from ")) != -1) {
636 tmp
= strrchr(namebuf
, '!') + 1;
638 sizeof (namebuf
) - (tmp
- namebuf
),
641 nstrcat(namebuf
, sizeof (namebuf
), "!");
646 for (cp
= namebuf
; *cp
== '!'; cp
++);
647 while (ishost(host
, cp
))
648 cp
= strchr(cp
, '!') + 1;
649 if (value("mustbang") && !strchr(cp
, '!')) {
650 snprintf(linebuf
, sizeof (linebuf
), "%s!%s",
654 if (cp2
= hfield("from", mp
, addto
))
655 return(splice(cp
, cp2
));
661 * Splice an address into a commented recipient header.
664 splice(char *addr
, char *hdr
)
669 if (cp
= strchr(hdr
, '<')) {
670 cp2
= strchr(cp
, '>');
672 nstrcpy(buf
, sizeof (buf
), addr
);
674 snprintf(buf
, sizeof (buf
), "%.*s%s%s",
675 cp
- hdr
+ 1, hdr
, addr
, cp2
);
677 } else if (cp
= strchr(hdr
, '(')) {
678 snprintf(buf
, sizeof (buf
), "%s %s",
681 nstrcpy(buf
, sizeof (buf
), addr
);
682 return savestr(ripoff(buf
));
686 ripoff(register char *buf
)
690 cp
= buf
+ strlen(buf
);
691 while (--cp
>= buf
&& isspace(*cp
));
692 if (cp
>= buf
&& *cp
== ',')
699 * Are any of the characters in the two strings the same?
703 anyof(register char *s1
, register char *s2
)
707 while ((c
= *s1
++) != 0)
714 * See if the given header field is supposed to be ignored.
715 * Fields of the form "Content-*" can't be ignored when saving.
718 isign(char *field
, int saving
)
720 char realfld
[BUFSIZ
];
723 * Lower-case the string, so that "Status" and "status"
724 * will hash to the same place.
726 istrcpy(realfld
, sizeof (realfld
), field
);
728 if (saving
&& strncmp(realfld
, "content-", 8) == 0)
732 return (!member(realfld
, retain
));
734 return (member(realfld
, ignore
));
738 member(register char *realfield
, register struct ignore
**table
)
740 register struct ignore
*igp
;
742 for (igp
= table
[hash(realfield
)]; igp
!= 0; igp
= igp
->i_link
)
743 if (equal(igp
->i_field
, realfield
))
750 * This routine looks for string2 in string1.
751 * If found, it returns the position string2 is found at,
752 * otherwise it returns a -1.
755 substr(char *string1
, char *string2
)
757 int i
, j
, len1
, len2
;
759 len1
= strlen(string1
);
760 len2
= strlen(string2
);
761 for (i
= 0; i
< len1
- len2
+ 1; i
++) {
762 for (j
= 0; j
< len2
&& string1
[i
+j
] == string2
[j
]; j
++)
771 * Copies src to the dstsize buffer at dst. The copy will never
772 * overflow the destination buffer and the buffer will always be null
776 nstrcpy(char *dst
, int dstsize
, char *src
)
783 while (--dstsize
> 0 && *cp
!= '\0')
790 * Appends src to the dstsize buffer at dst. The append will never
791 * overflow the destination buffer and the buffer will always be null
795 nstrcat(char *dst
, int dstsize
, char *src
)
802 while (*cp2
!= '\0') {
806 while (--dstsize
> 0 && *cp
!= '\0')