xref: /illumos-gate/usr/src/cmd/mailx/head.c (revision 55fea89d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22196c7f05SJoshua M. Clulow 
23196c7f05SJoshua M. Clulow /*
24196c7f05SJoshua M. Clulow  * Copyright 2014 Joyent, Inc.
25196c7f05SJoshua M. Clulow  */
26196c7f05SJoshua M. Clulow 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
297c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
337c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
387c478bd9Sstevel@tonic-gate  * The Regents of the University of California
397c478bd9Sstevel@tonic-gate  * All Rights Reserved
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
427c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
437c478bd9Sstevel@tonic-gate  * contributors.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
46196c7f05SJoshua M. Clulow #include <err.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include "rcv.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
527c478bd9Sstevel@tonic-gate  *	mail program
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * Routines for processing and detecting headlines.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate 
57196c7f05SJoshua M. Clulow static int nextword(const char *, custr_t *, const char **);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * See if the passed line buffer is a mail header.
617c478bd9Sstevel@tonic-gate  * Return true if yes.
627c478bd9Sstevel@tonic-gate  */
63196c7f05SJoshua M. Clulow boolean_t
is_headline(const char * linebuf)64196c7f05SJoshua M. Clulow is_headline(const char *linebuf)
657c478bd9Sstevel@tonic-gate {
66196c7f05SJoshua M. Clulow 	headline_t *hl;
67196c7f05SJoshua M. Clulow 	boolean_t ret;
68196c7f05SJoshua M. Clulow 
69196c7f05SJoshua M. Clulow 	if (strncmp("From ", linebuf, 5) != 0) {
70196c7f05SJoshua M. Clulow 		return (B_FALSE);
71196c7f05SJoshua M. Clulow 	}
72196c7f05SJoshua M. Clulow 
73196c7f05SJoshua M. Clulow 	if (headline_alloc(&hl) != 0 || parse_headline(linebuf, hl) != 0) {
74196c7f05SJoshua M. Clulow 		err(1, "could not parse headline");
757c478bd9Sstevel@tonic-gate 	}
76196c7f05SJoshua M. Clulow 
77196c7f05SJoshua M. Clulow 	ret = custr_len(hl->hl_from) > 0 ? B_TRUE : B_FALSE;
78196c7f05SJoshua M. Clulow 
79196c7f05SJoshua M. Clulow 	headline_free(hl);
80196c7f05SJoshua M. Clulow 	return (ret);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
84196c7f05SJoshua M. Clulow  * Manage headline_t objects:
857c478bd9Sstevel@tonic-gate  */
86196c7f05SJoshua M. Clulow void
headline_free(headline_t * hl)87196c7f05SJoshua M. Clulow headline_free(headline_t *hl)
88196c7f05SJoshua M. Clulow {
89196c7f05SJoshua M. Clulow 	custr_free(hl->hl_from);
90196c7f05SJoshua M. Clulow 	custr_free(hl->hl_tty);
91196c7f05SJoshua M. Clulow 	custr_free(hl->hl_date);
92196c7f05SJoshua M. Clulow 	free(hl);
93196c7f05SJoshua M. Clulow }
94196c7f05SJoshua M. Clulow 
95196c7f05SJoshua M. Clulow int
headline_alloc(headline_t ** hl)96196c7f05SJoshua M. Clulow headline_alloc(headline_t **hl)
977c478bd9Sstevel@tonic-gate {
98196c7f05SJoshua M. Clulow 	int en;
99196c7f05SJoshua M. Clulow 	headline_t *t;
100196c7f05SJoshua M. Clulow 
101196c7f05SJoshua M. Clulow 	if ((t = calloc(1, sizeof (*t))) == NULL) {
102196c7f05SJoshua M. Clulow 		return (-1);
103196c7f05SJoshua M. Clulow 	}
1047c478bd9Sstevel@tonic-gate 
105196c7f05SJoshua M. Clulow 	if (custr_alloc(&t->hl_from) != 0 || custr_alloc(&t->hl_tty) != 0 ||
106196c7f05SJoshua M. Clulow 	    custr_alloc(&t->hl_date) != 0) {
107196c7f05SJoshua M. Clulow 		en = errno;
1087c478bd9Sstevel@tonic-gate 
109196c7f05SJoshua M. Clulow 		headline_free(t);
1107c478bd9Sstevel@tonic-gate 
111196c7f05SJoshua M. Clulow 		errno = en;
112196c7f05SJoshua M. Clulow 		return (-1);
113196c7f05SJoshua M. Clulow 	}
114196c7f05SJoshua M. Clulow 
115196c7f05SJoshua M. Clulow 	*hl = t;
116196c7f05SJoshua M. Clulow 	return (0);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
120196c7f05SJoshua M. Clulow  * Clear all of the strings in a headline_t:
1217c478bd9Sstevel@tonic-gate  */
122196c7f05SJoshua M. Clulow void
headline_reset(headline_t * hl)123196c7f05SJoshua M. Clulow headline_reset(headline_t *hl)
124196c7f05SJoshua M. Clulow {
125196c7f05SJoshua M. Clulow 	custr_reset(hl->hl_from);
126196c7f05SJoshua M. Clulow 	custr_reset(hl->hl_tty);
127196c7f05SJoshua M. Clulow 	custr_reset(hl->hl_date);
128196c7f05SJoshua M. Clulow }
1297c478bd9Sstevel@tonic-gate 
130196c7f05SJoshua M. Clulow int
parse_headline(const char * line,headline_t * hl)131196c7f05SJoshua M. Clulow parse_headline(const char *line, headline_t *hl)
1327c478bd9Sstevel@tonic-gate {
133196c7f05SJoshua M. Clulow 	const char *c = line;
134196c7f05SJoshua M. Clulow 
135196c7f05SJoshua M. Clulow 	headline_reset(hl);
136196c7f05SJoshua M. Clulow 
137196c7f05SJoshua M. Clulow 	/*
138196c7f05SJoshua M. Clulow 	 * Load the first word from the line and ensure that it is "From".
139196c7f05SJoshua M. Clulow 	 */
140196c7f05SJoshua M. Clulow 	if (nextword(c, hl->hl_from, &c) != 0) {
141196c7f05SJoshua M. Clulow 		return (-1);
142196c7f05SJoshua M. Clulow 	}
143196c7f05SJoshua M. Clulow 	if (strcmp(custr_cstr(hl->hl_from), "From") != 0) {
144196c7f05SJoshua M. Clulow 		errno = EINVAL;
145196c7f05SJoshua M. Clulow 		return (-1);
146196c7f05SJoshua M. Clulow 	}
147196c7f05SJoshua M. Clulow 	custr_reset(hl->hl_from);
148196c7f05SJoshua M. Clulow 
149196c7f05SJoshua M. Clulow 	/*
150196c7f05SJoshua M. Clulow 	 * The next word will be the From address.
151196c7f05SJoshua M. Clulow 	 */
152196c7f05SJoshua M. Clulow 	if (nextword(c, hl->hl_from, &c) != 0) {
153196c7f05SJoshua M. Clulow 		return (-1);
154196c7f05SJoshua M. Clulow 	}
155196c7f05SJoshua M. Clulow 
156196c7f05SJoshua M. Clulow 	/*
157196c7f05SJoshua M. Clulow 	 * If there is a next word, the rest of the string is the Date.
158196c7f05SJoshua M. Clulow 	 */
159196c7f05SJoshua M. Clulow 	if (c != NULL) {
160196c7f05SJoshua M. Clulow 		if (custr_append(hl->hl_date, c) != 0) {
161196c7f05SJoshua M. Clulow 			return (-1);
162196c7f05SJoshua M. Clulow 		}
163196c7f05SJoshua M. Clulow 	}
164196c7f05SJoshua M. Clulow 
165196c7f05SJoshua M. Clulow 	errno = 0;
166196c7f05SJoshua M. Clulow 	return (0);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
170196c7f05SJoshua M. Clulow  * Collect a space- or tab-delimited word into the word buffer, if one is
171196c7f05SJoshua M. Clulow  * passed.  The double quote character (") can be used to include whitespace
172196c7f05SJoshua M. Clulow  * within a word.  Set "nextword" to the location of the first character of the
173196c7f05SJoshua M. Clulow  * _next_ word, or NULL if there were no more words.  Returns 0 on success or
174196c7f05SJoshua M. Clulow  * -1 otherwise.
1757c478bd9Sstevel@tonic-gate  */
176196c7f05SJoshua M. Clulow static int
nextword(const char * input,custr_t * word,const char ** nextword)177196c7f05SJoshua M. Clulow nextword(const char *input, custr_t *word, const char **nextword)
1787c478bd9Sstevel@tonic-gate {
179196c7f05SJoshua M. Clulow 	boolean_t in_quotes = B_FALSE;
180196c7f05SJoshua M. Clulow 	const char *c = input != NULL ? input : "";
181196c7f05SJoshua M. Clulow 
182196c7f05SJoshua M. Clulow 	/*
183196c7f05SJoshua M. Clulow 	 * Collect the first word into the word buffer, if one is provided.
184196c7f05SJoshua M. Clulow 	 */
185196c7f05SJoshua M. Clulow 	for (;;) {
186196c7f05SJoshua M. Clulow 		if (*c == '\0') {
187196c7f05SJoshua M. Clulow 			/*
188196c7f05SJoshua M. Clulow 			 * We have reached the end of the string.
189196c7f05SJoshua M. Clulow 			 */
190196c7f05SJoshua M. Clulow 			*nextword = NULL;
191196c7f05SJoshua M. Clulow 			return (0);
192196c7f05SJoshua M. Clulow 		}
193196c7f05SJoshua M. Clulow 
194196c7f05SJoshua M. Clulow 		if (*c == '"') {
195196c7f05SJoshua M. Clulow 			/*
196196c7f05SJoshua M. Clulow 			 * Either beginning or ending a quoted string.
197196c7f05SJoshua M. Clulow 			 */
198196c7f05SJoshua M. Clulow 			in_quotes = in_quotes ? B_FALSE : B_TRUE;
199196c7f05SJoshua M. Clulow 		}
200196c7f05SJoshua M. Clulow 
201196c7f05SJoshua M. Clulow 		if (!in_quotes && (*c == ' ' || *c == '\t')) {
202196c7f05SJoshua M. Clulow 			/*
203196c7f05SJoshua M. Clulow 			 * We have reached a whitespace region.
204196c7f05SJoshua M. Clulow 			 */
205196c7f05SJoshua M. Clulow 			break;
206196c7f05SJoshua M. Clulow 		}
207196c7f05SJoshua M. Clulow 
208196c7f05SJoshua M. Clulow 		/*
209196c7f05SJoshua M. Clulow 		 * Copy this character into the word buffer.
210196c7f05SJoshua M. Clulow 		 */
211196c7f05SJoshua M. Clulow 		if (word != NULL) {
212196c7f05SJoshua M. Clulow 			if (custr_appendc(word, *c) != 0) {
213196c7f05SJoshua M. Clulow 				return (-1);
214196c7f05SJoshua M. Clulow 			}
215196c7f05SJoshua M. Clulow 		}
216196c7f05SJoshua M. Clulow 		c++;
217196c7f05SJoshua M. Clulow 	}
218196c7f05SJoshua M. Clulow 
219196c7f05SJoshua M. Clulow 	/*
220196c7f05SJoshua M. Clulow 	 * Find the beginning of the next word, if there is one.
221196c7f05SJoshua M. Clulow 	 */
222196c7f05SJoshua M. Clulow 	for (;;) {
223196c7f05SJoshua M. Clulow 		if (*c == '\0') {
224196c7f05SJoshua M. Clulow 			/*
225196c7f05SJoshua M. Clulow 			 * We have reached the end of the string.
226196c7f05SJoshua M. Clulow 			 */
227196c7f05SJoshua M. Clulow 			*nextword = NULL;
228196c7f05SJoshua M. Clulow 			return (0);
2297c478bd9Sstevel@tonic-gate 
230196c7f05SJoshua M. Clulow 		} else if (*c != ' ' && *c != '\t') {
231196c7f05SJoshua M. Clulow 			/*
232196c7f05SJoshua M. Clulow 			 * We have located the next word.
233196c7f05SJoshua M. Clulow 			 */
234196c7f05SJoshua M. Clulow 			*nextword = c;
235196c7f05SJoshua M. Clulow 			return (0);
236196c7f05SJoshua M. Clulow 		}
237196c7f05SJoshua M. Clulow 		c++;
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate  * Copy str1 to str2, return pointer to null in str2.
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate char *
copy(char * str1,char * str2)2467c478bd9Sstevel@tonic-gate copy(char *str1, char *str2)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	register char *s1, *s2;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	s1 = str1;
2517c478bd9Sstevel@tonic-gate 	s2 = str2;
2527c478bd9Sstevel@tonic-gate 	while (*s1)
2537c478bd9Sstevel@tonic-gate 		*s2++ = *s1++;
2547c478bd9Sstevel@tonic-gate 	*s2 = 0;
2557c478bd9Sstevel@tonic-gate 	return(s2);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Is ch any of the characters in str?
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate 
262*55fea89dSDan Cross int
any(int ch,char * str)2637c478bd9Sstevel@tonic-gate any(int ch, char *str)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate 	register char *f;
2666c83d09fSrobbin 	int c;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	f = str;
2697c478bd9Sstevel@tonic-gate 	c = ch;
2707c478bd9Sstevel@tonic-gate 	while (*f)
2717c478bd9Sstevel@tonic-gate 		if (c == *f++)
2727c478bd9Sstevel@tonic-gate 			return(1);
2737c478bd9Sstevel@tonic-gate 	return(0);
2747c478bd9Sstevel@tonic-gate }
275