- int ws_pending;
- const char *begin, *ps;
- char comment[STRING], phrase[STRING];
- size_t phraselen = 0, commentlen = 0;
- address_t *cur, *last = NULL;
-
- RFC822Error = 0;
-
- last = top;
- while (last && last->next)
- last = last->next;
-
- ws_pending = isspace ((unsigned char) *s);
-
- begin = s = vskipspaces(s);
- while (*s) {
- if (*s == ',') {
- if (phraselen) {
- terminate_buffer (phrase, phraselen);
- add_addrspec (&top, &last, phrase, comment, &commentlen,
- sizeof (comment) - 1);
- }
- else if (commentlen && last && !last->personal) {
- terminate_buffer (comment, commentlen);
- last->personal = m_strdup(comment);
- }
-
- commentlen = 0;
- phraselen = 0;
- s++;
- begin = vskipspaces(s);
- }
- else if (*s == '(') {
- if (commentlen && commentlen < sizeof (comment) - 1)
- comment[commentlen++] = ' ';
- if ((ps =
- next_token (s, comment, &commentlen,
- sizeof (comment) - 1)) == NULL) {
- address_delete (&top);
- return NULL;
- }
- s = ps;
- }
- else if (*s == ':') {
- cur = address_new ();
- terminate_buffer (phrase, phraselen);
- cur->mailbox = m_strdup(phrase);
- cur->group = 1;
-
- if (last)
- last->next = cur;
- else
- top = cur;
- last = cur;
-
- phraselen = 0;
- commentlen = 0;
- s++;
- begin = vskipspaces(s);
- }
- else if (*s == ';') {
- if (phraselen) {
- terminate_buffer (phrase, phraselen);
- add_addrspec (&top, &last, phrase, comment, &commentlen,
- sizeof (comment) - 1);
- }
- else if (commentlen && last && !last->personal) {
- terminate_buffer (comment, commentlen);
- last->personal = m_strdup(comment);
- }
-
- /* add group terminator */
- cur = address_new ();
- if (last) {
- last->next = cur;
- last = cur;
- }
-
- phraselen = 0;
- commentlen = 0;
- s++;
- begin = vskipspaces(s);
- }
- else if (*s == '<') {
- terminate_buffer (phrase, phraselen);
- cur = address_new ();
- if (phraselen) {
- if (cur->personal)
- p_delete(&cur->personal);
- /* if we get something like "Michael R. Elkins" remove the quotes */
- rfc822_dequote_comment (phrase);
- cur->personal = m_strdup(phrase);
- }
- if ((ps =
- parse_route_addr (s + 1, comment, &commentlen,
- sizeof (comment) - 1, cur)) == NULL) {
- address_delete (&top);
- address_delete (&cur);
- return NULL;
- }
-
- if (last)
- last->next = cur;
- else
- top = cur;
- last = cur;
+ struct rfc822_parse_ctx ctx = { NULL, "", 0, "", 0 };
+ int ws_pending = 0;
+ address_t **last;
+
+ last = address_list_last(&top);
+
+ for (;;) {
+ ws_pending = ISSPACE(*s);
+ s = skipspaces(s);
+
+ switch (*s) {
+ case '\0':
+ if (ctx.phraselen) {
+ terminate_buffer(ctx.phrase);
+ terminate_buffer(ctx.comment);
+ last = add_addrspec(last, &ctx);
+ } else
+ if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+ terminate_buffer(ctx.comment);
+ ctx.cur->personal = m_strdup(ctx.comment);
+ }
+ return top;
+
+ default:
+ if (ctx.phraselen && ctx.phraselen < sizeof(ctx.phrase) - 1 && ws_pending)
+ ctx.phrase[ctx.phraselen++] = ' ';
+ s = next_token(s, ctx.phrase, &ctx.phraselen, sizeof(ctx.phrase) - 1);
+ if (!s) {
+ address_delete(&top);
+ return NULL;
+ }
+ continue;
+
+ case '(':
+ if (ctx.commentlen && ctx.commentlen < sizeof(ctx.comment) - 1)
+ ctx.comment[ctx.commentlen++] = ' ';
+ s = next_token(s, ctx.comment, &ctx.commentlen, sizeof(ctx.comment) - 1);
+ if (!s) {
+ address_delete (&top);
+ return NULL;
+ }
+ continue;
+
+ case ',':
+ if (ctx.phraselen) {
+ terminate_buffer(ctx.phrase);
+ last = add_addrspec(last, &ctx);
+ } else
+ if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+ terminate_buffer(ctx.comment);
+ ctx.cur->personal = m_strdup(ctx.comment);
+ }
+ break;
+
+ case ':':
+ terminate_buffer(ctx.phrase);
+ *last = address_new();
+ (*last)->mailbox = m_strdup(ctx.phrase);
+ (*last)->group = 1;
+ last = &(*last)->next;
+ break;
+
+ case ';':
+ if (ctx.phraselen) {
+ terminate_buffer(ctx.phrase);
+ last = add_addrspec(last, &ctx);
+ } else
+ if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+ terminate_buffer(ctx.comment);
+ ctx.cur->personal = m_strdup(ctx.comment);
+ }
+
+ /* add group terminator */
+ *last = address_new();
+ return top;
+
+ case '<':
+ terminate_buffer(ctx.phrase);
+ ctx.cur = address_new ();
+ if (ctx.phraselen) {
+ /* if we get something like "Michael R. Elkins" remove the quotes */
+ rfc822_dequote_comment(ctx.phrase);
+ ctx.cur->personal = m_strdup(ctx.phrase);
+ }
+
+ s = parse_address(skipspaces(s + 1), &ctx);
+ if (!s || *s != '>' || !ctx.cur->mailbox) {
+ address_delete(&top);
+ address_delete(&ctx.cur);
+ return NULL;
+ }
+
+ *last = ctx.cur;
+ break;
+ }