static void send_header(FILE *fout, const char *line, size_t len) { int i; if (strncasecmp("To:", line, 3) != 0 && strncasecmp("Cc:", line, 3) != 0 && strncasecmp("Bcc:", line, 4) != 0 && strncasecmp("From:", line, 5) != 0) { send_line(fout, 0, "%.*s", (int)len, line); return; } if (len >= sizeof pstate.buf) { send_line(fout, 0, "%.*s", (int)len, line); return; } /* XXX * To, Cc and Bcc may need rewrite, we can reuse the * msg recipients field since former content has already * been used at this point. */ memset(&pstate, 0, sizeof(pstate)); memcpy(pstate.buf, line, len); pstate.buf[len] = 0; pstate.wpos = len - 1; msg.rcpts = NULL; msg.rcpt_cnt = 0; if (strncasecmp("From:", line, 5) == 0) { parse_addr_terminal(1); send_line(fout, 0, "%s\n", msg.from); } else { parse_addr_terminal(0); for (i = 0; i < msg.rcpt_cnt; ++i) if (*msg.rcpts[i] != '\0') send_line(fout, 0, "%s%s%s\n", i > 0 ? "\t" : "", msg.rcpts[i], i < msg.rcpt_cnt - 1 ? "," : ""); } }
static void parse_addr(char *s, size_t len, int is_from) { size_t pos = 0; int terminal = 0; /* unless this is a continuation... */ if (!WSP(s[pos]) && s[pos] != ',' && s[pos] != ';') { /* ... skip over everything before the ':' */ for (; pos < len && s[pos] != ':'; pos++) ; /* nothing */ /* ... and check & reset parser state */ parse_addr_terminal(is_from); } /* skip over ':' ',' ';' and whitespace */ for (; pos < len && !pstate.quote && (WSP(s[pos]) || s[pos] == ':' || s[pos] == ',' || s[pos] == ';'); pos++) ; /* nothing */ for (; pos < len; pos++) { if (!pstate.esc && !pstate.quote && s[pos] == '(') pstate.comment++; if (!pstate.comment && !pstate.esc && s[pos] == '"') pstate.quote = !pstate.quote; if (!pstate.comment && !pstate.quote && !pstate.esc) { if (s[pos] == ':') { /* group */ for(pos++; pos < len && WSP(s[pos]); pos++) ; /* nothing */ pstate.wpos = 0; } if (s[pos] == '\n' || s[pos] == '\r') break; if (s[pos] == ',' || s[pos] == ';') { terminal = 1; break; } if (s[pos] == '<') { pstate.brackets = 1; pstate.wpos = 0; } if (pstate.brackets && s[pos] == '>') terminal = 1; } if (!pstate.comment && !terminal && (!(!(pstate.quote || pstate.esc) && (s[pos] == '<' || WSP(s[pos]))))) { if (pstate.wpos >= sizeof(pstate.buf)) errx(1, "address exceeds buffer size"); pstate.buf[pstate.wpos++] = s[pos]; } if (!pstate.quote && pstate.comment && s[pos] == ')') pstate.comment--; if (!pstate.esc && !pstate.comment && !pstate.quote && s[pos] == '\\') pstate.esc = 1; else pstate.esc = 0; } if (terminal) parse_addr_terminal(is_from); for (; pos < len && (s[pos] == '\r' || s[pos] == '\n'); pos++) ; /* nothing */ if (pos < len) parse_addr(s + pos, len - pos, is_from); }
static int parse_message(FILE *fin, int get_from, int tflag, FILE *fout) { char *buf; size_t len; u_int i, cur = HDR_NONE; u_int header_seen = 0, header_done = 0; bzero(&pstate, sizeof(pstate)); for (;;) { buf = fgetln(fin, &len); if (buf == NULL && ferror(fin)) err(1, "fgetln"); if (buf == NULL && feof(fin)) break; if (buf == NULL || len < 1) err(1, "fgetln weird"); /* account for \r\n linebreaks */ if (len >= 2 && buf[len - 2] == '\r' && buf[len - 1] == '\n') buf[--len - 1] = '\n'; if (len == 1 && buf[0] == '\n') /* end of header */ header_done = 1; if (!WSP(buf[0])) { /* whitespace -> continuation */ if (cur == HDR_FROM) parse_addr_terminal(1); if (cur == HDR_TO || cur == HDR_CC || cur == HDR_BCC) parse_addr_terminal(0); cur = HDR_NONE; } /* not really exact, if we are still in headers */ if (len + (buf[len - 1] == '\n' ? 0 : 1) >= LINESPLIT) msg.need_linesplit = 1; for (i = 0; !header_done && cur == HDR_NONE && i < nitems(keywords); i++) if (len > strlen(keywords[i].word) && !strncasecmp(buf, keywords[i].word, strlen(keywords[i].word))) cur = keywords[i].type; if (cur != HDR_NONE) header_seen = 1; if (cur != HDR_BCC) { fprintf(fout, "%.*s", (int)len, buf); if (buf[len - 1] != '\n') fputc('\n', fout); if (ferror(fout)) err(1, "write error"); } /* * using From: as envelope sender is not sendmail compatible, * but I really want it that way - maybe needs a knob */ if (cur == HDR_FROM) { msg.saw_from++; if (get_from) parse_addr(buf, len, 1); } if (tflag && (cur == HDR_TO || cur == HDR_CC || cur == HDR_BCC)) parse_addr(buf, len, 0); if (cur == HDR_DATE) msg.saw_date++; if (cur == HDR_MSGID) msg.saw_msgid++; if (cur == HDR_MIME_VERSION) msg.saw_mime_version = 1; if (cur == HDR_CONTENT_TYPE) msg.saw_content_type = 1; if (cur == HDR_CONTENT_DISPOSITION) msg.saw_content_disposition = 1; if (cur == HDR_CONTENT_TRANSFER_ENCODING) msg.saw_content_transfer_encoding = 1; if (cur == HDR_USER_AGENT) msg.saw_user_agent = 1; } return (!header_seen); }