Mercurial > hg > pnewss
view server.php @ 7:01dc7eeaf5df
Added some more checks to article data, added some commands, added 'dot stuffing' for block transfers
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Tue, 12 Apr 2011 14:10:41 +0200 |
parents | 5d62af5270dd |
children | 005339a1b2ce |
line wrap: on
line source
#!/usr/bin/php <?php chdir(__DIR__); require_once './common.php'; $logfile = fopen('./server.log', 'w'); $currentgroup = NULL; $currentarticle = NULL; function exception_handler($exception) { nntp_writeline(STDOUT, ''); nntp_writeline(STDOUT, '590 Exception: '.$exception->getMessage()); die(); } function error_handler($errno, $errstr, $errfile, $errline) { nntp_writeline(STDOUT, ''); nntp_writeline(STDOUT, '590 Error in file '.$errfile.' line '.$errline.' error '.$errno.' '.$errstr); die(); } set_exception_handler('exception_handler'); set_error_handler("error_handler"); nntp_writeline(STDOUT, '200 pNewss ready'); while (TRUE) { $line = nntp_readline(STDIN); if ($line === FALSE || $line === NULL) break; $cmd = strtoupper(strtok($line, " \t")); switch ($cmd) { case 'CAPABILITIES': nntp_writeline(STDOUT, '101 Capability list:'); nntp_writeline_data(STDOUT, 'VERSION 2'); nntp_writeline_data(STDOUT, 'IMPLEMENTATION pNewss [http://wiki.ucis.nl/pNewss]'); nntp_writeline_data(STDOUT, 'POST'); nntp_writeline_data(STDOUT, 'READER'); nntp_writeline_data(STDOUT, 'IHAVE'); nntp_writeline_data(STDOUT, 'LIST ACTIVE'); nntp_writeline(STDOUT, '.'); //HDR, LIST, OVER, STARTTLS, STREAMING, break; case 'DATE': nntp_writeline(STDOUT, '111 '.gmdate('YmdHis')); break; case 'HELP': nntp_writeline(STDOUT, '100 Help text follows:'); nntp_writeline_data(STDOUT, 'Supported commands: CAPABILITIES,DATE,HELP,LIST,GROUP,LISTGROUP,STAT,HEAD,BODY,ARTICLE,LAST,NEXT,POST,IHAVE,QUIT'); nntp_writeline(STDOUT, '.'); break; case 'LIST': nntp_writeline(STDOUT, '215 list of groups follows'); foreach ($db->evalAllAssoc('SELECT * FROM `groups`') as $group) { $groupmessages = $db->evalRow('SELECT MIN(`number`), MAX(`number`) FROM `groupmessages` WHERE `group` = ?', $group['id']); nntp_writeline_data(STDOUT, $group['name'].' '.intval($groupmessages[1]).' '.intval($groupmessages[0]).' n'); } nntp_writeline(STDOUT, '.'); break; case 'GROUP': case 'LISTGROUP': $groupname = strtok(" \t"); if ($groupname === FALSE) { $group = $currentgroup; } else { $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); } if ($group === FALSE) { nntp_writeline(STDOUT, '411 No such group '.$groupname); } else { $currentgroup = $group; $groupmessages = $db->evalRow('SELECT MIN(`number`), MAX(`number`), COUNT(`number`) FROM `groupmessages` WHERE `group` = ?', $group['id']); nntp_writeline(STDOUT, '211 '.intval($groupmessages[2]).' '.intval($groupmessages[0]).' '.intval($groupmessages[1]).' '.$group['name']); if ($groupmessages[0] === NULL) { $currentarticle = NULL; } else { $currentarticle = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` = ?', array($group['id'], $groupmessages[0])); if ($currentarticle === FALSE) $currentarticle = NULL; } if ($cmd == 'LISTGROUP') { $range = strtok(" \t"); if ($range !== FALSE) { $parts = explode('-', $range); if (count($parts) == 1 || !strlen($parts[1])) { $query = 'SELECT `number` FROM `groupmessages` WHERE `group` = ? AND `number` >= ?'; $queryargs = array($group['id'], $parts[0]); } else { $query = 'SELECT `number` FROM `groupmessages` WHERE `group` = ? AND `number` BETWEEN ? AND ?'; $queryargs = array($group['id'], $parts[0], $parts[1]); } } else { $query = 'SELECT `number` FROM `groupmessages` WHERE `group` = ?'; $queryargs = array($group['id']); } foreach ($db->evalColumn($query, $queryargs) as $number) nntp_writeline_data(STDOUT, $number); nntp_writeline(STDOUT, '.'); } } break; case 'STAT': case 'HEAD': case 'BODY': case 'ARTICLE': $article = nntp_get_article(strtok(" \t")); if ($article === NULL) break; switch ($cmd) { case 'ARTICLE': nntp_writeline(STDOUT, '220 '.$article['messagenumber'].' <'.$article['messageid'].'> article'); break; case 'HEAD': nntp_writeline(STDOUT, '221 '.$article['messagenumber'].' <'.$article['messageid'].'> head'); break; case 'BODY': nntp_writeline(STDOUT, '222 '.$article['messagenumber'].' <'.$article['messageid'].'> body'); break; case 'STAT': nntp_writeline(STDOUT, '223 '.$article['messagenumber'].' <'.$article['messageid'].'> stat'); break; default: throw new Exception('Internal error'); } if ($cmd == 'HEAD' || $cmd == 'ARTICLE') foreach (explode("\r\n", $article['header']) as $line) nntp_writeline_data(STDOUT, $line); if ($cmd == 'ARTICLE') nntp_writeline(STDOUT, ''); if ($cmd == 'BODY' || $cmd == 'ARTICLE') foreach (explode("\r\n", $article['body']) as $line) nntp_writeline_data(STDOUT, $line); if ($cmd != 'STAT') nntp_writeline(STDOUT, '.'); break; case 'LAST': case 'NEXT': if ($currentarticle === NULL) { nntp_writeline(STDOUT, '420 no current article has been selected'); break; } switch ($cmd) { case 'LAST': $query = 'SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` < ? ORDER BY `number` DESC LIMIT 1'; break; case 'NEXT': $query = 'SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` > ? ORDER BY `number` ASC LIMIT 1'; break; default: throw new Exception('Internal error'); } $article = $db->evalRowAssoc($query, array($currentarticle['group'], $currentarticle['number'])); if ($article === FALSE) { nntp_writeline(STDOUT, '422 no previous article in this group'); } else { $articlea = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); if ($articlea === FALSE) { nntp_writeline(STDOUT, '430 no such article found'); return NULL; } $currentarticle = $article; 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); try { $messageid = nntp_article_store($lines); nntp_writeline(STDOUT, '240 Article received <'.$messageid.'>'); } catch (Exception $ex) { nntp_writeline(STDOUT, '441 '.$ex->getMessage()); } break; case 'IHAVE': $messageid = strtok(" \t"); if ($messageid === FALSE || strlen($messageid) <= 2 || $messageid[0] != '<' || $messageid[strlen($messageid)-1] == '>') { nntp_writeline(STDOUT, '435 Argument error'); break; } $messageid = substr($messageid, 1, -1); if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) { nntp_writeline(STDOUT, '435 Duplicate'); break; } nntp_writeline(STDOUT, '335 Send article to be transferred'); $lines = nntp_readlines(STDIN); try { $messageid = nntp_article_store($lines); nntp_writeline(STDOUT, '235 Article received <'.$messageid.'>'); } catch (Exception $ex) { nntp_writeline(STDOUT, '437 '.$ex->getMessage()); } break; case 'QUIT': nntp_writeline(STDOUT, '205 Bye.'); return; default: nntp_writeline(STDOUT, '500 Command not understood'); break; } } function nntp_get_article($article) { global $currentgroup, $currentarticle, $db; if ($article === FALSE) { if ($currentarticle === NULL) { nntp_writeline(STDOUT, '420 no current article has been selected'); return NULL; } $messagenumber = $currentarticle['number']; $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $currentarticle['message']); if ($article === FALSE) { nntp_writeline(STDOUT, '430 no such article found'); return NULL; } } elseif (strlen($article) > 2 && $article[0] == '<' && $article[strlen($article)-1] == '>') { $messagenumber = 0; $article = substr($article, 1, -1); $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `messageid` = ?', $article); if ($article === FALSE) { nntp_writeline(STDOUT, '430 no such article found'); return NULL; } } elseif (is_numeric($article)) { if ($currentgroup === NULL) { nntp_writeline(STDOUT, '412 no newsgroup has been selected'); return NULL; } $article = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` = ?', array($currentgroup['id'], $article)); if ($article === FALSE) { nntp_writeline(STDOUT, '423 no such article number in this group'); return NULL; } $currentarticle = $article; $messagenumber = $article['number']; $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); if ($article === FALSE) { nntp_writeline(STDOUT, '430 no such article found'); return NULL; } } else { nntp_writeline(STDOUT, '500 Error in arguments'); } $article['messagenumber'] = $messagenumber; return $article; } function writelog($line) { global $logfile; fwrite($logfile, $line."\n"); }