Mercurial > hg > pnewss
changeset 2:40e545510a57
Added support for POSTing to the server, added readme and todo, added support for upstream synchronization using POST
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Tue, 12 Apr 2011 00:29:41 +0200 |
parents | 61fac319ca3e |
children | 0dcdb73cbcbf |
files | config.php.example database.mysql fetchnews.php readme.txt server.php todo.txt |
diffstat | 6 files changed, 126 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- 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 @@ <?php $db = PDOWrapper::connectMysql('localhost', 'dbname', 'username', 'password'); +//For other databases (see also http://nl2.php.net/manual/en/pdo.construct.php): +//$db = new PDOWrapper($dsn, $user = NULL, $pass = NULL, $options = NULL); +
--- a/database.mysql Mon Apr 11 23:17:27 2011 +0200 +++ b/database.mysql Tue Apr 12 00:29:41 2011 +0200 @@ -3,7 +3,7 @@ -- http://www.phpmyadmin.net -- -- Machine: localhost --- Genereertijd: 11 Apr 2011 om 23:15 +-- Genereertijd: 12 Apr 2011 om 00:18 -- Serverversie: 5.0.51 -- PHP-Versie: 5.3.3-7 @@ -78,6 +78,8 @@ CREATE TABLE IF NOT EXISTS `peers` ( `id` int(10) unsigned NOT NULL auto_increment, `address` varchar(255) collate utf8_unicode_ci NOT NULL, + `post` tinyint(1) unsigned NOT NULL, + `lastposted` int(10) unsigned default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--- a/fetchnews.php Mon Apr 11 23:17:27 2011 +0200 +++ b/fetchnews.php Tue Apr 12 00:29:41 2011 +0200 @@ -1,4 +1,5 @@ <?php +chdir(__DIR__); require_once './pdo.php'; require_once './config.php'; @@ -7,7 +8,10 @@ if ($socket === FALSE) die("Could not connect to peer $peer[address]\n"); $line = nntp_readline($socket); $code = strtok($line, " \t"); - if ($code != 200) die("Error code $code from $peer[address]\n"); + if ($code == 200) { + } else if ($code == 201) { + $peer['post'] = 0; + } else die("Error code $code from $peer[address]\n"); foreach ($db->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); }
--- /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
--- 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 <?php -chdir('/home/ivo/projects/pnewss'); +chdir(__DIR__); require_once './pdo.php'; require_once './config.php'; @@ -24,7 +24,7 @@ nntp_writeline(STDOUT, '200 pNewss ready'); while (TRUE) { $line = nntp_readline(STDIN); - if ($line === FALSE || $line === NULL) break; + if ($line === FALSE || $line === NULL) break; $cmd = strtok($line, " \t"); switch (strtoupper($cmd)) { case 'LIST': @@ -116,6 +116,66 @@ nntp_writeline(STDOUT, '223 '.$article['number'].' <'.$articlea['messageid'].'> 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;
--- /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)