/* Distributed Checksum Clearinghouse
 *
 * build DCC headers
 *
 * Copyright (c) 2005 by Rhyolite Software
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.2.74-1.19 $Revision$
 */

#include "dcc_clnt.h"
#include "dcc_xhdr.h"


/* add text to the growing X-DCC-Warning header line */
void
dcc_add_header(DCC_HEADER_BUF *hdr, const char *p, ...)
{
	char *hp;
	u_int lim, base, n;
	va_list args;

	lim = sizeof(hdr->buf) - hdr->used;
	if (lim <= 4) {
		dcc_error_msg("header buffer too small");
		return;
	}
	hp = &hdr->buf[hdr->used];
	if (hdr->used > hdr->start_len) {
		hp[0] = ' ';
		--lim;
		base = 1;
	} else {
		base = 0;
	}
	va_start(args, p);
	n = base + vsnprintf(hp+base, lim-base, p, args);
	va_end(args);
	if (n >= lim) {
		hdr->used += lim;
		dcc_error_msg("header buffer too small");
		return;
	}
	hdr->col += n;
	/* follow RFC 2822 and limit lines to 78 */
	if (hdr->col >= DCC_MAX_HDR_LINE    /* if pushed past line end, */
	    && hdr->col-n > 8		/* & we didn't start at left margin */
	    && base == 1		/* & not the first cksum report */
	    && *(hp-1) != ';'
	    && lim-n > 1) {		/* & there is buffer space */
		memmove(hp+1, hp, n+1);	/* then break the line */
		hp[0] = '\n';
		hp[1] = '\t';
		hdr->col = n-1+8;
		++n;
	}
	hdr->used += n;
}



int
dcc_xhdr_start(char *xhdr, int xhdr_len)
{
	int inx, i;
	const char *p;

	if (!dcc_clnt_info
	    || (inx =
		dcc_clnt_info->dcc.act_inx) >= dcc_clnt_info->dcc.num_addrs) {
		p = "";
		i = 0;
	} else {
		p = dcc_clnt_info->dcc.addrs[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_START"%.*s-Metrics", i, p);
	if (i >= xhdr_len)
		i = xhdr_len-1;
	return i;
}



void
dcc_header_init(DCC_HEADER_BUF *hdr, DCC_SRVR_ID srvr_id)
{
	hdr->used = dcc_xhdr_start(hdr->buf, sizeof(hdr->buf)-8);
	hdr->col = hdr->used;
	hdr->start_len = hdr->used;

	if (srvr_id < DCC_SRVR_ID_MIN || srvr_id > DCC_SRVR_ID_MAX) {
		dcc_add_header(hdr, ": %s ??;", dcc_clnt_hostname);
	} else {
		dcc_add_header(hdr, ": %s %d;", dcc_clnt_hostname, srvr_id);
	}
}



/* add a checksum and its counts to a growing X-DCC-Warning header line */
void
dcc_add_header_ck(DCC_HEADER_BUF *hdr,
		  DCC_CK_TYPES type,	/* which kind of checksum */
		  DCC_TGTS tgts)
{
	char tbuf[30], ckcnt[10];

	dcc_add_header(hdr, DCC_XHDR_CK_PAT,
		       dcc_type2str(tbuf, sizeof(tbuf), type, 0, 0),
		       dcc_cnt2str(ckcnt, sizeof(ckcnt), tgts, 0));
}
