/************************************************************************/
/* */
/* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <lprintf.h>
#include <jobid.h>
#include <history.h>
#include <active.h>
#include <header.h>
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);
}