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