+/*
+ * RFC 5322 specifies that header line length SHOULD be no more than 78
+ * lets make it so!
+ * pdkim_headcat
+ * returns char*
+ *
+ * col: this int holds and receives column number (octets since last '\n')
+ * str: partial string to append to
+ * 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 loinger than 78, or bogus col. Input is assumed to be free of line breaks.
+ */
+
+static char *pdkim_headcat(int *col, pdkim_str *str, const char*pad,const char *intro, const char *payload ) {
+ size_t l;
+ if( pad)
+ {
+ l = strlen(pad);
+ if( *col + l > 78 )
+ {
+ pdkim_strcat(str, "\r\n\t");
+ *col=1;
+ }
+ pdkim_strncat(str, pad,l);
+ *col +=l;
+ }
+
+ l=(pad?1:0) + (intro?strlen(intro):0 );
+
+ if( *col + l > 78 )
+ { /*can't fit intro - start a new line to make room.*/
+ pdkim_strcat(str, "\r\n\t");
+ *col=1;
+ l= intro?strlen(intro):0;
+ }
+
+ l += payload ? strlen(payload):0 ;
+
+ while(l>77)
+ { /* this fragment will not fit on a single line */
+ if( pad )
+ {
+ pdkim_strcat(str, " ");
+ *col +=1;
+ pad=NULL; // only want this once
+ l--;
+ }
+ if( intro )
+ {
+ size_t sl=strlen(intro);
+ pdkim_strncat(str, intro,sl);
+ *col +=sl;
+ l-=sl;
+ intro=NULL; // only want this once
+ }
+ if(payload)
+ {
+ size_t sl=strlen(payload);
+ size_t chomp = *col+sl < 77 ? sl : 78-*col;
+ pdkim_strncat(str, payload,chomp);
+ *col +=chomp;
+ payload+=chomp;
+ l-=chomp-1;
+ }
+ // the while precondition tells us it didn't fit.
+ pdkim_strcat(str, "\r\n\t");
+ *col=1;
+ }
+ if( *col + l > 78 )
+ {
+ pdkim_strcat(str, "\r\n\t");
+ *col=1;
+ pad=NULL;
+ }
+
+ if( pad )
+ {
+ pdkim_strcat(str, " ");
+ *col +=1;
+ pad=NULL;
+ }
+
+ if( intro )
+ {
+ size_t sl=strlen(intro);
+ pdkim_strncat(str, intro,sl);
+ *col +=sl;
+ l-=sl;
+ intro=NULL;
+ }
+ if(payload)
+ {
+ size_t sl=strlen(payload);
+ pdkim_strncat(str, payload,sl);
+ *col +=sl;
+ }
+
+ return str->str;
+}