xref: /illumos-gate/usr/src/cmd/mailx/head.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2014 Joyent, Inc.
25  */
26 
27 /*
28  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31 
32 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
33 /*	  All Rights Reserved  	*/
34 
35 
36 /*
37  * University Copyright- Copyright (c) 1982, 1986, 1988
38  * The Regents of the University of California
39  * All Rights Reserved
40  *
41  * University Acknowledgment- Portions of this document are derived from
42  * software developed by the University of California, Berkeley, and its
43  * contributors.
44  */
45 
46 #include <err.h>
47 
48 #include "rcv.h"
49 
50 /*
51  * mailx -- a modified version of a University of California at Berkeley
52  *	mail program
53  *
54  * Routines for processing and detecting headlines.
55  */
56 
57 static int nextword(const char *, custr_t *, const char **);
58 
59 /*
60  * See if the passed line buffer is a mail header.
61  * Return true if yes.
62  */
63 boolean_t
64 is_headline(const char *linebuf)
65 {
66 	headline_t *hl;
67 	boolean_t ret;
68 
69 	if (strncmp("From ", linebuf, 5) != 0) {
70 		return (B_FALSE);
71 	}
72 
73 	if (headline_alloc(&hl) != 0 || parse_headline(linebuf, hl) != 0) {
74 		err(1, "could not parse headline");
75 	}
76 
77 	ret = custr_len(hl->hl_from) > 0 ? B_TRUE : B_FALSE;
78 
79 	headline_free(hl);
80 	return (ret);
81 }
82 
83 /*
84  * Manage headline_t objects:
85  */
86 void
87 headline_free(headline_t *hl)
88 {
89 	custr_free(hl->hl_from);
90 	custr_free(hl->hl_tty);
91 	custr_free(hl->hl_date);
92 	free(hl);
93 }
94 
95 int
96 headline_alloc(headline_t **hl)
97 {
98 	int en;
99 	headline_t *t;
100 
101 	if ((t = calloc(1, sizeof (*t))) == NULL) {
102 		return (-1);
103 	}
104 
105 	if (custr_alloc(&t->hl_from) != 0 || custr_alloc(&t->hl_tty) != 0 ||
106 	    custr_alloc(&t->hl_date) != 0) {
107 		en = errno;
108 
109 		headline_free(t);
110 
111 		errno = en;
112 		return (-1);
113 	}
114 
115 	*hl = t;
116 	return (0);
117 }
118 
119 /*
120  * Clear all of the strings in a headline_t:
121  */
122 void
123 headline_reset(headline_t *hl)
124 {
125 	custr_reset(hl->hl_from);
126 	custr_reset(hl->hl_tty);
127 	custr_reset(hl->hl_date);
128 }
129 
130 int
131 parse_headline(const char *line, headline_t *hl)
132 {
133 	const char *c = line;
134 
135 	headline_reset(hl);
136 
137 	/*
138 	 * Load the first word from the line and ensure that it is "From".
139 	 */
140 	if (nextword(c, hl->hl_from, &c) != 0) {
141 		return (-1);
142 	}
143 	if (strcmp(custr_cstr(hl->hl_from), "From") != 0) {
144 		errno = EINVAL;
145 		return (-1);
146 	}
147 	custr_reset(hl->hl_from);
148 
149 	/*
150 	 * The next word will be the From address.
151 	 */
152 	if (nextword(c, hl->hl_from, &c) != 0) {
153 		return (-1);
154 	}
155 
156 	/*
157 	 * If there is a next word, the rest of the string is the Date.
158 	 */
159 	if (c != NULL) {
160 		if (custr_append(hl->hl_date, c) != 0) {
161 			return (-1);
162 		}
163 	}
164 
165 	errno = 0;
166 	return (0);
167 }
168 
169 /*
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.
175  */
176 static int
177 nextword(const char *input, custr_t *word, const char **nextword)
178 {
179 	boolean_t in_quotes = B_FALSE;
180 	const char *c = input != NULL ? input : "";
181 
182 	/*
183 	 * Collect the first word into the word buffer, if one is provided.
184 	 */
185 	for (;;) {
186 		if (*c == '\0') {
187 			/*
188 			 * We have reached the end of the string.
189 			 */
190 			*nextword = NULL;
191 			return (0);
192 		}
193 
194 		if (*c == '"') {
195 			/*
196 			 * Either beginning or ending a quoted string.
197 			 */
198 			in_quotes = in_quotes ? B_FALSE : B_TRUE;
199 		}
200 
201 		if (!in_quotes && (*c == ' ' || *c == '\t')) {
202 			/*
203 			 * We have reached a whitespace region.
204 			 */
205 			break;
206 		}
207 
208 		/*
209 		 * Copy this character into the word buffer.
210 		 */
211 		if (word != NULL) {
212 			if (custr_appendc(word, *c) != 0) {
213 				return (-1);
214 			}
215 		}
216 		c++;
217 	}
218 
219 	/*
220 	 * Find the beginning of the next word, if there is one.
221 	 */
222 	for (;;) {
223 		if (*c == '\0') {
224 			/*
225 			 * We have reached the end of the string.
226 			 */
227 			*nextword = NULL;
228 			return (0);
229 
230 		} else if (*c != ' ' && *c != '\t') {
231 			/*
232 			 * We have located the next word.
233 			 */
234 			*nextword = c;
235 			return (0);
236 		}
237 		c++;
238 	}
239 }
240 
241 /*
242  * Copy str1 to str2, return pointer to null in str2.
243  */
244 
245 char *
246 copy(char *str1, char *str2)
247 {
248 	register char *s1, *s2;
249 
250 	s1 = str1;
251 	s2 = str2;
252 	while (*s1)
253 		*s2++ = *s1++;
254 	*s2 = 0;
255 	return(s2);
256 }
257 
258 /*
259  * Is ch any of the characters in str?
260  */
261 
262 int
263 any(int ch, char *str)
264 {
265 	register char *f;
266 	int c;
267 
268 	f = str;
269 	c = ch;
270 	while (*f)
271 		if (c == *f++)
272 			return(1);
273 	return(0);
274 }
275