Better crossposts: 0.4.0-pre1
Patrik Rådman <[email protected]>
| Newsgroups | gmane.network.sn |
|---|---|
| Message-ID | <[email protected]> |
Hi all, I've implemented proper Xref: headers for crossposts, finally. :) This means that after reading a crossposted article in one group, your news reader will mark it as read in all other groups as well. The patch is called 0.4.0-pre1, and is attached to this message. It is also available from <http://www.iki.fi/patrik/patches/>. How to apply the patch: 1. cd to the 0.3.8 source directory 2. Run "patch -p0 -s < location/of/patch" NOTE: After installing 0.4.0-pre1 you need to rebuild your article ID database in order to take advantage of the new feature. How to do this is explained in INSTALL.notes. (Note that the procedure has changed slightly since 0.3.8, you should no longer use the -n option for snscan.) Please test, and report any bugs/problems/weirdness. Implementation details follow, you can stop reading here if you aren't interested. :) I implemented this feature by allowing multiple entries for one Message-ID (in different newsgroups) in the database, and always generating the Xref:-header from the database. This of course means that sn now searches the database every time it prints out a message, or XOVER data, or anything which contains Xref:. This causes a slight speed hit, but should not be noticeable. In my testing, sncat:ing 10000 articles to /dev/null took about 0.15 seconds with 0.3.8, and 0.25 seconds with 0.4.0-pre1. (Celeron 733 MHz, entire group in the disk cache.) -- Patrik Rådman patrik at iki dot fi http://www.iki.fi/patrik/
sn-0.4.0-pre1.patch
(text/plain, 22.7 KB)
Index: commands.c
===================================================================
--- commands.c (.../0.3.8) (revision 68)
+++ commands.c (.../0.4.0-pre1) (revision 68)
@@ -86,13 +86,13 @@
if ('<' == *spec)
{
- struct data d;
+ struct data d = { 0, };
d.messageid = spec + 1;
if ((p = strchr(d.messageid, '>')))
{
*p = '\0';
- if (0 == dh_find(&d, FALSE))
+ if (0 == dh_find(&d, DH_FIND_FIRST, FALSE))
{
spechi = speclo = d.serial;
specgroup = d.newsgroup; /* is static */
@@ -253,10 +253,10 @@
/* should never have let Xref into header, now have to remove it */
p = strstr(article.head, "Xref:");
if (p && (p == article.head || '\n' == p[-1]))
- writef(1, "%SXref: %s %s:%d%s",
- p - article.head, article.head, me, specgroup, speclo, p + 5);
+ writef(1, "%SXref: %s%s",
+ p - article.head, article.head, art_makexref(me, article.head, specgroup, speclo), p + 5);
else
- writef(1, "%sXref: %s %s:%d\r\n", article.head, me, specgroup, speclo);
+ writef(1, "%sXref: %s\r\n", article.head, art_makexref(me, article.head, specgroup, speclo));
if (PUTHEAD == flag)
break;
write(1, "\r\n", 2);
@@ -455,7 +455,7 @@
struct xover x;
art_makexover(&article, &x);
- writef(1, "%d\t%S\t%S\t%S\t%S\t%S\t%S\t%S\tXref: %s %s:%d\r\n",
+ writef(1, "%d\t%S\t%S\t%S\t%S\t%S\t%S\t%S\tXref: %s\r\n",
speclo,
x.subject.len, x.subject.pointer,
x.from.len, x.from.pointer,
@@ -464,7 +464,7 @@
x.references.len, x.references.pointer,
x.bytes.len, x.bytes.pointer,
x.lines.len, x.lines.pointer,
- me, specgroup, speclo);
+ art_makexref(me, article.head, specgroup, speclo));
}
void do_xover (void) { xlooper(args[1], putxover, "224 XOVER follows\r\n"); }
@@ -476,8 +476,8 @@
id = art_findfield(article.head, args[1]);
if (*id)
args_write(1, "%d %s\r\n", speclo, id);
- else if (strcasecmp(args[1], "xref") == 0) /* Xref needs to be generated on the fly */
- args_write(1, "%d %s %s:%d\r\n", speclo, me, specgroup, speclo);
+ else if (strcasecmp(args[1], "Xref") == 0) /* Xref needs to be generated on the fly */
+ args_write(1, "%d %s\r\n", speclo, art_makexref(me, article.head, specgroup, speclo));
}
void do_xhdr (void) { xlooper(args[2], putxhdr, "221 XHDR follows\r\n"); }
Index: sndelgroup.c
===================================================================
--- sndelgroup.c (.../0.3.8) (revision 68)
+++ sndelgroup.c (.../0.4.0-pre1) (revision 68)
@@ -70,7 +70,7 @@
v[2] = argv[i];
v[3] = 0;
LOG1("expiring %s", argv[i]);
- pid = cmdopen(v, 0, 0);
+ pid = cmdopen(v, NULL, NULL);
if (pid <= 0)
fail(2, "Unable to run snexpire on %s", argv[i]);
if (cmdwait(pid))
Index: snsend.c
===================================================================
--- snsend.c (.../0.3.8) (revision 68)
+++ snsend.c (.../0.4.0-pre1) (revision 68)
@@ -153,19 +153,29 @@
static int store_local (char *group)
{
- struct data d;
+ struct data d = { 0, }, *dp;
d.messageid = messageid;
- if (group)
+ if (group != NULL)
if (check_exist)
- if (0 == dh_find(&d, FALSE))
- if (0 == strcasecmp(group, d.newsgroup))
+ if (dh_find(&d, DH_FIND_ALL, FALSE) == 0)
+ {
+ bool found = FALSE;
+ dp = &d;
+ while (!found && dp != NULL)
{
+ found = (strcasecmp(group, dp->newsgroup) == 0);
+ dp = dp->next;
+ }
+ dh_find_cleanup(&d);
+ if (found)
+ {
LOG1("store_local:<%s> already exists in %s, not storing", messageid, group);
return 1;
}
+ }
d.serial = sto_add(group ? group : JUNK_GROUP, &art);
- if (-1 == d.serial)
+ if (d.serial == -1)
{
if (group)
_exit(2); /* FIXME: safe to return -1 here? */
@@ -181,16 +191,18 @@
{
if (EEXIST == errno)
{
- LOG1("store_local:oops, stored <%s> but it already exists", messageid);
+ LOG1("store_local:oops, stored <%s> in %s, but it already exists", messageid, group);
}
else
- LOG("store_local:can't insert in db for <%s> in %s:%d, %m?",
+ LOG("store_local:can't insert in db for <%s> %s:%d, %m?",
messageid, group, d.serial);
}
}
if (report)
writef(1, "%s %u <%s>\n", group ? group : JUNK_GROUP, d.serial, messageid);
- return (group ? d.serial : 0);
+ else
+ LOG3("%s %u <%s>\n", group ? group : JUNK_GROUP, d.serial, messageid);
+ return (group != NULL ? d.serial : 0);
}
static char *av[] = { "sh", 0, 0 };
Index: Makefile
===================================================================
--- Makefile (.../0.3.8) (revision 68)
+++ Makefile (.../0.4.0-pre1) (revision 68)
@@ -52,7 +52,7 @@
# You can stop editing here.
#
-VERSION =0.3.8
+VERSION =0.4.0-pre1
AOBJS =art.o cache.o group.o times.o dh_find.o dhash.o \
allocate.o newsgroup.o hostname.o \
store.o parameters.o args.o body.o unfold.o path.o \
Index: snprimedb.c
===================================================================
--- snprimedb.c (.../0.3.8) (revision 68)
+++ snprimedb.c (.../0.4.0-pre1) (revision 68)
@@ -68,11 +68,11 @@
{
if (EEXIST == errno)
{
- LOG("insert:\"%s\" already exists in %s:%d", d.messageid, newsgroup, serial);
+ LOG("insert:\"%s\", %s:%d already exists", d.messageid, newsgroup, serial);
return 1;
}
else
- LOG("insert:Can't insert record \"%s %s %d\":%m\n", newsgroup, d.messageid, serial);
+ LOG("insert:Can't insert record \"%s %s:%d\":%m\n", d.messageid, newsgroup, serial);
return -1;
}
nr++;
Index: snscan.c
===================================================================
--- snscan.c (.../0.3.8) (revision 68)
+++ snscan.c (.../0.4.0-pre1) (revision 68)
@@ -92,7 +92,7 @@
if (host && newsgroup && serial)
{
- formats(buf, sizeof (buf) - 1, "Xref: %s %s:%d\r\n", host, newsgroup, serial);
+ formats(buf, sizeof (buf) - 1, "Xref: %s\r\n", art_makexref(host, ap->head, newsgroup, serial));
v[i].iov_base = buf;
v[i].iov_len = strlen(buf);
i++;
@@ -130,7 +130,7 @@
if (host && newsgroup && serial)
{
- formats(buf, sizeof (buf) - 1, "Xref: %s %s:%d\n\n", host, newsgroup, serial);
+ formats(buf, sizeof (buf) - 1, "Xref: %s\n\n", art_makexref(host, ap->head, newsgroup, serial));
b_append(&b, buf);
}
else
@@ -187,7 +187,7 @@
{
struct file *fp;
struct article a;
- struct data d;
+ struct data d = { 0, };
int slot, fd, er;
char path[GROUPNAMELEN + 32];
char *id;
@@ -202,8 +202,8 @@
errors++;
return -1;
}
- if ('<' == *id)
- id++;
+ if ((p = strchr(id, '<')))
+ id = ++p;
if ((p = strrchr(id, '>')))
*p = '\0';
@@ -219,8 +219,10 @@
slot = serial % ARTSPERFILE;
fp->info[slot].hoffset = fp->info[slot].boffset = -1;
d.messageid = id;
+ d.newsgroup = newsgroup;
+ d.serial = serial;
if (dh_delete(&d))
- LOG1("dh_delete(<%s>):%m", id);
+ LOG1("dh_delete(<%s> %d:%s):%m", id, newsgroup, serial);
return 0;
}
else
@@ -399,15 +401,14 @@
if (-1 == group_init())
fail(2, "group_init:%m");
- if (!dhro || useid)
- if (-1 == dh_open(NULL, dhro))
- fail(2, "Can't open database");
+ if (-1 == dh_open(NULL, dhro))
+ fail(2, "Can't open database");
if (useid)
{
for (; opt_ind < argc && argv[opt_ind]; opt_ind++)
{
- struct data d = { 0, };
+ struct data d = { 0, }, *dp;
if ('<' == *argv[opt_ind])
{
@@ -417,7 +418,7 @@
}
else
d.messageid = argv[opt_ind];
- if (-1 == dh_find(&d, dhro))
+ if (dh_find(&d, DH_FIND_ALL, dhro) == -1)
continue;
if (-1 == group_info(d.newsgroup, &g))
fail(2, "group_info(%s):%m", d.newsgroup);
@@ -431,6 +432,16 @@
continue;
}
(*doit) (d.newsgroup, d.serial);
+ if (doit == snscan || doit == sncancel)
+ {
+ dp = d.next;
+ while (dp != NULL)
+ {
+ (*doit) (dp->newsgroup, dp->serial);
+ dp = dp->next;
+ }
+ }
+ dh_find_cleanup(&d);
}
dh_close();
_exit(0);
@@ -516,7 +527,6 @@
if (since)
times_fin();
group_fin();
- if (!dhro)
- dh_close();
+ dh_close();
_exit(errors ? 3 : 0);
}
Index: snfetch.c
===================================================================
--- snfetch.c (.../0.3.8) (revision 68)
+++ snfetch.c (.../0.4.0-pre1) (revision 68)
@@ -277,10 +277,10 @@
{
if (n < nr_arts)
{
- struct data d;
+ struct data d = { 0, };
d.messageid = arts[n].id;
- if (0 == dh_find(&d, FALSE))
+ if (0 == dh_find(&d, DH_FIND_FIRST, FALSE))
{
nrhave++;
arts[n].serial = -1;
Index: lib/format.c
===================================================================
--- lib/format.c (.../0.3.8) (revision 68)
+++ lib/format.c (.../0.4.0-pre1) (revision 68)
@@ -82,8 +82,11 @@
int formats (char *buf, int size, char *fmt, ...)
{
va_list ap;
+ int ret;
va_start(ap, fmt);
- return formatv(buf, size, fmt, ap);
+ ret = formatv(buf, size, fmt, ap);
va_end(ap);
+
+ return ret;
}
Index: art.c
===================================================================
--- art.c (.../0.3.8) (revision 68)
+++ art.c (.../0.4.0-pre1) (revision 68)
@@ -18,10 +18,12 @@
#include <string.h>
#include <errno.h>
#include <ctype.h>
+#include <stdio.h>
#include "config.h"
#include "art.h"
#include "artfile.h"
#include "cache.h"
+#include "dhash.h"
#include <b.h>
#include <out.h>
#include <format.h>
@@ -410,3 +412,36 @@
}
return "";
}
+
+char *art_makexref (char *me, char *head, char *newsgroup, int serial)
+{
+ char tmp[20];
+ struct data d = { 0, }, *dp;
+ static struct b b = { 0, };
+
+ b.used = 0;
+ /* Remove <> */
+ d.messageid = art_findfield(head, "Message-ID") + 1;
+ d.messageid[strlen(d.messageid) - 1] = '\0';
+ if (dh_find(&d, DH_FIND_ALL, TRUE) == -1)
+ {
+ LOG("art_makexref:Message-ID for %s:%d missing, database needs rebuilding", newsgroup, serial);
+ LOG("art_makexref:Faking Xref: header...");
+ d.newsgroup = newsgroup;
+ d.serial = serial;
+ d.next = NULL;
+ }
+ b_append(&b, me);
+ dp = &d;
+ while (dp != NULL)
+ {
+ b_append(&b, " ");
+ b_append(&b, dp->newsgroup);
+ b_append(&b, ":");
+ snprintf(tmp, 20, "%d", dp->serial);
+ b_append(&b, tmp);
+ dp = dp->next;
+ }
+ dh_find_cleanup(&d);
+ return b.buf;
+}
Index: CHANGES
===================================================================
--- CHANGES (.../0.3.8) (revision 68)
+++ CHANGES (.../0.4.0-pre1) (revision 68)
@@ -1,3 +1,6 @@
+
+Implemented proper Xref: headers for crossposts by allowing multiple entries
+ for one Message-ID in the database, and always generating Xref: from the database.
--
0.3.8 Tue Aug 10 15:15:34 EEST 2004
SNHELLO: CR chars had accidentally become LFs, fixed.
Index: newsgroup.c
===================================================================
--- newsgroup.c (.../0.3.8) (revision 68)
+++ newsgroup.c (.../0.4.0-pre1) (revision 68)
@@ -225,6 +225,11 @@
return nr;
}
+int ng_reload (void)
+{
+ return reload();
+}
+
int ng_ident (char *group)
{
struct ng *np;
Index: dh_find.c
===================================================================
--- dh_find.c (.../0.3.8) (revision 68)
+++ dh_find.c (.../0.4.0-pre1) (revision 68)
@@ -15,6 +15,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
+#include <stdlib.h>
#include "config.h"
#include "dhash.h"
#include "allocate.h"
@@ -68,7 +69,10 @@
if (lockf(dh_fd, F_TLOCK, 0) == 0)
return 0;
if (errno != EAGAIN)
+ {
+ LOG("dhlock:lockf:%m");
return -1;
+ }
nap(0, 500);
}
return -1;
@@ -140,23 +144,65 @@
return -1;
}
-int dh_find (struct data *dp, bool readonly)
+int dh_find (struct data *dp, dh_search search, bool readonly)
{
struct chain *chp;
unsigned char *x;
+ unsigned index;
+ bool first = TRUE;
if (!readonly) /* lockf() fails on read-only file, and locking not needed anyway for R/O? */
if (dhlock() == -1)
return -1;
chp = dhlocatechain(dp->messageid);
if (chp == NULL)
- goto fail;
- while (strcmp(dp->messageid, chp->messageid) != 0)
+ goto fail; /* Empty chain */
+ while (chp != NULL)
{
- unsigned index = chp->next;
+ while (strcmp(dp->messageid, chp->messageid) != 0)
+ {
+ index = chp->next;
+ if (index == 0)
+ {
+ if (first)
+ goto fail; /* Nothing found */
+ else
+ goto leave; /* Reached end of chain */
+ }
+ chp = allo_deref(index);
+ if (chp == NULL)
+ {
+ LOG2("dh_find:bad allo deref");
+ goto fail;
+ }
+ }
+ if (!first)
+ {
+ if((dp->next = malloc(sizeof (struct data))) == NULL)
+ fail(2, "No memory");
+ dp->next->messageid = dp->messageid;
+ dp = dp->next;
+ }
+ dp->serial = chp->serial;
+ x = (unsigned char *) chp->newsgroup;
+ dp->newsgroup = ng_newsgroup(char2toint(x));
+ if (dp->newsgroup == NULL)
+ {
+ /* Newsgroup name not found. Run ng_reload() and retry, in case we are
+ snfetch and the group has just been added to .newsgroup by snstore. */
+ if (ng_reload() == -1)
+ goto fail;
+ if ((dp->newsgroup = ng_newsgroup(char2toint(x))) == NULL)
+ goto fail;
+ }
+ if (first && search == DH_FIND_FIRST)
+ break;
+ first = FALSE;
+
+ index = chp->next;
if (index == 0)
- goto fail;
+ break; /* Reached end of chain */
chp = allo_deref(index);
if (chp == NULL)
{
@@ -164,11 +210,9 @@
goto fail;
}
}
- dp->serial = chp->serial;
- x = (unsigned char *) chp->newsgroup;
- dp->newsgroup = ng_newsgroup(char2toint(x));
- if (dp->newsgroup == NULL)
- goto fail;
+
+leave:
+ dp->next = NULL;
if (!readonly)
dhunlock();
return 0;
@@ -179,6 +223,21 @@
return -1;
}
+/* Deletes everything malloc()ed by dh_find(). NOP for non-crossposts. */
+
+void dh_find_cleanup (struct data *dp)
+{
+ struct data *tmp;
+
+ dp = dp->next;
+ while (dp != NULL)
+ {
+ tmp = dp;
+ dp = dp->next;
+ free(tmp);
+ }
+}
+
int dh_open (char *pre, bool readonly)
{
struct stat st;
Index: art.h
===================================================================
--- art.h (.../0.3.8) (revision 68)
+++ art.h (.../0.4.0-pre1) (revision 68)
@@ -54,6 +54,7 @@
extern int art_makexover (struct article *ap, struct xover *xp);
extern char *art_findfield (char *head, char *fieldname);
+extern char *art_makexref (char *me, char *head, char *newsgroup, int serial);
extern void art_filecachestat (int *hit, int *miss);
#endif
Index: newsgroup.h
===================================================================
--- newsgroup.h (.../0.3.8) (revision 68)
+++ newsgroup.h (.../0.4.0-pre1) (revision 68)
@@ -19,6 +19,10 @@
extern int ng_init (void);
+/* Check .newsgroup for new groups */
+
+extern int ng_reload (void);
+
/* Get newsgroupname given its ident */
extern char *ng_newsgroup (int ident);
Index: INSTALL.notes
===================================================================
--- INSTALL.notes (.../0.3.8) (revision 68)
+++ INSTALL.notes (.../0.4.0-pre1) (revision 68)
@@ -122,11 +122,11 @@
$ rm .newsgroup .table .chain
$ find . -type f -name "+*" -exec rm -f {} \;
$ snprimedb -i
- $ snscan -n * | snprimedb; rm -f .noservice
+ $ snscan * | snprimedb; rm -f .noservice
- Don't forget the "-n" to snscan. This will rebuild the database
- completely. Its a good idea to place these lines in your system
- rc files so this is done on every reboot, after fsck.
+ This will rebuild the database completely. It's a good idea to place
+ these lines in your system rc files so this is done on every reboot,
+ after fsck.
To see which newsgroups are popular:
Run a daemon or shell script that reads newsgroup names from
Index: get.c
===================================================================
--- get.c (.../0.3.8) (revision 68)
+++ get.c (.../0.4.0-pre1) (revision 68)
@@ -98,11 +98,11 @@
static int store_get (void)
{
- if (!nstores)
+ if (nstores == 0)
{
int pid;
- pid = cmdopen(argv_snstore, 0, stores);
+ pid = cmdopen(argv_snstore, NULL, stores);
if (pid <= 0)
{
if (-19 == pid)
@@ -593,7 +593,7 @@
{
if ((jp->pid = fork()) > -1)
{
- if (0 == jp->pid)
+ if (jp->pid == 0) /* Child? */
break;
if (throttlerate)
{
@@ -688,8 +688,10 @@
sigchld = FALSE;
if (-1 == (pid = fork()))
fail(2, "Can't fork for SNHELLO:%m");
- if (0 == pid)
+ if (pid == 0)
{
+ /* Child */
+
char *v[2];
if (-1 == chdir(".outgoing"))
Index: snmail.c
===================================================================
--- snmail.c (.../0.3.8) (revision 68)
+++ snmail.c (.../0.4.0-pre1) (revision 68)
@@ -256,7 +256,7 @@
}
args[i] = 0;
set_path_var();
- if ((storepid = cmdopen(args, 0, &fd)) <= 0)
+ if ((storepid = cmdopen(args, NULL, &fd)) <= 0)
fail(2, "Can't exec snstore:%m?");
}
else
Index: dhash.c
===================================================================
--- dhash.c (.../0.3.8) (revision 68)
+++ dhash.c (.../0.4.0-pre1) (revision 68)
@@ -73,7 +73,7 @@
int dh_insert (struct data *dp)
{
- struct chain *chp;
+ struct chain *chp, *last;
unsigned h;
int off;
int len;
@@ -93,9 +93,12 @@
if (strcmp(dp->messageid, chp->messageid) == 0)
{
- dhunlock();
- errno = EEXIST;
- return -1;
+ if (memcmp(inttochar2(ng_ident(dp->newsgroup)), chp->newsgroup, 2) == 0) /* Allow crossposts */
+ {
+ dhunlock();
+ errno = EEXIST;
+ return -1;
+ }
}
index = (unsigned) chp->next;
if (index == 0)
@@ -108,6 +111,7 @@
}
}
+ last = chp;
len = sizeof (struct chain) + strlen(dp->messageid) + 1 - sizeof (chp->messageid);
off = allo_make(len);
chp = allo_deref(off);
@@ -123,8 +127,8 @@
int ident;
ident = ng_ident(dp->newsgroup);
- if (-1 == ident)
- if (-1 == (ident = ng_addgroup(dp->newsgroup)))
+ if (ident == -1)
+ if ((ident = ng_addgroup(dp->newsgroup)) == -1)
return -1;
memcpy(chp->newsgroup, inttochar2(ident), 2);
}
@@ -137,6 +141,7 @@
* object, and we have two of them instead of one.
*/
+ /* Changing this to insert at the tail of the chain instead of the head... - PR
h = dhhash(dp->messageid);
{
@@ -145,6 +150,20 @@
chp->next = char3toint(x);
memcpy(x, inttochar3(off), 3);
}
+ */
+
+ if (last == NULL)
+ { /* Empty chain */
+ h = dhhash(dp->messageid);
+ {
+ unsigned char *x = dh_table->next + h * 3;
+ memcpy(x, inttochar3(off), 3);
+ }
+ }
+ else
+ last->next = off;
+ chp->next = 0;
+
dhunlock();
return 0;
}
@@ -166,7 +185,9 @@
if (chp == NULL)
goto fail;
- while (strcmp(chp->messageid, dp->messageid) != 0)
+ while (strcmp(chp->messageid, dp->messageid) != 0 ||
+ (memcmp(inttochar2(ng_ident(dp->newsgroup)), chp->newsgroup, 2) != 0 ||
+ dp->serial != chp->serial))
{
unsigned index = chp->next;
Index: dhash.h
===================================================================
--- dhash.h (.../0.3.8) (revision 68)
+++ dhash.h (.../0.4.0-pre1) (revision 68)
@@ -8,6 +8,8 @@
#ifndef DHASH_H
#define DHASH_H
+#include "config.h"
+
/* Relative to snroot, current directory */
#ifndef DH_TABLEFILE
@@ -33,6 +35,7 @@
char *messageid;
char *newsgroup;
int serial;
+ struct data *next; /* For crossposts */
};
/*
@@ -42,10 +45,13 @@
* only dp->messageid is used. All returned values are readonly.
*/
+typedef enum { DH_FIND_ALL, DH_FIND_FIRST } dh_search;
+
extern int dh_open (char *pre, bool readonly);
extern int dh_close (void);
extern int dh_insert (struct data *dp);
-extern int dh_find (struct data *dp, bool readonly);
+extern int dh_find (struct data *dp, dh_search search, bool readonly);
+extern void dh_find_cleanup (struct data *dp);
extern int dh_delete (struct data *dp);
/* Stuff to link in with sndumpdb */
Index: snexpire.c
===================================================================
--- snexpire.c (.../0.3.8) (revision 68)
+++ snexpire.c (.../0.4.0-pre1) (revision 68)
@@ -174,19 +174,32 @@
id = art_findfield(a.head, "message-id");
if (id && *id)
{
- struct data d;
+ struct data d = { 0, }, *dp;
char *cp;
- if ('<' == *id)
- id++;
- if ((cp = strchr(id, '>')))
+ if ((cp = strchr(id, '<')))
+ id = ++cp;
+ if ((cp = strrchr(id, '>')))
*cp = '\0';
d.messageid = id;
- if (0 == dh_find(&d, FALSE))
- if (0 == strcmp(d.newsgroup, newsgroup))
- if (d.serial == serial)
- if (-1 == dh_delete(&d))
- LOG2("expire:can't delete id %s for %s:%d", id, newsgroup, serial);
+ if (dh_find(&d, DH_FIND_ALL, FALSE) == 0)
+ {
+ bool found = FALSE;
+ dp = &d;
+ while (!found && dp != NULL)
+ {
+ found = (strcasecmp(newsgroup, dp->newsgroup) == 0 && serial == dp->serial);
+ dp = dp->next;
+ }
+ dh_find_cleanup(&d);
+ if (found)
+ {
+ d.newsgroup = newsgroup;
+ d.serial = serial;
+ if (dh_delete(&d) == -1)
+ LOG2("expire:can't delete id %s for %s:%d", id, newsgroup, serial);
+ }
+ }
if (report)
writef(1, "%s %d %s\n", newsgroup, serial, id);
}