import mail(1) from openbsd
[unleashed.git] / usr / src / cmd / mailx / head.c
blobb6d09f076720fa3a69c179e09f56bdef1eb34351
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
24 * Copyright 2014 Joyent, Inc.
28 * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
32 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
33 /* All Rights Reserved */
37 * University Copyright- Copyright (c) 1982, 1986, 1988
38 * The Regents of the University of California
39 * All Rights Reserved
41 * University Acknowledgment- Portions of this document are derived from
42 * software developed by the University of California, Berkeley, and its
43 * contributors.
46 #include <err.h>
48 #include "rcv.h"
51 * mailx -- a modified version of a University of California at Berkeley
52 * mail program
54 * Routines for processing and detecting headlines.
57 static int nextword(const char *, custr_t *, const char **);
60 * See if the passed line buffer is a mail header.
61 * Return true if yes.
63 boolean_t
64 is_headline(const char *linebuf)
66 headline_t *hl;
67 boolean_t ret;
69 if (strncmp("From ", linebuf, 5) != 0) {
70 return (B_FALSE);
73 if (headline_alloc(&hl) != 0 || parse_headline(linebuf, hl) != 0) {
74 err(1, "could not parse headline");
77 ret = custr_len(hl->hl_from) > 0 ? B_TRUE : B_FALSE;
79 headline_free(hl);
80 return (ret);
84 * Manage headline_t objects:
86 void
87 headline_free(headline_t *hl)
89 custr_free(hl->hl_from);
90 custr_free(hl->hl_tty);
91 custr_free(hl->hl_date);
92 free(hl);
95 int
96 headline_alloc(headline_t **hl)
98 int en;
99 headline_t *t;
101 if ((t = calloc(1, sizeof (*t))) == NULL) {
102 return (-1);
105 if (custr_alloc(&t->hl_from) != 0 || custr_alloc(&t->hl_tty) != 0 ||
106 custr_alloc(&t->hl_date) != 0) {
107 en = errno;
109 headline_free(t);
111 errno = en;
112 return (-1);
115 *hl = t;
116 return (0);
120 * Clear all of the strings in a headline_t:
122 void
123 headline_reset(headline_t *hl)
125 custr_reset(hl->hl_from);
126 custr_reset(hl->hl_tty);
127 custr_reset(hl->hl_date);
131 parse_headline(const char *line, headline_t *hl)
133 const char *c = line;
135 headline_reset(hl);
138 * Load the first word from the line and ensure that it is "From".
140 if (nextword(c, hl->hl_from, &c) != 0) {
141 return (-1);
143 if (strcmp(custr_cstr(hl->hl_from), "From") != 0) {
144 errno = EINVAL;
145 return (-1);
147 custr_reset(hl->hl_from);
150 * The next word will be the From address.
152 if (nextword(c, hl->hl_from, &c) != 0) {
153 return (-1);
157 * If there is a next word, the rest of the string is the Date.
159 if (c != NULL) {
160 if (custr_append(hl->hl_date, c) != 0) {
161 return (-1);
165 errno = 0;
166 return (0);
170 * Collect a space- or tab-delimited word into the word buffer, if one is
171 * passed. The double quote character (") can be used to include whitespace
172 * within a word. Set "nextword" to the location of the first character of the
173 * _next_ word, or NULL if there were no more words. Returns 0 on success or
174 * -1 otherwise.
176 static int
177 nextword(const char *input, custr_t *word, const char **nextword)
179 boolean_t in_quotes = B_FALSE;
180 const char *c = input != NULL ? input : "";
183 * Collect the first word into the word buffer, if one is provided.
185 for (;;) {
186 if (*c == '\0') {
188 * We have reached the end of the string.
190 *nextword = NULL;
191 return (0);
194 if (*c == '"') {
196 * Either beginning or ending a quoted string.
198 in_quotes = in_quotes ? B_FALSE : B_TRUE;
201 if (!in_quotes && (*c == ' ' || *c == '\t')) {
203 * We have reached a whitespace region.
205 break;
209 * Copy this character into the word buffer.
211 if (word != NULL) {
212 if (custr_appendc(word, *c) != 0) {
213 return (-1);
216 c++;
220 * Find the beginning of the next word, if there is one.
222 for (;;) {
223 if (*c == '\0') {
225 * We have reached the end of the string.
227 *nextword = NULL;
228 return (0);
230 } else if (*c != ' ' && *c != '\t') {
232 * We have located the next word.
234 *nextword = c;
235 return (0);
237 c++;
242 * Copy str1 to str2, return pointer to null in str2.
245 char *
246 copy(char *str1, char *str2)
248 register char *s1, *s2;
250 s1 = str1;
251 s2 = str2;
252 while (*s1)
253 *s2++ = *s1++;
254 *s2 = 0;
255 return(s2);
259 * Is ch any of the characters in str?
262 int
263 any(int ch, char *str)
265 register char *f;
266 int c;
268 f = str;
269 c = ch;
270 while (*f)
271 if (c == *f++)
272 return(1);
273 return(0);