--- rnews.c.orig Sat May 18 22:21:26 2002
+++ rnews.c Wed Aug 4 03:43:51 2004
@@ -2,6 +2,8 @@
* S-News version 0.1.9 - A Simple News Server
* Copyright (C) 1998 Christopher John Purnell
* cjp@lost.org.uk
+ * Supersedes/cancel modifications (C) 2002 Tony Houghton
+ * tony@realh.co.uk
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +52,8 @@
#include "snews.h"
+#define DEBLOG(a) /* fprintf a */
+
struct header
{
struct header *next;
@@ -78,14 +82,23 @@
static FILE *open_lock(char *);
static int file_name(struct header *,char *,unsigned);
static GDBM_FILE open_history(char *,int);
+static int read_string(FILE *,char *,unsigned);
+static void delete_msg(const char *);
+static int whole_string(struct header_pointer *,char *,unsigned);
+static int read_line(FILE *,char *,unsigned);
+static int isolate_addr(char *);
static char *progname;
static char fqdn[BUFLEN];
static char msgid[BUFLEN];
static char article[BUFLEN];
+static char vsender[BUFLEN];
+static char cancel[BUFLEN];
static char queue=0,approved=0;
+static int cancel_only;
struct header junk = { 0, "junk", 0 };
+struct header control_cancel = { 0, "control.cancel", 0 };
int main(int argc,char **argv)
{
@@ -95,6 +108,16 @@
set_ug_id();
+ /* For logging, remove this in release */
+ /*
+ i = open("/var/log/news/rnews", O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (i)
+ {
+ close(2);
+ dup2(i, 2);
+ }
+ */
+
progname = argv[0];
if (get_fqdn())
@@ -116,12 +139,18 @@
return (1);
}
+ cancel[0] = 0;
+ vsender[0] = 0;
+ cancel_only = 0;
+
if (!(hdr = read_header()))
return (1);
if (!(ngrp = parse_header(hdr)))
return (1);
+ DEBLOG((stderr, "Message-ID: %s\n", msgid));
+
if (!(fp = open_lock(CONFDIR"/active.n")))
{
perror(progname);
@@ -130,8 +159,16 @@
if (!(i = chk_article(msgid)))
{
- if (!(ngrp = update_active(CONFDIR"/active",CONFDIR"/active.n",
- fp,ngrp)))
+ DEBLOG((stderr, "chk_article OK\n"));
+ if (cancel_only)
+ {
+ ngrp = update_active(CONFDIR"/active",
+ CONFDIR"/active.n",
+ fp,&control_cancel);
+ DEBLOG((stderr, "cancel_only, ngrp = %d\n", ngrp));
+ }
+ else if (!(ngrp = update_active(CONFDIR"/active",
+ CONFDIR"/active.n",fp,ngrp)))
{
rewind(fp);
if (ftruncate(fileno(fp),0))
@@ -144,8 +181,11 @@
i = !ngrp;
}
+ DEBLOG((stderr, "After chk_article and update_active, result = %d (0 is good)\n", i));
+
if (fclose(fp) || i || write_article(hdr,ngrp))
{
+ DEBLOG((stderr, "fclose || i || write_article failed\n"));
unlink(CONFDIR"/active.n");
return (1);
}
@@ -158,6 +198,9 @@
return (1);
}
+ if (cancel[0])
+ delete_msg(cancel);
+
if (!queue) return (0);
execl(QNEWSPATH,QNEWSARG0,article,0);
@@ -301,11 +344,78 @@
{
approved=1;
}
+ else if (!strncasecmp(hdr->line,"Sender:",7))
+ {
+ hp.hdr = hdr;
+ hp.ptr = hdr->line+7;
+ if (whole_string(&hp,vsender,BUFLEN)<=0)
+ {
+ fprintf(stderr,"%s: bad Sender\n",
+ progname);
+ return (0);
+ }
+ DEBLOG((stderr, "Found Sender: %s\n", vsender));
+ }
+ else if (!vsender[0] && !strncasecmp(hdr->line,"From:",5))
+ {
+ hp.hdr = hdr;
+ hp.ptr = hdr->line+5;
+ if (whole_string(&hp,vsender,BUFLEN)<=0)
+ {
+ fprintf(stderr,"%s: bad From\n",
+ progname);
+ return (0);
+ }
+ DEBLOG((stderr, "Found From: %s\n", vsender));
+ }
+ else if (!strncasecmp(hdr->line,"Supersedes:",11))
+ {
+ hp.hdr = hdr;
+ hp.ptr = hdr->line+11;
+ if (whole_string(&hp,cancel,BUFLEN)<=0)
+ {
+ fprintf(stderr,"%s: bad Supersedes\n",
+ progname);
+ return (0);
+ }
+ DEBLOG((stderr, "Found Supersedes: %s\n", cancel));
+ }
+ else if (!strncasecmp(hdr->line,"Control: cancel",15))
+ {
+ hp.hdr = hdr;
+ hp.ptr = hdr->line+15;
+ if (whole_string(&hp,cancel,BUFLEN)<=0)
+ {
+ fprintf(stderr,"%s: bad cancel\n",
+ progname);
+ return (0);
+ }
+ DEBLOG((stderr, "Found cancel: %s\n", cancel));
+ cancel_only = 1;
+ }
+ else if (!strncasecmp(hdr->line,"Also-Control: cancel",20))
+ {
+ hp.hdr = hdr;
+ hp.ptr = hdr->line+20;
+ if (whole_string(&hp,cancel,BUFLEN)<=0)
+ {
+ fprintf(stderr,"%s: bad cancel\n",
+ progname);
+ return (0);
+ }
+ DEBLOG((stderr, "Found also-cancel: %s\n", cancel));
+ }
}
hdr = hdr->next;
}
+ if (vsender[0])
+ {
+ DEBLOG((stderr,"vsender address = %s (result %d)\n",
+ vsender,isolate_addr(vsender)));
+ }
+
return (*msgid?ret:0);
}
@@ -597,7 +707,10 @@
int ret;
if (!(dbf = open_history(CONFDIR"/history",GDBM_READER)))
+ {
+ DEBLOG((stderr, "chk_article: Couldn't open history\n"));
return (1);
+ }
key.dsize = strlen(key.dptr = id) + 1;
@@ -605,6 +718,7 @@
gdbm_close(dbf);
+ DEBLOG((stderr, "chk_article: %s exists: %d\n", id, ret));
return (ret);
}
@@ -642,3 +756,232 @@
}
return (dbf);
}
+
+/* Added by Tony Houghton <tony@realh.co.uk>, mostly copied from expire.c */
+
+static void delete_msg(const char *msgid)
+{
+ char buf[BUFLEN];
+ char sender[BUFLEN];
+ struct stat st;
+ FILE *fp;
+ GDBM_FILE dbf;
+ datum key,value;
+ char *file;
+
+ DEBLOG((stderr, "Deleting %s\n", msgid));
+ if (!(dbf = open_history(CONFDIR"/history",GDBM_READER)))
+ return;
+ key.dsize = strlen(key.dptr = (char *) msgid) + 1;
+ value = gdbm_fetch(dbf, key);
+ if ((file = value.dptr) == NULL)
+ return;
+ DEBLOG((stderr, "Filename is %s\n", file));
+
+ if (!(fp = fopen(file,"r")))
+ {
+ if (errno != ENOENT)
+ perror(file);
+ free(file);
+ return;
+ }
+
+ if (fstat(fileno(fp),&st))
+ {
+ perror(file);
+ free(file);
+ return;
+ }
+
+ sender[0] = 0;
+ while (fgets(buf,6,fp))
+ {
+ if (!sender[0] && !strcasecmp(buf,"From:"))
+ {
+ if (read_line(fp,sender,BUFLEN) <= 0)
+ {
+ fclose(fp);
+ fprintf(stderr,"%s: bad From header\n",file);
+ free(file);
+ return;
+ }
+ DEBLOG((stderr, "From: %s\n", sender));
+ }
+ else if (!strcasecmp(buf,"Sende") && fgetc(fp) == 'r' &&
+ fgetc(fp) == ':')
+ {
+ if (read_line(fp,sender,BUFLEN) <= 0)
+ {
+ fclose(fp);
+ fprintf(stderr,"%s: bad Sender\n",file);
+ free(file);
+ return;
+ }
+ DEBLOG((stderr, "Sender: %s\n", sender));
+ }
+ else if (buf[0] == '\n')
+ break;
+ }
+ rewind(fp);
+ if (isolate_addr(sender) == -1)
+ {
+ fprintf(stderr,"Invalid sender, can't cancel\n");
+ free(file);
+ fclose(fp);
+ return;
+ }
+ DEBLOG((stderr,"Sender address = %s\n",sender));
+
+ if (strcasecmp(sender,vsender))
+ {
+ fprintf(stderr,"Wrong sender, can't cancel\n");
+ free(file);
+ fclose(fp);
+ return;
+ }
+
+ while (fgets(buf,6,fp))
+ {
+ char *cp;
+ int c;
+
+ if (strcasecmp(buf,"Xref:"))
+ {
+ if ((cp = strchr(buf,'\n')))
+ {
+ if (cp == buf) break;
+ }
+ else
+ {
+ while ((c = fgetc(fp)) != EOF && c != '\n');
+ if (c == EOF) break;
+ }
+ }
+ else
+ {
+ if ((read_string(fp,buf,BUFLEN) <= 0) ||
+ strcasecmp(buf,fqdn))
+ {
+ fclose(fp);
+ fprintf(stderr,"%s: bad Xref line\n",file);
+ free(file);
+ return;
+ }
+
+ while ((c = read_string(fp,buf,BUFLEN)))
+ {
+ if (c < 0)
+ {
+ fclose(fp);
+ fprintf(stderr,"%s: bad Xref line\n",
+ file);
+ free(file);
+ return;
+ }
+
+ cp = buf;
+ while ((c = *cp))
+ {
+ if (c == '.' || c ==':')
+ *cp = '/';
+ ++cp;
+ }
+
+ if (strcmp(file,buf) &&
+ unlink(buf) && errno != ENOENT)
+ {
+ perror(buf);
+ fclose(fp);
+ free(file);
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+ if (ferror(fp))
+ {
+ perror(file);
+ free(file);
+ fclose(fp);
+ return;
+ }
+
+ fclose(fp);
+ if (unlink(file))
+ perror(file);
+ free(file);
+}
+
+static int read_string(FILE *fp,char *str,unsigned len)
+{
+ int c;
+ unsigned i=0;
+
+ while ((c = fgetc(fp)) != EOF && c != '\n' && isspace(c));
+
+ while (c != EOF && !isspace(c))
+ {
+ str[i]=c;
+ if (++i>=len) return (-1);
+ c = fgetc(fp);
+ }
+ str[i]='\0';
+
+ return (i);
+}
+
+static int whole_string(struct header_pointer *hp,char *str,unsigned len)
+{
+ unsigned i=0;
+ unsigned char c;
+
+ while ((c = next_char(hp)) && isspace(c));
+
+ while (c && c != '\n')
+ {
+ str[i]=c;
+ if (++i>=len) return (-1);
+ c = next_char(hp);
+ }
+ str[i]='\0';
+
+ return (i);
+}
+
+static int read_line(FILE *fp,char *str,unsigned len)
+{
+ int c;
+ unsigned i=0;
+
+ while ((c = fgetc(fp)) != EOF && c != '\n' && isspace(c));
+
+ while (c != EOF && c != '\n')
+ {
+ str[i]=c;
+ if (++i>=len) return (-1);
+ c = fgetc(fp);
+ }
+ str[i]='\0';
+
+ return (i);
+}
+
+static int isolate_addr(char *str)
+{
+ char *at;
+ unsigned len;
+
+ if (!(at=strchr(str,'@')))
+ return -1;
+ while (at != str && !isspace(*(at-1)) && *(at-1) != '<')
+ --at;
+ for (len = 0;
+ len <= strlen(at) && !isspace(at[len]) && at[len] !='>';
+ ++len);
+ memmove(str,at,len);
+ str[len]=0;
+ return 0;
+}
+
syntax highlighted by Code2HTML, v. 0.9.1