/************************************************************************/ /* */ /* News header file processing */ /* */ /* This source is public domain. Bug reports should be sent to */ /* */ /* harald@os2point.ping.de */ /* harald@haport.sesam.com */ /* Fido: 2:2448/434 */ /* */ /************************************************************************/ #include #include #include #include #include #include #include #include #include #include static KEYWORD key[] = { { "Approved" , ID_Approved }, { "Control" , ID_Control }, { "Date" , ID_Date }, { "Distribution", ID_Distribution }, { "Expires" , ID_Expires }, { "Followup-To" , ID_Followup_To }, { "From" , ID_From }, { "Keywords" , ID_Keywords }, { "Lines" , ID_Lines }, { "Message-ID" , ID_Message_ID }, { "Newsgroups" , ID_Newsgroups }, { "Organization", ID_Organization }, { "Path" , ID_Path }, { "References" , ID_References }, { "Reply-To" , ID_Reply_To }, { "Sender" , ID_Sender }, { "Subject" , ID_Subject }, { "Summary" , ID_Summary }, { "X-Newsgroups", ID_X_Newsgroups }, { "Xref" , ID_Xref } }; HEADER header[ID_LASTENTRY]; char *xheader[MAX_XHEADER]; int nxheader; int nkeys = (sizeof(key) / sizeof(*key)); static int cmpkey(char *line, KEYWORD *pkey); /************************************************************************/ /* */ /* read_header */ /* */ /* Reads an article header from file fp into buf with size bufsiz. */ /* Note that buf may contain a previously read string. */ /* */ /* Returns number of bytes read or zero on any error. */ /* */ /************************************************************************/ long read_header(FILE *fp, char *buf, int *bufsiz) { long rv = 0; char *line = buf; int buflen = *bufsiz; int boff = strlen(buf); /* Any previously read characters */ int first = 1; int cont; char *cp, *cp1, *cp2; int i; *bufsiz = 0; /* * Initialize header storage */ nxheader = 0; memset(header, 0, sizeof(header)); for(i = 0; i < nkeys; i++) header[key[i].idx].key = key[i].name; /* * Read all lines upto the first empty line and * interpret them as header lines. */ while(buflen > boff && fgets(line + boff, buflen - boff, fp)) { /* * If linefeed is missing, either the input file * is broken or we ran out of space. */ if((cp = strchr(line, '\r')) == NULL) cp = strchr(line, '\n'); if(cp == NULL) { lprintf("Article header too big or article broken"); rv = 0; break; } /* * Chop off the line feed and check if this line is empty. */ *cp = '\0'; rv += strlen(line) + 1 + boff; boff = 0; if(*line == '\0') break; /* * Continuation lines start with space or tab. Ignore * them until we found our first real header entry. */ if((cont = (*line == ' ' || *line == '\t')) != 0 && first) continue; /* * Ignore 'From ' and 'Received: ' lines which may have been * left over by some mailers. */ if(!strnicmp(line, "From ", 5) || !strnicmp(line, ">From ", 6)) continue; if(!strnicmp(line, "Received: ", 10)) continue; /* * Pack the line by removing extra spaces and control characters. */ cp1 = line - 1; cp2 = line; while(*cp2) { if(*cp2 == ' ' || *cp2 == '\t') { if(*cp1 && *cp1 != ' ' && *cp1 != '\t') *++cp1 = ' '; } else if(!iscntrl(*cp2)) *++cp1 = *cp2; cp2++; } *(cp1 + 1) = '\0'; while(*cp1 == ' ') *cp1-- = '\0'; /* * On continuation lines we will change the string delimiter * of our previous line to a space. */ if(cont) { *(line - 1) = ' '; cont = 0; } else { cp = strchr(line, ':'); if(cp) { KEYWORD *pkey; *cp = '\0'; pkey = bsearch(line, key, nkeys, sizeof(KEYWORD), cmpkey); *cp = ':'; if(pkey) { for(cp++; *cp == ' ' || *cp == '\t'; cp++) ; header[pkey->idx].info = cp; } else { if(nxheader < MAX_XHEADER) { xheader[nxheader++] = line; } } } } first = strlen(line) + 1; buflen -= first; *bufsiz += first; first = 0; line = cp1 + 2; } return(rv); } static int cmpkey(char *line, KEYWORD *pkey) { return(stricmp(line, pkey->name)); } /************************************************************************/ /* */ /* */ /************************************************************************/ char *rfc_date(char *buf, int bufsiz) { time_t t; time(&t); strftime(buf, bufsiz, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); return(buf); } /************************************************************************/ /* */ /* write_header */ /* */ /* Writes an article header to a file pointed at by fp. */ /* */ /************************************************************************/ long write_header(FILE *fp) { long rv = 0; int i; for(i = 0; i < ID_Lines; i++) if(header[i].info) rv += fprintf(fp, "%s: %s\n", header[i].key, header[i].info); for(i = 0; i < nxheader; i++) rv += fprintf(fp, "%s\n", xheader[i]); return(rv); } /************************************************************************/ /* */ /* */ /* */ /************************************************************************/ int write_xref(FILE *fp, char *node, char **ngarray) { int rv = 0; int cxref = 0; char *line = NULL; int i; char snum[12]; long himsg; for(i = 0; ngarray[i] != NULL; i++) { if(find_active(NULL, ngarray[i], NULL, &himsg)) { if(line == NULL) { line = malloc(MAX_XREFSIZE); strcpy(line, "Xref: "); strcat(line, node); } strcat(line, " "); strcat(line, ngarray[i]); strcat(line, ":"); strcat(line, ltoa(himsg + 1, snum, 10)); cxref++; } } if(line) { if(cxref > 1) rv = fprintf(fp, "%s\n", line); free(line); } return(rv); }