1 /* $Id: ov.c 6135 2003-01-19 01:15:40Z rra $
3 ** The implementation of the overview API.
5 ** This code handles calls to the overview API by passing them along to the
6 ** appropriate underlying overview method, as well as implementing those
7 ** portions of the overview subsystem that are independent of storage
20 #include "inn/innconf.h"
23 #include "ovinterface.h"
24 #include "ovmethods.h"
26 /* FIXME: The following variables are shared between this file and expire.c.
27 This should be cleaned up with a better internal interface. */
28 static bool OVdelayrm;
42 /* if innconf isn't already read in, do so. */
44 if (!innconf_read(NULL))
46 if (!innconf->enableoverview) {
47 syslog(L_FATAL, "enableoverview is not true");
48 fprintf(stderr, "enableoverview is not true\n");
51 if (innconf->ovmethod == NULL) {
52 syslog(L_FATAL, "ovmethod is not defined");
53 fprintf(stderr, "ovmethod is not defined\n");
56 for (i=0;i<NUM_OV_METHODS;i++) {
57 if (!strcmp(innconf->ovmethod, ov_methods[i].name))
60 if (i == NUM_OV_METHODS) {
61 syslog(L_FATAL, "%s is not found for ovmethod", innconf->ovmethod);
62 fprintf(stderr, "%s is not found for ovmethod\n", innconf->ovmethod);
66 val = (*ov.open)(mode);
67 if (atexit(OVclose) < 0) {
71 if (innconf->ovgrouppat != NULL) {
72 for (i = 1, p = innconf->ovgrouppat; *p && (p = strchr(p+1, ',')); i++);
74 OVpatterns = xmalloc(OVnumpatterns * sizeof(char *));
75 for (i = 0, p = strtok(innconf->ovgrouppat, ","); p != NULL && i <= OVnumpatterns ; i++, p = strtok(NULL, ","))
76 OVpatterns[i] = xstrdup(p);
77 if (i != OVnumpatterns) {
78 syslog(L_FATAL, "extra ',' in pattern");
79 fprintf(stderr, "extra ',' in pattern");
87 OVgroupstats(char *group, int *lo, int *hi, int *count, int *flag)
91 syslog(L_ERROR, "ovopen must be called first");
92 fprintf(stderr, "ovopen must be called first");
95 return ((*ov.groupstats)(group, lo, hi, count, flag));
99 OVgroupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag)
101 /* lomark should never be changed in each ovmethod if lo is 0 */
104 syslog(L_ERROR, "ovopen must be called first");
105 fprintf(stderr, "ovopen must be called first");
108 return ((*ov.groupadd)(group, lo, hi, flag));
112 OVgroupdel(char *group)
116 syslog(L_ERROR, "ovopen must be called first");
117 fprintf(stderr, "ovopen must be called first");
120 return ((*ov.groupdel)(group));
124 OVadd(TOKEN token, char *data, int len, time_t arrived, time_t expires)
126 char *next, *nextcheck;
127 static char *xrefdata, *patcheck, *overdata;
128 char *xrefstart = NULL;
130 static int xrefdatalen = 0, overdatalen = 0;
139 syslog(L_ERROR, "ovopen must be called first");
140 fprintf(stderr, "ovopen must be called first");
145 * find last Xref: in the overview line. Note we need to find the *last*
146 * Xref:, since there have been corrupted articles on Usenet with Xref:
147 * fragments stuck in other header lines. The last Xref: is guaranteed
148 * to be from our server.
151 for (next = data; ((len - (next - data)) > 6 ) && ((next = memchr(next, 'X', len - (next - data))) != NULL); ) {
152 if (memcmp(next, "Xref: ", 6) == 0) {
163 for (i = 0; (i < 2) && (next < (data + len)); i++) {
164 if ((next = memchr(next, ' ', len - (next - data))) == NULL)
168 xreflen = len - (next - data);
171 * If there are other fields beyond Xref in overview, then
172 * we must find Xref's end, or data following is misinterpreted.
174 if ((xrefend = memchr(next, '\t', xreflen)) != NULL)
175 xreflen = xrefend - next;
177 if (xrefdatalen == 0) {
178 xrefdatalen = BIG_BUFFER;
179 xrefdata = xmalloc(xrefdatalen);
180 if (innconf->ovgrouppat != NULL)
181 patcheck = xmalloc(xrefdatalen);
183 if (xreflen > xrefdatalen) {
184 xrefdatalen = xreflen;
185 xrefdata = xrealloc(xrefdata, xrefdatalen + 1);
186 if (innconf->ovgrouppat != NULL)
187 patcheck = xrealloc(patcheck, xrefdatalen + 1);
189 if (overdatalen == 0) {
190 overdatalen = BIG_BUFFER;
191 overdata = xmalloc(overdatalen);
193 if (len + 16 > overdatalen) {
194 overdatalen = len + 16;
195 overdata = xrealloc(overdata, overdatalen);
198 if (innconf->ovgrouppat != NULL) {
199 memcpy(patcheck, next, xreflen);
200 patcheck[xreflen] = '\0';
201 for (group = patcheck; group && *group; group = memchr(nextcheck, ' ', xreflen - (nextcheck - patcheck))) {
202 while (isspace((int)*group))
204 if ((nextcheck = memchr(group, ':', xreflen - (patcheck - group))) == NULL)
207 if (!OVgroupmatch(group)) {
208 if (!SMprobe(SELFEXPIRE, &token, NULL) && innconf->groupbaseexpiry)
209 /* this article will never be expired, since it does not
210 have self expiry function in stored method and
211 groupbaseexpiry is true */
213 return OVADDGROUPNOMATCH;
217 memcpy(xrefdata, next, xreflen);
218 xrefdata[xreflen] = '\0';
219 for (group = xrefdata; group && *group; group = memchr(next, ' ', xreflen - (next - xrefdata))) {
220 /* Parse the xref part into group name and article number */
221 while (isspace((int)*group))
223 if ((next = memchr(group, ':', xreflen - (group - xrefdata))) == NULL)
230 sprintf(overdata, "%ld\t", artnum);
231 i = strlen(overdata);
232 memcpy(overdata + i, data, len);
234 memcpy(overdata + i, "\r\n", 2);
237 if(! (*ov.add)(group, artnum, token, overdata, i, arrived, expires))
241 return OVADDCOMPLETED;
245 OVcancel(TOKEN token)
249 syslog(L_ERROR, "ovopen must be called first");
250 fprintf(stderr, "ovopen must be called first");
253 return ((*ov.cancel)(token));
257 OVopensearch(char *group, int low, int high)
261 syslog(L_ERROR, "ovopen must be called first");
262 fprintf(stderr, "ovopen must be called first");
265 return ((*ov.opensearch)(group, low, high));
269 OVsearch(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token,
274 syslog(L_ERROR, "ovopen must be called first");
275 fprintf(stderr, "ovopen must be called first");
278 return ((*ov.search)(handle, artnum, data, len, token, arrived));
282 OVclosesearch(void *handle)
286 syslog(L_ERROR, "ovopen must be called first");
287 fprintf(stderr, "ovopen must be called first");
290 (*ov.closesearch)(handle);
295 OVgetartinfo(char *group, ARTNUM artnum, TOKEN *token)
299 syslog(L_ERROR, "ovopen must be called first");
300 fprintf(stderr, "ovopen must be called first");
303 return ((*ov.getartinfo)(group, artnum, token));
307 OVexpiregroup(char *group, int *lo, struct history *h)
311 syslog(L_ERROR, "ovopen must be called first");
312 fprintf(stderr, "ovopen must be called first");
315 return ((*ov.expiregroup)(group, lo, h));
319 OVctl(OVCTLTYPE type, void *val)
323 syslog(L_ERROR, "ovopen must be called first");
324 fprintf(stderr, "ovopen must be called first");
328 case OVGROUPBASEDEXPIRE:
329 if (!innconf->groupbaseexpiry) {
330 syslog(L_ERROR, "OVGROUPBASEDEXPIRE is not allowed if groupbaseexpiry if false");
331 fprintf(stderr, "OVGROUPBASEDEXPIRE is not allowed if groupbaseexpiry if false");
334 if (((OVGE *)val)->delayrm) {
335 if ((((OVGE *)val)->filename == NULL) || (strlen(((OVGE *)val)->filename) == 0)) {
336 syslog(L_ERROR, "file name must be specified");
337 fprintf(stderr, "file name must be specified");
340 if ((EXPunlinkfile = fopen(((OVGE *)val)->filename, "w")) == NULL) {
341 syslog(L_ERROR, "fopen: %s failed: %m", ((OVGE *)val)->filename);
342 fprintf(stderr, "fopen: %s failed: %s", ((OVGE *)val)->filename,
347 OVdelayrm = ((OVGE *)val)->delayrm;
348 OVusepost = ((OVGE *)val)->usepost;
349 OVrealnow = ((OVGE *)val)->now;
350 OVnow = ((OVGE *)val)->now + (time_t)((OVGE *)val)->timewarp;
351 OVquiet = ((OVGE *)val)->quiet;
352 OVkeep = ((OVGE *)val)->keep;
353 OVearliest = ((OVGE *)val)->earliest;
354 OVignoreselfexpire = ((OVGE *)val)->ignoreselfexpire;
357 OVstatall = *(bool *)val;
360 return ((*ov.ctl)(type, val));
370 memset(&ov, '\0', sizeof(ov));