added channel mode +S to the $modes list
[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                 "S" => self::MODE_TYPE_D,
71                 
72                 //special behavior
73                 "o" => self::MODE_TYPE_B,
74                 "v" => self::MODE_TYPE_B
75         );
76         private static $modevalues = null;
77         private $modeflags = 0;
78         private $modeparams = array();
79         private $channel;
80         
81         public function __construct($channel) {
82                 if(self::$modevalues == null) {
83                         //build modevalues array
84                         $flag = 1;
85                         self::$modevalues = array();
86                         foreach(self::$modes as $mode => $type) {
87                                 self::$modevalues[$mode] = $flag;
88                                 $flag <<= 1;
89                         }
90                 }
91                 $this->channel = $channel;
92         }
93         
94         public function parseModes($modes) {
95                 $args = explode(" ",$modes);
96                 $c = 1;
97                 for($i = 0; $i < strlen($args[0]); $i++) {
98                         $mode = $args[0][$i];
99                         if($mode == "+") continue;
100                         if($mode == "-") { //we have no - flag on parseModes???
101                                 trigger_error("unexpected MODE_DEL (-) on parseModes (".$modes.").", E_USER_WARNING);
102                                 break;
103                         }
104                         if(!array_key_exists($mode, self::$modevalues)) {
105                                 trigger_error("unknown mode (".$mode.") on parseModes (".$modes.").", E_USER_WARNING);
106                                 continue;
107                         }
108                         $flag = self::$modevalues[$mode];
109                         if(self::$modes[$mode] == self::MODE_TYPE_A) continue; //we shouldn't get such a mode on parseModes
110                         $this->modeflags |= $flag;
111                         if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
112                                 $this->modeparams[$mode] = $args[$c++];
113                         }
114                 }
115                 return $c-1;
116         }
117         
118         public function setModes($modes, $returndiff = false) {
119                 $args = explode(" ",$modes);
120                 $c = 1;
121                 $add = true;
122                 $modestradd = "+";
123                 $paramstradd = "";
124                 $modestrdel = "-";
125                 $paramstrdel = "";
126                 for($i = 0; $i < strlen($args[0]); $i++) {
127                         $mode = $args[0][$i];
128                         if($mode == "+") {
129                                 $add = true;
130                                 continue;
131                         }
132                         if($mode == "-") { 
133                                 $add = false;
134                                 continue;
135                         }
136                         if(!array_key_exists($mode, self::$modevalues)) {
137                                 trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
138                                 continue;
139                         }
140                         if($mode == "o" || $mode == "v") {
141                                 if($this->setPrivs($add, $mode, $args[$c++])) {
142                                         if($returndiff && $add) {
143                                                 $modestradd .= $mode;
144                                                 $paramstradd .= " ".$args[$c-1];
145                                         } else if($returndiff && !$add) {
146                                                 $modestrdel .= $mode;
147                                                 $paramstrdel .= " ".$args[$c-1];
148                                         }
149                                 }
150                                 continue;
151                         } else if($mode == "b") {
152                                 if($this->handleBan($add, $mode, $args[$c++])) {
153                                         if($returndiff && $add) {
154                                                 $modestradd .= $mode;
155                                                 $paramstradd .= " ".$args[$c-1];
156                                         } else if($returndiff && !$add) {
157                                                 $modestrdel .= $mode;
158                                                 $paramstrdel .= " ".$args[$c-1];
159                                         }
160                                 }
161                                 continue;
162                         }
163                         $flag = self::$modevalues[$mode];
164                         if($add) {
165                                 if($returndiff && !($this->modeflags & $flag)) {
166                                         $modestradd .= $mode;
167                                         if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
168                                                 $paramstradd .= " ".$args[$c];
169                                         }
170                                 }
171                                 $this->modeflags |= $flag;
172                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
173                                         $this->modeparams[$mode] = $args[$c++];
174                                 }
175                         } else {
176                                 if($returndiff && ($this->modeflags & $flag)) {
177                                         $modestrdel .= $mode;
178                                         if(self::$modes[$mode] == self::MODE_TYPE_C) {
179                                                 $paramstrdel .= " ".$args[$c];
180                                         }
181                                 }
182                                 $this->modeflags &= ~$flag;
183                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
184                                         unset($this->modeparams[$mode]);
185                                 }
186                                 if(self::$modes[$mode] == self::MODE_TYPE_C) $c++;
187                         }
188                 }
189                 if($returndiff) {
190                         $modediff = ($modestradd == "+" ? "" : $modestradd);
191                         $modediff .= ($modestrdel == "-" ? "" : $modestrdel);
192                         $modediff .= $paramstradd.$paramstrdel;
193                         return $modediff;
194                 }
195         }
196         
197         private function handleBan($add, $mode, $mask) {
198                 //no ban management right now...
199                 return true;
200         }
201         
202         private function setPrivs($add, $mode, $user) {
203                 $user = P10_User::getUserByNum($user);
204                 if($user == null) {
205                         trigger_error("Tried to set privs on a User that does not exist.", E_USER_ERROR);
206                         return;
207                 }
208                 $privs = $this->channel->getUserPrivs($user);
209                 $privFlag = 0;
210                 if($mode == "o") $privFlag = P10_Channel::USERPRIV_OPED;
211                 if($mode == "v") $privFlag = P10_Channel::USERPRIV_VOICE;
212                 if(!($add xor ($privs & $privFlag)))
213                         return false;
214                 if($add) $privs |= $privFlag;
215                 else $privs &= ~$privFlag;
216                 $this->channel->setUserPrivs($user, $privs);
217                 return true;
218                 
219         }
220         
221         public function getModeString() {
222                 $modestr = "+";
223                 $paramstr = "";
224                 foreach(self::$modevalues as $mode => $flag) {
225                         if(($this->modeflags & $flag)) {
226                                 $modestr .= $mode;
227                                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
228                                         $paramstr .= " ".$this->modeparams[$mode];
229                                 }
230                         }
231                 }
232                 return $modestr.$paramstr;
233         }
234         
235         public function hasMode($mode) {
236                 if(!array_key_exists($mode, self::$modevalues)) {
237                         trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
238                         continue;
239                 }
240                 $flag = self::$modevalues[$mode];
241                 if(self::$modes[$mode] == self::MODE_TYPE_B || self::$modes[$mode] == self::MODE_TYPE_C) {
242                         return (($this->modeflags & $flag) ? $this->modeparams[$mode] : false);
243                 } else
244                         return ($this->modeflags & $flag);
245         }
246         
247 }
248
249 class P10_UserModeSet {
250         const MODE_WITHOUT_PARAMETER = 1, MODE_WITH_PARAMETER = 2;
251         private static $modes = array(
252                 "o" => self::MODE_WITHOUT_PARAMETER,
253                 "O" => self::MODE_WITHOUT_PARAMETER,
254                 "i" => self::MODE_WITHOUT_PARAMETER,
255                 "w" => self::MODE_WITHOUT_PARAMETER,
256                 "s" => self::MODE_WITHOUT_PARAMETER,
257                 "d" => self::MODE_WITHOUT_PARAMETER,
258                 "k" => self::MODE_WITHOUT_PARAMETER,
259                 "g" => self::MODE_WITHOUT_PARAMETER,
260                 "r" => self::MODE_WITH_PARAMETER,
261                 "f" => self::MODE_WITH_PARAMETER,
262                 "n" => self::MODE_WITHOUT_PARAMETER,
263                 "I" => self::MODE_WITHOUT_PARAMETER,
264                 "X" => self::MODE_WITHOUT_PARAMETER,
265                 "S" => self::MODE_WITHOUT_PARAMETER,
266                 "H" => self::MODE_WITHOUT_PARAMETER,
267                 "c" => self::MODE_WITHOUT_PARAMETER,
268                 "W" => self::MODE_WITHOUT_PARAMETER,
269                 "t" => self::MODE_WITHOUT_PARAMETER,
270                 "D" => self::MODE_WITHOUT_PARAMETER,
271                 "x" => self::MODE_WITHOUT_PARAMETER
272         );
273         private static $modevalues = null;
274         private $modeflags = 0;
275         private $modeparams = array();
276         
277         public function __construct($modes) {
278                 if(self::$modevalues == null) {
279                         //build modevalues array
280                         $flag = 1;
281                         self::$modevalues = array();
282                         foreach(self::$modes as $mode => $type) {
283                                 self::$modevalues[$mode] = $flag;
284                                 $flag <<= 1;
285                         }
286                 }
287                 $this->parseModes($modes);
288         }
289         
290         public function parseModes($modes) {
291                 $args = explode(" ",$modes);
292                 $c = 1;
293                 for($i = 0; $i < strlen($args[0]); $i++) {
294                         $mode = $args[0][$i];
295                         if($mode == "+") continue;
296                         if($mode == "-") { //we have no - flag on parseModes???
297                                 trigger_error("unexpected MODE_DEL (-) on parseModes (".$modes.").", E_USER_WARNING);
298                                 break;
299                         }
300                         if(!array_key_exists($mode, self::$modevalues)) {
301                                 trigger_error("unknown mode (".$mode.") on parseModes (".$modes.").", E_USER_WARNING);
302                                 continue;
303                         }
304                         $flag = self::$modevalues[$mode];
305                         $this->modeflags |= $flag;
306                         if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
307                                 $this->modeparams[$mode] = $args[$c++];
308                         }
309                 }
310         }
311         
312         public function setModes($modes, $returndiff = false) {
313                 $args = explode(" ",$modes);
314                 $c = 1;
315                 $add = true;
316                 $modestradd = "+";
317                 $paramstradd = "";
318                 $modestrdel = "-";
319                 for($i = 0; $i < strlen($args[0]); $i++) {
320                         $mode = $args[0][$i];
321                         if($mode == "+") {
322                                 $add = true;
323                                 continue;
324                         }
325                         if($mode == "-") { 
326                                 $add = false;
327                                 continue;
328                         }
329                         if(!array_key_exists($mode, self::$modevalues)) {
330                                 trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
331                                 continue;
332                         }
333                         $flag = self::$modevalues[$mode];
334                         if($add) {
335                                 if($returndiff && !($this->modeflags & $flag)) {
336                                         $modestradd .= $mode;
337                                         if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
338                                                 $paramstradd .= " ".$args[$c];
339                                         }
340                                 }
341                                 $this->modeflags |= $flag;
342                                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
343                                         $this->modeparams[$mode] = $args[$c++];
344                                 }
345                         } else {
346                                 if($returndiff && ($this->modeflags & $flag)) {
347                                         $modestrdel .= $mode;
348                                 }
349                                 $this->modeflags &= ~$flag;
350                         }
351                 }
352                 if($returndiff) {
353                         $modediff = ($modestradd == "+" ? "" : $modestradd);
354                         $modediff .= ($modestrdel == "-" ? "" : $modestrdel);
355                         $modediff .= $paramstradd;
356                         return $modediff;
357                 }
358         }
359         
360         public function getModeString() {
361                 $modestr = "+";
362                 $paramstr = "";
363                 foreach(self::$modevalues as $mode => $flag) {
364                         if(($this->modeflags & $flag)) {
365                                 $modestr .= $mode;
366                                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
367                                         $paramstr .= " ".$this->modeparams[$mode];
368                                 }
369                         }
370                 }
371                 return $modestr.$paramstr;
372         }
373         
374         public function hasMode($mode) {
375                 if(!array_key_exists($mode, self::$modevalues)) {
376                         trigger_error("unknown mode (".$mode.") on setModes (".$modes.").", E_USER_WARNING);
377                         continue;
378                 }
379                 $flag = self::$modevalues[$mode];
380                 if(self::$modes[$mode] == self::MODE_WITH_PARAMETER) {
381                         return (($this->modeflags & $flag) ? $this->modeparams[$mode] : false);
382                 } else
383                         return ($this->modeflags & $flag);
384         }
385         
386 }
387
388 ?>