--- /dev/null
+/*
+ * Copyright (c) 2009 Christopher L. Mikkelson <chris@mikk.net>
+ * All Rights Reserved, for now.
+ */
+
+#include <string.h>
+#include "msgproc.h"
+
+/* needs to be published for other callers */
+#define MULTIPART_BOUNDARY 1
+
+struct multipart_state {
+ char *boundary;
+ int blen;
+ char *line;
+ int l;
+ int state;
+};
+
+static void
+multipart_start(msgproc *m)
+{
+ struct multipart_state *mps = malloc(sizeof(struct multipart_state));
+ if (mps) {
+ bzero(mps, sizeof(*mps));
+ }
+ msgproc_setpriv(m, (void*)mps);
+}
+
+static void
+setboundary(msgproc *m, int type, void *data, size_t size)
+{
+ struct multipart_state *mps = msgproc_getpriv(m);
+ if (type != MULTIPART_BOUNDARY) return;
+ if (mps) {
+ mps->boundary = malloc(size + 2);
+ if (!mps->boundary) return;
+ mps->boundary[0] = mps->boundary[1] = '-';
+ memcpy(mps->boundary + 2, data, size);
+ mps->blen = size + 2;
+ }
+}
+
+#define STATE_INMATCH 0
+#define STATE_MATCH 1
+#define STATE_MATCHEOL 2
+#define STATE_NOMATCH 3
+#define STATE_NOMATCHEOL 4
+#define STATE_MATCHEND 5
+#define STATE_DONE 6
+
+static void
+multipart_process(msgproc *m, char *buf, size_t len)
+{
+ struct multipart_state *mps = msgproc_getpriv(m);
+ msgproc *next;
+ char *s, *t;
+ int r, n;
+
+ /* r = number of characters in current line which match
+ boundary and resided in previous buffer.
+
+ n = number of characters in current line which match
+ boundary and reside in current buffer.
+
+ mps->l = number of characters in boundary matched by
+ current line (regardless of which buffer(s)).
+
+ s = current character in buffer.
+
+ t = beginning of current part in current buffer.
+ */
+
+ if (!mps) return;
+ if (mps->state == STATE_DONE) return;
+ if (!mps->boundary) return;
+ r = mps->l;
+ next = msgproc_next(m);
+
+ for (s = t = buf; s < buf + len; s++) {
+
+ switch (mps->state) {
+ case STATE_INMATCH:
+ if (mps->boundary[mps->l++] != *s) {
+ mps->state = STATE_NOMATCH;
+ n = mps->l = 0;
+ continue;
+ }
+ n++;
+ if (mps->l < mps->blen) continue;
+ mps->state = STATE_MATCH;
+ if (*s == '\r') mps->state = STATE_MATCHEOL;
+ if (*s == '-') mps->state = STATE_MATCHEND;
+ continue;
+ case STATE_MATCH:
+ if (*s == '\r') mps->state = STATE_MATCHEOL;
+ continue;
+ case STATE_NOMATCH:
+ if (*s == '\r') mps->state = STATE_NOMATCHEOL;
+ continue;
+ case STATE_MATCHEOL:
+ if (*s == '\n') {
+ mps->state = STATE_INMATCH;
+ n = mps->l;
+ mps->l = 0;
+ break;
+ }
+ mps->state = STATE_MATCH;
+ continue;
+ case STATE_NOMATCHEOL:
+ if (*s == '\n') mps->state = STATE_INMATCH;
+ mps->state = STATE_NOMATCH;
+ continue;;
+ case STATE_MATCHEND:
+ if (*s != '-') {
+ mps->state = STATE_MATCH;
+ continue;
+ }
+ mps->state = STATE_DONE;
+ n = mps->l;
+ mps->l = 0;
+ break;
+ case STATE_DONE:
+ t=s;
+ continue;
+ }
+
+ /* "break" above lands down here, continue skips to next char */
+ /* send stuff downstream. (including a chunk of
+ boundary if partial match happened at end
+ of previous segment) */
+ if (r) {
+ msgproc_process(next, mps->boundary, r);
+ r = 0;
+ }
+ msgproc_process(next, t, s - t - n);
+ n = 0;
+
+ if (mps->state == STATE_DONE) return;
+ }
+
+ /* reached end of buffer. Process what we have. */
+ msgproc_process(next, t, s - t - n);
+}
+
+void
+multipart_finish(msgproc *m)
+{
+ struct multipart_state *mps = msgproc_getpriv(m);
+ if (mps) {
+ free(mps->boundary);
+ }
+ free(mps);
+ msgproc_free(m);
+}
+
+msgproc_module msgproc_multipart = {
+ MSGPROC_MULTIPART, /* type */
+ NULL, /* module init */
+ setboundary, /* set module parameter */
+ multipart_start, /* start module instance */
+ NULL, /* set module instance parameter */
+ multipart_process, /* process data */
+ multipart_finish, /* shut down, free module instance */
+ NULL /* shut down, free module */
+};