1/************************************************************************
2 *	Routines to deal with the header-field objects in formail	*
3 *									*
4 *	Copyright (c) 1990-2000, S.R. van den Berg, The Netherlands	*
5 *	#include "../README"						*
6 ************************************************************************/
7#ifdef RCS
8static /*const*/char rcsid[]=
9 "$Id: fields.c,v 1.31 2001/08/04 07:09:42 guenther Exp $";
10#endif
11#include "includes.h"
12#include "formail.h"
13#include "sublib.h"
14#include "shell.h"
15#include "common.h"
16#include "fields.h"
17#include "ecommon.h"
18#include "formisc.h"
19				/* find a field in the linked list of fields */
20struct field*findf(p,ah)const struct field*const p;register struct field**ah;
21{ size_t i;int uhead;char*chp;register struct field*h;
22  uhead=ah==&uheader||ah==&Uheader;
23  for(i=p->id_len,chp=(char*)p->fld_text,h= *ah;h;h= *(ah= &h->fld_next))
24     if(i>=h->id_len&&!strncasecmp(chp,h->fld_text,h->id_len))
25      { if(i>h->id_len&&uhead)			     /* finalise the header? */
26	   *ah=0,(*(ah=addfield(ah,chp,i)))->fld_next=h,(h= *ah)->fld_ref=0;
27	return h;
28      }
29  return (struct field*)0;
30}
31
32void cleanheader P((void))		  /* zorch whitespace before the ':' */
33{ struct field**pp,*p;char*cp;
34  for(pp=&rdheader;p= *pp;pp= &(*pp)->fld_next)
35     if((cp=p->fld_text+p->id_len-1,*cp==HEAD_DELIMITER)&&	    /* has : */
36	(*--cp==' '||*cp=='\t'))				   /* has ws */
37      { char*q=cp++;int diff;
38	while(*--q==' '||*q=='\t');		      /* find the field name */
39	tmemmove(++q,cp,p->Tot_len-p->id_len+1);		   /* zappo! */
40	p->id_len-=(diff=cp-q);
41	p->Tot_len-=diff;
42      }
43}
44
45void clear_uhead(hdr)register struct field*hdr;
46{ for(;hdr;hdr=hdr->fld_next)
47     hdr->fld_ref=0;
48}
49
50struct field**addfield(pointer,text,totlen)struct field**pointer;
51 const char*const text;const size_t totlen;    /* add field to a linked list */
52{ register struct field*p,**pp;int idlen;
53  for(pp=pointer;*pp;pp= &(*pp)->fld_next);   /* skip to the end of the list */
54  (*pp=p=malloc(FLD_HEADSIZ+totlen))->fld_next=0;idlen=breakfield(text,totlen);
55  p->id_len=idlen>0?idlen:pp==&rdheader?0:-idlen;	    /* copy contents */
56  tmemmove(p->fld_text,text,p->Tot_len=totlen);
57  return pp;
58}
59
60struct field*delfield(pointer)struct field**pointer;
61{ struct field*fldp;
62  *pointer=(fldp= *pointer)->fld_next;free(fldp);
63  return *pointer;
64}
65
66void concatenate(fldp)struct field*const fldp;
67{ register char*p;register size_t l;	    /* concatenate a continued field */
68  l=fldp->Tot_len;
69  if(!eqFrom_(p=fldp->fld_text))	    /* don't concatenate From_ lines */
70     while(l--)
71	if(*p++=='\n'&&l)    /* by substituting all newlines except the last */
72	   p[-1]=' ';
73}
74
75static void extractfield(p)register const struct field*p;
76{ if(xheader||Xheader)					 /* extracting only? */
77   { if(findf(p,&xheader))			   /* extract field contents */
78      { char*chp,*echp;
79	echp=(chp=(char*)p->fld_text+p->id_len)+(int)(p->Tot_len-p->id_len-1);
80	if(zap)
81	 { chp=skpspace(chp);
82	   while(chp<echp)
83	    { switch(*--echp)
84	       { case ' ':case '\t':continue;
85	       }
86	      echp++;
87	      break;
88	    }
89	 }
90	putssn(chp,echp-chp);putcs('\n');
91	return;
92      }
93     if(!findf(p,&Xheader))				   /* extract fields */
94	return;
95   }
96  lputssn(p->fld_text,p->Tot_len);		      /* display it entirely */
97}
98
99void flushfield(pointer)register struct field**pointer;	 /* delete and print */
100{ register struct field*p,*q;				   /* them as you go */
101  for(p= *pointer,*pointer=0;p;p=q)
102     q=p->fld_next,extractfield(p),free(p);
103}
104
105void dispfield(p)register const struct field*p;
106{ for(;p;p=p->fld_next)			     /* print list non-destructively */
107     if(p->id_len+1<p->Tot_len)			 /* any contents to display? */
108	extractfield(p);
109}
110		    /* try and append one valid field to rdheader from stdin */
111int readhead P((void))
112{ int idlen;
113  pm_getline();
114  if((idlen=breakfield(buf,buffilled))<=0) /* not the start of a valid field */
115     return 0;
116  if(idlen==STRLEN(FROM)&&eqFrom_(buf))			/* it's a From_ line */
117   { if(rdheader)
118	return 0;			       /* the From_ line was a fake! */
119     for(;buflast=='>';pm_getline());	    /* gather continued >From_ lines */
120   }
121  else
122     for(;;pm_getline())		      /* get the rest of the continued field */
123      { switch(buflast)			     /* will this line be continued? */
124	 { case ' ':case '\t':				  /* yep, it sure is */
125	      continue;
126	 }
127	break;
128      }
129  addbuf();			  /* phew, got the field, add it to rdheader */
130  return 1;
131}
132
133void addbuf P((void))
134{ addfield(&rdheader,buf,buffilled);buffilled=0;
135}
136