1 /* QServer.c - NeonServ v5.6
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"
27 #include "IOHandler.h"
31 typedef uint32_t socklen_t;
34 #define QSERVER_TIMEOUT 30
35 #define QSERVER_MAXCLIENTS 100
37 #define QSERVER_FLAG_AUTHED 0x01
38 #define QSERVER_FLAG_IN_USE 0x02
40 struct QServerClient {
41 struct IODescriptor *iofd;
44 struct QServerClient *next;
47 static struct IODescriptor *server_iofd = NULL;
48 struct QServerClient *qserver_clients = NULL;
49 static int qserver_clientcount = 0;
51 static IOHANDLER_CALLBACK(qserver_callback);
54 if(get_int_field("QServer.enabled")) {
55 char *host = get_string_field("QServer.host");
58 int port = get_int_field("QServer.port");
61 server_iofd = iohandler_listen(host, port, qserver_callback);
68 struct QServerClient *client, *next;
69 for (client = qserver_clients; client; client = next) {
72 iohandler_close(client->iofd);
75 qserver_clients = NULL;
76 qserver_clientcount = 0;
77 iohandler_close(server_iofd);
81 static int qserver_write(struct QServerClient *client, char* msg, int len) {
82 if (!client || !client->iofd) return 0;
85 iohandler_send(client->iofd, msg, len);
89 static void qserver_put(struct QServerClient *client, const char *text, ...) {
93 if (!client || !client->iofd) return;
95 va_start(arg_list, text);
96 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
98 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
100 sendBuf[pos+1] = '\0';
101 qserver_write(client, sendBuf, pos+1);
104 static void qserver_update_lastmsg(struct QServerClient *client) {
105 struct timeval timeout;
106 gettimeofday(&timeout, NULL);
107 timeout.tv_sec += QSERVER_TIMEOUT;
108 iohandler_set_timeout(client->iofd, &timeout);
111 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
112 if(client->flags & QSERVER_FLAG_AUTHED) {
113 qserver_put(client, "E :Already Authed");
117 qserver_put(client, "E :Missing Parameter");
120 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
121 qserver_put(client, "E :Wrong Password");
124 client->flags |= QSERVER_FLAG_AUTHED;
125 qserver_update_lastmsg(client);
126 qserver_put(client, "A :Logged in");
129 #define QSERVER_COMMAND_HEADER {\
130 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
131 qserver_put(client, "E :Not Authed");\
134 qserver_update_lastmsg(client);\
137 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
138 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
139 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
140 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
141 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
143 static void qserver_parse(struct QServerClient *client, char *line) {
145 char *argv[MAXNUMPARAMS];
147 //skip leading spaces
151 //the rest is a single parameter
152 argv[argc++] = line + 1;
156 if (argc >= MAXNUMPARAMS)
158 while (*line != ' ' && *line)
161 if(!stricmp(argv[0], "A")) //AUTH
162 qserver_parse_A(client, argv+1, argc-1);
163 else if(!stricmp(argv[0], "U")) //get User
164 qserver_parse_U(client, argv+1, argc-1);
165 else if(!stricmp(argv[0], "C")) //get Channel
166 qserver_parse_C(client, argv+1, argc-1);
167 else if(!stricmp(argv[0], "AC")) //get All Channels
168 qserver_parse_AC(client, argv+1, argc-1);
169 else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
170 qserver_parse_ACU(client, argv+1, argc-1);
171 else if(!stricmp(argv[0], "R")) //RAW
172 qserver_parse_R(client, argv+1, argc-1);
174 qserver_put(client, "E :Unknown Command");
177 static void qserver_accept(int sockfd) {
178 struct IODescriptor *client_iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, qserver_callback);
179 client_iofd->state = IO_CONNECTED;
180 iohandler_update(client_iofd);
181 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
182 iohandler_printf(client_iofd, "E :Maximum QServer Connections reached");
183 iohandler_close(client_iofd);
186 struct QServerClient *client = malloc(sizeof(*client));
187 client->iofd = client_iofd;
188 client->references = 0;
189 client->next = qserver_clients;
190 qserver_clients = client;
191 qserver_clientcount++;
194 static void qserver_cleanup() {
195 struct QServerClient *client, *next, *prev = NULL;
196 for (client = qserver_clients; client; client = next) {
198 if(client->iofd == NULL && !(client->flags & QSERVER_FLAG_IN_USE)) {
200 prev->next = client->next;
202 qserver_clients = client->next;
203 qserver_clientcount--;
209 static IOHANDLER_CALLBACK(qserver_callback) {
210 struct QServerClient *client = event->iofd->data;
211 switch(event->type) {
212 case IOEVENT_TIMEOUT:
213 qserver_put(client, "E :Timeout");
217 qserver_parse(client, event->data.recv_str);
220 iohandler_close(client->iofd);
224 qserver_accept(event->data.accept_fd);
236 static USERAUTH_CALLBACK(qserver_parse_U_async);
237 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
238 QSERVER_COMMAND_HEADER;
240 qserver_put(client, "E :Missing Parameter");
243 struct UserNode *cuser = getUserByNick(argv[0]);
245 cuser = createTempUser(argv[0]);
247 qserver_put(client, "U 0 :Unknown User");
250 cuser->flags |= USERFLAG_ISTMPUSER;
252 client->references++;
253 client->flags |= QSERVER_FLAG_IN_USE;
254 get_userauth(cuser, 0, qserver_parse_U_async, client);
257 static USERAUTH_CALLBACK(qserver_parse_U_async) {
258 struct QServerClient *qclient = data;
259 qclient->references--;
260 if(!qclient->references)
261 qclient->flags &= ~QSERVER_FLAG_IN_USE;
263 qserver_put(qclient, "U 0 :Unknown User");
266 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);
269 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
270 QSERVER_COMMAND_HEADER;
272 qserver_put(client, "E :Missing Parameter");
275 struct ChanNode *chan = getChanByName(argv[0]);
277 qserver_put(client, "C 0 :Unknown Channel");
281 getModeString(chan->modes, tmpStr);
282 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
285 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
286 QSERVER_COMMAND_HEADER;
287 struct ChanNode *chan;
289 for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
290 getModeString(chan->modes, tmpStr);
291 qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
293 qserver_put(client, "ACE"); //AllChannelsEnd
296 static USERLIST_CALLBACK(qserver_parse_ACU_async);
297 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
298 QSERVER_COMMAND_HEADER;
300 qserver_put(client, "E :Missing Parameter");
303 struct ChanNode *chan = getChanByName(argv[0]);
305 qserver_put(client, "ACUE 0 :Unknown Channel");
308 if(argc > 1 && !stricmp(argv[1], "1")) {
309 client->references++;
310 client->flags |= QSERVER_FLAG_IN_USE;
311 get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
316 struct ChanUser *chanuser;
317 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
319 if(chanuser->flags & CHANUSERFLAG_OPPED)
320 tmpStr[tmpStrPos++] = '@';
321 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
322 tmpStr[tmpStrPos++] = '%';
323 if(chanuser->flags & CHANUSERFLAG_VOICED)
324 tmpStr[tmpStrPos++] = '+';
325 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
326 tmpStr[tmpStrPos++] = '<';
327 tmpStr[tmpStrPos] = '\0';
328 qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
330 qserver_put(client, "ACUE 1");
333 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
334 struct QServerClient *qclient = data;
335 qclient->references--;
336 if(!qclient->references)
337 qclient->flags &= ~QSERVER_FLAG_IN_USE;
340 struct ChanUser *chanuser;
341 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
343 if(chanuser->flags & CHANUSERFLAG_OPPED)
344 tmpStr[tmpStrPos++] = '@';
345 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
346 tmpStr[tmpStrPos++] = '%';
347 if(chanuser->flags & CHANUSERFLAG_VOICED)
348 tmpStr[tmpStrPos++] = '+';
349 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
350 tmpStr[tmpStrPos++] = '<';
351 tmpStr[tmpStrPos] = '\0';
352 qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
354 qserver_put(qclient, "ACUE 1");
357 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
358 QSERVER_COMMAND_HEADER;
360 qserver_put(client, "E :Missing Parameter");
363 struct ClientSocket *bot;
364 if(!strcmp(argv[0], "1")) {
365 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
366 if(!stricmp(bot->user->nick, argv[1])) break;
369 struct ClientSocket *low_bot;
370 int botid = resolve_botalias(argv[1]);
372 botid = atoi(argv[1]);
373 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
374 if(bot->botid == botid) {
375 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
383 qserver_put(client, "R 0 :Bot not found");
386 putsock(bot, "%s", argv[2]);
387 qserver_put(client, "R 1");