--- /dev/null
+/* ircd_client.c - NextIRCd
+ * Copyright (C) 2012-2013 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tools.h"
+#include "IOHandler/IOSockets.h"
+
+typedef int cmd_client_t(struct Client *client, char *argv[], int argc);
+typedef int cmd_auth_t(struct Auth *auth, char *argv[], int argc);
+typedef int cmd_server_t(struct Server *server, char *argv[], int argc);
+
+static struct ServerMsg parse_static_srvmsg;
+
+#define PARSE_CLIFLAG_OPONLY 0x01
+
+//include all commands
+#include "cmd_ping.h"
+
+
+struct {
+ struct {
+ const char *client;
+ const char *server;
+ } tokens;
+ struct {
+ cmd_client_t *function;
+ unsigned int min_argc : 8;
+ unsigned int max_argc : 8;
+ unsigned int flags : 8;
+ } client;
+ struct {
+ cmd_auth_t *function;
+ unsigned int min_argc : 8;
+ unsigned int max_argc : 8;
+ unsigned int flags : 8;
+ } auth;
+ struct {
+ cmd_server_t *function;
+ unsigned int min_argc : 8;
+ unsigned int max_argc : 8;
+ unsigned int flags : 8;
+ } server;
+
+} parse_command_list {
+ {{"PING", "P"}, /* Ping Command */
+ {NULL, 0, 1, 0}, /* Client */
+ {NULL, 0, 1, 0}, /* Unauthed */
+ {NULL, 0, 1, 0} /* Server */
+ },
+
+ {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}}
+};
+
+static char *parse_irc_token(char **data) {
+ //find next " "
+ int i;
+ char *token = *data;
+ for(i = 0; *data[i]; i++) {
+ if(*data[i] != ' ') {
+ *data[i] = '\0';
+ *data += i+1;
+ break;
+ }
+ }
+ return token;
+}
+
+static char **parse_irc_params(char *data, int *argc, int maxargs) {
+ if(maxargs == 0) {
+ *argc = 0;
+ return NULL;
+ }
+ char **argv = calloc(maxargs, sizeof(*argv));
+ while(*data) {
+ //skip leading spaces
+ while (*line == ' ')
+ *line++ = 0;
+ if (*line == ':') {
+ //the rest is a single parameter
+ argv[*argc++] = line + 1;
+ break;
+ }
+ argv[*argc++] = line;
+ if (argc >= maxargs)
+ break;
+ while (*line != ' ' && *line)
+ line++;
+ }
+ return argv;
+}
+
+/* Client Data Format
+* <TOKEN> <arg1> <arg2>
+*/
+void parse_client_data(struct Client *client, char *data) {
+ char *token = parse_irc_token(&data);
+ int found = 0;
+ int i;
+ for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) {
+ if(stricmp(parse_command_list[i].tokens.client, token)) {
+ found = 1;
+ break;
+ }
+ }
+ if(found && !parse_command_list[i].client.function) {
+ // reply 462 You may not reregister
+ } else if(found) {
+ int argc;
+ char **argv = parse_irc_params(data, &argc, parse_command_list[i].client.max_argc);
+ if(argc < parse_command_list[i].client.min_argc) {
+ // reply 461 Not enough parameters
+ } else {
+ int ret = parse_command_list[i].client.function(client, argv, argc);
+ if(ret) {
+ // error occurred!
+ // do something?
+ }
+ }
+ free(argv);
+ } else {
+ // reply 421 Unknown command
+ }
+}
+
+void parse_unauth_data(struct Auth *auth, char *data) {
+ char *token = parse_irc_token(&data);
+ int found = 0;
+ int i;
+ for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) {
+ if(stricmp(parse_command_list[i].tokens.client, token)) {
+ found = 1;
+ break;
+ }
+ }
+ if(found && !parse_command_list[i].auth.function) {
+ // reply 451 Register first.
+ } else if(found) {
+ int argc;
+ char **argv = parse_irc_params(data, &argc, parse_command_list[i].auth.max_argc);
+ if(argc < parse_command_list[i].auth.min_argc) {
+ // reply 461 Not enough parameters
+ } else {
+ int ret = parse_command_list[i].auth.function(auth, argv, argc);
+ if(ret) {
+ // error occurred!
+ // do something?
+ }
+ }
+ free(argv);
+ } else {
+ // reply 421 Unknown command
+ }
+}
+
+/* Unicast Multicast Broadcast
+* <src-srvnum> 4 Bytes <source> 4 Bytes <source> 4 Bytes
+* <length> 2 Bytes <length> 2 Bytes <length> 2 Bytes
+* <flags> 1 Byte <flags> 1 Byte <flags> 1 Byte
+* <token> x Bytes <token> x Bytes <token> x Bytes
+* " " 1 Byte " " 1 Byte " " 1 Byte
+* <dst-srvnum> 4 Bytes <servers> 1 Byte <ttl> 1 Byte
+* <dst-srv01> 4 Bytes
+* <dst-srv02> 4 Bytes
+* <args> <args> <args>
+*/
+void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer) {
+ struct ServerMsg *srvmsg = &parse_static_srvmsg;
+ unsigned char *buf = (unsigned char *)buffer->buffer;
+ unsigned int buflen, require_more = 0;
+ int i;
+
+ while(buffer->bufpos >= 9 && !require_more) { //require at least 9 Bytes
+ srvmsg->source.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+ srvmsg->resolved_source = 0;
+ srvmsg->msglen = ((buf[4] << 8) | buf[5]);
+ srvmsg->msgflags = buf[6];
+ srvmsg->msgtype = (buf[6] & SERVERMSG_TYPEMASK);
+
+ if(buffer->bufpos < srvmsg->msglen) {
+ require_more = 1;
+ break;
+ }
+
+ for(i = 0; buffer->bufpos > i+7; i++) {
+ if(buf[i+7] == ' ') {
+ if(i >= MAXSERVERTOKENLEN)
+ srvmsg->token[MAXSERVERTOKENLEN] = '\0';
+ else
+ srvmsg->token[i] = '\0';
+ break;
+ }
+ if(i >= MAXSERVERTOKENLEN)
+ continue;
+ srvmsg->token[i] = buf[i+7];
+ }
+ if(buf[i+7] != ' ') {
+ require_more = 1;
+ break;
+ }
+ buf += i+8;
+ buflen = buffer->bufpos - (i+8);
+
+ switch(srvmsg->msgtype) {
+ case SERVERMSG_TYPE_UNICAST:
+ if(buflen < 4) {
+ require_more = 1;
+ break;
+ }
+ srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap));
+ srvmsg->destinations->dstcount = 1;
+ srvmsg->destinations->dst[0].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+ srvmsg->destinations->dst[0].destination.resolved_destination = 0;
+ break;
+ case SERVERMSG_TYPE_MULTICAST:
+ if(buflen < 5) {
+ require_more = 1;
+ break;
+ }
+ unsigned int srvcount = buf[0];
+ buf++;
+ buflen--;
+ if(buflen < (srvcount * 4)) {
+ require_more = 1;
+ break;
+ }
+ srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap) + (sizeof(struct ServerMsgDestination) * (srvcount - 1)));
+ srvmsg->destinations->dstcount = srvcount;
+ for(i = 0; i < srvcount; i++) {
+ srvmsg->destinations->dst[i].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+ srvmsg->destinations->dst[i].destination.resolved_destination = 0;
+ buf += 4;
+ buflen -= 4;
+ }
+ break;
+ case SERVERMSG_TYPE_BROADCAST:
+ if(buflen == 0) {
+ require_more = 1;
+ break;
+ }
+ srvmsg->destinations = NULL;
+ srvmsg->msgttl = buf[0];
+ buf++;
+ buflen--;
+ break;
+ default:
+ // PARSE ERROR
+ goto parse_server_data_finish;
+ }
+
+ srvmsg->arglen = srvmsg->msglen - (buf - buffer->buffer);
+ srvmsg->args = buf;
+
+ int found = 0;
+ for(i = 0; (parse_command_list[i].tokens.client || parse_command_list[i].tokens.server); i++) {
+ if(stricmp(parse_command_list[i].tokens.server, srvmsg->token)) {
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ goto parse_server_data_finish;
+
+ //exec command function
+
+
+ parse_server_data_finish:
+ if(srvmsg->destinations)
+ free(srvmsg->destinations);
+
+ if(srvmsg->msglen > buffer->bufpos) {
+ memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos);
+ buffer->bufpos -= srvmsg->msglen;
+ } else
+ srvmsg->bufpos = 0;
+ }
+}
+
--- /dev/null
+/* struct_servermsg.h - NextIRCd
+ * Copyright (C) 2012-2013 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _struct_servermsg_h
+#define _struct_servermsg_h
+
+#define MAXSERVERTOKENLEN 5
+
+#define SERVERMSG_TYPE_UNICAST 0x01
+#define SERVERMSG_TYPE_MULTICAST 0x02
+#define SERVERMSG_TYPE_BROADCAST 0x03
+#define SERVERMSG_TYPEMASK 0x07
+#define SERVERMSG_FLAG_ENCRYPTED 0x08
+#define SERVERMSG_FLAGMASK 0xF8
+
+struct ServerMsgDestination {
+ union {
+ struct Server *server;
+ unsigned int srvnum;
+ } destination;
+ unsigned int resolved_destination : 1;
+};
+
+struct ServerMsgDstMap {
+ unsigned int dstcount : 8;
+ struct ServerMsgDestination dst[1];
+};
+
+struct ServerMsg {
+ union {
+ struct Server *server;
+ unsigned int srvnum;
+ } source;
+ unsigned int resolved_source : 1;
+
+ unsigned int msgtype : 3;
+ unsigned int msgflags : 8;
+ unsigned int msglen : 16;
+ unsigned int arglen : 16;
+ unsigned int msgttl : 8;
+
+ char token[MAXSERVERTOKENLEN+1];
+
+ struct ServerMsgDstMap *destinations;
+
+
+ unsigned char *args;
+};
+
+#endif