1 /*
2  * Copyright 1998-2002 Ben Smithurst <ben@smithurst.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * strip Received: (and other) headers from mail folders to save space.
29  * used by ~/bin/rotatemail when archiving old mail.
30  */
31 
32 static const char rcsid[] =
33 	"$BCPS: src/mailutils/mail-strip.c,v 1.42 2003/01/19 19:18:25 ben Exp $";
34 
35 #include "misc.h"
36 
37 void usage(void);
38 int strip_file(FILE *, FILE *);
39 int strip_maildir(int, char *, FILE *);
40 
41 int
main(int argc,char * argv[])42 main(int argc, char *argv[]) {
43 	if (getopt(argc, argv, "") != -1)
44 		usage();
45 
46 	argv += optind;
47 	argc -= optind;
48 
49 	signal(SIGTERM, signal_handler);
50 	signal(SIGINT, signal_handler);
51 
52 	return (process(argv, strip_file, strip_maildir) ? 0 : 1);
53 }
54 
55 int
strip_maildir(int reset,char * fn,FILE * in_fp)56 strip_maildir(int reset, char *fn, FILE *in_fp) {
57 	FILE *out_fp;
58 	char *outfn;
59 	int e, ret;
60 
61 	if ((outfn = strdup(fn)) == NULL)
62 		return (RET_ERROR);
63 	assert (strncmp(fn, "new/", 4) == 0 || strncmp(fn, "cur/", 4) == 0);
64 	memcpy(outfn, "tmp/", 4);
65 
66 	if ((out_fp = fopen(outfn, "w")) == NULL) {
67 		e = errno;
68 		free(outfn);
69 		errno = e;
70 		return (RET_ERROR);
71 	}
72 
73 	ret = strip_file(in_fp, out_fp);
74 	e = errno;
75 
76 	if (ret == RET_CHANGE) {
77 		if (rename(outfn, fn) != 0) {
78 			ret = RET_ERROR;
79 			e = errno;
80 		} else
81 			ret = RET_NOCHANGE;
82 	}
83 
84 	fclose(out_fp);
85 	free(outfn);
86 	errno = e;
87 	return (ret);
88 }
89 
90 int
strip_file(FILE * fp,FILE * out)91 strip_file(FILE *fp, FILE *out) {
92 	int ignore, keep, header, retval, hdr_len;
93 	size_t len;
94 	char **pp, *line, *hdr_name;
95 
96 	/*
97 	 * headers to keep. MUST be lowercase and MUST be sorted.
98 	 */
99 	char *keeplist[] = {
100 		"cc", "date", "from", "in-reply-to", "message-id",
101 		"mime-version", "references", "reply-to", "sender", "status",
102 		"subject", "to", "x-status", NULL
103 	};
104 
105 	header = 1;
106 	ignore = 0;
107 	retval = RET_NOCHANGE;
108 	hdr_name = NULL;
109 	hdr_len = 0;
110 
111 	while ((line = gl_getline(fp)) != NULL) {
112 		len = strlen(line);
113 		if (sig_count > 0) {
114 			warnx("strip_file: signal received, returning");
115 			free(hdr_name);
116 			return (RET_LOCALERROR);
117 		}
118 
119 		chop(line, len);
120 
121 		if (is_from(line, 1)) {
122 			header = 1;
123 			ignore = 0;
124 			fprintf(out, "%s\n", line);
125 			continue;
126 		}
127 
128 		/* check for end of headers */
129 		if (*line == '\0') {
130 			header = 0;
131 			ignore = 0;
132 		}
133 
134 		if (header && !isspace(*line)) {
135 			/*
136 			 * it's a new header (i.e., not a long one which
137 			 * has been folded). get the header name and
138 			 * deal with it later.
139 			 */
140 			char *colon;
141 
142 			ignore = 0;
143 			colon = strchr(line, ':');
144 			if (colon == NULL) {
145 				/*
146 				 * probably not really headers. Originally,
147 				 * this would cause the program to abort,
148 				 * but some mailboxes do have lines
149 				 * starting with From_ which aren't the
150 				 * start of a new message.
151 				 */
152 				header = 0;
153 				fprintf(out, "%s\n", line);
154 				continue;
155 			} else {
156 				int i;
157 
158 				/*
159 				 * If the already allocated space isn't
160 				 * large enough, free it and allocate
161 				 * space which is large enough.
162 				 */
163 				i = colon - line + 1;
164 				if (i > hdr_len) {
165 					free(hdr_name);
166 					hdr_name = malloc(i);
167 					if (hdr_name == NULL)
168 						return (RET_ERROR);
169 					hdr_len = i;
170 				}
171 
172 				/* Do the actual copy. */
173 				i = 0;
174 				while (line + i < colon) {
175 					hdr_name[i] = tolower(line[i]);
176 					i++;
177 				}
178 				hdr_name[i] = '\0';
179 			}
180 		} else {
181 			/*
182 			 * it's either a subsequent line of a multiline
183 			 * header or it's in the body. print it,
184 			 * unless it's part of a header we're ignoring.
185 			 * (ignore === 0 in the body).
186 			 */
187 			if (!ignore)
188 				fprintf(out, "%s\n", line);
189 			continue;
190 		}
191 
192 		/* check if it's a header we want to keep */
193 		keep = strncmp(hdr_name, "content-", 8) == 0;
194 		keep = keep || (strncmp(hdr_name, "x-spam-", 7) == 0);
195 		if (!keep) {
196 			int diff;
197 			for (pp = keeplist; *pp != NULL; pp++) {
198 				diff = strcmp(hdr_name, *pp);
199 				if (diff == 0) {
200 					/* header found in keeplist */
201 					keep = 1;
202 					break;
203 				} else if (diff < 0)
204 					/*
205 					 * header from list is greater
206 					 * than the header we're checking,
207 					 * so this header isn't in the list.
208 					 */
209 					break;
210 			}
211 		}
212 
213 		if (keep)
214 			fprintf(out, "%s\n", line);
215 		else {
216 			ignore = 1;
217 			retval = RET_CHANGE;
218 		}
219 	}
220 
221 	gl_destroy(fp);
222 
223 	free(hdr_name);
224 	return (retval);
225 }
226 
227 void
usage(void)228 usage(void) {
229 	fprintf(stderr, "usage: mail-strip [file ...]\n");
230 	exit(EX_USAGE);
231 }
232