From 1ea27d4a804631040db6e3d5023e90a3806dbc6c Mon Sep 17 00:00:00 2001 From: Michiel Broek Date: Mon, 10 May 2004 13:44:21 +0000 Subject: [PATCH] Updated post command --- mbnntp/Makefile | 27 +- mbnntp/addpkt.c | 296 +++++++++++++++++ mbnntp/addpkt.h | 9 + mbnntp/atoul.c | 45 +++ mbnntp/atoul.h | 8 + mbnntp/commands.c | 47 +++ mbnntp/commands.h | 1 + mbnntp/hash.c | 52 +++ mbnntp/hash.h | 8 + mbnntp/lhash.c | 500 +++++++++++++++++++++++++++++ mbnntp/lhash.h | 147 +++++++++ mbnntp/mbnntp.c | 4 + mbnntp/mkftnhdr.c | 594 ++++++++++++++++++++++++++++++++++ mbnntp/mkftnhdr.h | 10 + mbnntp/msgflags.c | 133 ++++++++ mbnntp/msgflags.h | 13 + mbnntp/postecho.c | 480 ++++++++++++++++++++++++++++ mbnntp/postecho.h | 8 + mbnntp/qualify.c | 63 ++++ mbnntp/qualify.h | 23 ++ mbnntp/rfc2ftn.c | 795 ++++++++++++++++++++++++++++++++++++++++++++++ mbnntp/rfc2ftn.h | 8 + mbnntp/rollover.c | 43 +++ 23 files changed, 3309 insertions(+), 5 deletions(-) create mode 100644 mbnntp/addpkt.c create mode 100644 mbnntp/addpkt.h create mode 100644 mbnntp/atoul.c create mode 100644 mbnntp/atoul.h create mode 100644 mbnntp/hash.c create mode 100644 mbnntp/hash.h create mode 100644 mbnntp/lhash.c create mode 100644 mbnntp/lhash.h create mode 100644 mbnntp/mkftnhdr.c create mode 100644 mbnntp/mkftnhdr.h create mode 100644 mbnntp/msgflags.c create mode 100644 mbnntp/msgflags.h create mode 100644 mbnntp/postecho.c create mode 100644 mbnntp/postecho.h create mode 100644 mbnntp/qualify.c create mode 100644 mbnntp/qualify.h create mode 100644 mbnntp/rfc2ftn.c create mode 100644 mbnntp/rfc2ftn.h create mode 100644 mbnntp/rollover.c diff --git a/mbnntp/Makefile b/mbnntp/Makefile index ad8761a8..ad0f0ebf 100644 --- a/mbnntp/Makefile +++ b/mbnntp/Makefile @@ -3,9 +3,15 @@ include ../Makefile.global -SRCS = mbnntp.c openport.c ttyio.c auth.c commands.c -HDRS = mbnntp.h openport.h ttyio.h auth.h commands.h -OBJS = mbnntp.o openport.o ttyio.o auth.o commands.o +SRCS = mbnntp.c openport.c ttyio.c auth.c commands.c rfc2ftn.c \ + hash.c lhash.c msgflags.c postecho.c addpkt.c qualify.c \ + storeecho.c rollover.c mkftnhdr.c atoul.c +HDRS = mbnntp.h openport.h ttyio.h auth.h commands.h rfc2ftn.h \ + hash.h lhash.h msgflags.h postecho.h addpkt.h qualify.h \ + storeecho.h rollover.h mkftnhdr.h atoul.h +OBJS = mbnntp.o openport.o ttyio.o auth.o commands.o rfc2ftn.o \ + hash.o lhash.o msgflags.o postecho.o addpkt.o qualify.o \ + storeecho.o rollover.o mkftnhdr.o atoul.o LIBS += ../lib/libmbse.a ../lib/libmsgbase.a ../lib/libdbase.a OTHER = Makefile @@ -56,8 +62,19 @@ depend: # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # Dependencies generated by make depend mbnntp.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbsedb.h ../lib/msg.h openport.h ttyio.h auth.h commands.h mbnntp.h -openport.o: ../config.h ../lib/mbselib.h openport.h +openport.o: ../config.h ../lib/mbselib.h ttyio.h openport.h ttyio.o: ../config.h ../lib/mbselib.h ttyio.h auth.o: ../config.h ../lib/mbselib.h ../lib/users.h mbnntp.h auth.h -commands.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/msg.h ../lib/msgtext.h ttyio.h mbnntp.h commands.h +commands.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/msg.h ../lib/msgtext.h ttyio.h mbnntp.h rfc2ftn.h commands.h +rfc2ftn.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbinet.h ../lib/mbsedb.h ../lib/msg.h ../lib/msgtext.h mkftnhdr.h hash.h postecho.h msgflags.h rfc2ftn.h +hash.o: ../config.h ../lib/mbselib.h hash.h lhash.h +lhash.o: ../config.h ../lib/mbselib.h lhash.h +msgflags.o: ../config.h ../lib/mbselib.h msgflags.h +postecho.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/msg.h ../lib/msgtext.h ../lib/mbsedb.h postecho.h storeecho.h addpkt.h rollover.h qualify.h +addpkt.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbsedb.h addpkt.h +qualify.o: ../config.h ../lib/mbselib.h qualify.h +storeecho.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/msg.h ../lib/msgtext.h ../lib/mbsedb.h rollover.h storeecho.h +rollover.o: ../config.h ../lib/mbselib.h rollover.h +mkftnhdr.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbsedb.h atoul.h hash.h msgflags.h mkftnhdr.h +atoul.o: ../config.h ../lib/mbselib.h atoul.h # End of generated dependencies diff --git a/mbnntp/addpkt.c b/mbnntp/addpkt.c new file mode 100644 index 00000000..460629ea --- /dev/null +++ b/mbnntp/addpkt.c @@ -0,0 +1,296 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: Add mail to .pkt + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "../lib/users.h" +#include "../lib/mbsedb.h" +#include "addpkt.h" + + + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + +/* + * Prepare ARCmail, this is actually just a rename of the temporary + * .pkt file on the queue to a permanent .pkt name that will later + * be added to the real ARCmail bundle. + */ +int PrepARC(char *, fidoaddr); +int PrepARC(char *Queue, fidoaddr Dest) +{ + char *pktfile; + FILE *fp; + + Syslog('p', "Prepare ARCmail for %s", aka2str(Dest)); + + if (!SearchNode(Dest)) { + WriteError("Downlink %s not found", aka2str(Dest)); + return FALSE; + } + + pktfile = calloc(PATH_MAX, sizeof(char)); + sprintf(pktfile, "%s/%d.%d.%d.%d/%08lx.pkt", CFG.out_queue, Dest.zone, Dest.net, Dest.node, Dest.point, sequencer()); + Syslog('p', "Rename .pkt to %s", pktfile); + + if (rename(Queue, pktfile)) { + WriteError("$Can't rename %s to %s", Queue, pktfile); + free(pktfile); + return FALSE; + } + + /* + * Add zero word to end of .pkt file + */ + if ((fp = fopen(pktfile, "a+")) == NULL) { + WriteError("$Can't open %s", pktfile); + free(pktfile); + return FALSE; + } + putc('\0', fp); + putc('\0', fp); + fsync(fileno(fp)); + fclose(fp); + + free(pktfile); + return TRUE; +} + + + +FILE *CreatePkt(char *, fidoaddr, fidoaddr, char *); +FILE *CreatePkt(char *Queue, fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + static FILE *qp; + unsigned char buffer[0x3a]; + time_t Now; + int i; + struct tm *Tm; + char str[81]; + + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't create Queue %s", Queue); + return NULL; + } + + /* + * Write .PKT header, see FSC-0039 rev. 4 + */ + memset(&buffer, 0, sizeof(buffer)); + Now = time(NULL); + Tm = localtime(&Now); + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + buffer[0x00] = (Orig.node & 0x00ff); + buffer[0x01] = (Orig.node & 0xff00) >> 8; + buffer[0x02] = (Dest.node & 0x00ff); + buffer[0x03] = (Dest.node & 0xff00) >> 8; + buffer[0x04] = ((Tm->tm_year + 1900) & 0x00ff); + buffer[0x05] = ((Tm->tm_year + 1900) & 0xff00) >> 8; + buffer[0x06] = Tm->tm_mon; + buffer[0x08] = Tm->tm_mday; + buffer[0x0a] = Tm->tm_hour; + buffer[0x0c] = Tm->tm_min; + buffer[0x0e] = Tm->tm_sec; + buffer[0x12] = 2; + buffer[0x14] = (Orig.net & 0x00ff); + buffer[0x15] = (Orig.net & 0xff00) >> 8; + buffer[0x16] = (Dest.net & 0x00ff); + buffer[0x17] = (Dest.net & 0xff00) >> 8; + buffer[0x18] = (PRODCODE & 0x00ff); + buffer[0x19] = (VERSION_MAJOR & 0x00ff); + + memset(&str, 0, 8); /* Packet password */ + if (SearchNode(Dest)) { + if (strlen(nodes.Epasswd)) { + sprintf(str, "%s", nodes.Epasswd); + } + } + + for (i = 0; i < 8; i++) + buffer[0x1a + i] = toupper(str[i]); /* FSC-0039 only talks about A-Z, 0-9, so force uppercase */ + + buffer[0x22] = (Orig.zone & 0x00ff); + buffer[0x23] = (Orig.zone & 0xff00) >> 8; + buffer[0x24] = (Dest.zone & 0x00ff); + buffer[0x25] = (Dest.zone & 0xff00) >> 8; + buffer[0x29] = 1; + buffer[0x2a] = (PRODCODE & 0xff00) >> 8; + buffer[0x2b] = (VERSION_MINOR & 0x00ff); + buffer[0x2c] = 1; + buffer[0x2e] = buffer[0x22]; + buffer[0x2f] = buffer[0x23]; + buffer[0x30] = buffer[0x24]; + buffer[0x31] = buffer[0x25]; + buffer[0x32] = (Orig.point & 0x00ff); + buffer[0x33] = (Orig.point & 0xff00) >> 8; + buffer[0x34] = (Dest.point & 0x00ff); + buffer[0x35] = (Dest.point & 0xff00) >> 8; + buffer[0x36] = 'm'; + buffer[0x37] = 'b'; + buffer[0x38] = 's'; + buffer[0x39] = 'e'; + fwrite(buffer, 1, 0x3a, qp); + + fsync(fileno(qp)); + return qp; +} + + + +/* + * Open a .pkt file on the queue, create a fresh one if needed. + * If CFG.maxpktsize is set then it will add the .pkt to the + * ARCmail archive when possible. + */ +FILE *OpenPkt(fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + char *Queue; + static FILE *qp; + + Queue = calloc(PATH_MAX, sizeof(char)); + + sprintf(Queue, "%s/%d.%d.%d.%d/mailpkt.%s", CFG.out_queue, Dest.zone, Dest.net, Dest.node, Dest.point, Extension); + mkdirs(Queue, 0750); + + if (file_exist(Queue, R_OK)) + qp = CreatePkt(Queue, Orig, Dest, Extension); + else { + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't reopen Queue %s", Queue); + free(Queue); + return NULL; + } + + if (CFG.maxpktsize && (ftell(qp) >= (CFG.maxpktsize * 1024)) && (strcmp(Extension, "qqq") == 0)) { + /* + * It's a pkt that's meant to be send archived and it's + * bigger then maxpktsize. Try to add this pkt to the + * outbound archive for this node. + */ + fsync(fileno(qp)); + fclose(qp); + if (PrepARC(Queue, Dest) == TRUE) { + /* + * If the pack succeeded create a fresh packet. + */ + qp = CreatePkt(Queue, Orig, Dest, Extension); + } else { + /* + * If the pack failed the existing queue is + * reopened and we continue adding to that + * existing packet. + */ + Syslog('s', "PrepARC failed"); + qp = fopen(Queue, "a"); + } + + /* + * Go back to the original inbound directory. + */ + chdir(CFG.inbound); + } + } + + free(Queue); + return qp; +} + + + +int AddMsgHdr(FILE *fp, faddr *f, faddr *t, int flags, int cost, time_t date, char *tname, char *fname, char *subj) +{ + unsigned char buffer[0x0e]; + struct tm *Tm; + + if ((tname == NULL) || (strlen(tname) > 36) || + (fname == NULL) || (strlen(fname) > 36) || + (subj == NULL) || (strlen(subj) > 72)) { + if (tname == NULL) + WriteError("AddMsgHdr() error, To name is NULL"); + else if (strlen(tname) > 36) + WriteError("AddMsgHdr() error, To name length %d", strlen(tname)); + if (fname == NULL) + WriteError("AddMsgHdr() error, From name is NULL"); + else if (strlen(fname) > 36) + WriteError("AddMsgHdr() error, From name length %d", strlen(fname)); + if (subj == NULL) + WriteError("AddMsgHdr() error, Subject is NULL"); + else if (strlen(subj) > 72) + WriteError("AddMsgHdr() error, Subject length %d", strlen(subj)); + return 1; + } + + buffer[0x00] = 2; + buffer[0x01] = 0; + buffer[0x02] = (f->node & 0x00ff); + buffer[0x03] = (f->node & 0xff00) >> 8; + buffer[0x04] = (t->node & 0x00ff); + buffer[0x05] = (t->node & 0xff00) >> 8; + buffer[0x06] = (f->net & 0x00ff); + buffer[0x07] = (f->net & 0xff00) >> 8; + buffer[0x08] = (t->net & 0x00ff); + buffer[0x09] = (t->net & 0xff00) >> 8; + buffer[0x0a] = (flags & 0x00ff); + buffer[0x0b] = (flags & 0xff00) >> 8; + buffer[0x0c] = (cost & 0x00ff); + buffer[0x0d] = (cost & 0xff00) >> 8; + fwrite(buffer, 1, sizeof(buffer), fp); + + if (date == (time_t)0) { + date = time(NULL); + Tm = localtime(&date); + } else + Tm = gmtime(&date); + + /* + * According to the manpage the tm_sec value is in the range 0..61 + * to allow leap seconds. FTN networks don't allow this, so if this + * happens we reset the leap seconds. + */ + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + fprintf(fp, "%02d %-3.3s %02d %02d:%02d:%02d%c", + Tm->tm_mday % 100, months[Tm->tm_mon], Tm->tm_year % 100, + Tm->tm_hour % 100, Tm->tm_min % 100, Tm->tm_sec % 100, '\0'); + + fprintf(fp, "%s%c", tname, '\0'); + fprintf(fp, "%s%c", fname, '\0'); + fprintf(fp, "%s%c", subj, '\0'); + fsync(fileno(fp)); + return 0; +} + diff --git a/mbnntp/addpkt.h b/mbnntp/addpkt.h new file mode 100644 index 00000000..13f1ce5b --- /dev/null +++ b/mbnntp/addpkt.h @@ -0,0 +1,9 @@ +#ifndef _ADDPKT_H +#define _ADDPKT_H + +/* $Id$ */ + +FILE *OpenPkt(fidoaddr, fidoaddr, char *); +int AddMsgHdr(FILE *, faddr *, faddr *, int, int, time_t, char *, char *, char *); + +#endif diff --git a/mbnntp/atoul.c b/mbnntp/atoul.c new file mode 100644 index 00000000..1ec0c9bc --- /dev/null +++ b/mbnntp/atoul.c @@ -0,0 +1,45 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: MBSE BBS Mail Gate + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "atoul.h" + + +unsigned long atoul(char *str) +{ + unsigned long x; + + if (sscanf(str,"%lu",&x) == 1) + return x; + else + return 0xffffffff; +} + diff --git a/mbnntp/atoul.h b/mbnntp/atoul.h new file mode 100644 index 00000000..620979a6 --- /dev/null +++ b/mbnntp/atoul.h @@ -0,0 +1,8 @@ +#ifndef _ATOUL_H +#define _ATOUL_H + +/* $Id$ */ + +unsigned long atoul(char*); + +#endif diff --git a/mbnntp/commands.c b/mbnntp/commands.c index b320b4b2..4b576414 100644 --- a/mbnntp/commands.c +++ b/mbnntp/commands.c @@ -34,6 +34,7 @@ #include "../lib/msgtext.h" #include "ttyio.h" #include "mbnntp.h" +#include "rfc2ftn.h" #include "commands.h" @@ -48,6 +49,10 @@ void send_xlat(char *); char *make_msgid(char *); +#define POST_MAXSIZE 10000 + + + /* * Safe sending to the client with charset translation. */ @@ -373,6 +378,48 @@ void command_list(char *cmd) +/* + * POST + */ +void command_post(char *cmd) +{ + FILE *fp = NULL; + int rc, Done = FALSE; + char buf[1024]; + + if ((fp = tmpfile()) == NULL) { + WriteError("$Can't create tmpfile"); + send_nntp("503 Out of memory"); + return; + } + + send_nntp("340 Send article to be posted. End with ."); + + while (Done == FALSE) { + rc = get_nntp(buf, sizeof(buf) -1); + if (rc < 0) { + WriteError("nntp_get failed, abort"); + return; + } + if ((rc == 1) && (buf[0] == '.')) { + Done = TRUE; + } else { + fwrite(&buf, strlen(buf), 1, fp); + fputc('\n', fp); + } + } + + rc = rfc2ftn(fp); + fclose(fp); + + if (rc) + send_nntp("503 Post failed:"); + else + send_nntp("240 Article posted"); +} + + + /* * XOVER */ diff --git a/mbnntp/commands.h b/mbnntp/commands.h index 07449dcc..7d458a16 100644 --- a/mbnntp/commands.h +++ b/mbnntp/commands.h @@ -6,6 +6,7 @@ void command_abhs(char *); /* ARTICLE/BODY/HEADER/STAT */ void command_group(char *); /* GROUP */ void command_list(char *); /* LIST */ +void command_post(char *); /* POST */ void command_xover(char *); /* XOVER */ #endif diff --git a/mbnntp/hash.c b/mbnntp/hash.c new file mode 100644 index 00000000..d25093fa --- /dev/null +++ b/mbnntp/hash.c @@ -0,0 +1,52 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: MBSE BBS Mail Gate + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "hash.h" +#include "lhash.h" + + +void hash_update_s(unsigned long *id, char *mod) +{ + *id ^= lh_strhash(mod); +} + + + +void hash_update_n(unsigned long *id, unsigned long mod) +{ + char buf[32]; + + sprintf(buf,"%030lu",mod); + *id ^= lh_strhash(buf); +} + + diff --git a/mbnntp/hash.h b/mbnntp/hash.h new file mode 100644 index 00000000..511bcdd9 --- /dev/null +++ b/mbnntp/hash.h @@ -0,0 +1,8 @@ +#ifndef HASH_H +#define HASH_H + +void hash_update_s(unsigned long *, char *); +void hash_update_n(unsigned long *, unsigned long); + + +#endif diff --git a/mbnntp/lhash.c b/mbnntp/lhash.c new file mode 100644 index 00000000..9b4886f1 --- /dev/null +++ b/mbnntp/lhash.c @@ -0,0 +1,500 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: MBSE BBS Mail Gate + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "lhash.h" + +/* crypto/lhash/lhash.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +char *lh_version=(char *)"lhash part of SSLeay 0.6.4 30-Aug-1996"; + +/* Code for dynamic hash table routines + * Author - Eric Young v 2.0 + * + * 2.0 eay - Fixed a bug that occured when using lh_delete + * from inside lh_doall(). As entries were deleted, + * the 'table' was 'contract()ed', making some entries + * jump from the end of the table to the start, there by + * skiping the lh_doall() processing. eay - 4/12/95 + * + * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs + * were not being free()ed. 21/11/95 + * + * 1.8 eay - Put the stats routines into a seperate file, lh_stats.c + * 19/09/95 + * + * 1.7 eay - Removed the fputs() for realloc failures - the code + * should silently tolerate them. I have also fixed things + * lint complained about 04/05/95 + * + * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92 + * + * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992 + * + * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91 + * + * 1.3 eay - Fixed a few lint problems 19/3/1991 + * + * 1.2 eay - Fixed lh_doall problem 13/3/1991 + * + * 1.1 eay - Added lh_doall + * + * 1.0 eay - First version + */ + + +#undef MIN_NODES +#define MIN_NODES 16 +#define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */ +#define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */ + +#ifndef NOPROTO + +#define P_CP char * +#define P_CPP char *,char * +static void expand(LHASH *lh); +static void contract(LHASH *lh); +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash); + +#else + +#define P_CP +#define P_CPP +static void expand(); +static void contract(); +static LHASH_NODE **getrn(); + +#endif + +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)) +{ + LHASH *ret; + int i; + + if ((ret=(LHASH *)malloc(sizeof(LHASH))) == NULL) + goto err0; + if ((ret->b=(LHASH_NODE **)malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL) + goto err1; + for (i=0; ib[i]=NULL; + ret->comp=((c == NULL)?(int (*)(char *, char *))strcmp:c); + ret->hash=((h == NULL)?(unsigned long (*)(char *))lh_strhash:h); + ret->num_nodes=MIN_NODES/2; + ret->num_alloc_nodes=MIN_NODES; + ret->p=0; + ret->pmax=MIN_NODES/2; + ret->up_load=UP_LOAD; + ret->down_load=DOWN_LOAD; + ret->num_items=0; + + ret->num_expands=0; + ret->num_expand_reallocs=0; + ret->num_contracts=0; + ret->num_contract_reallocs=0; + ret->num_hash_calls=0; + ret->num_comp_calls=0; + ret->num_insert=0; + ret->num_replace=0; + ret->num_delete=0; + ret->num_no_delete=0; + ret->num_retreve=0; + ret->num_retreve_miss=0; + ret->num_hash_comps=0; + + return(ret); +err1: + free((char *)ret); +err0: + return(NULL); +} + + + +void lh_free(LHASH *lh) +{ + unsigned int i; + LHASH_NODE *n,*nn; + + for (i=0; inum_nodes; i++) + { + n=lh->b[i]; + while (n != NULL) + { + nn=n->next; + free(n); + n=nn; + } + } + free((char *)lh->b); + free((char *)lh); +} + + + +char *lh_insert(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)) + expand(lh); + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + if ((nn=(LHASH_NODE *)malloc(sizeof(LHASH_NODE))) == NULL) + return(NULL); + nn->data=data; + nn->next=NULL; + nn->hash=hash; + *rn=nn; + ret=NULL; + lh->num_insert++; + lh->num_items++; + } + else /* replace same key */ + { + ret= (*rn)->data; + (*rn)->data=data; + lh->num_replace++; + } + return(ret); +} + + + +char *lh_delete(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_no_delete++; + return(NULL); + } + else + { + nn= *rn; + *rn=nn->next; + ret=nn->data; + free((char *)nn); + lh->num_delete++; + } + + lh->num_items--; + if ((lh->num_nodes > MIN_NODES) && + (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))) + contract(lh); + + return(ret); +} + + + +char *lh_retrieve(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE **rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_retreve_miss++; + return(NULL); + } + else + { + ret= (*rn)->data; + lh->num_retreve++; + } + return(ret); +} + + + +void lh_doall(LHASH *lh, void (*func)(char *, char *)) +{ + lh_doall_arg(lh,func,NULL); +} + + + +void lh_doall_arg(LHASH *lh, void(*func)(char *, char *), char *arg) +{ + int i; + LHASH_NODE *a,*n; + + /* reverse the order so we search from 'top to bottom' + * We were having memory leaks otherwise */ + for (i=lh->num_nodes-1; i>=0; i--) + { + a=lh->b[i]; + while (a != NULL) + { + /* 28/05/91 - eay - n added so items can be deleted + * via lh_doall */ + n=a->next; + func(a->data,arg); + a=n; + } + } +} + + + +static void expand(LHASH *lh) +{ + LHASH_NODE **n,**n1,**n2,*np; + unsigned int p,i,j; + unsigned long hash,nni; + + lh->num_nodes++; + lh->num_expands++; + p=(int)lh->p++; + n1= &(lh->b[p]); + n2= &(lh->b[p+(int)lh->pmax]); + *n2=NULL; /* 27/07/92 - eay - undefined pointer bug */ + nni=lh->num_alloc_nodes; + + for (np= *n1; np != NULL; ) + { + hash=np->hash; + if ((hash%nni) != p) + { /* move it */ + *n1= (*n1)->next; + np->next= *n2; + *n2=np; + } + else + n1= &((*n1)->next); + np= *n1; + } + + if ((lh->p) >= lh->pmax) + { + j=(int)lh->num_alloc_nodes*2; + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)sizeof(LHASH_NODE *)*j); + if (n == NULL) + { + WriteError("lhash: realloc error in expand()"); + lh->p=0; + return; + } + /* else */ + for (i=(int)lh->num_alloc_nodes; ipmax=lh->num_alloc_nodes; + lh->num_alloc_nodes=j; + lh->num_expand_reallocs++; + lh->p=0; + lh->b=n; + } +} + + + +static void contract(LHASH *lh) +{ + LHASH_NODE **n,*n1,*np; + + np=lh->b[lh->p+lh->pmax-1]; + lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */ + if (lh->p == 0) + { + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)(sizeof(LHASH_NODE *)*lh->pmax)); + if (n == NULL) + { + WriteError("lhash: realloc error in contract()"); + return; + } + lh->num_contract_reallocs++; + lh->num_alloc_nodes/=2; + lh->pmax/=2; + lh->p=lh->pmax-1; + lh->b=n; + } + else + lh->p--; + + lh->num_nodes--; + lh->num_contracts++; + + n1=lh->b[(int)lh->p]; + if (n1 == NULL) + lh->b[(int)lh->p]=np; + else + { + while (n1->next != NULL) + n1=n1->next; + n1->next=np; + } +} + + + +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash) +{ + LHASH_NODE **ret,*n1; + unsigned long hash,nn; + int (*cf)(char *, char *); + + hash=(*(lh->hash))(data); + lh->num_hash_calls++; + *rhash=hash; + + nn=hash%lh->pmax; + if (nn < lh->p) + nn=hash%lh->num_alloc_nodes; + + cf=lh->comp; + ret= &(lh->b[(int)nn]); + for (n1= *ret; n1 != NULL; n1=n1->next) + { + lh->num_hash_comps++; + if (n1->hash != hash) + { + ret= &(n1->next); + continue; + } + lh->num_comp_calls++; + if ((*cf)(n1->data,data) == 0) + break; + ret= &(n1->next); + } + return(ret); +} + +/* +static unsigned long lh_strhash(str) +char *str; + { + int i,l; + unsigned long ret=0; + unsigned short *s; + + if (str == NULL) return(0); + l=(strlen(str)+1)/2; + s=(unsigned short *)str; + for (i=0; i>2)^v)&0x0f; + ret=(ret<>(32-r)); + ret&=0xFFFFFFFFL; + ret^=v*v; + c++; + } + return((ret>>16)^ret); +} + diff --git a/mbnntp/lhash.h b/mbnntp/lhash.h new file mode 100644 index 00000000..d7071c47 --- /dev/null +++ b/mbnntp/lhash.h @@ -0,0 +1,147 @@ +/* crypto/lhash/lhash.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Header for dynamic hash table routines + * Author - Eric Young + */ + +#ifndef HEADER_LHASH_H +#define HEADER_LHASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lhash_node_st + { + char *data; + struct lhash_node_st *next; +#ifndef NO_HASH_COMP + unsigned long hash; +#endif + } LHASH_NODE; + +typedef struct lhash_st + { + LHASH_NODE **b; + int (*comp)(char *, char *); + unsigned long (*hash)(char *); + unsigned int num_nodes; + unsigned int num_alloc_nodes; + unsigned int p; + unsigned int pmax; + unsigned long up_load; /* load times 256 */ + unsigned long down_load; /* load times 256 */ + unsigned long num_items; + + unsigned long num_expands; + unsigned long num_expand_reallocs; + unsigned long num_contracts; + unsigned long num_contract_reallocs; + unsigned long num_hash_calls; + unsigned long num_comp_calls; + unsigned long num_insert; + unsigned long num_replace; + unsigned long num_delete; + unsigned long num_no_delete; + unsigned long num_retreve; + unsigned long num_retreve_miss; + unsigned long num_hash_comps; + } LHASH; + +#define LH_LOAD_MULT 256 + +#ifndef NOPROTO +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)); +void lh_free(LHASH *lh); +char *lh_insert(LHASH *lh, char *data); +char *lh_delete(LHASH *lh, char *data); +char *lh_retrieve(LHASH *lh, char *data); +void lh_doall(LHASH *lh, void (*func)(char *, char *)); +void lh_doall_arg(LHASH *lh, void (*func)(char *, char *),char *arg); +unsigned long lh_strhash(char *c); + +#ifndef WIN16 +void lh_stats(LHASH *lh, FILE *out); +void lh_node_stats(LHASH *lh, FILE *out); +void lh_node_usage_stats(LHASH *lh, FILE *out); +#endif + +#ifdef HEADER_BUFFER_H +void lh_stats_bio(LHASH *lh, BIO *out); +void lh_node_stats_bio(LHASH *lh, BIO *out); +void lh_node_usage_stats_bio(LHASH *lh, BIO *out); +#else +void lh_stats_bio(LHASH *lh, char *out); +void lh_node_stats_bio(LHASH *lh, char *out); +void lh_node_usage_stats_bio(LHASH *lh, char *out); +#endif +#else +LHASH *lh_new(); +void lh_free(); +char *lh_insert(); +char *lh_delete(); +char *lh_retrieve(); +void lh_doall(); +void lh_doall_arg(); +unsigned long lh_strhash(); + +#ifndef WIN16 +void lh_stats(); +void lh_node_stats(); +void lh_node_usage_stats(); +#endif +void lh_stats_bio(); +void lh_node_stats_bio(); +void lh_node_usage_stats_bio(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mbnntp/mbnntp.c b/mbnntp/mbnntp.c index 493a8da7..39b909e1 100644 --- a/mbnntp/mbnntp.c +++ b/mbnntp/mbnntp.c @@ -276,6 +276,9 @@ void nntp(void) } else if (strncasecmp(buf, "HEAD", 4) == 0) { if (check_auth(buf)) command_abhs(buf); + } else if (strncasecmp(buf, "HEAD", 4) == 0) { + if (check_auth(buf)) + command_post(buf); } else if (strncasecmp(buf, "IHAVE", 5) == 0) { send_nntp("435 Article not wanted - do not send it"); } else if (strncasecmp(buf, "NEWGROUPS", 9) == 0) { @@ -312,6 +315,7 @@ void nntp(void) send_nntp("LIST"); send_nntp("NEWGROUPS (not implemented, always returns an empty list)"); send_nntp("NEWNEWS (not implemented, always returns an empty list)"); + send_nntp("POST"); send_nntp("QUIT"); send_nntp("SLAVE (has no effect)"); send_nntp("STAT"); diff --git a/mbnntp/mkftnhdr.c b/mbnntp/mkftnhdr.c new file mode 100644 index 00000000..f2c96422 --- /dev/null +++ b/mbnntp/mkftnhdr.c @@ -0,0 +1,594 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: MBSE BBS Mail Gate + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +/* Base on E.C. Crosser's ifmail. + * + * ### Modified by P.Saratxaga on 19 Sep 1995 ### + * - Added X-FTN-From and X-FTN-To support + * - added code by T.Tanaka, dated 13 Mar 1995, to put the freename in the ftn + * header, instead of the userid, when the address is fido parseable + * - modified ^aREPLY: code, to look in In-Reply-To: + * - support to decode MSGID from fidogate "Message-ID: " + * - suport for X-Apparently-To: (generated by the french fido->usenet gate) + * - added don't regate code by Wim Van Sebroeck + * - corriged a bug when Organization: has only blanks + */ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "../lib/users.h" +#include "../lib/mbsedb.h" +#include "atoul.h" +#include "hash.h" +#include "msgflags.h" +//#include "aliasdb.h" +#include "mkftnhdr.h" + + + +#ifndef ULONG_MAX +#define ULONG_MAX 4294967295 +#endif + + +char *replyaddr=NULL; +char *ftnmsgidstyle=NULL; +faddr *bestaka; + + + +int ftnmsgid(char *msgid, char **s, unsigned long *n, char *areaname) +{ + char *buf, *l, *r, *p; + unsigned long nid = 0L; + faddr *tmp; + static int ftnorigin = 0; + + if (msgid == NULL) { + *s = NULL; + *n = 0L; + return ftnorigin; + } + + buf = malloc(strlen(msgid)+65); + strcpy(buf, msgid); + if ((l = strchr(buf,'<'))) + l++; + else + l = buf; + while (isspace(*l)) + l++; + if ((r = strchr(l,'>'))) + *r = '\0'; + r = l + strlen(l) - 1; + while (isspace(*r) && (r > l)) + (*r--)='\0'; + if ((tmp = parsefaddr(l))) { + if (tmp->name) { + if (strspn(tmp->name,"0123456789") == strlen(tmp->name)) + nid = atoul(tmp->name); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) { + hash_update_s(&nid, tmp->name); + } else + ftnorigin = 1; + } else { + hash_update_s(&nid,l); + } + *s = xstrcpy(ascfnode(tmp, 0x1f)); + tidy_faddr(tmp); + } else { + if ((r=strchr(l,'@')) == NULL) { /* should never happen */ + Syslog('!', "ftnmsgid: should never happen"); + *s = xstrcpy(l); + hash_update_s(&nid,l); + /* */ + } else if (strncmp(l,"MSGID_",6) == 0) { + *r = '\0'; + r = strrchr(l+6,'_'); + if (r) + *r++ = '\0'; + *s = xstrcpy(l+6); + if (r) + sscanf(r,"%lx",&nid); + ftnorigin = 1; + /* */ + } else if (strncmp(l,"NOMSGID_",8) == 0) { + *s = NULL; + *n = 0L; + ftnorigin = 1; + return ftnorigin; + /* */ + } else if (strncmp(l,"ftn_",4) == 0) { + *r = '\0'; + if ((r = strchr(l+4,'$')) || (r=strchr(l+4,'#'))) { + if (*r=='$') + *r='@'; + if ((r=strchr(l+4,'.'))) + *r=':'; + if ((r=strchr(l+4,'.'))) + *r='/'; + } + while ((r=strrchr(l+4,'_')) != strchr(l+4,'_')) + *r='\0'; + r=strchr(l+4,'_'); + *r++='\0'; + *s=xstrcpy(l+4); + sscanf(r,"%lx",&nid); + ftnorigin=1; + /* */ + } else if (strncmp(l,"wgcid$",6) == 0) { + *r='\0'; + if ((r=strstr(l+6,"$g"))) { + *r='\0'; + *s=xstrcpy(l+6); + *s=xstrcat(*s,(char *)":"); + l=r+2; + } + if ((r=strstr(l,"$h"))) { + *r++='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"/"); + l=r+2; + } + if ((r=strstr(l,"$i"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"."); + l=r+2; + } + if ((r=strstr(l,"$k"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"@"); + l=r+2; + } + if ((r=strstr(l,"$j"))) { + *r='\0'; + *s=xstrcat(*s,l); + sscanf(r+2,"%lx",&nid); + } + } else { + *r='\0'; + if ((p=strchr(l,'%'))) { + *p='\0'; + if (strspn(l,"0123456789") == strlen(l)) { + *r='@'; + r=p; + } else + *p='%'; + } + r++; + if (strspn(l,"0123456789") == strlen(l)) + nid = atoul(l); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) + hash_update_s(&nid,l); + *s=xstrcpy(r); + } + } + *n=nid; + + free(buf); + return ftnorigin; +} + + + +ftnmsg *mkftnhdr(rfcmsg *msg, int newsmode, faddr *recipient) +{ + char *freename = NULL, *rfcfrom = NULL, *p, *q, *l, *r; + char *fbuf = NULL, *ftnfrom=NULL; + static ftnmsg *tmsg; + int needreplyaddr = 1; + faddr *tmp, *tmp2; + + tmsg=(ftnmsg *)malloc(sizeof(ftnmsg)); + memset(tmsg, 0, sizeof(ftnmsg)); + + if (newsmode) { + p = xstrcpy(hdr((char *)"Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-FTN-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Fidonet-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Apparently-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"To", msg)); /* 14-Aug-2001 MB */ + if (p) { + if ((tmsg->to = parsefaddr(p)) == NULL) + tmsg->to = parsefaddr((char *)"All@p0.f0.n0.z0"); + if ((l = strrchr(p,'<')) && (r = strchr(p,'>')) && (l < r)) { + r = l; + *r-- = '\0'; + if ((l = strchr(p,'"')) && (r = strrchr(p,'"')) && (l < r)) { + l++; + *r-- = '\0'; + } + while (isspace(*r)) + *r-- = '\0'; + if (!l) + l = p; + while (isspace(*l)) + l++; + } else if ((l = strrchr(p,'(')) && (r = strchr(p,')')) && (l < r)) { + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + l++; + while (isspace(*l)) + l++; + } else { + l = p; + while (isspace(*l)) + l++; + r = p + strlen(p) -1; + if (*r == '\n') + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + } + + if (*l) { + if (strlen(l) > MAXNAME) + l[MAXNAME]='\0'; + free(tmsg->to->name); + tmsg->to->name=xstrcpy(l); + } + free(p); + /* + * It will become echomail, the destination FTN address must + * be our address. 14-Aug-2001 MB. + */ + tmsg->to->zone = msgs.Aka.zone; + tmsg->to->net = msgs.Aka.net; + tmsg->to->node = msgs.Aka.node; + tmsg->to->point = msgs.Aka.point; + tmsg->to->domain = xstrcpy(msgs.Aka.domain); + } else { + /* + * Filling a default To: address. + */ + tmsg->to = (faddr*)malloc(sizeof(faddr)); + tmsg->to->name = xstrcpy((char *)"All"); + tmsg->to->zone = msgs.Aka.zone; + tmsg->to->net = msgs.Aka.net; + tmsg->to->node = msgs.Aka.node; + tmsg->to->point = msgs.Aka.point; + tmsg->to->domain = xstrcpy(msgs.Aka.domain); + } + Syslog('N', "TO: %s",ascfnode(tmsg->to,0xff)); + } else { + if (recipient) { + /* + * In mbmail mode the recipient is valid and must be used + * as the destination address. The To: field is probably + * an RFC address an cannot be used to route the message. + */ + tmsg->to = (faddr *)malloc(sizeof(faddr)); + tmsg->to->point = recipient->point; + tmsg->to->node = recipient->node; + tmsg->to->net = recipient->net; + tmsg->to->zone = recipient->zone; + tmsg->to->name = xstrcpy(recipient->name); + if (tmsg->to->name && (strlen(tmsg->to->name) > MAXNAME)) + tmsg->to->name[MAXNAME]='\0'; + tmsg->to->domain = xstrcpy(recipient->domain); + Syslog('m', "Recipient TO: %s", ascfnode(tmsg->to,0xff)); + } else { + p = xstrcpy(hdr((char *)"To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Apparently-To",msg)); + if (p) { + if ((tmsg->to = parsefaddr(p)) == NULL) + WriteError("Unparsable destination address"); + else + Syslog('m', "RFC parsed TO: %s",ascfnode(tmsg->to,0xff)); + } + } + } /* else (newsmode) */ + + p = fbuf = xstrcpy(hdr((char *)"Reply-To", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + fbuf = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + fbuf = xstrcat(fbuf, (char *)"@"); + fbuf = xstrcat(fbuf, parserfcaddr(q).target); + } + rfcfrom = fbuf; + } + if (p) + free(p); + p = NULL; + if (!rfcfrom) + rfcfrom = xstrcpy((char *)"postmaster"); + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + if ((q) && (*q != '\0')) + freename = parserfcaddr(q).comment; + else + freename = NULL; + } else + freename = xstrcpy((char *)"Unidentified User"); + if (freename) { + while (isspace(*freename)) + freename++; + } + + if (rfcfrom) { + while (isspace(*rfcfrom)) + rfcfrom++; + p = rfcfrom + strlen(rfcfrom) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + } + + if ((freename) && (*freename != '\0')) { + while (isspace(*freename)) + freename++; + p = freename + strlen(freename) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + if ((*freename == '\"') && (*(p=freename+strlen(freename)-1) == '\"')) { + freename++; + *p='\0'; + } + } + // if (*freename == '\0') freename=rfcfrom; + if ((!freename) || ((freename) && (*freename == '\0')) || (strcmp(freename,".")==0)) + freename=rfcfrom; + + if (newsmode) + Syslog('M', "FROM: %s <%s>", freename, rfcfrom); + else + Syslog('+', "from: %s <%s>",freename,rfcfrom); + + needreplyaddr = 1; + if ((tmsg->from=parsefaddr(rfcfrom)) == NULL) { + if (freename && rfcfrom) + Syslog('-', "at removed registrate()"); +// if (!strchr(freename,'@') && !strchr(freename,'%') && +// strncasecmp(freename,rfcfrom,MAXNAME) && +// strncasecmp(freename,"uucp",4) && +// strncasecmp(freename,"usenet",6) && +// strncasecmp(freename,"news",4) && +// strncasecmp(freename,"super",5) && +// strncasecmp(freename,"admin",5) && +// strncasecmp(freename,"postmaster",10) && +// strncasecmp(freename,"sys",3)) +// needreplyaddr=registrate(freename,rfcfrom); + } else { + tmsg->ftnorigin = 1; + tmsg->from->name = xstrcpy(freename); + if (strlen(tmsg->from->name) > MAXNAME) + tmsg->from->name[MAXNAME]='\0'; + } + if (replyaddr) { + free(replyaddr); + replyaddr=NULL; + } + if (needreplyaddr && (tmsg->from == NULL)) { + Syslog('M', "fill replyaddr with \"%s\"",rfcfrom); + replyaddr=xstrcpy(rfcfrom); + } + + if (tmsg->from) + Syslog('m', "From address was%s distinguished as ftn", tmsg->from ? "" : " not"); + + if (newsmode) { + tmp2 = fido2faddr(msgs.Aka); + bestaka = bestaka_s(tmp2); + tidy_faddr(tmp2); + } else + bestaka = bestaka_s(tmsg->to); + + if ((tmsg->from == NULL) && (bestaka)) { + if (CFG.dontregate) { + p = xstrcpy(hdr((char *)"X-FTN-Sender",msg)); + if (p == NULL) { + if ((p = hdr((char *)"X-FTN-From",msg))) { + tmp = parsefnode(p); + p = xstrcpy(ascinode(tmp, 0xff)); + tidy_faddr(tmp); + } + } + if (p) { + q = p; + while (isspace(*q)) + q++; + ftnfrom = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + ftnfrom = xstrcat(ftnfrom,(char *)"@"); + ftnfrom = xstrcat(ftnfrom,parserfcaddr(q).target); + } + Syslog('m', "Ftn gateway: \"%s\"", ftnfrom); + Syslog('+', "Ftn sender: %s",ftnfrom); + if (ftnfrom) + tmsg->from = parsefaddr(ftnfrom); + if ((tmsg->from) && (!tmsg->from->name)) + tmsg->from->name = xstrcpy(rfcfrom); + } + if (p) + free(p); + p = NULL; + if (tmsg->from == NULL) { + tmsg->from=(faddr *)malloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } else { + tmsg->from=(faddr *)xmalloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } + if (fbuf) + free(fbuf); + fbuf = NULL; + + p = hdr((char *)"Subject", msg); + if (p) { + while (isspace(*p)) + p++; + tmsg->subj = xstrcpy(p); + if (*(p=tmsg->subj+strlen(tmsg->subj)-1) == '\n') + *p='\0'; + if (strlen(tmsg->subj) > MAXSUBJ) + tmsg->subj[MAXSUBJ]='\0'; + } else { + tmsg->subj = xstrcpy((char *)" "); + } + Syslog('M', "SUBJ: \"%s\"", tmsg->subj); + + if ((p = hdr((char *)"X-FTN-FLAGS",msg))) + tmsg->flags |= flagset(p); + if (hdr((char *)"Return-Receipt-To",msg)) + tmsg->flags |= M_RRQ; + if (hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) + tmsg->flags |= M_RRQ; + if (!newsmode) { + tmsg->flags |= M_PVT; + tmsg->flags |= M_KILLSENT; + } + + if ((p = hdr((char *)"X-Origin-Date",msg))) + tmsg->date = parsedate(p, NULL); + else if ((p = hdr((char *)"Date",msg))) + tmsg->date = parsedate(p, NULL); + else + tmsg->date = time((time_t *)NULL); + + /* + * SunMail 1.0 creates invalid date formats like: Wed, 19 Jun 2002 18:21:07 GMT-08:00 + * ^---- not allowed. + */ + if (tmsg->date == -1) { + Syslog('!', "Parsing date \"%s\" failed, using current date", p); + tmsg->date = time((time_t *)NULL); + } + + if ((p = hdr((char *)"X-FTN-MSGID", msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)".MSGID",msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)"Message-ID",msg))) { + tmsg->ftnorigin &= ftnmsgid(p,&(tmsg->msgid_a),&(tmsg->msgid_n),tmsg->area); + } else + tmsg->msgid_a = NULL; + + if ((p = hdr((char *)"X-FTN-REPLY",msg))) { + while (isspace(*p)) + p++; + tmsg->reply_s = xstrcpy(p); + if (*(p=tmsg->reply_s + strlen(tmsg->reply_s) -1) == '\n') + *p='\0'; + } else { + if (newsmode) { + p = hdr((char *)"References",msg); + if (p) { + l = xstrcpy(p); + r = strtok(l," \t\n"); + while ((l=strtok(NULL," \t\n")) != NULL) + r = l; + p = r; + free(l); + } + } else + p = hdr((char *)"In-Reply-To",msg); + } + if (p) + (void)ftnmsgid(p,&(tmsg->reply_a),&(tmsg->reply_n),NULL); + else + tmsg->reply_a=NULL; + + Syslog('M', "DATE: %s, MSGID: %s %lx, REPLY: %s %lx", + ftndate(tmsg->date), MBSE_SS(tmsg->msgid_a),tmsg->msgid_n, MBSE_SS(tmsg->reply_a),tmsg->reply_n); + + p = hdr((char *)"Organization",msg); + if (p == NULL) + p = hdr((char *)"Organisation",msg); + if (p) { + while (isspace(*p)) + p++; + tmsg->origin = xstrcpy(p); + if (tmsg->origin) + if (*(p = tmsg->origin + strlen(tmsg->origin)-1) == '\n') + *p='\0'; + } else { + /* + * No Organization header, insert the default BBS origin. + */ + tmsg->origin = xstrcpy(CFG.origin); + } + + Syslog('M', "ORIGIN: %s", MBSE_SS(tmsg->origin)); + return tmsg; +} + + diff --git a/mbnntp/mkftnhdr.h b/mbnntp/mkftnhdr.h new file mode 100644 index 00000000..428473f7 --- /dev/null +++ b/mbnntp/mkftnhdr.h @@ -0,0 +1,10 @@ +#ifndef _MKFTNHDR_H +#define _MKFTNHDR_H + + +int ftnmsgid(char *,char **,unsigned long *,char *); +ftnmsg *mkftnhdr(rfcmsg *, int, faddr *); + + +#endif + diff --git a/mbnntp/msgflags.c b/mbnntp/msgflags.c new file mode 100644 index 00000000..a2e0228f --- /dev/null +++ b/mbnntp/msgflags.c @@ -0,0 +1,133 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: MBSE BBS Mail Gate + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "msgflags.h" + + +static char *flnm[] = { + (char *)"PVT",(char *)"CRS",(char *)"RCV",(char *)"SNT", + (char *)"ATT",(char *)"TRN",(char *)"ORP",(char *)"K/S", + (char *)"LOC",(char *)"HLD",(char *)"RSV",(char *)"FRQ", + (char *)"RRQ",(char *)"RRC",(char *)"ARQ",(char *)"FUP" +}; + + + +int flagset(char *s) +{ + char *buf,*p; + int i; + int fl=0; + + buf=xstrcpy(s); + for (p=strtok(buf," ,\t\n"); p; p=strtok(NULL," ,\t\n")) { + for (i=0;i<16;i++) + if (!strcasecmp(p,flnm[i])) { + fl |= (1 << i); + } + } + free(buf); + return fl; +} + + + +char *compose_flags(int flags, char *fkludge) +{ + int i; + char *buf = NULL, *p; + + if ((fkludge == NULL) && (!flags)) + return buf; + + if (fkludge) { + if (!isspace(fkludge[0])) + buf=xstrcpy((char *)" "); + buf=xstrcat(buf,fkludge); + p=buf+strlen(buf)-1; + while (isspace(*p)) + *p--='\0'; + } + + for (i = 0; i < 16; i++) + if ((flags & (1 << i)) && (!flag_on(flnm[i],buf))) { + buf=xstrcat(buf,(char *)" "); + buf=xstrcat(buf,flnm[i]); + } + return buf; +} + + + +char *strip_flags(char *flags) +{ + char *p,*q=NULL,*tok; + int canonic,i; + + if (flags == NULL) + return NULL; + + p=xstrcpy(flags); + for (tok=strtok(flags,", \t\n");tok;tok=strtok(NULL,", \t\n")) { + canonic=0; + for (i=0;i<16;i++) + if (strcasecmp(tok,flnm[i]) == 0) + canonic=1; + if (!canonic) { + q=xstrcat(q,(char *)" "); + q=xstrcat(q,tok); + } + } + free(p); + return q; +} + + + +int flag_on(char *flag, char *flags) +{ + char *p, *tok; + int up = FALSE; + + if (flags == NULL) + return FALSE; + + p = xstrcpy(flags); + for (tok = strtok(p, ", \t\n"); tok; tok = strtok(NULL, ", \t\n")) { + if (strcasecmp(flag, tok) == 0) + up = TRUE; + } + free(p); + return up; +} + + diff --git a/mbnntp/msgflags.h b/mbnntp/msgflags.h new file mode 100644 index 00000000..c5eeac94 --- /dev/null +++ b/mbnntp/msgflags.h @@ -0,0 +1,13 @@ +#ifndef _MSGFLAGS_H +#define _MSGFLAGS_H + +/* $Id$ */ + +int flag_on(char *,char *); +int flagset(char *); +char *compose_flags(int,char *); +char *strip_flags(char *); +int flag_on(char *,char *); + +#endif + diff --git a/mbnntp/postecho.c b/mbnntp/postecho.c new file mode 100644 index 00000000..a991d34c --- /dev/null +++ b/mbnntp/postecho.c @@ -0,0 +1,480 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: Post echomail message. + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "../lib/users.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/mbsedb.h" +#include "postecho.h" +#include "storeecho.h" +#include "addpkt.h" +#include "rollover.h" +#include "qualify.h" + + + + +#define MAXPATH 73 +#define MAXSEEN 70 + + +int EchoOut(fidoaddr, char *, char *, char *, FILE *, int, int, time_t); + + + + +/* + * Add echomail mesage to the queue. + */ +int EchoOut(fidoaddr aka, char *toname, char *fromname, char *subj, FILE *fp, int flags, int cost, time_t date) +{ + char *buf, ext[4]; + FILE *qp; + faddr *From, *To; + int rc; + + /* + * Pack flavor for echomail packets. + */ + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + + if ((qp = OpenPkt(msgs.Aka, aka, (char *)ext)) == NULL) { + WriteError("EchoOut(): OpenPkt failed"); + return 1; + } + + From = fido2faddr(msgs.Aka); + To = fido2faddr(aka); + rc = AddMsgHdr(qp, From, To, flags, cost, date, toname, fromname, subj); + tidy_faddr(To); + tidy_faddr(From); + if (rc) { + WriteError("EchoOut(): AddMsgHdr failed"); + return 1; + } + + rewind(fp); + buf = calloc(MAX_LINE_LENGTH +1, sizeof(char)); + + while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) { + Striplf(buf); + fprintf(qp, "%s\r", buf); + } + + free(buf); + putc(0, qp); + fsync(fileno(qp)); + fclose(qp); + return 0; +} + + + +/* + * Post echomail message, forward if needed. + * pkt_from, from, to, subj, orig, mdate, flags, cost, file + * The msgs record must be in memory. + * + * 1 - Cannot open message base. + * 4 - Rejected echomail message. + * + * For echomail, the crc32 is calculated over the ^AREA kludge, subject, + * message date, origin line, message id. + */ +int postecho(faddr *p_from, faddr *f, faddr *t, char *orig, char *subj, time_t mdate, int flags, int cost, FILE *fp, int tonews) +{ + char *buf, *msgid = NULL, *reply = NULL, *p, sbe[16]; + int First = TRUE, rc = 0, i, dupe = FALSE, bad = TRUE, seenlen, oldnet; + faddr *Faddr; + unsigned long crc; + sysconnect Link; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + qualify *qal = NULL, *tmpq; + FILE *nfp; + time_t ddate; + + memset(&Link, 0, sizeof(Link)); + crc = 0xffffffff; + + /* + * p_from is set for tossed echomail, it is NULL for local posted echomail and gated news. + */ + if (p_from) { + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((p_from->zone == Link.aka.zone) && (p_from->net == Link.aka.net) && (p_from->node == Link.aka.node)) { + bad = FALSE; + break; + } + } + if (bad && msgs.UnSecure) { + bad = FALSE; + memset(&Link, 0, sizeof(Link)); + Syslog('!', "Warning, unsecure echomail from %s accepted in area %s", ascfnode(p_from, 0x1f), msgs.Tag); + } + if (bad) { + Syslog('+', "Node %s not connected to area %s", ascfnode(p_from, 0x1f), msgs.Tag); + return 4; + } + if (Link.cutoff && !bad) { + Syslog('+', "Echomail from %s in %s refused, cutoff", ascfnode(p_from, 0x1f), msgs.Tag); + bad = TRUE; + return 4; + } + if (!Link.receivefrom && !bad) { + Syslog('+', "Echomail from %s in %s refused, read only", ascfnode(p_from, 0x1f), msgs.Tag); + bad = TRUE; + return 4; + } + } else { + /* + * Fake the zone entry to be our own zone, this prevents + * zonegate behaviour. It's also not a bad message yet. + */ + Link.aka.zone = msgs.Aka.zone; + bad = FALSE; + } + + /* + * Read the message for kludges we need. + */ + buf = calloc(MAX_LINE_LENGTH +1, sizeof(char)); + First = TRUE; + rewind(fp); + while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) { + + Striplf(buf); + + if (First && (!strncmp(buf, "AREA:", 5))) { + crc = upd_crc32(buf, crc, strlen(buf)); + First = FALSE; + } + if (!strncmp(buf, "\001MSGID: ", 8)) { + msgid = xstrcpy(buf + 8); + } + if (!strncmp(buf, "\001REPLY: ", 8)) + reply = xstrcpy(buf + 8); + if (!strncmp(buf, "SEEN-BY:", 8)) { + p = xstrcpy(buf + 9); + fill_list(&sbl, p, NULL); + free(p); + } + if (!strncmp(buf, "\001PATH:", 6)) { + p = xstrcpy(buf + 7); + fill_path(&ptl, p); + free(p); + } + } /* end of checking kludges */ + + + /* + * Further dupe checking. + */ + crc = upd_crc32(subj, crc, strlen(subj)); + if (orig == NULL) + Syslog('!', "No origin line found"); + else + crc = upd_crc32(orig, crc, strlen(orig)); + + /* + * Some tossers don't bother the seconds in the message, also some + * rescanning software changes the seconds of a message. Do the + * timestamp check without the seconds. + */ + ddate = mdate - (mdate % 60); + crc = upd_crc32((char *)&ddate, crc, sizeof(ddate)); + + if (msgid != NULL) { + crc = upd_crc32(msgid, crc, strlen(msgid)); + } else { + /* + * If a MSGID is missing it is possible that dupes from some offline + * readers slip through because these readers use the same date for + * each message. In this case the message text is included in the + * dupecheck. Redy Rodriguez. + */ + rewind(fp); + while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) { + Striplf(buf); + if (strncmp(buf, "---", 3) == 0) + break; + if ((strncmp(buf, "\001", 1) != 0 ) && (strncmp(buf,"AREA:",5) != 0 )) + crc = upd_crc32(buf, crc , strlen(buf)); + } + } + dupe = CheckDupe(crc, D_ECHOMAIL, CFG.toss_dupes); + + + if (!dupe && !msgs.UnSecure) { + /* + * Check if the message is for us. Don't check point address, + * echomail messages don't have point destination set. + */ + if ((msgs.Aka.zone != t->zone) || (msgs.Aka.net != t->net) || (msgs.Aka.node != t->node)) { + bad = TRUE; + /* + * If we are a hub or host and have all our echomail + * connected to the hub/host aka, echomail from points + * under a nodenumber aka isn't accepted. The match + * must be further tested. + */ + if ((msgs.Aka.zone == t->zone) && (msgs.Aka.net == t->net)) { + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == t->zone) && + (CFG.aka[i].net == t->net) && (CFG.aka[i].node == t->node)) + bad = FALSE; /* Undo the result */ + } + } + } + if (bad) { + WriteError("Msg in %s not for us (%s) but for %s", msgs.Tag, aka2str(msgs.Aka), ascfnode(t,0x1f)); + free(buf); + if (msgid) + free(msgid); + if (reply) + free(reply); + return 4; + } + } + + + /* + * The echomail message is accepted for post/forward/gate + */ + if (!dupe) { + + if (msgs.Aka.zone != Link.aka.zone) { + /* + * If it is a zonegated echomailmessage the SEEN-BY lines + * are stripped off including that of the other zone's + * gate. Add the gate's aka to the SEEN-BY + */ + Syslog('m', "Gated echomail, clean SB"); + tidy_falist(&sbl); + sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node); + Syslog('m', "Add gate SB %s", sbe); + fill_list(&sbl, sbe, NULL); + } + + /* + * Add more aka's to SEENBY if in the same zone as our system. + * When ready filter dupe's, there is at least one. + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && (CFG.aka[i].point == 0) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL); + } + } + uniq_list(&sbl); + } + + + /* + * Add our system to the path for later export. + */ + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl, sbe); + uniq_list(&ptl); /* remove possible duplicate own aka */ + + /* + * Build a list of qualified systems to receive this message. + * Complete the SEEN-BY lines. + */ + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + Faddr = fido2faddr(Link.aka); + if (p_from == NULL) { + fill_qualify(&qal, Link.aka, FALSE, in_list(Faddr, &sbl, FALSE)); + } else { + fill_qualify(&qal, Link.aka, ((p_from->zone == Link.aka.zone) && + (p_from->net == Link.aka.net) && (p_from->node == Link.aka.node) && + (p_from->point == Link.aka.point)), in_list(Faddr, &sbl, FALSE)); + } + tidy_faddr(Faddr); + } + } + + + /* + * Add SEEN-BY for nodes qualified to receive this message. + * When ready, filter the dupes and sort the SEEN-BY entries. + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + sprintf(sbe, "%u/%u", tmpq->aka.net, tmpq->aka.node); + fill_list(&sbl, sbe, NULL); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + + /* + * Create a new tmpfile with a copy of the message + * without original PATH and SEENBY lines, add the + * new PATH and SEENBY lines. + */ + rewind(fp); + if ((nfp = tmpfile()) == NULL) + WriteError("$Unable to open tmpfile"); + while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) { + Striplf(buf); + fprintf(nfp, "%s", buf); + /* + * Don't write SEEN-BY and PATH lines + */ + if (strncmp(buf, " * Origin:", 10) == 0) + break; + fprintf(nfp, "\n"); + } + + + /* + * Now add new SEEN-BY and PATH lines + */ + seenlen = MAXSEEN + 1; + /* + * Ensure that it will not match for the first entry. + */ + oldnet = sbl->addr->net - 1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(nfp, "\nSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + + seenlen = MAXPATH + 1; + /* + * Ensure it will not match for the first entry + */ + oldnet = ptl->addr->net - 1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(nfp, "\n\001PATH:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + fprintf(nfp, "\n"); + fflush(nfp); + rewind(nfp); + + + /* + * Import this echomail, even if it's bad or a dupe. + */ + if ((rc = storeecho(f, t, mdate, flags, subj, msgid, reply, bad, dupe, nfp)) || bad || dupe) { + /* + * Store failed or it was bad or a dupe. Only log failed store. + */ + if (rc) + WriteError("Store echomail in JAM base failed"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + if (msgid) + free(msgid); + if (reply) + free(reply); + fclose(nfp); + return rc; + } + + /* + * Forward to other links + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + if (SearchNode(tmpq->aka)) { + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(tmpq->aka); + if (EchoOut(tmpq->aka, t->name, f->name, subj, nfp, flags, cost, mdate)) + WriteError("Forward echomail to %s failed", aka2str(tmpq->aka)); + } else { + WriteError("Forward echomail to %s failed, noderecord not found", aka2str(tmpq->aka)); + } + } + } + + fclose(nfp); + + /* + * Free memory used by SEEN-BY, ^APATH and Qualified lines. + */ + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + + if (rc < 0) + rc =-rc; + free(buf); + if (msgid) + free(msgid); + if (reply) + free(reply); + return rc; +} + + + diff --git a/mbnntp/postecho.h b/mbnntp/postecho.h new file mode 100644 index 00000000..431804d9 --- /dev/null +++ b/mbnntp/postecho.h @@ -0,0 +1,8 @@ +#ifndef _POSTECHO_H +#define _POSTECHO_H + +/* $Id$ */ + +int postecho(faddr *, faddr *, faddr *, char *, char *, time_t, int, int, FILE *, int); + +#endif diff --git a/mbnntp/qualify.c b/mbnntp/qualify.c new file mode 100644 index 00000000..724eac36 --- /dev/null +++ b/mbnntp/qualify.c @@ -0,0 +1,63 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: List of qualified systems + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "qualify.h" + + + +void tidy_qualify(qualify **qal) +{ + qualify *tmp, *old; + + for (tmp = *qal; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *qal = NULL; +} + + + +void fill_qualify(qualify **qal, fidoaddr aka, int orig, int insb) +{ + qualify *tmp; + + tmp = (qualify *)malloc(sizeof(qualify)); + tmp->next = *qal; + tmp->aka = aka; + tmp->inseenby = insb; + tmp->send = ((!insb) && (!orig)); + tmp->orig = orig; + *qal = tmp; +} + + diff --git a/mbnntp/qualify.h b/mbnntp/qualify.h new file mode 100644 index 00000000..4670ca52 --- /dev/null +++ b/mbnntp/qualify.h @@ -0,0 +1,23 @@ +#ifndef _QUALIFY_H +#define _QUALIFY_H + +/* $Id$ */ + +/* + * Structure for qualified systems to receive a echomail message/tic file + */ +typedef struct _qualify { + struct _qualify *next; /* Linked list */ + fidoaddr aka; /* AKA of the linked system */ + unsigned inseenby : 1; /* System is in SEEN-BY */ + unsigned send : 1; /* Send message to link */ + unsigned orig : 1; /* Is originator of message */ +} qualify; + + + +void tidy_qualify(qualify **); +void fill_qualify(qualify **, fidoaddr, int, int); + + +#endif diff --git a/mbnntp/rfc2ftn.c b/mbnntp/rfc2ftn.c new file mode 100644 index 00000000..f93833b7 --- /dev/null +++ b/mbnntp/rfc2ftn.c @@ -0,0 +1,795 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: Convert RFC to FTN + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "../lib/users.h" +#include "../lib/mbinet.h" +#include "../lib/mbsedb.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "mkftnhdr.h" +#include "hash.h" +#include "postecho.h" +#include "msgflags.h" +#include "rfc2ftn.h" + + +#define MAXHDRSIZE 2048 +#define MAXSEEN 70 +#define MAXPATH 73 + + +/* + * Global variables + */ +static int ftnorigin; +static int removemime; +static int removemsgid; +static int removeref; +static int removeinreply; +static int removereplyto; +static int removereturnto; + + + +/* + * External variables + */ +extern char *replyaddr; + + +/* + * Internal functions + */ +int needputrfc(rfcmsg *, int); + + + +int charwrite(char *, FILE *); +int charwrite(char *s, FILE *fp) +{ + if ((strlen(s) >= 3) && (strncmp(s,"---",3) == 0) && (s[3] != '-')) { + putc('-',fp); + putc(' ',fp); + } + while (*s) { + putc(*s, fp); + s++; + } + return 0; +} + + + +/* + * write (multiline) header to kluge: change \n to ' ' and end line with \n + */ +int kludgewrite(char *, FILE *); +int kludgewrite(char *s, FILE *fp) +{ + while (*s) { + if (*s == '\r') + putc('\n', fp); + else { + if (*s != '\n') + putc(*s, fp); + else if (*(s+1)) + putc(' ',fp); + } + s++; + } + putc('\n',fp); + return 0; +} + + + +/* + * Input a RFC news message. + */ +int rfc2ftn(FILE *fp) +{ + char sbe[16], *p, *q, *temp, *origin, newsubj[4 * (MAXSUBJ+1)], *oldsubj; + int i, rc, newsmode, seenlen, oldnet; + rfcmsg *msg = NULL, *tmsg, *tmp; + ftnmsg *fmsg = NULL; + FILE *ofp; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + faddr *ta, *fta; + unsigned long svmsgid, svreply; + int sot_kludge = FALSE, eot_kludge = FALSE, tinyorigin = FALSE; + int needsplit, hdrsize, datasize, splitpart, forbidsplit, rfcheaders; + time_t Now; + + temp = calloc(4097, sizeof(char)); + Syslog('m', "Entering rfc2ftn"); + rewind(fp); + Syslog('m', "========== RFC Start"); + while ((fgets(temp, 4095, fp)) != NULL) { + Syslogp('m', printable(temp, 0)); + } + Syslog('m', "========== RFC end"); + rewind(fp); + msg = parsrfc(fp); + + newsmode = hdr((char *)"Newsgroups", msg) ?TRUE:FALSE; + if (newsmode == FALSE) { + WriteError("Not a news article"); + return 1; + } + + if ((fmsg = mkftnhdr(msg, newsmode, NULL)) == NULL) { + WriteError("Unable to create FTN headers from RFC ones, aborting"); + tidyrfc(msg); + return 1; + } + + fmsg->area = xstrcpy(msgs.Tag); + svmsgid = fmsg->msgid_n; + svreply = fmsg->reply_n; + if ((p = hdr((char *)"Message-ID",msg))) { + ftnmsgid(p, &fmsg->msgid_a, &fmsg->msgid_n, fmsg->area); + hash_update_s(&fmsg->msgid_n, fmsg->area); + } + + if ((p = hdr((char *)"References",msg))) { + p = strrchr(p,' '); + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } else if ((p = hdr((char *)"In-Reply-To",msg))) { + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } + + chkftnmsgid(hdr((char *)"Message-ID",msg)); // ?? + removemime = FALSE; + removemsgid = FALSE; + removeref = FALSE; + removeinreply = FALSE; + removereplyto = TRUE; + removereturnto = TRUE; + ftnorigin = fmsg->ftnorigin; + + q = hdr((char *)"Content-Transfer-Encoding",msg); + if (q) + while (*q && isspace(*q)) + q++; + if (!(q)) + q = (char *)"8bit"; + if ((p = hdr((char *)"Content-Type",msg))) { + while (*p && isspace(*p)) + p++; + + /* + * Check for mime to remove. + */ + if ((strncasecmp(p, "text/plain", 10) == 0) && ((q == NULL) || + (strncasecmp(q,"7bit",4) == 0) || (strncasecmp(q,"8bit",4) == 0))) { + removemime = TRUE; /* no need in MIME headers */ + Syslog('m', "removemime=%s", removemime ? "True":"False"); + } + } + + if ((p = hdr((char *)"Message-ID",msg))) { + if (!removemsgid) + removemsgid = chkftnmsgid(p); + } + Syslog('m', "removemsgid = %s", removemsgid ? "True":"False"); + + if ((!removeref) && (p = hdr((char *)"References",msg))) { + p = xstrcpy(p); + q = strtok(p," \t\n"); + if ((q) && (strtok(NULL," \t\n") == NULL)) + removeref = chkftnmsgid(q); + free(p); + } + if (removeref) + Syslog('m', "removeref = %s", removeref ? "True":"False"); + + if ((p = hdr((char *)"Reply-To",msg))) { + removereplyto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); + p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereplyto = TRUE; + } + } + Syslog('m', "removereplyto = %s", removereplyto ? "True":"False"); + + if ((p = hdr((char *)"Return-Receipt-To",msg))) { + removereturnto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + + r = xstrcpy(p); + p = r; + while (*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereturnto = TRUE; + } + } + if (!removereturnto) + Syslog('m', "removereturnto = %s", removereturnto ? "True":"False"); + + p = ascfnode(fmsg->from,0x1f); + i = 79-11-3-strlen(p); + if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) { + /* This is a kludge... I don't like it too much. But well, + if this is a message of FTN origin, the original origin (:) + line MUST have been short enough to fit in 79 chars... + So we give it a try. Probably it would be better to keep + the information about the address format from the origin + line in a special X-FTN-... header, but this seems even + less elegant. Any _good_ ideas, anyone? */ + + /* OK, I am keeping this, though if should never be used + al long as X-FTN-Origin is used now */ + + p = ascfnode(fmsg->from,0x0f); + Syslog('m', "checkorigin 3"); + i = 79-11-3-strlen(p); + tinyorigin = TRUE; + } + if (tinyorigin) + Syslog('m', "tinyorigin = %s", tinyorigin ? "True":"False"); + + if ((fmsg->origin) && (strlen(fmsg->origin) > i)) + fmsg->origin[i]='\0'; + forbidsplit = (ftnorigin || ((p = hdr((char *)"X-FTN-Split",msg)) && (strcasecmp(p," already\n") == 0))); + needsplit = 0; + splitpart = 0; + hdrsize = 20; + hdrsize += (fmsg->subj)?strlen(fmsg->subj):0; + if (fmsg->from) + hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0; + if (fmsg->to) + hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0; + do { + Syslog('m', "split loop, splitpart = %d", splitpart); + datasize = 0; + + if (splitpart) { + sprintf(newsubj,"[part %d] ",splitpart+1); + strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj)); + } else { + strncpy(newsubj,fmsg->subj,MAXSUBJ); + } + newsubj[MAXSUBJ]='\0'; + + if (splitpart) { + hash_update_n(&fmsg->msgid_n,splitpart); + } + oldsubj = fmsg->subj; + fmsg->subj = newsubj; + + /* + * Create a new temp message in FTN style format + */ + if ((ofp = tmpfile()) == NULL) { + WriteError("$Can't open second tmpfile"); + tidyrfc(msg); + return 1; + } + + if (newsmode) { + fprintf(ofp, "AREA:%s\n", msgs.Tag); + } else { + if (fmsg->to->point != 0) + fprintf(ofp, "\001TOPT %d\n", fmsg->to->point); + if (fmsg->from->point != 0) + fprintf(ofp, "\001FMPT %d\n", fmsg->from->point); + fprintf(ofp, "\001INTL %d:%d/%d %d:%d/%d\n", fmsg->to->zone, fmsg->to->net, fmsg->to->node, + fmsg->from->zone, fmsg->from->net, fmsg->from->node); + } + fprintf(ofp, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(ofp, "\1REPLY: %s\n", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(ofp, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n); + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + fprintf(ofp, "\001TZUTC: %s\n", gmtoffset(Now)); + fmsg->subj = oldsubj; + if ((p = hdr((char *)"X-FTN-REPLYADDR",msg))) { + hdrsize += 10+strlen(p); + fprintf(ofp,"\1REPLYADDR:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + hdrsize += 10+strlen(replyaddr); + fprintf(ofp,"\1REPLYADDR: "); + kludgewrite(replyaddr,ofp); + } + if ((p = hdr((char *)"X-FTN-REPLYTO",msg))) { + hdrsize += 8+strlen(p); + fprintf(ofp,"\1REPLYTO:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + hdrsize += 15; + if (newsmode) + fprintf(ofp,"\1REPLYTO: %s UUCP\n", aka2str(msgs.Aka)); + else { + fta = bestaka_s(fmsg->to); + fprintf(ofp,"\1REPLYTO: %s UUCP\n", ascfnode(fta, 0x1f)); + tidy_faddr(fta); + } + } else if ((p = hdr((char *)"Reply-To",msg))) { + if ((ta = parsefaddr(p))) { + if ((q = hdr((char *)"From",msg))) { + if (!strcasestr(q,p)) { + fprintf(ofp,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name); + } + } + tidy_faddr(ta); + } + } + if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) { + hdrsize += 15; + fprintf(ofp,"\1FLAGS:%s\n",p); + free(p); + } + if (!hdr((char *)"X-FTN-PID", msg)) { + p = hdr((char *)"User-Agent", msg); + if (p == NULL) + p = hdr((char *)"X-Newsreader", msg); + if (p == NULL) + p = hdr((char *)"X-Mailer", msg); + if (p) { + hdrsize += 4 + strlen(p); + fprintf(ofp, "\1PID:"); + kludgewrite(p, ofp); + } else { + fprintf(ofp, "\001PID: MBSE-NNTPD %s (%s-%s)\n", VERSION, OsName(), OsCPU()); + } + } + + if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) { + sprintf(temp, " MBSE-FIDO %s (%s-%s)", VERSION, OsName(), OsCPU()); + hdrsize += 4 + strlen(temp); + fprintf(ofp, "\1TID:"); + kludgewrite(temp, ofp); + } + + if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) { + for (tmp = msg; tmp; tmp = tmp->next) { + if ((!strncmp(tmp->key,"X-Fsc-",6)) || (!strncmp(tmp->key,"X-FTN-",6) && + strcasecmp(tmp->key,"X-FTN-Tearline") && + strcasecmp(tmp->key,"X-FTN-Origin") && + strcasecmp(tmp->key,"X-FTN-Sender") && + strcasecmp(tmp->key,"X-FTN-Split") && + strcasecmp(tmp->key,"X-FTN-FLAGS") && + strcasecmp(tmp->key,"X-FTN-AREA") && + strcasecmp(tmp->key,"X-FTN-MSGID") && + strcasecmp(tmp->key,"X-FTN-REPLY") && + strcasecmp(tmp->key,"X-FTN-SEEN-BY") && + strcasecmp(tmp->key,"X-FTN-PATH") && + strcasecmp(tmp->key,"X-FTN-REPLYADDR") && + strcasecmp(tmp->key,"X-FTN-REPLYTO") && + strcasecmp(tmp->key,"X-FTN-To") && + strcasecmp(tmp->key,"X-FTN-From") && + strcasecmp(tmp->key,"X-FTN-CHARSET") && + strcasecmp(tmp->key,"X-FTN-CHRS") && + strcasecmp(tmp->key,"X-FTN-CODEPAGE") && + strcasecmp(tmp->key,"X-FTN-ORIGCHRS") && + strcasecmp(tmp->key,"X-FTN-SOT") && + strcasecmp(tmp->key,"X-FTN-EOT") && + strcasecmp(tmp->key,"X-FTN-Via"))) { + if ((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0)) { + if (!strcasecmp(tmp->val," SOT:\n")) + sot_kludge = TRUE; + else if (!strcasecmp(tmp->val," EOT:\n")) + eot_kludge = TRUE; + else { + hdrsize += strlen(tmp->val); + fprintf(ofp,"\1"); + /* we should have restored the original string here... */ + kludgewrite((tmp->val)+1,ofp); + } + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+6); + kludgewrite(tmp->val,ofp); + } + } + } + + /* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-ZC-",5))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+2); + kludgewrite(tmp->val,ofp); + } + + /* mondo.org gateway uses ".MSGID: ..." in usenet */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+1); + kludgewrite(tmp->val,ofp); + } + + + /* + * Add the Received: header from this system to the mesage. + */ + if (!newsmode) { + Now = time(NULL); + fprintf(ofp, "\1RFC-Received: by %s (mbfido) via RFC2FTN; %s\n", CFG.sysdomain, rfcdate(Now)); + hdrsize += 72+strlen(CFG.sysdomain); + } + + for (tmp = msg; tmp; tmp = tmp->next) { + if ((needputrfc(tmp, newsmode) == 1)) { + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"\1RFC-Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1RFC-%s:",tmp->key); + } + kludgewrite(tmp->val, ofp); + } + } + + rfcheaders=0; + for (tmp=msg;tmp;tmp=tmp->next) { + if ((needputrfc(tmp, newsmode) > 1)) { + rfcheaders++; + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"%s:",tmp->key); + } + charwrite(tmp->val, ofp); + } + } + + if (rfcheaders) + charwrite((char *)"\n",ofp); + if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge)) + fprintf(ofp,"\1SOT:\n"); + } + if (replyaddr) { + replyaddr = NULL; + } + + if (needsplit) { + fprintf(ofp," * Continuation %d of a split message *\n\n", splitpart); + needsplit = FALSE; + } else if ((p=hdr((char *)"X-Body-Start",msg))) { + datasize += strlen(p); + charwrite(p, ofp); + } + while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) || + (!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(temp,4096-1,fp))) { + datasize += strlen(temp); + charwrite(temp, ofp); + } + + if (needsplit) { + fprintf(ofp,"\n * Message split, to be continued *\n"); + splitpart++; + } + if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge)) + fprintf(ofp,"\1EOT:\n"); + + if ((p=hdr((char *)"X-FTN-Tearline",msg))) { + fprintf(ofp,"---"); + if (strcasecmp(p," (none)\n") == 0) + charwrite((char *)"\n",ofp); + else + charwrite(p,ofp); + } else + fprintf(ofp,"%s\n", TearLine()); + + if ((p = hdr((char *)"X-FTN-Origin",msg))) { + if (*(q=p+strlen(p)-1) == '\n') + *q='\0'; + origin = xstrcpy((char *)" * Origin: "); + origin = xstrcat(origin, p); + } else { + origin = xstrcpy((char *)" * Origin: "); + if (fmsg->origin) + origin = xstrcat(origin, fmsg->origin); + else + origin = xstrcat(origin, CFG.origin); + origin = xstrcat(origin, (char *)" ("); + origin = xstrcat(origin, ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + origin = xstrcat(origin, (char *)")"); + } + fprintf(ofp, "%s", origin); + + if (newsmode) { + /* + * Setup SEEN-BY lines, first SEEN-BY from RFC message, then all matching AKA's + */ + for (tmsg = msg; tmsg; tmsg = tmsg->next) + if (strcasecmp(tmsg->key, "X-FTN-SEEN-BY") == 0) + fill_list(&sbl, tmsg->val, NULL); + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (CFG.aka[i].point == 0) && (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL); + } + } + if (msgs.Aka.point == 0) { + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_list(&sbl, sbe, NULL); + } + + /* + * Only add SEEN-BY lines if there are any + */ + if (sbl != NULL) { + uniq_list(&sbl); + sort_list(&sbl); + seenlen = MAXSEEN + 1; + memset(&sbe, 0, sizeof(sbe)); + /* ensure it will not match for the first entry */ + oldnet = sbl->addr->net-1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(ofp,"\nSEEN-BY:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + tidy_falist(&sbl); + } + + /* + * Setup PATH lines + */ + for (tmp = msg; tmp; tmp = tmp->next) + if (!strcasecmp(tmp->key,"X-FTN-PATH")) + fill_path(&ptl,tmp->val); + if (msgs.Aka.point == 0) { + sprintf(sbe,"%u/%u",msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl,sbe); + } + + /* + * Only add PATH line if there is something + */ + if (ptl != NULL) { + uniq_list(&ptl); + seenlen = MAXPATH+1; + /* ensure it will not match for the first entry */ + oldnet = ptl->addr->net-1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(ofp,"\n\1PATH:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + tidy_falist(&ptl); + } + } /* if (newsmode) */ + + /* + * Add newline and message is ready. + */ + fprintf(ofp,"\n"); + fflush(ofp); + rewind(ofp); + + Syslog('m', "========== Fido start"); + while (fgets(temp, 4096, ofp) != NULL) { + /* + * Only log kludges, skip the body + */ + if ((temp[0] == '\001') || !strncmp(temp, "AREA:", 5) || !strncmp(temp, "SEEN-BY", 7)) { + Striplf(temp); + Syslogp('m', printable(temp, 0)); + } + } + Syslog('m', "========== Fido end"); + + rc = postecho(NULL, fmsg->from, fmsg->to, origin, fmsg->subj, fmsg->date, fmsg->flags, 0, ofp, FALSE); + + free(origin); + fclose(ofp); + } while (needsplit); + free(temp); + tidyrfc(msg); + tidy_ftnmsg(fmsg); + UpdateMsgs(); + + return 0; +} + + + +/* + * Test which kludges to add; + * <1 junk + * 1 make kludge + * >1 pass + */ +int needputrfc(rfcmsg *msg, int newsmode) +{ + faddr *ta; + +// Syslog('M', "needputrfc(%s)", printable(msg->key,0)); + if ((msg->key == NULL) || (strlen(msg->key) == 0)) return 0; + + if (!strcasecmp(msg->key,"X-UUCP-From")) return -1; + if (!strcasecmp(msg->key,"X-Body-Start")) return -1; + if (!strncasecmp(msg->key,".",1)) return 0; + if (!strncasecmp(msg->key,"X-FTN-",6)) return 0; + if (!strncasecmp(msg->key,"X-Fsc-",6)) return 0; + if (!strncasecmp(msg->key,"X-ZC-",5)) return 0; + if (!strcasecmp(msg->key,"X-Gateway")) return 0; + if (!strcasecmp(msg->key,"Path")) return 0; + if (!strcasecmp(msg->key,"Newsgroups")) { + if ((hdr((char *)"X-Origin-Newsgroups",msg))) + return 0; + else if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) { + if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"Control")) { + if (CFG.allowcontrol) { + if (strstr(msg->val,"cancel")) + return 1; + else + return 0; + } else + return 0; + } + if (!strcasecmp(msg->key,"Return-Path")) return 1; + if (!strcasecmp(msg->key,"Xref")) return 0; + if (!strcasecmp(msg->key,"Approved")) return 1; + if (!strcasecmp(msg->key,"X-URL")) return 0; + if (!strcasecmp(msg->key,"Return-Receipt-To")) return removereturnto? 0:1; + if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) return 0; + if (!strcasecmp(msg->key,"Received")) return newsmode?0:2; + if (!strcasecmp(msg->key,"From")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else { + return 1; /* 28-Jul-2001 MB (was 2) */ + } + } + if (!strcasecmp(msg->key,"To")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return 2; + } + if (!strcasecmp(msg->key,"Cc")) return 2; + if (!strcasecmp(msg->key,"Bcc")) return 0; + if (!strcasecmp(msg->key,"Reply-To")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return -1; + } else + return removereplyto ?0:4; + } + if (!strcasecmp(msg->key,"Lines")) return 0; + if (!strcasecmp(msg->key,"Date")) return 0; + if (!strcasecmp(msg->key,"Subject")) { + if ((msg->val) && (strlen(msg->val) > MAXSUBJ)) + return 2; + else + return 0; + } + if (!strcasecmp(msg->key,"Organization")) return 1; + if (!strcasecmp(msg->key,"Organisation")) return 1; + if (!strcasecmp(msg->key,"Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Apparently-To")) return 0; + if (!strcasecmp(msg->key,"X-Originating-IP")) return 0; + if (!strcasecmp(msg->key,"X-Virus-Scanned")) return 0; + if (!strcasecmp(msg->key,"X-AntiVirus")) return 0; + if (!strcasecmp(msg->key,"X-Delivery-Agent")) return 0; + if (!strcasecmp(msg->key,"X-Virtual-Domain")) return 0; + if (!strcasecmp(msg->key,"Apparently-To")) return 0; + if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) return 0; + if (!strcasecmp(msg->key,"Keywords")) return 2; + if (!strcasecmp(msg->key,"Summary")) return 2; + if (!strcasecmp(msg->key,"MIME-Version")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Type")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Length")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Name")) return 2; + if (!strcasecmp(msg->key,"Content-Description")) return 2; + if (!strcasecmp(msg->key,"Message-ID")) return removemsgid ?0:1; + if (!strcasecmp(msg->key,"References")) return removeref ?0:1; + if (!strcasecmp(msg->key,"Supersedes")) return 1; + if (!strcasecmp(msg->key,"Distribution")) return ftnorigin ?0:0; + if (!strcasecmp(msg->key,"X-Newsreader")) return 0; + if (!strcasecmp(msg->key,"X-Mailer")) return 0; + if (!strcasecmp(msg->key,"User-Agent")) return 0; + if (!strncasecmp(msg->key,"NNTP-",5)) return 0; + if (!strncasecmp(msg->key,"X-Trace",7)) return 0; + if (!strncasecmp(msg->key,"X-Complaints",12)) return 0; + if (!strncasecmp(msg->key,"X-MSMail",9)) return 0; + if (!strncasecmp(msg->key,"X-MimeOLE",9)) return 0; + if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) return 0; + if (!strcasecmp(msg->key,"X-Origin-Date")) return 0; + if (!strncasecmp(msg->key,"X-PGP-",6)) return 0; + if (!strncasecmp(msg->key,"Resent-",7)) return 0; + if (!strncasecmp(msg->key,"X-MS-",5)) return -1; + if (!strcasecmp(msg->key,"X-Mailing-List")) return 0; + if (!strcasecmp(msg->key,"X-Loop")) return 0; + if (!strcasecmp(msg->key,"Precedence")) return 0; + if (!strcasecmp(msg->key,"X-Face")) return 0; + if (!strcasecmp(msg->key,"X-Accept-Language")) return 0; + if (!strncasecmp(msg->key,"X-Spam-", 7)) return 0; + /*if (!strcasecmp(msg->key,"")) return ;*/ + return 1; +} + + diff --git a/mbnntp/rfc2ftn.h b/mbnntp/rfc2ftn.h new file mode 100644 index 00000000..b5bd6ed6 --- /dev/null +++ b/mbnntp/rfc2ftn.h @@ -0,0 +1,8 @@ +#ifndef _RFC2FTN_H +#define _RFC2FTN_H + +/* $Id$ */ + +int rfc2ftn(FILE *fp); + +#endif diff --git a/mbnntp/rollover.c b/mbnntp/rollover.c new file mode 100644 index 00000000..838dc5be --- /dev/null +++ b/mbnntp/rollover.c @@ -0,0 +1,43 @@ +/***************************************************************************** + * + * $Id$ + * Purpose ...............: Statistic rollover util. + * + ***************************************************************************** + * Copyright (C) 1997-2004 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "../config.h" +#include "../lib/mbselib.h" +#include "rollover.h" + + +void StatAdd(statcnt *S, unsigned long V) +{ + S->total += V; + S->tweek += V; + S->tdow[Diw] += V; + S->month[Miy] += V; +} +