Commit 21f360b3 21f360b3f1544fd3b3288d9bb3bf291168c360db by Sergey Poznyakoff

(burst_digest): Initial implementation of RFC 934

1 parent 31f391f3
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);
......