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
is_headline(const char * linebuf)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
headline_free(headline_t * hl)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
headline_alloc(headline_t ** hl)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
headline_reset(headline_t * hl)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
parse_headline(const char * line,headline_t * hl)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
nextword(const char * input,custr_t * word,const char ** nextword)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 *
copy(char * str1,char * str2)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
any(int ch,char * str)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