Imported Upstream version 0.66.1
[hcoop/debian/courier-authlib.git] / libs / rfc822 / imapsubj.c
1 /*
2 ** Copyright 2000 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5
6 /*
7 */
8 #include "config.h"
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include "rfc822.h"
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 */
264 {
265 if (*r >= 'a' && *r <= 'z')
266 *r += 'A'-'a';
267 }
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 }