From 3e2f009cb32cc7a111c0d355997af87cb3baba56 Mon Sep 17 00:00:00 2001 From: Michiel Broek Date: Tue, 13 Apr 2004 18:25:50 +0000 Subject: [PATCH] Updated for the nntp server --- ChangeLog | 6 +- configure | 2 +- configure.in | 2 +- mbnntp/Makefile | 6 +- mbnntp/commands.c | 376 +++++++++++++++++++++++++++++++++++++++++++++- mbnntp/commands.h | 5 +- mbnntp/mbnntp.c | 42 +++++- mbsetup/Makefile | 2 +- 8 files changed, 424 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4e718e3..12709f6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,13 +18,17 @@ v0.51.4 11-Apr-2004 When a new echomail area is auto created, the creation date and the newsgroup name will be set. + mbnntp: + New program, news server to read echomail with a news client. + Reading news works, no posts yet. + mbsebbs: Added loging of virus scanner results. mbsetup: Added auto setup for message area creation date. Also creates a faked newsgroup name in echomail areas. Both settings are - needed for the (upcoming) newsserver. + needed for the newsserver. v0.51.3 22-Mar-2003 - 11-Apr-2004 diff --git a/configure b/configure index ca0101c3..15f7f7ab 100755 --- a/configure +++ b/configure @@ -1270,7 +1270,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_commands="$ac_config_commands default-1" -SUBDIRS="lib mbcico mbfido mbmon mbsebbs mbtask mbsetup unix lang examples html script" +SUBDIRS="lib mbcico mbfido mbmon mbsebbs mbnntp mbtask mbsetup unix lang examples html script" PACKAGE="mbsebbs" diff --git a/configure.in b/configure.in index 6eb1a185..54d8c568 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ dnl $Id$ AC_INIT(lib/mbselib.h) AM_CONFIG_HEADER(config.h) -SUBDIRS="lib mbcico mbfido mbmon mbsebbs mbtask mbsetup unix lang examples html script" +SUBDIRS="lib mbcico mbfido mbmon mbsebbs mbnntp mbtask mbsetup unix lang examples html script" AC_SUBST(SUBDIRS) dnl diff --git a/mbnntp/Makefile b/mbnntp/Makefile index a9c222fa..ad8761a8 100644 --- a/mbnntp/Makefile +++ b/mbnntp/Makefile @@ -6,7 +6,7 @@ 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 -LIBS += ../lib/libmbse.a ../lib/libdbase.a ../lib/libmsgbase.a +LIBS += ../lib/libmbse.a ../lib/libmsgbase.a ../lib/libdbase.a OTHER = Makefile ############################################################################# @@ -55,9 +55,9 @@ 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 openport.h ttyio.h auth.h commands.h mbnntp.h +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 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 mbnntp.h commands.h +commands.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/msg.h ../lib/msgtext.h ttyio.h mbnntp.h commands.h # End of generated dependencies diff --git a/mbnntp/commands.c b/mbnntp/commands.c index f6ebc6ff..753c8a9a 100644 --- a/mbnntp/commands.c +++ b/mbnntp/commands.c @@ -29,28 +29,392 @@ #include "../config.h" #include "../lib/mbselib.h" +#include "../lib/users.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "ttyio.h" #include "mbnntp.h" #include "commands.h" -void command_list(char *cmd) + +unsigned long article = 0L; /* Current article */ +char currentgroup[81]; /* Current newsgroup */ + +extern unsigned long sentbytes; + + + +/* + * Safe sending to the client with charset translation. + */ +void send_xlat(char *inp) +{ + char *xl, temp[1024]; + int i; + + memset(&temp, 0, sizeof(temp)); + + for (i = 0; i < strlen(inp); i++) { + if (inp[i] & 0x80) { + if ((xl = charset_map_c(inp[i], FALSE))) { + while (*xl) { + temp[i] = *xl++; + if (*xl) + i++; + } + } + } else { + temp[i] = inp[i]; + } + } + + Syslog('n', "> \"%s\"", printable(temp, 0)); + PUTSTR(temp); + PUTSTR((char *)"\r\n"); + FLUSHOUT(); + sentbytes += (strlen(temp) + 2); +} + + + +/* + * ARTICLE + * BODY + * HEADER + * STAT + */ +void command_abhs(char *buf) +{ + char *p, *cmd, *opt, dig[128]; + unsigned long art = 0L; + int i; + + Syslog('+', "%s", buf); + cmd = strtok(buf, " \0"); + opt = strtok(NULL, " \0"); + + IsDoing("Retrieve"); + + if (opt == NULL) { + send_nntp("420 No current article has been selected"); + return; + } + + if (strlen(currentgroup) == 0) { + send_nntp("412 No newsgroup has been selected"); + return; + } + + if (opt[0] == '<') { + Syslog('n', "\"%s\"", printable(opt, 0)); + strcpy(dig, opt+1); + Syslog('n', "\"%s\"", printable(dig, 0)); + for (i = 0; i < strlen(dig); i++) { + if (dig[i] == '$') { + dig[i] = '\0'; + break; + } + } + Syslog('n', "\"%s\"", printable(dig, 0)); + art = atoi(dig); + } else { + art = atoi(opt); + } + + Syslog('n', "Article %lu", art); + + if (art == 0L) { + send_nntp("420 No current article has been selected"); + return; + } + + if (! Msg_ReadHeader(art)) { + send_nntp("430 No such article found"); + return; + } + + if (strcasecmp(cmd, "STAT") == 0) { + send_nntp("223 %lu <%lu$%s@MBNNTP> Article retrieved", art, art, currentgroup); + return; + } + + /* + * Setup a default translation + */ + charset_set_in_out((char *)"x-ibmpc", (char *)"iso-8859-1"); + + if (Msg_Read(art, 75)) { + + if (strcasecmp(cmd, "ARTICLE") == 0) + send_nntp("220 %ld <%ld$%s@MBNNTP> Article retrieved - Head and body follow", art, art, currentgroup); + if (strcasecmp(cmd, "HEAD") == 0) + send_nntp("221 %ld <%ld$%s@MBNNTP> Article retrieved - Head follows", art, art, currentgroup); + if (strcasecmp(cmd, "BODY") == 0) + send_nntp("222 %ld <%ld$%s@MBNNTP> Article retrieved - Body follows", art, art, currentgroup); + + if ((strcasecmp(cmd, "ARTICLE") == 0) || (strcasecmp(cmd, "HEAD") == 0)) { + + send_nntp("Path: MBNNTP!not-for-mail"); + send_nntp("From: %s <%s>", Msg.From, Msg.FromAddress); + send_nntp("Newsgroups: %s", currentgroup); + send_nntp("Subject: %s", Msg.Subject); + send_nntp("Date: %s", rfcdate(Msg.Written)); + send_nntp("Message-ID: <%lu$%s@MBNNTP>", art, currentgroup); + if (Msg.Reply) + send_nntp("References: <%lu$%s@MBNNTP>", Msg.Reply, currentgroup); + send_nntp("X-JAM-From: %s <%s>", Msg.From, Msg.FromAddress); + if (strlen(Msg.To)) + send_nntp("X-JAM-To: %s", Msg.To); + if ((p = (char *)MsgText_First()) != NULL) { + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (p[0] == '\001') { + send_nntp("X-JAM-%s", p+1); + } else { + send_nntp("X-JAM-%s", p); + } + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + +// send_nntp("X-JAM-Attributes:"); + send_nntp("MIME-Version: 1.0"); + send_nntp("Content-Type: text/plain; charset=iso-8859-1; format=fixed"); + send_nntp("Content-Transfer-Encoding: 8bit"); + } + + if (strcasecmp(cmd, "ARTICLE") == 0) + send_nntp(""); + + if ((strcasecmp(cmd, "ARTICLE") == 0) || (strcasecmp(cmd, "BODY") == 0)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + /* + * Kludges, suppress + */ + } else { + if (strcmp(p, ".") == 0) /* Don't send a single dot */ + send_nntp(".."); + else + send_xlat(p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + send_nntp("."); + return; + } else { + send_nntp("503 Could not retrieve message"); + return; + } +} + + + +/* + * GROUP ggg + */ +void command_group(char *cmd) { FILE *fp; - char *temp; - - send_nntp("215 List of newsgroups follows"); + char *temp, *opt; + + IsDoing("Group"); + Syslog('+', "%s", cmd); + opt = strtok(cmd, " \0"); + opt = strtok(NULL, " \0"); + + if (opt == NULL) { + send_nntp("411 No such news group"); + return; + } + temp = calloc(PATH_MAX, sizeof(char)); sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); if ((fp = fopen(temp, "r"))) { fread(&msgshdr, sizeof(msgshdr), 1, fp); while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { - - fseek(fp, msgs.syssize, SEEK_CUR); + if (msgs.Active && ((msgs.Type == ECHOMAIL) || (msgs.Type == NEWS)) && strlen(msgs.Newsgroup) && + (strcasecmp(opt, msgs.Newsgroup) == 0) && Access(usrconfig.Security, msgs.RDSec)) { + Syslog('n', "Found the group"); + if (Msg_Open(msgs.Base)) { + Msg_Number(); + Msg_Highest(); + Msg_Lowest(); + send_nntp("211 %lu %lu %lu %s", MsgBase.Total, MsgBase.Lowest, MsgBase.Highest, msgs.Newsgroup); + sprintf(currentgroup, "%s", msgs.Newsgroup); + } else { + send_nntp("411 No such news group"); + } + fclose(fp); + free(temp); + return; + } + fseek(fp, msgshdr.syssize, SEEK_CUR); } + fclose(fp); } else { WriteError("$Can't open %s", temp); } + free(temp); + send_nntp("411 No such news group"); +} + + + +/* + * LIST + * LIST ACTIVE + * LIST NEWSGROUPS + * LIST OVERVIEW.FMT + */ +void command_list(char *cmd) +{ + FILE *fp; + char *temp, *opt; + int rw; + + IsDoing("List"); + Syslog('+', "%s", cmd); + opt = strtok(cmd, " \0"); + opt = strtok(NULL, " \0"); + + if ((opt == NULL) || (strcasecmp(opt, "ACTIVE") == 0) || (strcasecmp(opt, "NEWSGROUPS") == 0)) { + send_nntp("215 Information follows"); + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r"))) { + fread(&msgshdr, sizeof(msgshdr), 1, fp); + while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + if (msgs.Active && ((msgs.Type == ECHOMAIL) || (msgs.Type == NEWS)) && strlen(msgs.Newsgroup) && + Access(usrconfig.Security, msgs.RDSec)) { + if (Access(usrconfig.Security, msgs.WRSec)) + rw = 'y'; + else + rw = 'n'; + if (msgs.MsgKinds == RONLY) + rw = 'n'; + if (Msg_Open(msgs.Base)) { + if (opt && (strcasecmp(opt, "NEWSGROUPS") == 0)) + send_nntp("%s %s", msgs.Newsgroup, msgs.Name); + else + send_nntp("%s %lu %lu %c", msgs.Newsgroup, Msg_Lowest(), Msg_Highest(), rw); + Msg_Close(); + } + } + fseek(fp, msgshdr.syssize, SEEK_CUR); + } + fclose(fp); + } else { + WriteError("$Can't open %s", temp); + } + free(temp); + send_nntp("."); + return; + } + + if (opt && (strcasecmp(opt, "OVERVIEW.FMT") == 0)) { + send_nntp("215 Order of fields in overview database"); + send_nntp("Subject:"); + send_nntp("From:"); + send_nntp("Date:"); + send_nntp("Message-ID:"); + send_nntp("References:"); + send_nntp("Bytes:"); + send_nntp("Lines:"); +// send_nntp("Xref:full"); + send_nntp("."); + return; + } + + /* + * No recognized LIST command + */ + send_nntp("503 Function not available"); + + msleep(1); /* For the linker only */ + colour(0, 0); +} + + + +/* + * XOVER + */ +void command_xover(char *cmd) +{ + char *opt, *p, msgid[100], reply[100]; + unsigned long i, start, end; + int refs, bytecount, linecount; + + IsDoing("Xover"); + opt = strtok(cmd, " \0"); + opt = strtok(NULL, " \0"); + + if (MsgBase.Open == FALSE) { + send_nntp("411 No news group current selected"); + return; + } + + if ((opt == NULL) && (article == 0L)) { + send_nntp("420 No article selected"); + return; + } + + start = MsgBase.Lowest; + end = MsgBase.Highest; + + Syslog('n', "Start %ld, end %ld", start, end); + + if (opt != NULL) { + if (strchr(opt, '-')) { + /* + * We have a dash, format 12- or 12-16 + */ + p = strtok(opt, "-"); + start = atoi(p); + p = strtok(NULL, "\0"); + if (p != NULL) + end = atoi(p); + } else { + /* + * Must be a single digit + */ + start = end = atoi(opt); + } + } + + Syslog('n', "Start %ld, end %ld", start, end); + + send_nntp("224 Overview information follows"); + for (i = start; i <= end; i++) { + if (Msg_ReadHeader(i)) { + bytecount = linecount = refs = 0; + if (Msg.Original) + refs++; + if (Msg.Reply) + refs++; + if (Msg_Read(i, 80)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] != '\001') { + linecount++; + bytecount += strlen(p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + sprintf(msgid, "<%ld$%s@MBNNTP>", i, currentgroup); + reply[0] = 0; + if (Msg.Reply) + sprintf(reply, "<%ld$%s@MBNNTP>", Msg.Reply, currentgroup); + send_nntp("%lu\t%s\t%s <%s>\t%s\t%s\t%s\t%d\t%d", i, Msg.Subject, Msg.From, Msg.FromAddress, + rfcdate(Msg.Written), msgid, reply, bytecount, linecount); + } + } send_nntp("."); } diff --git a/mbnntp/commands.h b/mbnntp/commands.h index 7c57e5e9..07449dcc 100644 --- a/mbnntp/commands.h +++ b/mbnntp/commands.h @@ -3,6 +3,9 @@ /* $Id$ */ -void command_list(char *); /* LIST */ +void command_abhs(char *); /* ARTICLE/BODY/HEADER/STAT */ +void command_group(char *); /* GROUP */ +void command_list(char *); /* LIST */ +void command_xover(char *); /* XOVER */ #endif diff --git a/mbnntp/mbnntp.c b/mbnntp/mbnntp.c index b82d2a79..00800419 100644 --- a/mbnntp/mbnntp.c +++ b/mbnntp/mbnntp.c @@ -32,6 +32,7 @@ #include "../lib/mbselib.h" #include "../lib/users.h" #include "../lib/mbsedb.h" +#include "../lib/msg.h" #include "openport.h" #include "ttyio.h" #include "auth.h" @@ -43,6 +44,8 @@ time_t t_end; char *envptr = NULL; struct sockaddr_in peeraddr; pid_t mypid; +unsigned long rcvdbytes = 0L; +unsigned long sentbytes = 0L; extern char *ttystat[]; extern int authorized; @@ -52,6 +55,7 @@ void die(int onsig) { signal(onsig, SIG_IGN); CloseDupes(); + Msg_Close(); if (onsig) { if (onsig <= NSIG) @@ -61,6 +65,7 @@ void die(int onsig) } t_end = time(NULL); + Syslog('+', "Send [%6lu] Received [%6lu]", sentbytes, rcvdbytes); Syslog(' ', "MBNNTP finished in %s", t_elapsed(t_start, t_end)); if (envptr) @@ -162,8 +167,10 @@ int get_nntp(char *buf, int max) Syslog('+', "Receiver status %s", ttystat[- c]); return c; } - if ((c == '\r') || (c == '\n')) + if ((c == '\r') || (c == '\n')) { + rcvdbytes += (len + 1); return len; + } else { buf[len] = c; len++; @@ -174,7 +181,8 @@ int get_nntp(char *buf, int max) return len; } } - return 0; /* Not reached */ + + return 0; /* Not reached */ } @@ -193,6 +201,8 @@ void send_nntp(const char *format, ...) Syslog('n', "> \"%s\"", printable(out, 0)); PUTSTR(out); PUTSTR((char *)"\r\n"); + FLUSHOUT(); + sentbytes += (strlen(out) + 2); free(out); } @@ -205,16 +215,18 @@ void nntp(void) while (TRUE) { + IsDoing("Waiting"); len = get_nntp(buf, sizeof(buf) -1); if (len < 0) return; if (len == 0) continue; + Syslog('n', "< \"%s\"", printable(buf, 0)); + /* * Process received command */ - Syslog('n', "< \"%s\"", printable(buf, 0)); if (strncasecmp(buf, "QUIT", 4) == 0) { send_nntp("205 Goodbye\r\n"); return; @@ -222,9 +234,21 @@ void nntp(void) auth_user(buf); } else if (strncasecmp(buf, "AUTHINFO PASS", 13) == 0) { auth_pass(buf); + } else if (strncasecmp(buf, "ARTICLE", 7) == 0) { + if (check_auth(buf)) + command_abhs(buf); + } else if (strncasecmp(buf, "BODY", 4) == 0) { + if (check_auth(buf)) + command_abhs(buf); } else if (strncasecmp(buf, "LIST", 4) == 0) { if (check_auth(buf)) command_list(buf); + } else if (strncasecmp(buf, "GROUP", 5) == 0) { + if (check_auth(buf)) + command_group(buf); + } else if (strncasecmp(buf, "HEAD", 4) == 0) { + if (check_auth(buf)) + command_abhs(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) { @@ -235,22 +259,34 @@ void nntp(void) send_nntp("."); } else if (strncasecmp(buf, "SLAVE", 5) == 0) { send_nntp("202 Slave status noted"); + } else if (strncasecmp(buf, "STAT", 4) == 0) { + if (check_auth(buf)) + command_abhs(buf); } else if (strncasecmp(buf, "MODE READER", 11) == 0) { if (authorized) send_nntp("200 Server ready, posting allowed"); else send_nntp("201 Server ready, no posting allowed"); + } else if (strncasecmp(buf, "XOVER", 5) == 0) { + if (check_auth(buf)) + command_xover(buf); } else if (strncasecmp(buf, "HELP", 4) == 0) { send_nntp("100 Help text follows"); send_nntp("Recognized commands:"); send_nntp(""); + send_nntp("ARTICLE"); send_nntp("AUTHINFO"); + send_nntp("BODY"); + send_nntp("GROUP"); + send_nntp("HEAD"); send_nntp("IHAVE (not implemented, messages are always rejected)"); 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("QUIT"); send_nntp("SLAVE (has no effect)"); + send_nntp("STAT"); + send_nntp("XOVER"); send_nntp(""); send_nntp("MBNNTP supports most of RFC-977 and also has support for AUTHINFO and"); send_nntp("limited XOVER support (RFC-2980)"); diff --git a/mbsetup/Makefile b/mbsetup/Makefile index e2d93e53..89dd263e 100644 --- a/mbsetup/Makefile +++ b/mbsetup/Makefile @@ -75,7 +75,7 @@ grlist.o: ../config.h ../lib/mbselib.h screen.h grlist.h ledit.h m_domain.o: ../config.h ../lib/mbselib.h screen.h mutil.h ledit.h m_global.h m_menu.h m_domain.h m_fgroup.o: ../config.h ../lib/mbselib.h screen.h mutil.h ledit.h stlist.h m_global.h m_node.h m_archive.h m_ngroup.h m_ticarea.h m_fgroup.h m_lang.o: ../config.h ../lib/mbselib.h screen.h mutil.h ledit.h stlist.h m_global.h m_lang.h -m_marea.o: ../config.h ../lib/mbselib.h ../lib/msg.h ../lib/mbsedb.h screen.h mutil.h ledit.h grlist.h m_global.h m_node.h m_mgroup.h m_marea.h +m_marea.o: ../config.h ../lib/mbselib.h ../lib/msg.h ../lib/users.h ../lib/mbsedb.h screen.h mutil.h ledit.h grlist.h m_global.h m_node.h m_mgroup.h m_marea.h m_new.o: ../config.h ../lib/mbselib.h screen.h mutil.h ledit.h stlist.h m_global.h grlist.h m_new.h m_lang.h m_marea.h m_ngroup.h m_protocol.o: ../config.h ../lib/mbselib.h ../paths.h screen.h mutil.h ledit.h stlist.h m_global.h m_protocol.h m_ticarea.o: ../config.h ../lib/mbselib.h screen.h mutil.h ledit.h stlist.h grlist.h m_global.h m_node.h m_fgroup.h m_farea.h m_archive.h m_ticarea.h