# HG changeset patch # User Ivo Smits # Date 1302560981 -7200 # Node ID 40e545510a57e891249d318feab2964d9de1728c # Parent 61fac319ca3e127912512c9ea9861ee29b44e4d5 Added support for POSTing to the server, added readme and todo, added support for upstream synchronization using POST diff -r 61fac319ca3e -r 40e545510a57 config.php.example --- a/config.php.example Mon Apr 11 23:17:27 2011 +0200 +++ b/config.php.example Tue Apr 12 00:29:41 2011 +0200 @@ -1,2 +1,5 @@ evalAllAssoc('SELECT * FROM `peergroups` WHERE `peer` = ?', $peer['id']) as $peergroup) { $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `id` = ?', $peergroup['group']); nntp_writeline($socket, 'GROUP '.$group['name']); @@ -65,6 +69,46 @@ $db->update('UPDATE `peergroups` SET `low` = ?, `high` = ? WHERE `peer` = ? AND `group` = ?', array($low, $high, $peergroup['peer'], $peergroup['group'])); } } + while ($peer['post']) { + if ($peer['lastposted'] === NULL) { + $articles = $db->evalAllAssoc('SELECT * FROM `messages` LIMIT 10'); + } else { + $articles = $db->evalAllAssoc('SELECT * FROM `messages` WHERE `id` > ? LIMIT 10', $peer['lastposted']); + } + if (!count($articles)) break; + foreach ($articles as $article) { + nntp_writeline($socket, 'POST'); + $line = nntp_readline($socket); + $code = strtok($line, " \t"); + if ($code != 340) die("Error code $code from $peer[address]\n"); + foreach (explode("\r\n", $article['header']) as $line) { + $parts = explode(': ', $line, 2); + switch (strtoupper($parts[0])) { + case 'PATH': case 'FROM': case 'NEWSGROUPS': case 'SUBJECT': case 'DATE': case 'ORGANIZATION': + case 'LINES': case 'MESSAGE-ID': case 'MIME-VERSION': case 'CONTENT-TYPE': case 'CONTENT-TRANSFER-ENCODING': + case 'USER-AGENT': case 'REFERENCES': case 'REPLY-TO': case 'SENDER': case 'FOLLOWUP-TO': + case 'EXPIRES': case 'CONTROL': case 'DISTRIBUTION': case 'KEYWORDS': case 'SUMMARY': + case 'IN-REPLY-TO': + break; + case 'NNTP-POSTING-HOST': case 'X-TRACE': case 'XREF': case 'X-COMPLAINTS-TO': + case 'NNTP-POSTING-DATE': + $line = NULL; + break; + default: + print("Sending unknown header $parts[0]\n"); + } + if ($line !== NULL) nntp_writeline($socket, $line); + } + nntp_writeline($socket, ''); + foreach (explode("\r\n", $article['body']) as $line) nntp_writeline($socket, $line); + nntp_writeline($socket, '.'); + $line = nntp_readline($socket); + $code = strtok($line, " \t"); + if ($code != 240) print("Article $article[messageid] was not accepted ($code)\n"); + if ($article['id'] > $peer['lastposted']) $peer['lastposted'] = $article['id']; + } + $db->update('UPDATE `peers` SET `lastposted` = ? WHERE `id` = ?', array($peer['lastposted'], $peer['id'])); + } nntp_writeline($socket, 'QUIT'); fclose($socket); } diff -r 61fac319ca3e -r 40e545510a57 readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readme.txt Tue Apr 12 00:29:41 2011 +0200 @@ -0,0 +1,9 @@ +To use: + Set up some database (MySQL is recommended, but others should work too), with a schema as described in database.mysql + Rename/copy config.php.example to config.php and edit it according to your database settings + Add other news servers to the peers table in the database (address is in the format tcp://hostname:119, post is either 0 or 1 to try to post to this server) + Add newsgroups to the newsgroups table in the database + Add peer-group relations to the peergroups table in the database (peer is the id number from the peers table, group is the id number from the groups table) + Setup (x)inetd (or socat or netcat) to serve the server.php script on TCP port 119 + Run the fetchnews.php script to synchronize with your peers + Install the fetchnews.php script in crontab to automatically synchronize with your peers diff -r 61fac319ca3e -r 40e545510a57 server.php --- a/server.php Mon Apr 11 23:17:27 2011 +0200 +++ b/server.php Tue Apr 12 00:29:41 2011 +0200 @@ -1,6 +1,6 @@ #!/usr/bin/php ok'); } break; + case 'POST': + nntp_writeline(STDOUT, '340 Ok, recommended message-ID <'.md5(time().rand()).'@pNews.Core.UCIS.nl>'); + $lines = nntp_readlines(STDIN); + $header = array(); + $headers = array(); + while (count($lines)) { + $line = array_shift($lines); + if (!strlen($line)) break; + $parts = explode(': ', $line, 2); + $headers[strtoupper($parts[0])] = $parts[1]; + switch (strtoupper($parts[0])) { + case 'PATH': + $line = $parts[0].': pNews.Core.UCIS.nl!'.$parts[1]; + break; + case 'FROM': case 'NEWSGROUPS': case 'SUBJECT': case 'DATE': case 'ORGANIZATION': + case 'LINES': case 'MESSAGE-ID': case 'MIME-VERSION': case 'CONTENT-TYPE': case 'CONTENT-TRANSFER-ENCODING': + case 'USER-AGENT': case 'REFERENCES': case 'REPLY-TO': case 'SENDER': case 'FOLLOWUP-TO': + case 'EXPIRES': case 'CONTROL': case 'DISTRIBUTION': case 'KEYWORDS': case 'SUMMARY': + case 'IN-REPLY-TO': + break; + case 'NNTP-POSTING-HOST': case 'X-TRACE': case 'XREF': case 'X-COMPLAINTS-TO': + case 'NNTP-POSTING-DATE': + $line = NULL; + break; + default: + writelog("Received unknown header $parts[0]"); + } + if ($line !== NULL) $header[] = $line; + } + if (!isset($headers['NEWSGROUPS'])) { + nntp_writeline(STDOUT, '441 Missing required Newsgroups: header'); + break; + } + if (!isset($headers['MESSAGE-ID'])) { + $headers['MESSAGE-ID'] = '<'.md5(time().rand()).'@pNews.Core.UCIS.nl>'; + $header[] = 'Message-ID: '.$headers['MESSAGE-ID']; + } + if (!isset($headers['PATH'])) { + $headers['PATH'] = 'pNews.Core.UCIS.nl'; + $header[] = 'Path: '.$headers['PATH']; + } + $msgid = $headers['MESSAGE-ID']; + if (strlen($msgid) <= 2 || $msgid[0] != '<' || $msgid[strlen($msgid)-1] != '>') { + nntp_writeline(STDOUT, '441 435 Bad Message-ID'); + break; + } + $msgid = substr($msgid, 1, -1); + $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `messageid` = ?', $msgid); + if ($article !== FALSE) { + nntp_writeline(STDOUT, '441 435 Duplicate'); + return NULL; + } + $id = $db->insert('INSERT INTO `messages` (`messageid`, `header`, `body`) VALUES (?, ?, ?)', array($msgid, implode("\r\n", $header), implode("\r\n", $lines))); + foreach (explode(',', $headers['NEWSGROUPS']) as $groupname) { + $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); + if ($group === FALSE) continue; + $db->insert('INSERT INTO `groupmessages` (`group`, `message`) VALUES (?, ?)', array($group['id'], $id)); + } + nntp_writeline(STDOUT, '240 Article received <'.$msgid.'>'); + break; case 'QUIT': nntp_writeline(STDOUT, '205 .'); return; diff -r 61fac319ca3e -r 40e545510a57 todo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/todo.txt Tue Apr 12 00:29:41 2011 +0200 @@ -0,0 +1,4 @@ +- Make sure that group article numbers are never reused, not even if the last one is deleted (groupmessages table) +- Support IHAVE command to speed up synchronization +- Check Message-Id header in articles received from peers +- Handle received cross-posted messages (according to Newsgroups header)