1 /*
2 libutil -- stuff dealing with articles
3 
4 Written by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
5 Copyright 1998, 1999.
6 
7 See file COPYING for restrictions on the use of this software.
8 */
9 
10 #include "leafnode.h"
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <syslog.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include "mastring.h"
19 #include "ln_log.h"
20 
21 /**
22  * find a header in an article and return it, without its name.
23  */
24 char *
fgetheader(FILE * f,const char * header)25 fgetheader(FILE * f, const char *header)
26 {
27     char *hdr, *p;
28     size_t hlen;
29 
30     if (!header || !*header || header[(hlen = strlen(header))-1] != ':') {
31 	syslog(LOG_CRIT, "internal error in %s:%d", __FILE__, __LINE__); /* RATS: ignore */
32 	abort(); /* header must end with a colon */
33     }
34 
35     if (!f)
36 	return NULL;
37     rewind(f);
38     debug = 0;
39     hdr = NULL;
40     while ((p = getfoldedline(f, getaline)) && *p) {
41 	/* read only headers */
42 	char *q = p;
43 	if ((strncasecmp(q, header, hlen) == 0)) {
44 	    q += hlen;
45 	    while (q && *q && isspace((unsigned char)*q))
46 		q++;
47 	    hdr = critstrdup(q, "fgetheader");
48 	    free(p); p = NULL;
49 	    break;
50 	}
51 	free(p); p = NULL;
52     }
53     if (p) free(p);
54     debug = debugmode;
55     rewind(f);
56     return hdr;
57 }
58 
59 char *
getheader(const char * filename,const char * header)60 getheader(const char *filename, const char *header)
61 {
62     FILE *f;
63     char *hdr;
64     struct stat st;
65 
66     if ((f = fopen(filename, "r")) == NULL)
67 	return NULL;
68     if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode)) {
69 	(void)fclose(f);
70 	return NULL;
71     }
72     hdr = fgetheader(f, header);
73     fclose(f);
74     return hdr;
75 }
76 
77 /*
78  * store articles in newsgroups which are already stored in
79  * $SPOOLDIR/message.id/
80  */
81 void
store(const char * filename,FILE * filehandle,const char * ngs,const char * msgid)82 store(const char *filename,
83       FILE * filehandle, const char *ngs, const char *msgid)
84 {
85     char tmp[50]; /* RATS: ignore */
86     static struct newsgroup *cg;
87     static struct newsgroup *cg_active;
88     /* Ken Shan: we must not try to reuse the cg pointer,
89      * it becomes invalid as the "active" pointer is realloc()ed. */
90     mastr *xrefincase = mastr_new(4096);
91     char *p;
92     char *q;
93     char *newsgroups = critstrdup(ngs, "store");
94 
95     if (verbose > 2)
96 	printf(".storing %s: %s\n", msgid, newsgroups);
97 
98     p = newsgroups;
99     while (p && *p) {
100 	q = strchr(p, ',');
101 	if (q)
102 	    *q++ = '\0';
103 	SKIPLWS(p);
104 	if (*p) {
105 	    if (!cg || cg_active != active || strcmp(cg->name, p)) {
106 		cg = findgroup(p);
107 		cg_active = active;
108 		if (cg) {
109 		    if (isinteresting(cg->name) || create_all_links) {
110 			if (!chdirgroup(p, FALSE))
111 			    cg->first = cg->last + 1;
112 
113 			if (!chdirgroup(p, TRUE)) {
114 			    ln_log(LNLOG_SERR, LNLOG_CTOP,
115 				    "cannot create group directory for %s",
116 				    cg->name);
117 			    cg = NULL;
118 			}
119 		    } else {
120 			cg = NULL;
121 		    }
122 		}
123 	    }
124 
125 	    /* cg may have become NULL if we don't want to store */
126 	    if (cg) {
127 		int r;
128 
129 		if (cg->first < 1)
130 		    cg->first = 1;
131 
132 		if (cg->last < cg->first)
133 		    cg->last = cg->first++;
134 
135 		if (!chdirgroup(p, FALSE)) {
136 		    /* error */
137 		    p = q;
138 		    continue;
139 		}
140 		do {
141 		    sprintf(tmp, "%lu", ++cg->last);
142 		    errno = 0;
143 		} while ((r = link(filename, tmp)) < 0 && errno == EEXIST);
144 		if (r == 0 && verbose > 2)
145 		    printf("..as article %lu in %s\n", cg->last, cg->name);
146 		if (r < 0)
147 		    syslog(LOG_ERR, "error linking %s into %s: %m",
148 			   filename, p);
149 		else {
150 		    mastr_vcat(xrefincase, " ", cg->name, ":", tmp, NULL);
151 		}
152 	    } else {
153 		if (verbose > 2)
154 		    printf("..discarding unknown group %s\n", p);
155 	    }
156 	}
157 	p = q;
158     }
159     fprintf(filehandle, "Xref: %s%s\n", fqdn, mastr_str(xrefincase));
160     free(newsgroups);
161     mastr_delete(xrefincase);
162 }
163 
164 #ifdef TEST
165 int verbose = 0;
166 int debug = 0;
167 
main(int argc,char ** argv[])168 int main(int argc, char **argv[]) {
169     char *t;
170 
171     if (argc != 3) {
172 	fprintf(stderr, "usage: %s file header:\n", argv[0]);
173 	exit(1);
174     }
175 
176     t = getheader(argv[1], argv[2]);
177     printf("header %s in %s is:\n%s\n", argv[2], argv[1], t ? t : "(NULL)");
178     exit(0);
179 }
180 #endif
181