1 /* ircd_client.c - NextIRCd
2 * Copyright (C) 2012-2013 Philipp Kreil (pk910)
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.
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.
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/>.
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"
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);
32 static struct ServerMsg parse_static_srvmsg;
34 #define PARSE_CLIFLAG_OPONLY 0x01
36 //include all commands
46 cmd_client_t *function;
47 unsigned int min_argc : 8;
48 unsigned int max_argc : 8;
49 unsigned int flags : 8;
53 unsigned int min_argc : 8;
54 unsigned int max_argc : 8;
55 unsigned int flags : 8;
58 cmd_server_t *function;
59 unsigned int min_argc : 8;
60 unsigned int max_argc : 8;
61 unsigned int flags : 8;
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 */
70 {{"PASS", NULL}, /* PASS Command */
71 {NULL, 0, 1, 0}, /* Client */
72 {NULL, 0, 1, 0}, /* Unauthed */
73 {NULL, 0, 1, 0} /* Server */
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 */
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 */
86 {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}}
89 static char *parse_irc_token(char **data) {
93 for(i = 0; (*data)[i]; i++) {
94 if((*data)[i] == ' ') {
103 static char **parse_irc_params(char *data, int *argc, int maxargs) {
107 char **argv = calloc(maxargs, sizeof(*argv));
109 //skip leading spaces
113 //the rest is a single parameter
114 argv[*argc++] = data + 1;
117 argv[(*argc)++] = data;
118 if (*argc >= maxargs)
120 while (*data != ' ' && *data)
126 /* Client Data Format
127 * <TOKEN> <arg1> <arg2>
129 void parse_client_data(struct Client *client, char *data) {
130 char *token = parse_irc_token(&data);
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) == 0) {
139 if(found && !parse_command_list[i].client.function) {
140 // reply 462 You may not reregister
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
147 int ret = parse_command_list[i].client.function(client, argv, argc);
155 // reply 421 Unknown command
159 void parse_unauth_data(struct Auth *auth, char *data) {
160 char *token = parse_irc_token(&data);
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) == 0) {
169 if(found && !parse_command_list[i].auth.function) {
170 // reply 451 Register first.
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
177 int ret = parse_command_list[i].auth.function(auth, argv, argc);
185 // reply 421 Unknown command
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>
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;
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);
213 if(buffer->bufpos < srvmsg->msglen) {
218 for(i = 0; buffer->bufpos > i+7; i++) {
219 if(buf[i+7] == ' ') {
220 if(i >= MAXSERVERTOKENLEN)
221 srvmsg->token[MAXSERVERTOKENLEN] = '\0';
223 srvmsg->token[i] = '\0';
226 if(i >= MAXSERVERTOKENLEN)
228 srvmsg->token[i] = buf[i+7];
230 if(buf[i+7] != ' ') {
235 buflen = buffer->bufpos - (i+8);
237 switch(srvmsg->msgtype) {
238 case SERVERMSG_TYPE_UNICAST:
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;
248 case SERVERMSG_TYPE_MULTICAST:
253 unsigned int srvcount = buf[0];
256 if(buflen < (srvcount * 4)) {
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;
269 case SERVERMSG_TYPE_BROADCAST:
274 srvmsg->destinations = NULL;
275 srvmsg->msgttl = buf[0];
281 goto parse_server_data_finish;
284 srvmsg->arglen = srvmsg->msglen - (buf - (unsigned char*)buffer->buffer);
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)) {
295 goto parse_server_data_finish;
297 //exec command function
300 parse_server_data_finish:
301 if(srvmsg->destinations)
302 free(srvmsg->destinations);
304 if(srvmsg->msglen > buffer->bufpos) {
305 memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos);
306 buffer->bufpos -= srvmsg->msglen;