(burst_digest): Initial implementation of RFC 934
Showing
1 changed file
with
172 additions
and
3 deletions
... | @@ -163,6 +163,175 @@ burst_mime (mu_message_t msg) | ... | @@ -163,6 +163,175 @@ burst_mime (mu_message_t msg) |
163 | } | 163 | } |
164 | 164 | ||
165 | 165 | ||
166 | /* Digest messages */ | ||
167 | |||
168 | /* Bursting FSA states accoring to RFC 934: | ||
169 | |||
170 | S1 :: "-" S3 | ||
171 | | CRLF {CRLF} S1 | ||
172 | | c {c} S2 | ||
173 | |||
174 | S2 :: CRLF {CRLF} S1 | ||
175 | | c {c} S2 | ||
176 | |||
177 | S3 :: " " S2 | ||
178 | | c S4 ;; the bursting agent should consider the current | ||
179 | ;; message ended. | ||
180 | |||
181 | S4 :: CRLF S5 | ||
182 | | c S4 | ||
183 | |||
184 | S5 :: CRLF S5 | ||
185 | | c {c} S2 ;; The bursting agent should consider a new | ||
186 | ;; message started | ||
187 | */ | ||
188 | |||
189 | #define S1 1 | ||
190 | #define S2 2 | ||
191 | #define S3 3 | ||
192 | #define S4 4 | ||
193 | #define S5 5 | ||
194 | |||
195 | /* Negative state means no write */ | ||
196 | int transtab[][4] = { | ||
197 | /* DEF '\n' ' ' '-' */ | ||
198 | /* S1 */ { S2, S1, S2, -S3 }, | ||
199 | /* S2 */ { S2, S1, S2, S2 }, | ||
200 | /* S3 */ { -S4, -S4, -S2, -S4 }, | ||
201 | /* S4 */ { -S4, -S5, -S4, -S4 }, | ||
202 | /* S5 */ { S2, -S5, S2, S2 } | ||
203 | }; | ||
204 | |||
205 | static int | ||
206 | token_num(int c) | ||
207 | { | ||
208 | switch (c) | ||
209 | { | ||
210 | case '\n': | ||
211 | return 1; | ||
212 | case ' ': | ||
213 | return 2; | ||
214 | case '-': | ||
215 | return 3; | ||
216 | default: | ||
217 | return 0; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | static void | ||
222 | finish_stream (mu_stream_t *pstr) | ||
223 | { | ||
224 | mu_message_t msg; | ||
225 | mu_stream_seek (*pstr, 0, SEEK_SET); | ||
226 | msg = mh_stream_to_message (*pstr); | ||
227 | burst_or_copy (msg, recursive, 1); | ||
228 | mu_stream_close (*pstr); | ||
229 | mu_stream_destroy (pstr, mu_stream_get_owner (*pstr)); | ||
230 | } | ||
231 | |||
232 | static void | ||
233 | flush_stream (mu_stream_t *pstr, char *buf, size_t size) | ||
234 | { | ||
235 | int rc; | ||
236 | |||
237 | if (size == 0) | ||
238 | return; | ||
239 | if (!*pstr | ||
240 | && ((rc = mu_temp_file_stream_create (pstr, NULL)) != 0 | ||
241 | || (rc = mu_stream_open (*pstr)))) | ||
242 | { | ||
243 | mh_error (_("Cannot open temporary file: %s"), | ||
244 | mu_strerror (rc)); | ||
245 | exit (1); | ||
246 | } | ||
247 | rc = mu_stream_sequential_write (*pstr, buf, size); | ||
248 | if (rc) | ||
249 | { | ||
250 | mu_error (_("error writing temporary stream: %s"), | ||
251 | mu_strerror (rc)); | ||
252 | exit (1); /* FIXME: better error handling please */ | ||
253 | } | ||
254 | } | ||
255 | |||
256 | int | ||
257 | burst_digest (mu_message_t msg) | ||
258 | { | ||
259 | mu_stream_t is, os = NULL; | ||
260 | char *buf; | ||
261 | size_t bufsize; | ||
262 | size_t n; | ||
263 | int state = S1; | ||
264 | int rc; | ||
265 | size_t count = 0; | ||
266 | |||
267 | mu_message_size (msg, &bufsize); | ||
268 | |||
269 | for (; bufsize > 1; bufsize >>= 1) | ||
270 | if ((buf = malloc (bufsize))) | ||
271 | break; | ||
272 | |||
273 | if (!buf) | ||
274 | { | ||
275 | mh_error (_("cannot burst message: %s"), mu_strerror (ENOMEM)); | ||
276 | exit (1); | ||
277 | } | ||
278 | |||
279 | mu_message_get_stream (msg, &is); | ||
280 | |||
281 | while (mu_stream_sequential_read (is, buf, bufsize, &n) == 0 | ||
282 | && n > 0) | ||
283 | { | ||
284 | size_t start, i; | ||
285 | |||
286 | for (i = start = 0; i < n; i++) | ||
287 | { | ||
288 | int newstate = transtab[state-1][token_num(buf[i])]; | ||
289 | |||
290 | if (newstate < 0) | ||
291 | { | ||
292 | newstate = -newstate; | ||
293 | flush_stream (&os, buf + start, i - start); | ||
294 | start = i + 1; | ||
295 | } | ||
296 | |||
297 | |||
298 | if (state == S5 && newstate == S2) | ||
299 | { | ||
300 | /* As the automaton traverses from state S5 to S2, the | ||
301 | bursting agent should consider a new message started | ||
302 | and output the first character. */ | ||
303 | os = NULL; | ||
304 | count++; | ||
305 | } | ||
306 | else if (state == S3 && newstate == S4) | ||
307 | { | ||
308 | /* As the automaton traverses from state S3 to S4, the | ||
309 | bursting agent should consider the current message ended. */ | ||
310 | finish_stream (&os); | ||
311 | } | ||
312 | state = newstate; | ||
313 | } | ||
314 | |||
315 | flush_stream (&os, buf + start, i - start); | ||
316 | } | ||
317 | |||
318 | free (buf); | ||
319 | if (os) | ||
320 | { | ||
321 | if (count) | ||
322 | finish_stream (&os); | ||
323 | else | ||
324 | { | ||
325 | mu_stream_close (os); | ||
326 | mu_stream_destroy (&os, mu_stream_get_owner (os)); | ||
327 | } | ||
328 | } | ||
329 | VERBOSE((ngettext ("%lu message bursted", "%lu messages bursted", count), | ||
330 | count)); | ||
331 | return count > 0; | ||
332 | } | ||
333 | |||
334 | |||
166 | int | 335 | int |
167 | burst_or_copy (mu_message_t msg, int recursive, int copy) | 336 | burst_or_copy (mu_message_t msg, int recursive, int copy) |
168 | { | 337 | { |
... | @@ -177,8 +346,8 @@ burst_or_copy (mu_message_t msg, int recursive, int copy) | ... | @@ -177,8 +346,8 @@ burst_or_copy (mu_message_t msg, int recursive, int copy) |
177 | map.mime = 1; | 346 | map.mime = 1; |
178 | return burst_mime (msg); | 347 | return burst_mime (msg); |
179 | } | 348 | } |
180 | /* else if (is_digest (msg)) | 349 | else if (burst_digest (msg)) |
181 | return burst_digest (msg) */ | 350 | return 0; |
182 | } | 351 | } |
183 | 352 | ||
184 | if (copy) | 353 | if (copy) |
... | @@ -299,7 +468,7 @@ msg_copy (size_t num, char *file) | ... | @@ -299,7 +468,7 @@ msg_copy (size_t num, char *file) |
299 | while (rc == 0 | 468 | while (rc == 0 |
300 | && mu_stream_sequential_read (istream, buf, sizeof buf, &n) == 0 | 469 | && mu_stream_sequential_read (istream, buf, sizeof buf, &n) == 0 |
301 | && n > 0) | 470 | && n > 0) |
302 | /* FIXME: Implement RFC 934 FSA */ | 471 | /* FIXME: Implement RFC 934 FSA? */ |
303 | rc = mu_stream_sequential_write (ostream, buf, n); | 472 | rc = mu_stream_sequential_write (ostream, buf, n); |
304 | 473 | ||
305 | mu_stream_close (ostream); | 474 | mu_stream_close (ostream); | ... | ... |
-
Please register or sign in to post a comment