3 ** The newnews command.
8 #include "inn/innconf.h"
9 #include "inn/messages.h"
15 #define GROUP_LIST_DELTA 10
17 static bool FindHeader(ARTHANDLE *art, const char **pp, const char **qp,
18 const char* hdr, size_t hdrlen)
20 const char *p, *p1, *q;
23 p = wire_findheader(art->data, art->len, hdr);
27 for (p1 = NULL; p < art->data + art->len; p++) {
28 if (p1 != NULL && *p1 == '\r' && *p == '\n') {
38 if (p >= art->data + art->len)
51 static char *GetXref(ARTHANDLE *art) {
54 if (!FindHeader(art, &p, &q, "xref", sizeof("xref")))
56 return xstrndup(q, p - q);
60 ** Split newsgroup list into array of newsgroups. Return static pointer,
61 ** or NULL if there are no newsgroup.
63 static char **GetGroups(char *p) {
68 static char *Xrefbuf = NULL;
72 size = GROUP_LIST_DELTA;
73 list = xmalloc((size + 1) * sizeof(char *));
76 for (Xref++; *Xref == ' '; Xref++);
77 if ((Xref = strchr(Xref, ' ')) == NULL)
79 for (Xref++; *Xref == ' '; Xref++);
81 Xrefbuf = xmalloc(BIG_BUFFER);
82 strlcpy(Xrefbuf, Xref, BIG_BUFFER);
83 if ((q = strchr(Xrefbuf, '\t')) != NULL)
90 if (*p == '\0' || *p == '\n')
94 size += GROUP_LIST_DELTA;
95 list = xrealloc(list, (size + 1) * sizeof(char *));
97 for (list[i] = p; *p && *p != '\n' && !ISWHITE(*p); p++) {
104 return i ? list : NULL;
107 static bool HaveSeen(bool AllGroups, char *group, char **groups, char **xrefs) {
111 for ( ; *xrefs; xrefs++) {
113 if ((!AllGroups && PERMmatch(groups, list)) && (!PERMspecified || (PERMspecified && PERMmatch(PERMreadlist, list)))) {
114 if (!strcmp(*xrefs, group))
123 static char **groups;
126 process_newnews(char *group, bool AllGroups, time_t date)
133 ARTHANDLE *art = NULL;
142 if (PERMspecified && !PERMmatch(PERMreadlist, grplist))
144 if (!AllGroups && !PERMmatch(groups, grplist))
146 if (!OVgroupstats(group, &ARTlow, &ARThigh, &count, NULL))
148 if ((handle = OVopensearch(group, ARTlow, ARThigh)) != NULL) {
150 unsigned long artcount = 0;
151 struct cvector *vector = NULL;
153 if (innconf->nfsreader) {
155 /* move the start time back nfsreaderdelay seconds */
156 if (date >= innconf->nfsreaderdelay)
157 date -= innconf->nfsreaderdelay;
159 while (OVsearch(handle, &artnum, &data, &len, &token, &arrived)) {
160 if (innconf->nfsreader && arrived + innconf->nfsreaderdelay > now)
162 if (len == 0 || date > arrived)
165 vector = overview_split(data, len, NULL, vector);
166 if (overhdr_xref == -1) {
167 if ((art = SMretrieve(token, RETR_HEAD)) == NULL)
172 if (PERMaccessconf->nnrpdcheckart &&
173 !ARTinstorebytoken(token))
175 /* We only care about the newsgroup list here, virtual
176 * hosting isn't relevant */
177 p = overview_getheader(vector, overhdr_xref, OVextra);
181 xrefs = GetGroups(p);
185 if (HaveSeen(AllGroups, group, groups, xrefs))
187 p = overview_getheader(vector, OVERVIEW_MESSAGE_ID, OVextra);
192 cache_add(HashMessageID(p), token);
196 OVclosesearch(handle);
197 notice("%s newnews %s %lu", ClientHost, group, artcount);
199 cvector_free(vector);
204 ** NEWNEWS newsgroups date time ["GMT"]
205 ** Return the Message-ID of any articles after the specified date
207 void CMDnewnews(int ac, char *av[]) {
211 char line[BIG_BUFFER];
217 if (!PERMaccessconf->allownewnews) {
218 Reply("%d NEWNEWS command disabled by administrator\r\n", NNTP_ACCESS_VAL);
223 Reply("%s\r\n", NNTP_ACCESS);
227 /* Make other processes happier if someone uses NEWNEWS */
228 if (innconf->nicenewnews > 0) {
229 nice(innconf->nicenewnews);
230 innconf->nicenewnews = 0;
233 snprintf(line, sizeof(line), "%s %s %s %s", av[1], av[2], av[3],
234 (ac >= 5 && (*av[4] == 'G' || *av[4] == 'U')) ? "GMT" : "local");
235 notice("%s newnews %s", ClientHost, line);
237 TMRstart(TMR_NEWNEWS);
238 /* Optimization in case client asks for !* (no groups) */
239 if (strcmp(av[1], "!*") == 0) {
240 Reply("%s\r\n", NNTP_NEWNEWSOK);
242 TMRstop(TMR_NEWNEWS);
246 /* Parse the newsgroups. */
247 AllGroups = (strcmp(av[1], "*") == 0);
248 if (!AllGroups && !NGgetlist(&groups, av[1])) {
249 Reply("%d Bad newsgroup specifier %s\r\n", NNTP_SYNTAX_VAL, av[1]);
250 TMRstop(TMR_NEWNEWS);
254 /* Parse the date. */
255 local = !(ac > 4 && strcasecmp(av[4], "GMT") == 0);
256 date = parsedate_nntp(av[2], av[3], local);
257 if (date == (time_t) -1) {
258 Reply("%d Bad date\r\n", NNTP_SYNTAX_VAL);
259 TMRstop(TMR_NEWNEWS);
263 if (strcspn(av[1], "\\!*[?]") == strlen(av[1])) {
264 /* optimise case - don't need to scan the active file pattern
266 Reply("%s\r\n", NNTP_NEWNEWSOK);
267 for (i = 0; groups[i]; ++i) {
268 process_newnews(groups[i], AllGroups, date);
271 path = concatpath(innconf->pathdb, _PATH_ACTIVE);
274 if (errno == ENOENT) {
275 Reply("%d Can't open active\r\n", NNTP_TEMPERR_VAL);
277 syswarn("%s cant fopen %s", ClientHost, path);
278 Reply("%d Can't open active\r\n", NNTP_TEMPERR_VAL);
281 TMRstop(TMR_NEWNEWS);
286 Reply("%s\r\n", NNTP_NEWNEWSOK);
288 while ((p = QIOread(qp)) != NULL) {
289 for (q = p; *q != '\0'; q++) {
290 if (*q == ' ' || *q == '\t') {
295 process_newnews(p, AllGroups, date);
300 TMRstop(TMR_NEWNEWS);