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