-/* -------------------------------------------------------------------------- */
-char *pdkim_create_header(pdkim_signature *sig, int final) {
- char *rc = NULL;
- char *base64_bh = NULL;
- char *base64_b = NULL;
- pdkim_str *hdr = pdkim_strnew("DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
- if (hdr == NULL) return NULL;
-
- base64_bh = pdkim_encode_base64(sig->bodyhash, sig->bodyhash_len);
- if (base64_bh == NULL) goto BAIL;
-
- /* Required and static bits */
- if (
- pdkim_strcat(hdr,"; a=") &&
- pdkim_strcat(hdr,pdkim_algos[sig->algo]) &&
- pdkim_strcat(hdr,"; q=") &&
- pdkim_strcat(hdr,pdkim_querymethods[sig->querymethod]) &&
- pdkim_strcat(hdr,"; c=") &&
- pdkim_strcat(hdr,pdkim_canons[sig->canon_headers]) &&
- pdkim_strcat(hdr,"/") &&
- pdkim_strcat(hdr,pdkim_canons[sig->canon_body]) &&
- pdkim_strcat(hdr,"; d=") &&
- pdkim_strcat(hdr,sig->domain) &&
- pdkim_strcat(hdr,"; s=") &&
- pdkim_strcat(hdr,sig->selector) &&
- pdkim_strcat(hdr,";\r\n\th=") &&
- pdkim_strcat(hdr,sig->headernames) &&
- pdkim_strcat(hdr,"; bh=") &&
- pdkim_strcat(hdr,base64_bh) &&
- pdkim_strcat(hdr,";\r\n\t")
- ) {
- /* Optional bits */
- if (sig->identity != NULL) {
- if (!( pdkim_strcat(hdr,"i=") &&
- pdkim_strcat(hdr,sig->identity) &&
- pdkim_strcat(hdr,";") ) ) {
- goto BAIL;
- }
- }
- if (sig->created > 0) {
- if (!( pdkim_strcat(hdr,"t=") &&
- pdkim_numcat(hdr,sig->created) &&
- pdkim_strcat(hdr,";") ) ) {
- goto BAIL;
- }
- }
- if (sig->expires > 0) {
- if (!( pdkim_strcat(hdr,"x=") &&
- pdkim_numcat(hdr,sig->expires) &&
- pdkim_strcat(hdr,";") ) ) {
- goto BAIL;
- }
- }
- if (sig->bodylength >= 0) {
- if (!( pdkim_strcat(hdr,"l=") &&
- pdkim_numcat(hdr,sig->bodylength) &&
- pdkim_strcat(hdr,";") ) ) {
- goto BAIL;
- }
- }
- /* Extra linebreak */
- if (hdr->str[(hdr->len)-1] == ';') {
- if (!pdkim_strcat(hdr," \r\n\t")) goto BAIL;
+
+/* Extend a grwong header with a continuation-linebreak */
+static uschar *
+pdkim_hdr_cont(uschar * str, int * size, int * ptr, int * col)
+{
+*col = 1;
+return string_catn(str, size, ptr, US"\r\n\t", 3);
+}
+
+
+
+/*
+ * RFC 5322 specifies that header line length SHOULD be no more than 78
+ * lets make it so!
+ * pdkim_headcat
+ *
+ * returns uschar * (not nul-terminated)
+ *
+ * col: this int holds and receives column number (octets since last '\n')
+ * str: partial string to append to
+ * size: current buffer size for str
+ * ptr: current tail-pointer for str
+ * pad: padding, split line or space after before or after eg: ";"
+ * intro: - must join to payload eg "h=", usually the tag name
+ * payload: eg base64 data - long data can be split arbitrarily.
+ *
+ * this code doesn't fold the header in some of the places that RFC4871
+ * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
+ * pairs and inside long values. it also always spaces or breaks after the
+ * "pad"
+ *
+ * no guarantees are made for output given out-of range input. like tag
+ * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
+ */
+
+static uschar *
+pdkim_headcat(int * col, uschar * str, int * size, int * ptr,
+ const uschar * pad, const uschar * intro, const uschar * payload)
+{
+size_t l;
+
+if (pad)
+ {
+ l = Ustrlen(pad);
+ if (*col + l > 78)
+ str = pdkim_hdr_cont(str, size, ptr, col);
+ str = string_catn(str, size, ptr, pad, l);
+ *col += l;
+ }
+
+l = (pad?1:0) + (intro?Ustrlen(intro):0);
+
+if (*col + l > 78)
+ { /*can't fit intro - start a new line to make room.*/
+ str = pdkim_hdr_cont(str, size, ptr, col);
+ l = intro?Ustrlen(intro):0;
+ }
+
+l += payload ? Ustrlen(payload):0 ;
+
+while (l>77)
+ { /* this fragment will not fit on a single line */
+ if (pad)
+ {
+ str = string_catn(str, size, ptr, US" ", 1);
+ *col += 1;
+ pad = NULL; /* only want this once */
+ l--;