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