/* Distributed Checksum Clearinghouse * * build and parse headers * * --C-LICENSE-- * $Revision: 1.43 $ */ #include "dcc_clnt.h" #include "dcc_xhdr.h" /* add text to the growing X-DCC header line */ void xhdr_add_str(DCC_HEADER_BUF *hdr, const char *p, ...) { char *hp; u_int lim, n; va_list args; lim = sizeof(hdr->buf) - hdr->used; if (lim <= 0) return; hp = &hdr->buf[hdr->used]; if (*(hp-1) == '\n') { *(hp-1) = ' '; ++hdr->col; } va_start(args, p); n = vsnprintf(hp, lim, p, args); va_end(args); if (n >= lim-3) { dcc_error_msg("header buffer too small"); hdr->buf[lim-1] = '\n'; hdr->used = sizeof(hdr->buf); return; } hdr->col += n; hp[n++] = '\n'; hp[n] = '\0'; hdr->used += n; /* Follow RFC 2822 and limit lines to 78. * Help SpamAssassin and others by using a single \t for * folded whitespace. */ if (hdr->col > DCC_MAX_HDR_LINE /* if pushed past line end, */ && *(hp-1) == ' ' /* & not the first cksum report, */ && hdr->used < sizeof(hdr->buf)-2) { /* & have space */ memmove(hp+1, hp, n+1); /* then break the line */ *(hp-1) = '\n'; *hp = '\t'; hdr->col = n+8; ++hdr->used; } } /* generate X-DCC field name */ int /* bytes put into buffer */ get_xhdr_fname(char *xhdr, int xhdr_len, const DCC_CLNT_INFO *info) { SRVR_INX srvr_inx; const char *brand; int i; if (!info || (srvr_inx = info->dcc.srvr_inx, !VALID_SRVR(&info->dcc, srvr_inx))) { brand = ""; i = 0; } else { brand = info->dcc.addrs[srvr_inx].brand; i = xhdr_len-sizeof(DCC_XHDR_START); if (i < 0) i = 0; if (i > ISZ(DCC_BRAND)) i = ISZ(DCC_BRAND); } i = snprintf(xhdr, xhdr_len, DCC_XHDR_PAT, i, brand); if (i >= xhdr_len) i = xhdr_len-1; return i; } /* get ready to generate an X-DCC header including generating the * field name */ void xhdr_init(DCC_HEADER_BUF *hdr, DCC_SRVR_ID srvr_id) { if (!DCC_ID_SRVR_NORMAL(srvr_id)) { hdr->used = get_xhdr_fname(hdr->buf, sizeof(hdr->buf)-8, 0); } else { hdr->used = get_xhdr_fname(hdr->buf, sizeof(hdr->buf)-8, dcc_clnt_info); } hdr->col = hdr->used; hdr->start_len = hdr->used; xhdr_add_str(hdr, ": %s %d;", dcc_clnt_hostname, srvr_id); } /* add a checksum and its counts to a growing X-DCC-Warning header line */ void xhdr_add_ck(DCC_HEADER_BUF *hdr, DCC_CK_TYPES type, /* which kind of checksum */ DCC_TGTS tgts) { char tbuf[30], ckcnt[10]; if (type == DCC_CK_G_TRIPLE_R_BULK && tgts < DCC_TGTS_TOO_MANY) { xhdr_add_str(hdr, "%s=%d%%", type2str(tbuf, sizeof(tbuf), type, 0, 0, 0), tgts-1); return; } xhdr_add_str(hdr, "%s=%s", type2str(tbuf, sizeof(tbuf), type, 0, 0, 0), tgts2str(ckcnt, sizeof(ckcnt), tgts, 0)); } /* write header with lines ending with either "\n" or "\r\n" * the buffer must already contain '\n' as needed */ void xhdr_write(LOG_WRITE_FNC fnc, void *wctxt, const char *hdr, int hdr_len, u_char crlf) /* 1=use "\r\n" instead of "\n" */ { char c; int i; if (hdr_len == 0) return; i = 0; for (;;) { c = hdr[i]; if (c == '\n' && crlf) { if (i != 0) fnc(wctxt, hdr, i); fnc(wctxt, "\r\n", 2); ++i; hdr += i; hdr_len -= i; if (hdr_len <= 0) return; i = 0; continue; } if (++i >= hdr_len) { fnc(wctxt, hdr, i); return; } } } /* create a special X-DCC header for a whitelist mail message * it lacks a DCC server-ID because there is none and to let * DCC clients distinguish it from real X-DCC headers */ void xhdr_whitelist(DCC_HEADER_BUF *hdr) { hdr->col = 0; hdr->start_len = 0; hdr->used = 0; xhdr_add_str(hdr, DCC_XHDR_START DCC_XHDR_END": %s; "DCC_XHDR_WHITELIST, dcc_clnt_hostname); } /* see if an X-DCC header looks like one of our own and so should * be deleted */ u_char /* 1=is an X-DCC-...-metrics header */ is_xhdr(const char *buf, /* complete header */ int buf_len) { const char *e; if (buf[0] != 'X' && buf[0] != 'x') return 0; if (buf_len <= LITZ(DCC_XHDR_START DCC_XHDR_END":") || CLITCMP(buf, DCC_XHDR_START)) return 0; buf += LITZ(DCC_XHDR_START); buf_len -= LITZ(DCC_XHDR_START); /* look for the end of header field name */ e = memchr(buf, ':', buf_len); if (e) { buf_len = e - buf; if (buf_len < LITZ(DCC_XHDR_END)) return 0; } buf_len -= LITZ(DCC_XHDR_END); buf += buf_len; if (!CLITCMP(buf, DCC_XHDR_END)) return 1; return 0; }