0
|
1 #!/usr/bin/php |
|
2 <?php |
|
3 chdir('/home/ivo/projects/pnewss'); |
|
4 require_once './pdo.php'; |
|
5 require_once './config.php'; |
|
6 |
|
7 $logfile = fopen('./server.log', 'w'); |
|
8 $currentgroup = NULL; |
|
9 $currentarticle = NULL; |
|
10 |
|
11 function exception_handler($exception) { |
|
12 nntp_writeline(STDOUT, ''); |
|
13 nntp_writeline(STDOUT, '590 Exception: '.$exception->getMessage()); |
|
14 die(); |
|
15 } |
|
16 function error_handler($errno, $errstr, $errfile, $errline) { |
|
17 nntp_writeline(STDOUT, ''); |
|
18 nntp_writeline(STDOUT, '590 Error in file '.$errfile.' line '.$errline.' error '.$errno.' '.$errstr); |
|
19 die(); |
|
20 } |
|
21 set_exception_handler('exception_handler'); |
|
22 set_error_handler("error_handler"); |
|
23 |
|
24 nntp_writeline(STDOUT, '200 pNewss ready'); |
|
25 while (TRUE) { |
|
26 $line = nntp_readline(STDIN); |
|
27 if ($line === FALSE || $line === NULL) break; |
|
28 $cmd = strtok($line, " \t"); |
|
29 switch (strtoupper($cmd)) { |
|
30 case 'LIST': |
|
31 nntp_writeline(STDOUT, '215 List of groups follows'); |
|
32 foreach ($db->evalAllAssoc('SELECT * FROM `groups`') as $group) { |
|
33 $groupmessages = $db->evalRow('SELECT MIN(`number`), MAX(`number`) FROM `groupmessages` WHERE `group` = ?', $group['id']); |
|
34 nntp_writeline(STDOUT, $group['name'].' '.intval($groupmessages[1]).' '.intval($groupmessages[0]).' n'); |
|
35 } |
|
36 nntp_writeline(STDOUT, '.'); |
|
37 break; |
|
38 case 'GROUP': |
|
39 $groupname = strtok(" \t"); |
|
40 $group = $db->evalRowAssoc('SELECT * FROM `groups` WHERE `name` = ?', $groupname); |
|
41 if ($group === FALSE) { |
|
42 nntp_writeline(STDOUT, '411 No such group '.$groupname); |
|
43 } else { |
|
44 $currentgroup = $group; |
|
45 $groupmessages = $db->evalRow('SELECT MIN(`number`), MAX(`number`), COUNT(`number`) FROM `groupmessages` WHERE `group` = ?', $group['id']); |
|
46 nntp_writeline(STDOUT, '211 '.intval($groupmessages[2]).' '.intval($groupmessages[0]).' '.intval($groupmessages[1]).' '.$group['name']); |
|
47 if ($groupmessages[0] === NULL) { |
|
48 $currentarticle = NULL; |
|
49 } else { |
|
50 $currentarticle = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` = ?', array($group['id'], $groupmessages[0])); |
|
51 if ($currentarticle === FALSE) $currentarticle = NULL; |
|
52 } |
|
53 } |
|
54 break; |
|
55 case 'STAT': |
|
56 $article = nntp_get_article(strtok(" \t")); |
|
57 if ($article === NULL) break; |
|
58 nntp_writeline(STDOUT, '223 '.$article['messagenumber'].' <'.$article['messageid'].'> stat'); |
|
59 break; |
|
60 case 'HEAD': |
|
61 $article = nntp_get_article(strtok(" \t")); |
|
62 if ($article === NULL) break; |
|
63 nntp_writeline(STDOUT, '221 '.$article['messagenumber'].' <'.$article['messageid'].'> head'); |
|
64 foreach (explode("\r\n", $article['header']) as $line) nntp_writeline(STDOUT, $line); |
|
65 nntp_writeline(STDOUT, '.'); |
|
66 break; |
|
67 case 'BODY': |
|
68 $article = nntp_get_article(strtok(" \t")); |
|
69 if ($article === NULL) break; |
|
70 nntp_writeline(STDOUT, '222 '.$article['messagenumber'].' <'.$article['messageid'].'> body'); |
|
71 foreach (explode("\r\n", $article['body']) as $line) nntp_writeline(STDOUT, $line); |
|
72 nntp_writeline(STDOUT, '.'); |
|
73 break; |
|
74 case 'ARTICLE': |
|
75 $article = nntp_get_article(strtok(" \t")); |
|
76 if ($article === NULL) break; |
|
77 nntp_writeline(STDOUT, '220 '.$article['messagenumber'].' <'.$article['messageid'].'> article'); |
|
78 foreach (explode("\r\n", $article['header']) as $line) nntp_writeline(STDOUT, $line); |
|
79 nntp_writeline(STDOUT, ''); |
|
80 foreach (explode("\r\n", $article['body']) as $line) nntp_writeline(STDOUT, $line); |
|
81 nntp_writeline(STDOUT, '.'); |
|
82 break; |
|
83 case 'LAST': |
|
84 if ($currentarticle === NULL) { |
|
85 nntp_writeline(STDOUT, '420 no current article has been selected'); |
|
86 break; |
|
87 } |
|
88 $article = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` < ? ORDER BY `number` DESC LIMIT 1', array($currentarticle['group'], $currentarticle['number'])); |
|
89 if ($article === FALSE) { |
|
90 nntp_writeline(STDOUT, '422 no previous article in this group'); |
|
91 } else { |
|
92 $articlea = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); |
|
93 if ($articlea === FALSE) { |
|
94 nntp_writeline(STDOUT, '430 no such article found'); |
|
95 return NULL; |
|
96 } |
|
97 $currentarticle = $article; |
|
98 nntp_writeline(STDOUT, '223 '.$article['number'].' <'.$articlea['messageid'].'> ok'); |
|
99 } |
|
100 break; |
|
101 case 'NEXT': |
|
102 if ($currentarticle === NULL) { |
|
103 nntp_writeline(STDOUT, '420 no current article has been selected'); |
|
104 break; |
|
105 } |
|
106 $article = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` > ? ORDER BY `number` ASC LIMIT 1', array($currentarticle['group'], $currentarticle['number'])); |
|
107 if ($article === FALSE) { |
|
108 nntp_writeline(STDOUT, '422 no previous article in this group'); |
|
109 } else { |
|
110 $articlea = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); |
|
111 if ($articlea === FALSE) { |
|
112 nntp_writeline(STDOUT, '430 no such article found'); |
|
113 return NULL; |
|
114 } |
|
115 $currentarticle = $article; |
|
116 nntp_writeline(STDOUT, '223 '.$article['number'].' <'.$articlea['messageid'].'> ok'); |
|
117 } |
|
118 break; |
|
119 case 'QUIT': |
|
120 nntp_writeline(STDOUT, '205 .'); |
|
121 return; |
|
122 case 'XOVER': |
|
123 case 'MODE': |
|
124 case 'CAPABILITIES': |
|
125 nntp_writeline(STDOUT, '500 Command not implemented'); |
|
126 break; |
|
127 default: |
|
128 nntp_writeline(STDOUT, '500 Command not understood'); |
|
129 break; |
|
130 } |
|
131 } |
|
132 |
|
133 function nntp_get_article($article) { |
|
134 global $currentgroup, $currentarticle, $db; |
|
135 if ($article === FALSE) { |
|
136 if ($currentarticle === NULL) { |
|
137 nntp_writeline(STDOUT, '420 no current article has been selected'); |
|
138 return NULL; |
|
139 } |
|
140 $messagenumber = $currentarticle['number']; |
|
141 $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $currentarticle['message']); |
|
142 if ($article === FALSE) { |
|
143 nntp_writeline(STDOUT, '430 no such article found'); |
|
144 return NULL; |
|
145 } |
|
146 } elseif (strlen($article) > 2 && $article[0] == '<' && $article[strlen($article)-1] == '>') { |
|
147 $messagenumber = 0; |
|
148 $article = substr($article, 1, -1); |
|
149 $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `messageid` = ?', $article); |
|
150 if ($article === FALSE) { |
|
151 nntp_writeline(STDOUT, '430 no such article found'); |
|
152 return NULL; |
|
153 } |
|
154 } elseif (is_numeric($article)) { |
|
155 if ($currentgroup === NULL) { |
|
156 nntp_writeline(STDOUT, '412 no newsgroup has been selected'); |
|
157 return NULL; |
|
158 } |
|
159 $article = $db->evalRowAssoc('SELECT * FROM `groupmessages` WHERE `group` = ? AND `number` = ?', array($currentgroup['id'], $article)); |
|
160 if ($article === FALSE) { |
|
161 nntp_writeline(STDOUT, '423 no such article number in this group'); |
|
162 return NULL; |
|
163 } |
|
164 $currentarticle = $article; |
|
165 $messagenumber = $article['number']; |
|
166 $article = $db->evalRowAssoc('SELECT * FROM `messages` WHERE `id` = ?', $article['message']); |
|
167 if ($article === FALSE) { |
|
168 nntp_writeline(STDOUT, '430 no such article found'); |
|
169 return NULL; |
|
170 } |
|
171 } else { |
|
172 nntp_writeline(STDOUT, '500 Error in arguments'); |
|
173 } |
|
174 $article['messagenumber'] = $messagenumber; |
|
175 return $article; |
|
176 } |
|
177 |
|
178 function writelog($line) { |
|
179 global $logfile; |
|
180 fwrite($logfile, $line."\n"); |
|
181 } |
|
182 function nntp_readline($socket) { |
|
183 global $logfile; |
|
184 $line = fgets($socket, 512); |
|
185 if ($line === FALSE || $line === NULL) return $line; |
|
186 $line = rtrim($line, "\r\n"); |
|
187 fwrite($logfile, 'R: '.$line."\n"); |
|
188 return $line; |
|
189 } |
|
190 function nntp_writeline($socket, $line) { |
|
191 global $logfile; |
|
192 fwrite($logfile, 'W: '.$line."\n"); |
|
193 fwrite($socket, $line."\r\n"); |
|
194 } |
|
195 function nntp_readlines($socket) { |
|
196 $line = nntp_readline($socket); |
|
197 $lines = array(); |
|
198 while ($line != '.' && $line !== FALSE && $line !== FALSE) { |
|
199 $lines[] = $line; |
|
200 $line = nntp_readline($socket); |
|
201 } |
|
202 if ($line != '.') die("Unexpected end of message header\n"); |
|
203 return $lines; |
|
204 } |