Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
2 | ** Copyright 2000 Double Precision, Inc. | |
3 | ** See COPYING for distribution information. | |
4 | */ | |
5 | ||
6 | /* | |
d9898ee8 | 7 | */ |
b0322a85 | 8 | #include "config.h" |
d9898ee8 | 9 | #include <stdio.h> |
10 | #include <ctype.h> | |
11 | #include <stdlib.h> | |
12 | #include <string.h> | |
13 | #include "rfc822.h" | |
d9898ee8 | 14 | |
15 | #if HAVE_STRCASECMP | |
16 | ||
17 | #else | |
18 | #define strcasecmp stricmp | |
19 | #endif | |
20 | ||
21 | #if HAVE_STRNCASECMP | |
22 | ||
23 | #else | |
24 | #define strncasecmp strnicmp | |
25 | #endif | |
26 | ||
27 | /* Skip over blobs */ | |
28 | ||
29 | static char *skipblob(char *p, char **save_blob_ptr) | |
30 | { | |
31 | char *q; | |
32 | char *orig_p=p; | |
33 | int isalldigits=1; | |
34 | ||
35 | if (*p == '[') | |
36 | { | |
37 | for (q= p+1; *q; q++) | |
38 | if (*q == '[' || *q == ']') | |
39 | break; | |
40 | else if (strchr("0123456789", *q) == NULL) | |
41 | isalldigits=0; | |
42 | ||
43 | if (*q == ']') | |
44 | { | |
45 | p=q+1; | |
46 | ||
47 | while (isspace((int)(unsigned char)*p)) | |
48 | { | |
49 | ++p; | |
50 | } | |
51 | ||
52 | if (save_blob_ptr && *save_blob_ptr && !isalldigits) | |
53 | { | |
54 | while (orig_p != p) | |
55 | *(*save_blob_ptr)++=*orig_p++; | |
56 | } | |
57 | ||
58 | return (p); | |
59 | } | |
60 | } | |
61 | return (p); | |
62 | } | |
63 | ||
64 | static char *skipblobs(char *p, char **save_blob_ptr) | |
65 | { | |
66 | char *q=p; | |
67 | ||
68 | do | |
69 | { | |
70 | p=q; | |
71 | q=skipblob(p, save_blob_ptr); | |
72 | } while (q != p); | |
73 | return (q); | |
74 | } | |
75 | ||
76 | /* Remove artifacts from the subject header */ | |
77 | ||
78 | static void stripsubj(char *s, int *hasrefwd, char *save_blob_buf) | |
79 | { | |
80 | char *p; | |
81 | char *q; | |
82 | int doit; | |
83 | ||
84 | for (p=q=s; *p; p++) | |
85 | { | |
86 | if (!isspace((int)(unsigned char)*p)) | |
87 | { | |
88 | *q++=*p; | |
89 | continue; | |
90 | } | |
91 | while (p[1] && isspace((int)(unsigned char)p[1])) | |
92 | { | |
93 | ++p; | |
94 | } | |
95 | *q++=' '; | |
96 | } | |
97 | *q=0; | |
98 | ||
99 | do | |
100 | { | |
101 | doit=0; | |
102 | /* | |
103 | ** | |
104 | ** (2) Remove all trailing text of the subject that matches | |
105 | ** the subj-trailer ABNF, repeat until no more matches are | |
106 | ** possible. | |
107 | ** | |
108 | ** subj-trailer = "(fwd)" / WSP | |
109 | */ | |
110 | ||
111 | for (p=s; *p; p++) | |
112 | ; | |
113 | while (p > s) | |
114 | { | |
115 | if ( isspace((int)(unsigned char)p[-1])) | |
116 | { | |
117 | --p; | |
118 | continue; | |
119 | } | |
120 | if (p-s >= 5 && strncasecmp(p-5, "(FWD)", 5) == 0) | |
121 | { | |
122 | p -= 5; | |
123 | *hasrefwd |= CORESUBJ_FWD; | |
124 | continue; | |
125 | } | |
126 | break; | |
127 | } | |
128 | *p=0; | |
129 | ||
130 | for (p=s; *p; ) | |
131 | { | |
132 | for (;;) | |
133 | { | |
134 | char *orig_blob_ptr; | |
135 | int flag=CORESUBJ_FWD; | |
136 | ||
137 | /* | |
138 | ** | |
139 | ** (3) Remove all prefix text of the subject | |
140 | ** that matches the subj-leader ABNF. | |
141 | ** | |
142 | ** subj-leader = (*subj-blob subj-refwd) / WSP | |
143 | ** | |
144 | ** subj-blob = "[" *BLOBCHAR "]" *WSP | |
145 | ** | |
146 | ** subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" | |
147 | ** | |
148 | ** BLOBCHAR = %x01-5a / %x5c / %x5e-7f | |
149 | ** ; any CHAR except '[' and ']' | |
150 | */ | |
151 | ||
152 | if (isspace((int)(unsigned char)*p)) | |
153 | { | |
154 | ++p; | |
155 | continue; | |
156 | } | |
157 | ||
158 | q=skipblobs(p, NULL); | |
159 | ||
160 | if (strncasecmp(q, "RE", 2) == 0) | |
161 | { | |
162 | flag=CORESUBJ_RE; | |
163 | q += 2; | |
164 | } | |
165 | else if (strncasecmp(q, "FWD", 3) == 0) | |
166 | { | |
167 | q += 3; | |
168 | } | |
169 | else if (strncasecmp(q, "FW", 2) == 0) | |
170 | { | |
171 | q += 2; | |
172 | } | |
173 | else q=0; | |
174 | ||
175 | if (q) | |
176 | { | |
177 | orig_blob_ptr=save_blob_buf; | |
178 | ||
179 | q=skipblob(q, &save_blob_buf); | |
180 | if (*q == ':') | |
181 | { | |
182 | p=q+1; | |
183 | *hasrefwd |= flag; | |
184 | continue; | |
185 | } | |
186 | ||
187 | save_blob_buf=orig_blob_ptr; | |
188 | } | |
189 | ||
190 | ||
191 | /* | |
192 | ** (4) If there is prefix text of the subject | |
193 | ** that matches the subj-blob ABNF, and | |
194 | ** removing that prefix leaves a non-empty | |
195 | ** subj-base, then remove the prefix text. | |
196 | ** | |
197 | ** subj-base = NONWSP *([*WSP] NONWSP) | |
198 | ** ; can be a subj-blob | |
199 | */ | |
200 | ||
201 | orig_blob_ptr=save_blob_buf; | |
202 | ||
203 | q=skipblob(p, &save_blob_buf); | |
204 | ||
205 | if (q != p && *q) | |
206 | { | |
207 | p=q; | |
208 | continue; | |
209 | } | |
210 | save_blob_buf=orig_blob_ptr; | |
211 | break; | |
212 | } | |
213 | ||
214 | /* | |
215 | ** | |
216 | ** (6) If the resulting text begins with the | |
217 | ** subj-fwd-hdr ABNF and ends with the subj-fwd-trl | |
218 | ** ABNF, remove the subj-fwd-hdr and subj-fwd-trl and | |
219 | ** repeat from step (2). | |
220 | ** | |
221 | ** subj-fwd-hdr = "[fwd:" | |
222 | ** | |
223 | ** subj-fwd-trl = "]" | |
224 | */ | |
225 | ||
226 | if (strncasecmp(p, "[FWD:", 5) == 0) | |
227 | { | |
228 | q=strrchr(p, ']'); | |
229 | if (q && q[1] == 0) | |
230 | { | |
231 | *q=0; | |
232 | p += 5; | |
233 | *hasrefwd |= CORESUBJ_FWD; | |
234 | ||
235 | for (q=s; (*q++=*p++) != 0; ) | |
236 | ; | |
237 | doit=1; | |
238 | } | |
239 | } | |
240 | break; | |
241 | } | |
242 | } while (doit); | |
243 | ||
244 | q=s; | |
245 | while ( (*q++ = *p++) != 0) | |
246 | ; | |
247 | if (save_blob_buf) | |
248 | *save_blob_buf=0; | |
249 | } | |
250 | ||
251 | char *rfc822_coresubj(const char *s, int *hasrefwd) | |
252 | { | |
253 | char *q=strdup(s), *r; | |
254 | int dummy; | |
255 | ||
256 | if (!hasrefwd) | |
257 | hasrefwd= &dummy; | |
258 | ||
259 | *hasrefwd=0; | |
260 | if (!q) return (0); | |
261 | ||
262 | for (r=q; *r; r++) | |
263 | if ((*r & 0x80) == 0) /* Just US-ASCII casing, thanks */ | |
b0322a85 CE |
264 | { |
265 | if (*r >= 'a' && *r <= 'z') | |
266 | *r += 'A'-'a'; | |
267 | } | |
d9898ee8 | 268 | stripsubj(q, hasrefwd, 0); |
269 | return (q); | |
270 | } | |
271 | ||
272 | char *rfc822_coresubj_nouc(const char *s, int *hasrefwd) | |
273 | { | |
274 | char *q=strdup(s); | |
275 | int dummy; | |
276 | ||
277 | if (!hasrefwd) | |
278 | hasrefwd= &dummy; | |
279 | ||
280 | *hasrefwd=0; | |
281 | if (!q) return (0); | |
282 | ||
283 | stripsubj(q, hasrefwd, 0); | |
284 | return (q); | |
285 | } | |
286 | ||
287 | char *rfc822_coresubj_keepblobs(const char *s) | |
288 | { | |
289 | char *q=strdup(s), *r; | |
290 | int dummy; | |
291 | ||
292 | if (!q) return (0); | |
293 | ||
294 | r=strdup(s); | |
295 | if (!r) | |
296 | { | |
297 | free(q); | |
298 | return (0); | |
299 | } | |
300 | ||
301 | stripsubj(q, &dummy, r); | |
302 | strcat(r, q); | |
303 | free(q); | |
304 | return (r); | |
305 | } |