we need to parse +b even if we have no ban handler, yet
[PHP-P10.git] / Uplink / P10_ModeSets.class.php
1 <?php
2 /******************************* PHP-P10 v2 *****************************
3  * Copyright (C) 2011  Philipp Kreil (pk910)                            *
4  *                                                                      *
5  * This program is free software: you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation, either version 3 of the License, or    *
8  * (at your option) any later version.                                  *
9  *                                                                      * 
10  * This program is distributed in the hope that it will be useful,      *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
13  * GNU General Public License for more details.                         *
14  *                                                                      *
15  * You should have received a copy of the GNU General Public License    *
16  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17  *                                                                      *
18  ************************************************************************
19  * 
20  *  Uplink/P10_ModeSets.class.php
21  *
22  * classes to parse and store channel or user modes
23  *
24  */
25
26 class P10_ChannelModeSet {
27         const MODE_TYPE_A = 1, MODE_TYPE_B = 2, MODE_TYPE_C = 3, MODE_TYPE_D = 4;
28         /** http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
29          * Section 3.3 CHANMODES
30          *
31          * Type A: Modes that add or remove an address to or from a list.
32          *   These modes always take a parameter when sent by the server to a
33          *   client; when sent by a client, they may be specified without a
34          *   parameter, which requests the server to display the current
35          *   contents of the corresponding list on the channel to the client.
36          *
37          * Type B: Modes that change a setting on the channel.  These modes
38          *   always take a parameter.
39          *
40          * Type C: Modes that change a setting on the channel. These modes
41          *   take a parameter only when set; the parameter is absent when the
42          *   mode is removed both in the client's and server's MODE command.
43          *
44          * Type D: Modes that change a setting on the channel. These modes
45          *   never take a parameter.
46          **/
47         private static $modes = array(
48                 "b" => self::MODE_TYPE_A,
49                 "k" => self::MODE_TYPE_B,
50                 "a" => self::MODE_TYPE_C,
51                 "l" => self::MODE_TYPE_C,
52                 "f" => self::MODE_TYPE_C,
53                 "F" => self::MODE_TYPE_C,
54                 "c" => self::MODE_TYPE_D,
55                 "C" => self::MODE_TYPE_D,
56                 "i" => self::MODE_TYPE_D,
57                 "m" => self::MODE_TYPE_D,
58                 "M" => self::MODE_TYPE_D,
59                 "n" => self::MODE_TYPE_D,
60                 "N" => self::MODE_TYPE_D,
61                 "p" => self::MODE_TYPE_D,
62                 "r" => self::MODE_TYPE_D,
63                 "s" => self::MODE_TYPE_D,
64                 "t" => self::MODE_TYPE_D,
65                 "u" => self::MODE_TYPE_D,
66                 "D" => self::MODE_TYPE_D,
67                 "d" => self::MODE_TYPE_D,
68                 "R" => self::MODE_TYPE_D,
69                 "z" => self::MODE_TYPE_D,
70                 
71                 //special behavior
72                 "o" => self::MODE_TYPE_B,
73                 "v" => self::MODE_TYPE_B
74         );
75         private static $modevalues = null;
76         private $modeflags = 0;
77         private $modeparams = array();
78         private $channel;
79         
80         public function __construct($channel) {
81                 if(self::$modevalues == null) {
82                         //build modevalues array
83                         $flag = 1;
84                         self::$modevalues = array();
85                         foreach(self::$modes as $mode => $type) {
86                                 self::$modevalues[$mode] = $flag;
87                                 $flag <<= 1;
88                         }
89                 }
90                 $this->channel = $channel;
91         }
92         
93         public function parseModes($modes) {
94                 $args = explode(" ",$modes);
95                 $c = 1;
96                 for($i = 0; $i < strlen($args[0]); $i++) {
97                         $mode = $args[0][$i];
98                         if($mode == "+") continue;
99                         if($mode == "-") { //we have no - flag on parseModes???
100                                 trigger_error("unexpected MODE_DEL (-) on parseModes (".$modes.").", E_USER_WARNING);
101                                 break;
102                         }
103                         if(!array_key_exists($mode, self::$modevalues)) {
104                                 trigger_error("unknown mode (".$mode.") on parseModes (".$modes.").", E_USER_WARNING);
105                                 continue;
106                         }
107                         $flag = self::$modevalues[$mode];
108                         if(self::$modes[$mode] == self::MODE_TYPE_A) continue; //we shouldn't get such a mode on parseModes
109                         $this->modeflags |= $flag;
110                         if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
111                                 $this->modeparams[$mode] = $args[$c++];
112                         }
113                 }
114                 return $c-1;
115         }
116         
117         public function setModes($modes, $returndiff = false) {
118                 $args = explode(" ",$modes);
119                 $c = 1;
120                 $add = true;
121                 $modestradd = "+";
122                 $paramstradd = "";
123                 $modestrdel = "-";
124                 $paramstrdel = "";
125                 for($i = 0; $i < strlen($args[0]); $i++) {
126                         $mode = $args[0][$i];
127                         if($mode == "+") {
128                                 $add = true;
129                                 continue;
130                         }
131                         if($mode == "-") { 
132                                 $add = false;
133                                 continue;
134                         }
135                         if(!array_key_exists($mode, self::$modevalues)) {
136                                 trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
137                                 continue;
138                         }
139                         if($mode == "o" || $mode == "v") {
140                                 if($this->setPrivs($add, $mode, $args[$c++])) {
141                                         if($returndiff && $add) {
142                                                 $modestradd .= $mode;
143                                                 $paramstradd .= " ".$args[$c-1];
144                                         } else if($returndiff && !$add) {
145                                                 $modestrdel .= $mode;
146                                                 $paramstrdel .= " ".$args[$c-1];
147                                         }
148                                 }
149                                 continue;
150                         } else if($mode == "b") {
151                 if($this->handleBan($add, $mode, $args[$c++])) {
152                                         if($returndiff && $add) {
153                                                 $modestradd .= $mode;
154                                                 $paramstradd .= " ".$args[$c-1];
155                                         } else if($returndiff && !$add) {
156                                                 $modestrdel .= $mode;
157                                                 $paramstrdel .= " ".$args[$c-1];
158                                         }
159                                 }
160                 continue;
161             }
162                         $flag = self::$modevalues[$mode];
163                         if($add) {
164                                 if($returndiff && !($this->modeflags & $flag)) {
165                                         $modestradd .= $mode;
166                                         if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
167                                                 $paramstradd .= " ".$args[$c];
168                                         }
169                                 }
170                                 $this->modeflags |= $flag;
171                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
172                                         $this->modeparams[$mode] = $args[$c++];
173                                 }
174                         } else {
175                                 if($returndiff && ($this->modeflags & $flag)) {
176                                         $modestrdel .= $mode;
177                                         if(self::$modes[$mode] == self::MODE_TYPE_C) {
178                                                 $paramstrdel .= " ".$args[$c];
179                                         }
180                                 }
181                                 $this->modeflags &= ~$flag;
182                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
183                                         unset($this->modeparams[$mode]);
184                                 }
185                                 if(self::$modes[$mode] == self::MODE_TYPE_C) $c++;
186                         }
187                 }
188                 if($returndiff) {
189                         $modediff = ($modestradd == "+" ? "" : $modestradd);
190                         $modediff .= ($modestrdel == "-" ? "" : $modestrdel);
191                         $modediff .= $paramstradd.$paramstrdel;
192                         return $modediff;
193                 }
194         }
195         
196     private function handleBan($add, $mode, $mask) {
197         //no ban management right now...
198         return true;
199     }
200     
201         private function setPrivs($add, $mode, $user) {
202                 $user = P10_User::getUserByNum($user);
203                 if($user == null) {
204                         trigger_error("Tried to set privs on a User that does not exist.", E_USER_ERROR);
205                         return;
206                 }
207                 $privs = $this->channel->getUserPrivs($user);
208                 $privFlag = 0;
209                 if($mode == "o") $privFlag = P10_Channel::USERPRIV_OPED;
210                 if($mode == "v") $privFlag = P10_Channel::USERPRIV_VOICE;
211                 if(!($add xor ($privs & $privFlag)))
212                         return false;
213                 if($add) $privs |= $privFlag;
214                 else $privs &= ~$privFlag;
215                 $this->channel->setUserPrivs($user, $privs);
216                 return true;
217                 
218         }
219         
220         public function getModeString() {
221                 $modestr = "+";
222                 $paramstr = "";
223                 foreach(self::$modevalues as $mode => $flag) {
224                         if(($this->modeflags & $flag)) {
225                                 $modestr .= $mode;
226                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
227                                         $paramstr .= " ".$this->modeparams[$mode];
228                                 }
229                         }
230                 }
231                 return $modestr.$paramstr;
232         }
233         
234         public function hasMode($mode) {
235                 if(!array_key_exists($mode, self::$modevalues)) {
236                         trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
237                         continue;
238                 }
239                 $flag = self::$modevalues[$mode];
240                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
241                         return (($this->modeflags & $flag) ? $this->modeparams[$mode] : false);
242                 } else
243                         return ($this->modeflags & $flag);
244         }
245         
246 }
247
248 class P10_UserModeSet {
249         const MODE_WITHOUT_PARAMETER = 1, MODE_WITH_PARAMETER = 2;
250         private static $modes = array(
251                 "o" => self::MODE_WITHOUT_PARAMETER,
252                 "O" => self::MODE_WITHOUT_PARAMETER,
253                 "i" => self::MODE_WITHOUT_PARAMETER,
254                 "w" => self::MODE_WITHOUT_PARAMETER,
255                 "s" => self::MODE_WITHOUT_PARAMETER,
256                 "d" => self::MODE_WITHOUT_PARAMETER,
257                 "k" => self::MODE_WITHOUT_PARAMETER,
258                 "g" => self::MODE_WITHOUT_PARAMETER,
259                 "r" => self::MODE_WITH_PARAMETER,
260                 "f" => self::MODE_WITH_PARAMETER,
261                 "n" => self::MODE_WITHOUT_PARAMETER,
262                 "I" => self::MODE_WITHOUT_PARAMETER,
263                 "X" => self::MODE_WITHOUT_PARAMETER,
264                 "S" => self::MODE_WITHOUT_PARAMETER,
265                 "H" => self::MODE_WITHOUT_PARAMETER,
266                 "c" => self::MODE_WITHOUT_PARAMETER,
267                 "W" => self::MODE_WITHOUT_PARAMETER,
268                 "t" => self::MODE_WITHOUT_PARAMETER,
269                 "D" => self::MODE_WITHOUT_PARAMETER,
270                 "x" => self::MODE_WITHOUT_PARAMETER
271         );
272         private static $modevalues = null;
273         private $modeflags = 0;
274         private $modeparams = array();
275         
276         public function __construct($modes) {
277                 if(self::$modevalues == null) {
278                         //build modevalues array
279                         $flag = 1;
280                         self::$modevalues = array();
281                         foreach(self::$modes as $mode => $type) {
282                                 self::$modevalues[$mode] = $flag;
283                                 $flag <<= 1;
284                         }
285                 }
286                 $this->parseModes($modes);
287         }
288         
289         public function parseModes($modes) {
290                 $args = explode(" ",$modes);
291                 $c = 1;
292                 for($i = 0; $i < strlen($args[0]); $i++) {
293                         $mode = $args[0][$i];
294                         if($mode == "+") continue;
295                         if($mode == "-") { //we have no - flag on parseModes???
296                                 trigger_error("unexpected MODE_DEL (-) on parseModes (".$modes.").", E_USER_WARNING);
297                                 break;
298                         }
299                         if(!array_key_exists($mode, self::$modevalues)) {
300                                 trigger_error("unknown mode (".$mode.") on parseModes (".$modes.").", E_USER_WARNING);
301                                 continue;
302                         }
303                         $flag = self::$modevalues[$mode];
304                         $this->modeflags |= $flag;
305                         if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
306                                 $this->modeparams[$mode] = $args[$c++];
307                         }
308                 }
309         }
310         
311         public function setModes($modes, $returndiff = false) {
312                 $args = explode(" ",$modes);
313                 $c = 1;
314                 $add = true;
315                 $modestradd = "+";
316                 $paramstradd = "";
317                 $modestrdel = "-";
318                 for($i = 0; $i < strlen($args[0]); $i++) {
319                         $mode = $args[0][$i];
320                         if($mode == "+") {
321                                 $add = true;
322                                 continue;
323                         }
324                         if($mode == "-") { 
325                                 $add = false;
326                                 continue;
327                         }
328                         if(!array_key_exists($mode, self::$modevalues)) {
329                                 trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
330                                 continue;
331                         }
332                         $flag = self::$modevalues[$mode];
333                         if($add) {
334                                 if($returndiff && !($this->modeflags & $flag)) {
335                                         $modestradd .= $mode;
336                                         if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
337                                                 $paramstradd .= " ".$args[$c];
338                                         }
339                                 }
340                                 $this->modeflags |= $flag;
341                                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
342                                         $this->modeparams[$mode] = $args[$c++];
343                                 }
344                         } else {
345                                 if($returndiff && ($this->modeflags & $flag)) {
346                                         $modestrdel .= $mode;
347                                 }
348                                 $this->modeflags &= ~$flag;
349                         }
350                 }
351                 if($returndiff) {
352                         $modediff = ($modestradd == "+" ? "" : $modestradd);
353                         $modediff .= ($modestrdel == "-" ? "" : $modestrdel);
354                         $modediff .= $paramstradd;
355                         return $modediff;
356                 }
357         }
358         
359         public function getModeString() {
360                 $modestr = "+";
361                 $paramstr = "";
362                 foreach(self::$modevalues as $mode => $flag) {
363                         if(($this->modeflags & $flag)) {
364                                 $modestr .= $mode;
365                                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
366                                         $paramstr .= " ".$this->modeparams[$mode];
367                                 }
368                         }
369                 }
370                 return $modestr.$paramstr;
371         }
372         
373         public function hasMode($mode) {
374                 if(!array_key_exists($mode, self::$modevalues)) {
375                         trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
376                         continue;
377                 }
378                 $flag = self::$modevalues[$mode];
379                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
380                         return (($this->modeflags & $flag) ? $this->modeparams[$mode] : false);
381                 } else
382                         return ($this->modeflags & $flag);
383         }
384         
385 }
386
387 ?>