From b4dc5765eb7e2005be06e81bf73f323a6c906c2b Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Tue, 13 Nov 2001 05:18:48 +0000
Subject: [PATCH] Networks News (NNTP) server.

---
 exec/nntpservice.js | 205 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 205 insertions(+)
 create mode 100644 exec/nntpservice.js

diff --git a/exec/nntpservice.js b/exec/nntpservice.js
new file mode 100644
index 0000000000..3163c5071a
--- /dev/null
+++ b/exec/nntpservice.js
@@ -0,0 +1,205 @@
+// nntpservice.js
+
+// Synchronet Service for the Network News Transfer Protocol (RFC 977)
+
+// Example configuration (in ctrl/services.cfg):
+
+// NNTP		119	0-unlimited	0		nntpservice.js
+
+
+const VERSION = "1.00 Alpha";
+
+var debug = false;
+var authenticated = false;
+
+// Parse arguments
+for(i=0;i<argc;i++)
+	if(argv[i].toLowerCase()=="-d")
+		debug = true;
+
+// Write a string to the client socket
+function write(str)
+{
+	if(debug && 0)
+		log(format("rsp: %s",str));
+	client.socket.send(str);
+}
+
+function writeln(str)
+{
+	write(str + "\r\n");
+}
+
+var username='';
+var msgbase=null;
+
+writeln(format("200 %s News (Synchronet NNTP Service v%s)",system.name,VERSION));
+
+while(client.socket.is_connected) {
+
+	// Get Request
+	cmdline = client.socket.recvline(512 /*maxlen*/, 30 /*timeout*/);
+
+	if(cmdline==null) {
+		log("!TIMEOUT waiting for request");
+		exit();
+	}
+
+	if(cmdline=="") 	/* ignore blank commands */
+		continue;
+
+	log(format("cmd: %s",cmdline));
+
+	cmd=cmdline.split(' ');
+
+	switch(cmd[0].toUpperCase()) {
+		case "AUTHINFO":
+			switch(cmd[1].toUpperCase()) {
+				case "USER":
+					username='';
+					for(i=2;cmd[i]!=undefined;i++) {
+						if(i>2)
+							username+=' ';
+						username+=cmd[i];
+					}
+					writeln("381 More authentication required");
+					break;
+				case "PASS":
+					log(format("login(%s,%s)",username,cmd[2]));
+					if(login(username,cmd[2])) {
+						writeln("281 Authentication successful");
+						authenticated=true;
+					} else
+						writeln("502 Authentication failure");
+					break;
+				default:
+					writeln("500 Syntax error or unknown command");
+					break;
+			}
+			continue;
+		case "MODE":
+			writeln("200 Hello, you can post");
+			continue;
+		case "QUIT":
+			writeln("205 closing connection - goodbye!");
+			exit();
+			break;
+	}
+
+	if(!authenticated) {
+		writeln("502 Authentication required");
+		continue;
+	}
+
+	/* These commands require login/authentication */
+	switch(cmd[0].toUpperCase()) {
+		case "LIST":
+			writeln("215 list of newsgroups follows");
+			for(g in msg_area.grp_list) 
+				for(s in msg_area.grp_list[g].sub_list) {
+					msgbase=new MsgBase(msg_area.grp_list[g].sub_list[s].code);
+					writeln(format("%s %u %u %s"
+						,msg_area.grp_list[g].sub_list[s].newsgroup
+						,msgbase.total_msgs
+						,1
+						,"y"
+						));
+					msgbase.close();
+				}
+			writeln(".");	// end of list
+			break;
+		case "GROUP":
+			found=false;
+			for(g in msg_area.grp_list) 
+				for(s in msg_area.grp_list[g].sub_list) 
+					if(msg_area.grp_list[g].sub_list[s].newsgroup.toLowerCase()==cmd[1].toLowerCase()) {
+						found=true;
+						msgbase=new MsgBase(msg_area.grp_list[g].sub_list[s].code);
+						selected=msg_area.grp_list[g].sub_list[s].newsgroup;
+					}
+			if(found)
+				writeln(format("211 %u %u %u %s group selected"
+					,msgbase.total_msgs	// articles in group
+					,1	// first
+					,msgbase.total_msgs	// last
+					,selected
+					));
+			else
+				writeln("411 no such news group");
+			break;
+		case "XHDR":
+			if(msgbase==null) {
+				writeln("412 no news group selected");
+				break;
+			}
+			writeln("221 Header follows");
+			var first, last;
+			if(cmd[2].indexOf('-')>=0)	{ /* range */
+				range=cmd[2].split('-');
+				first=Number(range[0]);
+				last=Number(range[1]);
+			} else
+				first=last=Number(cmd[2]);
+			for(i=first;i<=last;i++) {
+				hdr=msgbase.get_msg_header(true,i);
+				if(hdr==null)
+					continue;
+				var field="";
+				switch(cmd[1].toLowerCase()) {	/* header */
+					case "subject":
+						field=hdr.subject;
+						break;
+					case "from":
+						field=hdr.from;
+						break;
+					case "reply-to":
+						field=hdr.reply_to;
+						break;
+					case "date":
+						field=system.timestr(hdr.when_written_time);
+						break;
+					case "message-id":
+						field=hdr.number;
+						break;
+					case "references":
+						field=hdr.thread_orig;
+						break;
+					case "lines":
+						field=Math.round(hdr.data_length/79);
+						break;
+				}
+
+				writeln(format("%u %s",i,field.toString()));
+			}
+			writeln(".");	// end of list
+			break;
+		case "ARTICLE":
+			if(cmd[1].indexOf('<')>=0)	{ /* message-id */
+				hdr=msgbase.get_msg_header(false,Number(cmd[1].slice(1,-1)));
+				body=msgbase.get_msg_body(false,Number(cmd[1].slice(1,-1))
+					,true /* remove ctrl-a codes */);
+			} else {						/* offset */
+				hdr=msgbase.get_msg_header(true,Number(cmd[1]));
+				body=msgbase.get_msg_body(true,Number(cmd[1])
+					,true /* remove ctrl-a codes */);
+			}
+			
+			writeln(format("220 <%u> article retrieved - head and body follow",hdr.number));
+
+			writeln("From: " + hdr.from);
+			writeln("Subject: " + hdr.subject);
+			writeln("Message-ID: " + hdr.number);
+			writeln("Date: " + system.timestr(hdr.when_written_time));
+			writeln("References: " + hdr.thread_orig);
+			writeln("");
+			write(body);
+			writeln(".");
+			break;
+			
+		default:
+			writeln("500 Syntax error or unknown command");
+			break;
+	}
+}
+
+/* End of nntpservice.js */
-- 
GitLab