comparison common.php @ 13:cccd73f72bf6 draft

Added filtering support and several bugfixes
author Ivo Smits <Ivo@UCIS.nl>
date Thu, 10 Jul 2014 22:26:45 +0200
parents 7917bd536187
children 372f4e195986
comparison
equal deleted inserted replaced
12:7917bd536187 13:cccd73f72bf6
22 22
23 The views and conclusions contained in the software and documentation are those of the 23 The views and conclusions contained in the software and documentation are those of the
24 authors and should not be interpreted as representing official policies, either expressed 24 authors and should not be interpreted as representing official policies, either expressed
25 or implied, of Ivo Smits.*/ 25 or implied, of Ivo Smits.*/
26 26
27 $pnewss_hooks = array('article_stored' => array()); 27 $pnewss_hooks = array('article_stored' => array(), 'article_filter' => array());
28 28
29 require_once './pdo.php'; 29 require_once './pdo.php';
30 require_once './config.php'; 30 require_once './config.php';
31 31
32 function nntp_readline($socket) { 32 function nntp_readline($socket) {
33 $line = fgets($socket, 512); 33 $line = fgets($socket);
34 if ($line === FALSE || $line === NULL) return $line; 34 if ($line === FALSE || $line === NULL) return $line;
35 $line = rtrim($line, "\r\n"); 35 $line = rtrim($line, "\r\n");
36 writelog('R: '.$line); 36 writelog('R: '.$line);
37 return $line; 37 return $line;
38 } 38 }
62 } 62 }
63 63
64 function pnewss_call_hooks($hooks, $args) { 64 function pnewss_call_hooks($hooks, $args) {
65 foreach ($hooks as $hook) call_user_func_array($hook, $args); 65 foreach ($hooks as $hook) call_user_func_array($hook, $args);
66 } 66 }
67 function pnewss_call_filter_hooks($hooks, $args) {
68 foreach ($hooks as $hook) if (!call_user_func_array($hook, $args)) return FALSE;
69 return TRUE;
70 }
71
72 function nntp_article_wanted($messageid) {
73 global $db, $pnewss_hooks;
74 if ($db->evalRow('SELECT `id` FROM `messages` WHERE `messageid` = ?', $messageid) !== FALSE) return FALSE;
75 if (!pnewss_call_filter_hooks($pnewss_hooks['article_filter'], array(array('messageid' => $messageid)))) return FALSE;
76 return TRUE;
77 }
67 78
68 function nntp_article_store($lines, $header = array()) { 79 function nntp_article_store($lines, $header = array()) {
69 global $db, $pnewss_hooks; 80 global $db, $pnewss_hooks;
70 $headers = array(); 81 $headers = array();
71 if (!count($header)) { 82 if (!count($header)) {
75 $header[] = $line; 86 $header[] = $line;
76 } 87 }
77 } 88 }
78 $headername = NULL; 89 $headername = NULL;
79 foreach ($header as $headerid => $line) { 90 foreach ($header as $headerid => $line) {
80 if (!strlen($line) || $line == '.') throw new Exception('Empty or terminating header line'); 91 if (!strlen($line)) throw new Exception('Empty header line');
81 if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in header line'); 92 if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in header line');
82 if (strlen($line) && strlen($headername) && ($line[0] == ' ' || $line[0] == "\t") && isset($headers[$headername])) { 93 if (strlen($line) && strlen($headername) && ($line[0] == ' ' || $line[0] == "\t") && isset($headers[$headername])) {
83 $headers[$headername] .= ' '.trim($line, " \t"); 94 $headers[$headername] .= ' '.trim($line, " \t");
84 unset($header[$headerid]); 95 unset($header[$headerid]);
85 continue; 96 continue;
87 $parts = explode(': ', $line, 2); 98 $parts = explode(': ', $line, 2);
88 $headername = strtoupper($parts[0]); 99 $headername = strtoupper($parts[0]);
89 switch ($headername) { 100 switch ($headername) {
90 case 'PATH': case 'FROM': case 'NEWSGROUPS': case 'SUBJECT': case 'DATE': case 'MESSAGE-ID': case 'SENDER': 101 case 'PATH': case 'FROM': case 'NEWSGROUPS': case 'SUBJECT': case 'DATE': case 'MESSAGE-ID': case 'SENDER':
91 if (isset($headers[$headername])) throw new Exception('Duplicate header: '.$headername); 102 if (isset($headers[$headername])) throw new Exception('Duplicate header: '.$headername);
92 $headers[strtoupper($parts[0])] = $parts[1]; 103 $headers[$headername] = $parts[1];
93 unset($header[$headerid]); 104 unset($header[$headerid]);
94 break; 105 break;
95 case 'ORGANIZATION': case 'LINES': 106 case 'ORGANIZATION': case 'LINES':
96 case 'MIME-VERSION': case 'CONTENT-TYPE': case 'CONTENT-TRANSFER-ENCODING': case 'USER-AGENT': 107 case 'MIME-VERSION': case 'CONTENT-TYPE': case 'CONTENT-TRANSFER-ENCODING': case 'USER-AGENT':
97 case 'REFERENCES': case 'REPLY-TO': case 'SENDER': case 'FOLLOWUP-TO': case 'IN-REPLY-TO': 108 case 'REFERENCES': case 'REPLY-TO': case 'FOLLOWUP-TO': case 'IN-REPLY-TO':
98 case 'EXPIRES': case 'CONTROL': case 'DISTRIBUTION': case 'KEYWORDS': case 'SUMMARY': 109 case 'EXPIRES': case 'CONTROL': case 'DISTRIBUTION': case 'KEYWORDS': case 'SUMMARY':
99 break; 110 break;
100 case 'NNTP-POSTING-HOST': case 'X-TRACE': case 'XREF': case 'X-COMPLAINTS-TO': 111 case 'NNTP-POSTING-HOST': case 'X-TRACE': case 'XREF': case 'X-COMPLAINTS-TO':
101 case 'NNTP-POSTING-DATE': 112 case 'NNTP-POSTING-DATE':
102 unset($header[$headerid]); 113 unset($header[$headerid]);
106 if ($headername[0] == 'X' && $headername[1] == '-') break; 117 if ($headername[0] == 'X' && $headername[1] == '-') break;
107 writelog("Received unknown header $headername"); 118 writelog("Received unknown header $headername");
108 } 119 }
109 } 120 }
110 foreach ($lines as $line) { 121 foreach ($lines as $line) {
111 if ($line == '.') throw new Exception('Terminating body line'); 122 if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in body line');
112 if (strpos($line, "\r") !== FALSE || strpos($line, "\n") !== FALSE || strpos($line, "\0")) throw new Exception('Invalid newline or NUL character in header line');
113 } 123 }
114 if (!isset($headers['NEWSGROUPS'])) throw new Exception('Missing required Newsgroups: header'); 124 if (!isset($headers['NEWSGROUPS'])) throw new Exception('Missing required Newsgroups header');
115 $newsgroups = array(); 125 $newsgroups = array();
116 foreach (explode(',', $headers['NEWSGROUPS']) as $groupname) { 126 foreach (explode(',', $headers['NEWSGROUPS']) as $groupname) {
117 $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); 127 $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname);
118 if ($group === FALSE) continue; 128 if ($group === FALSE) continue;
119 $newsgroups[] = $group['id']; 129 $newsgroups[] = $group['id'];
128 if ($article !== FALSE) throw new Exception('Duplicate'); 138 if ($article !== FALSE) throw new Exception('Duplicate');
129 $headers['PATH'] = 'pNewss.Core.UCIS.nl'.(isset($headers['PATH'])?'!'.$headers['PATH']:''); 139 $headers['PATH'] = 'pNewss.Core.UCIS.nl'.(isset($headers['PATH'])?'!'.$headers['PATH']:'');
130 foreach (array('Path', 'From', 'Newsgroups', 'Subject', 'Date', 'Message-ID', 'Sender') as $headername) { 140 foreach (array('Path', 'From', 'Newsgroups', 'Subject', 'Date', 'Message-ID', 'Sender') as $headername) {
131 if (isset($headers[strtoupper($headername)])) $header[] = $headername.': '.$headers[strtoupper($headername)]; 141 if (isset($headers[strtoupper($headername)])) $header[] = $headername.': '.$headers[strtoupper($headername)];
132 } 142 }
133 $id = $db->insert('INSERT INTO `messages` (`messageid`, `header`, `body`) VALUES (?, ?, ?)', array($messageid, implode("\r\n", $header), implode("\r\n", $lines))); 143 if (!pnewss_call_filter_hooks($pnewss_hooks['article_filter'], array(array('messageid' => $messageid, 'headers' => $headers, 'body' => $lines)))) throw new Exception('Filtered');
144 $headertext = implode("\r\n", $header);
145 $bodytext = implode("\r\n", $lines);
146 if (strlen($headertext) > 65535 || strlen($bodytext) > 16777215) throw new Exception('Message too big');
147 $id = $db->insert('INSERT INTO `messages` (`messageid`, `header`, `body`) VALUES (?, ?, ?)', array($messageid, $headertext, $bodytext));
134 foreach ($newsgroups as $groupid) $db->insert('INSERT INTO `groupmessages` (`group`, `message`) VALUES (?, ?)', array($groupid, $id)); 148 foreach ($newsgroups as $groupid) $db->insert('INSERT INTO `groupmessages` (`group`, `message`) VALUES (?, ?)', array($groupid, $id));
135 pnewss_call_hooks($pnewss_hooks['article_stored'], array(array('messageid' => $messageid, 'headers' => $headers, 'body' => $lines, 'dbid' => $id))); 149 pnewss_call_hooks($pnewss_hooks['article_stored'], array(array('messageid' => $messageid, 'headers' => $headers, 'body' => $lines, 'dbid' => $id)));
136 return $messageid; 150 return $messageid;
137 } 151 }