Merge remote-tracking branch 'IOMultiplexer/v2'
[NextIRCd.git] / src / ircd_parse.c
1 /* ircd_client.c - NextIRCd
2  * Copyright (C) 2012-2013  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "tools.h"
22 #include "IOHandler/IOSockets.h"
23 #include "ircd_parse.h"
24 struct Server;
25 #include "struct_client.h"
26 #include "struct_auth.h"
27 #include "struct_servermsg.h"
28
29 typedef int cmd_client_t(struct Client *client, char *argv[], int argc);
30 typedef int cmd_auth_t(struct Auth *auth, char *argv[], int argc);
31 typedef int cmd_server_t(struct Server *server, char *argv[], int argc);
32
33 static struct ServerMsg parse_static_srvmsg;
34
35 #define PARSE_CLIFLAG_OPONLY 0x01
36
37 //include all commands
38 #include "cmd_nick.h"
39
40
41 struct {
42         struct {
43                 const char *client;
44                 const char *server;
45         } tokens;
46         struct {
47                 cmd_client_t *function;
48                 unsigned int min_argc : 8;
49                 unsigned int max_argc : 8;
50                 unsigned int flags : 8;
51         } client;
52         struct {
53                 cmd_auth_t *function;
54                 unsigned int min_argc : 8;
55                 unsigned int max_argc : 8;
56                 unsigned int flags : 8;
57         } auth;
58         struct {
59                 cmd_server_t *function;
60                 unsigned int min_argc : 8;
61                 unsigned int max_argc : 8;
62                 unsigned int flags : 8;
63         } server;
64         
65 } parse_command_list[] = {
66         {{"PING", "P"}, /* Ping Command */
67                 {NULL, 0, 1, 0}, /* Client */
68                 {NULL, 0, 1, 0}, /* Unauthed */
69                 {NULL, 0, 1, 0}  /* Server */
70         },
71         {{"PASS", NULL}, /* PASS Command */
72                 {NULL, 0, 1, 0}, /* Client */
73                 {NULL, 0, 1, 0}, /* Unauthed */
74                 {NULL, 0, 1, 0}  /* Server */
75         },
76         {{"NICK", "N"}, /* Nick Command */
77                 {cmd_nick_cli, 1, 1, 0}, /* Client */
78                 {cmd_nick_auth, 1, 1, 0}, /* Unauthed */
79                 {NULL, 0, 1, 0}  /* Server */
80         },
81         {{"USER", "U"}, /* User Command */
82                 {NULL, 0, 1, 0}, /* Client */
83                 {NULL, 0, 1, 0}, /* Unauthed */
84                 {NULL, 0, 1, 0}  /* Server */
85         },
86         
87         {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}}
88 };
89
90 static char *parse_irc_token(char **data) {
91         //find next " "
92         int i;
93         char *token = *data;
94         for(i = 0; *data[i]; i++) {
95                 if(*data[i] != ' ') {
96                         *data[i] = '\0';
97                         *data += i+1;
98                         break;
99                 }
100         }
101         return token;
102 }
103
104 static char **parse_irc_params(char *data, int *argc, int maxargs) {
105         if(maxargs == 0) {
106                 *argc = 0;
107                 return NULL;
108         }
109     char **argv = calloc(maxargs, sizeof(*argv));
110     while(*data) {
111         //skip leading spaces
112         while (*data == ' ')
113             *data++ = 0;
114         if (*data == ':') {
115            //the rest is a single parameter
116            argv[*argc++] = data + 1;
117            break;
118         }
119         argv[*argc++] = data;
120         if (*argc >= maxargs)
121             break;
122         while (*data != ' ' && *data)
123             data++;
124     }
125     return argv;
126 }
127
128 /* Client Data Format
129 * <TOKEN> <arg1> <arg2>
130 */
131 void parse_client_data(struct Client *client, char *data) {
132     char *token = parse_irc_token(&data);
133         int found = 0;
134         int i;
135         for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
136                 if(stricmp(parse_command_list[i].tokens.client, token)) {
137                         found = 1;
138                         break;
139                 }
140         }
141         if(found && !parse_command_list[i].client.function) {
142                 // reply 462 You may not reregister
143         } else if(found) {
144                 int argc;
145                 char **argv = parse_irc_params(data, &argc, parse_command_list[i].client.max_argc);
146                 if(argc < parse_command_list[i].client.min_argc) {
147                         // reply 461 Not enough parameters
148                 } else {
149                         int ret = parse_command_list[i].client.function(client, argv, argc);
150                         if(ret) {
151                                 // error occurred!
152                                 // do something?
153                         }
154                 }
155                 free(argv);
156         } else {
157                 // reply 421 Unknown command
158         }
159 }
160
161 void parse_unauth_data(struct Auth *auth, char *data) {
162         char *token = parse_irc_token(&data);
163         int found = 0;
164         int i;
165         for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
166                 if(stricmp(parse_command_list[i].tokens.client, token)) {
167                         found = 1;
168                         break;
169                 }
170         }
171         if(found && !parse_command_list[i].auth.function) {
172                 // reply 451 Register first.
173         } else if(found) {
174                 int argc;
175                 char **argv = parse_irc_params(data, &argc, parse_command_list[i].auth.max_argc);
176                 if(argc < parse_command_list[i].auth.min_argc) {
177                         // reply 461 Not enough parameters
178                 } else {
179                         int ret = parse_command_list[i].auth.function(auth, argv, argc);
180                         if(ret) {
181                                 // error occurred!
182                                 // do something?
183                         }
184                 }
185                 free(argv);
186         } else {
187                 // reply 421 Unknown command
188         }
189 }
190
191 /* Unicast                  Multicast                 Broadcast
192 * <src-srvnum> 4 Bytes      <source>     4 Bytes      <source>     4 Bytes
193 * <length>     2 Bytes      <length>     2 Bytes      <length>     2 Bytes
194 * <flags>      1 Byte       <flags>      1 Byte       <flags>      1 Byte
195 * <token>      x Bytes      <token>      x Bytes      <token>      x Bytes
196 * " "          1 Byte       " "          1 Byte       " "          1 Byte
197 * <dst-srvnum> 4 Bytes      <servers>    1 Byte       <ttl>        1 Byte
198 *                           <dst-srv01>  4 Bytes      
199 *                           <dst-srv02>  4 Bytes      
200 * <args>                    <args>                    <args>
201 */
202 void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer) {
203         struct ServerMsg *srvmsg = &parse_static_srvmsg;
204         unsigned char *buf = (unsigned char *)buffer->buffer;
205         unsigned int buflen, require_more = 0;
206         int i;
207         
208         while(buffer->bufpos >= 9 && !require_more) { //require at least 9 Bytes
209                 srvmsg->source.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
210                 srvmsg->resolved_source = 0;
211                 srvmsg->msglen = ((buf[4] << 8) | buf[5]);
212                 srvmsg->msgflags = buf[6];
213                 srvmsg->msgtype  = (buf[6] & SERVERMSG_TYPEMASK);
214                 
215                 if(buffer->bufpos < srvmsg->msglen) {
216                         require_more = 1;
217                         break;
218                 }
219                 
220                 for(i = 0; buffer->bufpos > i+7; i++) {
221                         if(buf[i+7] == ' ') {
222                                 if(i >= MAXSERVERTOKENLEN)
223                                         srvmsg->token[MAXSERVERTOKENLEN] = '\0';
224                                 else
225                                         srvmsg->token[i] = '\0';
226                                 break;
227                         }
228                         if(i >= MAXSERVERTOKENLEN)
229                                 continue;
230                         srvmsg->token[i] = buf[i+7];
231                 }
232                 if(buf[i+7] != ' ') {
233                         require_more = 1;
234                         break;
235                 }
236                 buf += i+8;
237                 buflen = buffer->bufpos - (i+8);
238                 
239                 switch(srvmsg->msgtype) {
240                 case SERVERMSG_TYPE_UNICAST:
241                         if(buflen < 4) {
242                                 require_more = 1;
243                                 break;
244                         }
245                         srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap));
246                         srvmsg->destinations->dstcount = 1;
247                         srvmsg->destinations->dst[0].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
248                         srvmsg->destinations->dst[0].resolved_destination = 0;
249                         break;
250                 case SERVERMSG_TYPE_MULTICAST:
251                         if(buflen < 5) {
252                                 require_more = 1;
253                                 break;
254                         }
255                         unsigned int srvcount = buf[0];
256                         buf++;
257                         buflen--;
258                         if(buflen < (srvcount * 4)) {
259                                 require_more = 1;
260                                 break;
261                         }
262                         srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap) + (sizeof(struct ServerMsgDestination) * (srvcount - 1)));
263                         srvmsg->destinations->dstcount = srvcount;
264                         for(i = 0; i < srvcount; i++) {
265                                 srvmsg->destinations->dst[i].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
266                                 srvmsg->destinations->dst[i].resolved_destination = 0;
267                                 buf += 4;
268                                 buflen -= 4;
269                         }
270                         break;
271                 case SERVERMSG_TYPE_BROADCAST:
272                         if(buflen == 0) {
273                                 require_more = 1;
274                                 break;
275                         }
276                         srvmsg->destinations = NULL;
277                         srvmsg->msgttl = buf[0];
278                         buf++;
279                         buflen--;
280                         break;
281                 default:
282                         // PARSE ERROR
283                         goto parse_server_data_finish;
284                 }
285                 
286                 srvmsg->arglen = srvmsg->msglen - (buf - (unsigned char *)buffer->buffer);
287                 srvmsg->args = buf;
288                 
289                 int found = 0;
290                 for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
291                         if(stricmp(parse_command_list[i].tokens.server, srvmsg->token)) {
292                                 found = 1;
293                                 break;
294                         }
295                 }
296                 if(!found)
297                         goto parse_server_data_finish;
298                 
299                 //exec command function
300                 
301         
302                 parse_server_data_finish:
303                 if(srvmsg->destinations)
304                         free(srvmsg->destinations);
305                 
306                 if(srvmsg->msglen > buffer->bufpos) {
307                         memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos);
308                         buffer->bufpos -= srvmsg->msglen;
309                 } else 
310                         buffer->bufpos = 0;
311         }
312 }
313