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