1 /* QServer.c - NeonServ v5.3
2 * Copyright (C) 2011-2012 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/>.
23 #include "ClientSocket.h"
24 #include "WHOHandler.h"
25 #include "ConfigParser.h"
29 typedef uint32_t socklen_t;
32 #define QSERVER_TIMEOUT 30
33 #define QSERVER_MAXCLIENTS 100
35 #define QSERVER_FLAG_DISCONNECT 0x01
36 #define QSERVER_FLAG_AUTHED 0x02
37 #define QSERVER_FLAG_IN_USE 0x04
39 struct QServerClient {
46 struct QServerClient *next;
49 static int server_sockfd = 0;
50 struct QServerClient *qserver_clients = NULL;
51 static int qserver_clientcount = 0;
54 if(get_int_field("QServer.enabled")) {
55 server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
56 if (server_sockfd < 0)
58 struct sockaddr_in serv_addr;
59 memset(&serv_addr, 0, sizeof(serv_addr));
60 int portno = get_int_field("QServer.port");
63 serv_addr.sin_family = AF_INET;
64 serv_addr.sin_addr.s_addr = INADDR_ANY;
65 serv_addr.sin_port = htons(portno);
66 if (bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
68 listen(server_sockfd,5);
72 static int qserver_write(struct QServerClient *client, char* msg, int len) {
73 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
77 send(client->sock, msg, len, 0);
79 write(client->sock, msg, len);
84 static void qserver_put(struct QServerClient *client, const char *text, ...) {
88 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
90 va_start(arg_list, text);
91 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
93 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
95 sendBuf[pos+1] = '\0';
96 qserver_write(client, sendBuf, pos+1);
99 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
100 if(client->flags & QSERVER_FLAG_AUTHED) {
101 qserver_put(client, "E :Already Authed");
105 qserver_put(client, "E :Missing Parameter");
108 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
109 qserver_put(client, "E :Wrong Password");
112 client->flags |= QSERVER_FLAG_AUTHED;
113 client->lastmsg = time(0);
114 qserver_put(client, "A :Logged in");
117 #define QSERVER_COMMAND_HEADER {\
118 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
119 qserver_put(client, "E :Not Authed");\
122 client->lastmsg = time(0);\
125 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
126 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
127 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
128 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
129 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
131 static void qserver_parse(struct QServerClient *client, char *line, int len) {
133 char *argv[MAXNUMPARAMS];
135 //skip leading spaces
139 //the rest is a single parameter
140 argv[argc++] = line + 1;
144 if (argc >= MAXNUMPARAMS)
146 while (*line != ' ' && *line)
149 if(!stricmp(argv[0], "A")) //AUTH
150 qserver_parse_A(client, argv+1, argc-1);
151 else if(!stricmp(argv[0], "U")) //get User
152 qserver_parse_U(client, argv+1, argc-1);
153 else if(!stricmp(argv[0], "C")) //get Channel
154 qserver_parse_C(client, argv+1, argc-1);
155 else if(!stricmp(argv[0], "AC")) //get All Channels
156 qserver_parse_AC(client, argv+1, argc-1);
157 else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
158 qserver_parse_ACU(client, argv+1, argc-1);
159 else if(!stricmp(argv[0], "R")) //RAW
160 qserver_parse_R(client, argv+1, argc-1);
162 qserver_put(client, "E :Unknown Command");
165 void qserver_loop() {
166 if(!get_int_field("QServer.enabled"))
169 struct QServerClient *client, *next, *prev = NULL;
171 time_t now = time(0);
177 FD_SET(server_sockfd, &fds);
178 for (client = qserver_clients; client; client = next) {
180 if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
183 prev->next = client->next;
185 qserver_clients = client->next;
186 qserver_clientcount--;
191 if(client->flags & QSERVER_FLAG_DISCONNECT) continue;
192 if(now - client->lastmsg > QSERVER_TIMEOUT) {
193 qserver_put(client, "E :Timeout");
194 client->flags |= QSERVER_FLAG_DISCONNECT;
197 FD_SET(client->sock, &fds);
198 if(client->sock > ret)
201 ret = select(ret + 1, &fds, NULL, NULL, &tv);
205 if(FD_ISSET(server_sockfd, &fds)) {
207 struct sockaddr_in cli_addr;
209 client = malloc(sizeof(*client));
210 clilen = sizeof(cli_addr);
211 client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
213 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
214 qserver_put(client, "E :Maximum QServer Connections reached");
218 client->lastmsg = now;
219 client->bufferpos = 0;
220 client->references = 0;
221 client->next = qserver_clients;
222 qserver_clients = client;
223 qserver_clientcount++;
228 for (client = qserver_clients; client; client = next) {
230 if(FD_ISSET(client->sock, &fds)) {
232 bytes = recv(client->sock, buffer, sizeof(buffer), 0);
234 bytes = read(client->sock, buffer, sizeof(buffer));
237 client->flags |= QSERVER_FLAG_DISCONNECT;
240 for(i = 0; i < bytes; i++) {
241 if(client->bufferpos == MAXLEN-1) {
243 qserver_put(client, "E :Buffer Overflow");
244 client->flags |= QSERVER_FLAG_DISCONNECT;
247 if(buffer[i] == '\r') continue;
248 else if(buffer[i] == '\n') {
249 client->buffer[client->bufferpos] = '\0';
250 qserver_parse(client, client->buffer, client->bufferpos);
251 client->bufferpos = 0;
253 client->buffer[client->bufferpos++] = buffer[i];
260 void qserver_free() {
261 struct QServerClient *client, *next;
262 for (client = qserver_clients; client; client = next) {
267 qserver_clients = NULL;
268 qserver_clientcount = 0;
269 close(server_sockfd);
276 static USERAUTH_CALLBACK(qserver_parse_U_async);
277 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
278 QSERVER_COMMAND_HEADER;
280 qserver_put(client, "E :Missing Parameter");
283 struct UserNode *cuser = getUserByNick(argv[0]);
285 cuser = createTempUser(argv[0]);
287 qserver_put(client, "U 0 :Unknown User");
290 cuser->flags |= USERFLAG_ISTMPUSER;
292 client->references++;
293 client->flags |= QSERVER_FLAG_IN_USE;
294 get_userauth(cuser, qserver_parse_U_async, client);
297 static USERAUTH_CALLBACK(qserver_parse_U_async) {
298 struct QServerClient *qclient = data;
299 qclient->references--;
300 if(!qclient->references)
301 qclient->flags &= ~QSERVER_FLAG_IN_USE;
303 qserver_put(qclient, "U 0 :Unknown User");
306 qserver_put(qclient, "U 1 %s %s %s %s :%s", user->nick, user->ident, user->host, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "0"), user->realname);
309 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
310 QSERVER_COMMAND_HEADER;
312 qserver_put(client, "E :Missing Parameter");
315 struct ChanNode *chan = getChanByName(argv[0]);
317 qserver_put(client, "C 0 :Unknown Channel");
321 getModeString(chan->modes, tmpStr);
322 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
325 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
326 QSERVER_COMMAND_HEADER;
327 struct ChanNode *chan;
329 for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
330 getModeString(chan->modes, tmpStr);
331 qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
333 qserver_put(client, "ACE"); //AllChannelsEnd
336 static USERLIST_CALLBACK(qserver_parse_ACU_async);
337 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
338 QSERVER_COMMAND_HEADER;
340 qserver_put(client, "E :Missing Parameter");
343 struct ChanNode *chan = getChanByName(argv[0]);
345 qserver_put(client, "ACUE 0 :Unknown Channel");
348 if(argc > 1 && !stricmp(argv[1], "1")) {
349 client->references++;
350 client->flags |= QSERVER_FLAG_IN_USE;
351 get_userlist_if_invisible(chan, qserver_parse_ACU_async, client);
356 struct ChanUser *chanuser;
357 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
359 if(chanuser->flags & CHANUSERFLAG_OPPED)
360 tmpStr[tmpStrPos++] = '@';
361 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
362 tmpStr[tmpStrPos++] = '%';
363 if(chanuser->flags & CHANUSERFLAG_VOICED)
364 tmpStr[tmpStrPos++] = '+';
365 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
366 tmpStr[tmpStrPos++] = '<';
367 tmpStr[tmpStrPos] = '\0';
368 qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
370 qserver_put(client, "ACUE 1");
373 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
374 struct QServerClient *qclient = data;
375 qclient->references--;
376 if(!qclient->references)
377 qclient->flags &= ~QSERVER_FLAG_IN_USE;
380 struct ChanUser *chanuser;
381 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
383 if(chanuser->flags & CHANUSERFLAG_OPPED)
384 tmpStr[tmpStrPos++] = '@';
385 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
386 tmpStr[tmpStrPos++] = '%';
387 if(chanuser->flags & CHANUSERFLAG_VOICED)
388 tmpStr[tmpStrPos++] = '+';
389 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
390 tmpStr[tmpStrPos++] = '<';
391 tmpStr[tmpStrPos] = '\0';
392 qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
394 qserver_put(qclient, "ACUE 1");
397 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
398 QSERVER_COMMAND_HEADER;
400 qserver_put(client, "E :Missing Parameter");
403 struct ClientSocket *bot;
404 if(!strcmp(argv[0], "1")) {
405 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
406 if(!stricmp(bot->user->nick, argv[1])) break;
409 struct ClientSocket *low_bot;
410 int botid = resolve_botalias(argv[1]);
412 botid = atoi(argv[1]);
413 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
414 if(bot->botid == botid) {
415 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
423 qserver_put(client, "R 0 :Bot not found");
426 putsock(bot, "%s", argv[2]);
427 qserver_put(client, "R 1");