# HG changeset patch # User Ivo Smits # Date 1405024005 -7200 # Node ID cccd73f72bf66d585571ab1a10236461e3a025cb # Parent 7917bd536187e9c315ccae13ec7f08893b42a989 Added filtering support and several bugfixes diff -r 7917bd536187 -r cccd73f72bf6 common.php --- a/common.php Wed Jun 12 22:22:07 2013 +0200 +++ b/common.php Thu Jul 10 22:26:45 2014 +0200 @@ -24,13 +24,13 @@ authors and should not be interpreted as representing official policies, either expressed or implied, of Ivo Smits.*/ -$pnewss_hooks = array('article_stored' => array()); +$pnewss_hooks = array('article_stored' => array(), 'article_filter' => array()); require_once './pdo.php'; require_once './config.php'; function nntp_readline($socket) { - $line = fgets($socket, 512); + $line = fgets($socket); if ($line === FALSE || $line === NULL) return $line; $line = rtrim($line, "\r\n"); writelog('R: '.$line); @@ -64,6 +64,17 @@ function pnewss_call_hooks($hooks, $args) { foreach ($hooks as $hook) call_user_func_array($hook, $args); } +function pnewss_call_filter_hooks($hooks, $args) { + foreach ($hooks as $hook) if (!call_user_func_array($hook, $args)) return FALSE; + return TRUE; +} + +function nntp_article_wanted($messageid) { + global $db, $pnewss_hooks; + if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) return FALSE; + if (!pnewss_call_filter_hooks($pnewss_hooks['article_filter'], array(array('messageid' => $messageid)))) return FALSE; + return TRUE; +} function nntp_article_store($lines, $header = array()) { global $db, $pnewss_hooks; @@ -77,7 +88,7 @@ } $headername = NULL; foreach ($header as $headerid => $line) { - if (!strlen($line) || $line == '.') throw new Exception('Empty or terminating header line'); + if (!strlen($line)) throw new Exception('Empty header line'); if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in header line'); if (strlen($line) && strlen($headername) && ($line[0] == ' ' || $line[0] == "\t") && isset($headers[$headername])) { $headers[$headername] .= ' '.trim($line, " \t"); @@ -89,12 +100,12 @@ switch ($headername) { case 'PATH': case 'FROM': case 'NEWSGROUPS': case 'SUBJECT': case 'DATE': case 'MESSAGE-ID': case 'SENDER': if (isset($headers[$headername])) throw new Exception('Duplicate header: '.$headername); - $headers[strtoupper($parts[0])] = $parts[1]; + $headers[$headername] = $parts[1]; unset($header[$headerid]); break; case 'ORGANIZATION': case 'LINES': case 'MIME-VERSION': case 'CONTENT-TYPE': case 'CONTENT-TRANSFER-ENCODING': case 'USER-AGENT': - case 'REFERENCES': case 'REPLY-TO': case 'SENDER': case 'FOLLOWUP-TO': case 'IN-REPLY-TO': + case 'REFERENCES': case 'REPLY-TO': case 'FOLLOWUP-TO': case 'IN-REPLY-TO': case 'EXPIRES': case 'CONTROL': case 'DISTRIBUTION': case 'KEYWORDS': case 'SUMMARY': break; case 'NNTP-POSTING-HOST': case 'X-TRACE': case 'XREF': case 'X-COMPLAINTS-TO': @@ -108,10 +119,9 @@ } } foreach ($lines as $line) { - if ($line == '.') throw new Exception('Terminating body line'); - if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in header line'); + if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in body line'); } - if (!isset($headers['NEWSGROUPS'])) throw new Exception('Missing required Newsgroups: header'); + if (!isset($headers['NEWSGROUPS'])) throw new Exception('Missing required Newsgroups header'); $newsgroups = array(); foreach (explode(',', $headers['NEWSGROUPS']) as $groupname) { $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); @@ -130,7 +140,11 @@ foreach (array('Path', 'From', 'Newsgroups', 'Subject', 'Date', 'Message-ID', 'Sender') as $headername) { if (isset($headers[strtoupper($headername)])) $header[] = $headername.': '.$headers[strtoupper($headername)]; } - $id = $db->insert('INSERT INTO `messages` (`messageid`, `header`, `body`) VALUES (?, ?, ?)', array($messageid, implode("\r\n", $header), implode("\r\n", $lines))); + if (!pnewss_call_filter_hooks($pnewss_hooks['article_filter'], array(array('messageid' => $messageid, 'headers' => $headers, 'body' => $lines)))) throw new Exception('Filtered'); + $headertext = implode("\r\n", $header); + $bodytext = implode("\r\n", $lines); + if (strlen($headertext) > 65535 || strlen($bodytext) > 16777215) throw new Exception('Message too big'); + $id = $db->insert('INSERT INTO `messages` (`messageid`, `header`, `body`) VALUES (?, ?, ?)', array($messageid, $headertext, $bodytext)); foreach ($newsgroups as $groupid) $db->insert('INSERT INTO `groupmessages` (`group`, `message`) VALUES (?, ?)', array($groupid, $id)); pnewss_call_hooks($pnewss_hooks['article_stored'], array(array('messageid' => $messageid, 'headers' => $headers, 'body' => $lines, 'dbid' => $id))); return $messageid; diff -r 7917bd536187 -r cccd73f72bf6 fetchnews.php --- a/fetchnews.php Wed Jun 12 22:22:07 2013 +0200 +++ b/fetchnews.php Thu Jul 10 22:26:45 2014 +0200 @@ -61,7 +61,6 @@ $line = nntp_readline($socket); $code = strtok($line, " \t"); if ($code != 240 && $code != 235) print("Article $article[messageid] was not accepted ($code)\n"); - if ($article['id'] > $peer['lastposted']) $peer['lastposted'] = $article['id']; } else { print("IHAVE rejected by remote server, falling back to POST\n"); $peer['post'] = 1; @@ -104,6 +103,8 @@ if (!$groupmessage) { $db->insert('INSERT INTO `groupmessages` (`group`, `message`) VALUES (?, ?)', array($group['id'], $message['id'])); } + } else if (!nntp_article_wanted($messageid)) { + print("Ignoring filtered article $messageid\n"); } else { nntp_writeline($socket, 'ARTICLE '.$i); $line = nntp_readline($socket); diff -r 7917bd536187 -r cccd73f72bf6 reloadarticle.php --- a/reloadarticle.php Wed Jun 12 22:22:07 2013 +0200 +++ b/reloadarticle.php Thu Jul 10 22:26:45 2014 +0200 @@ -45,6 +45,9 @@ strtok(" \t"); //article number $lines = nntp_readlines($socket); nntp_article_store($lines); +nntp_writeline($socket, 'QUIT'); +nntp_readline($socket); +fclose($socket); function writelog($line) { print($line."\n"); diff -r 7917bd536187 -r cccd73f72bf6 server.php --- a/server.php Wed Jun 12 22:22:07 2013 +0200 +++ b/server.php Thu Jul 10 22:26:45 2014 +0200 @@ -95,9 +95,9 @@ if ($groupname === FALSE) { $group = $currentgroup; } else { - $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); + $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', array($groupname)); } - if ($group === FALSE) { + if (!$group) { nntp_writeline(STDOUT, '411 No such group '.$groupname); } else { $currentgroup = $group; @@ -173,10 +173,10 @@ $articlea = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); if ($articlea === FALSE) { nntp_writeline(STDOUT, '430 no such article found'); - return NULL; + } else { + $currentarticle = $article; + nntp_writeline(STDOUT, '223 '.$article['number'].' <'.$articlea['messageid'].'> ok'); } - $currentarticle = $article; - nntp_writeline(STDOUT, '223 '.$article['number'].' <'.$articlea['messageid'].'> ok'); } break; case 'POST': @@ -196,8 +196,8 @@ break; } $messageid = substr($messageid, 1, -1); - if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) { - nntp_writeline(STDOUT, '435 Duplicate'); + if (!nntp_article_wanted($messageid)) { + nntp_writeline(STDOUT, '435 Duplicate or filtered'); break; } nntp_writeline(STDOUT, '335 Send article to be transferred'); @@ -216,8 +216,8 @@ break; } $messageid = substr($messageid, 1, -1); - if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) { - nntp_writeline(STDOUT, '438 <'.$messageid.'> Duplicate'); + if (!nntp_article_wanted($messageid)) { + nntp_writeline(STDOUT, '438 <'.$messageid.'> Duplicate or filtered'); break; } nntp_writeline(STDOUT, '238 <'.$messageid.'> Send article to be transferred'); @@ -230,8 +230,8 @@ break; } $messageid = substr($messageid, 1, -1); - if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) { - nntp_writeline(STDOUT, '439 <'.$messageid.'> Duplicate'); + if (!nntp_article_wanted($messageid)) { + nntp_writeline(STDOUT, '439 <'.$messageid.'> Duplicate or filtered'); break; } try { @@ -290,6 +290,7 @@ } } else { nntp_writeline(STDOUT, '500 Error in arguments'); + return NULL; } $article['messagenumber'] = $messagenumber; return $article;