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