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