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"
30 typedef uint32_t socklen_t;
33 #define QSERVER_TIMEOUT 30
34 #define QSERVER_MAXCLIENTS 100
36 #define QSERVER_FLAG_AUTHED 0x01
37 #define QSERVER_FLAG_IN_USE 0x02
39 struct QServerClient {
40 struct IODescriptor *iofd;
43 struct QServerClient *next;
46 static struct IODescriptor *server_iofd = NULL;
47 struct QServerClient *qserver_clients = NULL;
48 static int qserver_clientcount = 0;
50 static IOHANDLER_CALLBACK(qserver_callback);
53 if(get_int_field("QServer.enabled")) {
54 char *host = get_string_field("QServer.host");
57 int port = get_int_field("QServer.port");
60 server_iofd = iohandler_listen(host, port, qserver_callback);
67 struct QServerClient *client, *next;
68 for (client = qserver_clients; client; client = next) {
71 iohandler_close(client->iofd);
74 qserver_clients = NULL;
75 qserver_clientcount = 0;
76 iohandler_close(server_iofd);
80 static int qserver_write(struct QServerClient *client, char* msg, int len) {
81 if (!client || !client->iofd) return 0;
84 iohandler_send(client->iofd, msg, len);
88 static void qserver_put(struct QServerClient *client, const char *text, ...) {
92 if (!client || !client->iofd) return;
94 va_start(arg_list, text);
95 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
97 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
99 sendBuf[pos+1] = '\0';
100 qserver_write(client, sendBuf, pos+1);
103 static void qserver_update_lastmsg(struct QServerClient *client) {
104 struct timeval timeout;
105 gettimeofday(&timeout, NULL);
106 timeout.tv_sec += QSERVER_TIMEOUT;
107 iohandler_set_timeout(client->iofd, &timeout);
110 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
111 if(client->flags & QSERVER_FLAG_AUTHED) {
112 qserver_put(client, "E :Already Authed");
116 qserver_put(client, "E :Missing Parameter");
119 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
120 qserver_put(client, "E :Wrong Password");
123 client->flags |= QSERVER_FLAG_AUTHED;
124 qserver_update_lastmsg(client);
125 qserver_put(client, "A :Logged in");
128 #define QSERVER_COMMAND_HEADER {\
129 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
130 qserver_put(client, "E :Not Authed");\
133 qserver_update_lastmsg(client);\
136 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
137 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
138 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
139 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
140 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
142 static void qserver_parse(struct QServerClient *client, char *line) {
144 char *argv[MAXNUMPARAMS];
146 //skip leading spaces
150 //the rest is a single parameter
151 argv[argc++] = line + 1;
155 if (argc >= MAXNUMPARAMS)
157 while (*line != ' ' && *line)
160 if(!stricmp(argv[0], "A")) //AUTH
161 qserver_parse_A(client, argv+1, argc-1);
162 else if(!stricmp(argv[0], "U")) //get User
163 qserver_parse_U(client, argv+1, argc-1);
164 else if(!stricmp(argv[0], "C")) //get Channel
165 qserver_parse_C(client, argv+1, argc-1);
166 else if(!stricmp(argv[0], "AC")) //get All Channels
167 qserver_parse_AC(client, argv+1, argc-1);
168 else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
169 qserver_parse_ACU(client, argv+1, argc-1);
170 else if(!stricmp(argv[0], "R")) //RAW
171 qserver_parse_R(client, argv+1, argc-1);
173 qserver_put(client, "E :Unknown Command");
176 static void qserver_accept(int sockfd) {
177 struct IODescriptor *client_iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, qserver_callback);
178 client_iofd->state = IO_CONNECTED;
179 iohandler_update(client_iofd);
180 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
181 iohandler_printf(client_iofd, "E :Maximum QServer Connections reached");
182 iohandler_close(client_iofd);
185 struct QServerClient *client = malloc(sizeof(*client));
186 client->iofd = client_iofd;
187 client->references = 0;
188 client->next = qserver_clients;
189 qserver_clients = client;
190 qserver_clientcount++;
193 static void qserver_cleanup() {
194 struct QServerClient *client, *next, *prev = NULL;
195 for (client = qserver_clients; client; client = next) {
197 if(client->iofd == NULL && !(client->flags & QSERVER_FLAG_IN_USE)) {
199 prev->next = client->next;
201 qserver_clients = client->next;
202 qserver_clientcount--;
208 static IOHANDLER_CALLBACK(qserver_callback) {
209 struct QServerClient *client = event->iofd->data;
210 switch(event->type) {
211 case IOEVENT_TIMEOUT:
212 qserver_put(client, "E :Timeout");
216 qserver_parse(client, event->data.recv_str);
219 iohandler_close(client->iofd);
223 qserver_accept(event->data.accept_fd);
235 static USERAUTH_CALLBACK(qserver_parse_U_async);
236 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
237 QSERVER_COMMAND_HEADER;
239 qserver_put(client, "E :Missing Parameter");
242 struct UserNode *cuser = getUserByNick(argv[0]);
244 cuser = createTempUser(argv[0]);
246 qserver_put(client, "U 0 :Unknown User");
249 cuser->flags |= USERFLAG_ISTMPUSER;
251 client->references++;
252 client->flags |= QSERVER_FLAG_IN_USE;
253 get_userauth(cuser, 0, qserver_parse_U_async, client);
256 static USERAUTH_CALLBACK(qserver_parse_U_async) {
257 struct QServerClient *qclient = data;
258 qclient->references--;
259 if(!qclient->references)
260 qclient->flags &= ~QSERVER_FLAG_IN_USE;
262 qserver_put(qclient, "U 0 :Unknown User");
265 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);
268 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
269 QSERVER_COMMAND_HEADER;
271 qserver_put(client, "E :Missing Parameter");
274 struct ChanNode *chan = getChanByName(argv[0]);
276 qserver_put(client, "C 0 :Unknown Channel");
280 getModeString(chan->modes, tmpStr);
281 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
284 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
285 QSERVER_COMMAND_HEADER;
286 struct ChanNode *chan;
288 for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
289 getModeString(chan->modes, tmpStr);
290 qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
292 qserver_put(client, "ACE"); //AllChannelsEnd
295 static USERLIST_CALLBACK(qserver_parse_ACU_async);
296 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
297 QSERVER_COMMAND_HEADER;
299 qserver_put(client, "E :Missing Parameter");
302 struct ChanNode *chan = getChanByName(argv[0]);
304 qserver_put(client, "ACUE 0 :Unknown Channel");
307 if(argc > 1 && !stricmp(argv[1], "1")) {
308 client->references++;
309 client->flags |= QSERVER_FLAG_IN_USE;
310 get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
315 struct ChanUser *chanuser;
316 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
318 if(chanuser->flags & CHANUSERFLAG_OPPED)
319 tmpStr[tmpStrPos++] = '@';
320 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
321 tmpStr[tmpStrPos++] = '%';
322 if(chanuser->flags & CHANUSERFLAG_VOICED)
323 tmpStr[tmpStrPos++] = '+';
324 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
325 tmpStr[tmpStrPos++] = '<';
326 tmpStr[tmpStrPos] = '\0';
327 qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
329 qserver_put(client, "ACUE 1");
332 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
333 struct QServerClient *qclient = data;
334 qclient->references--;
335 if(!qclient->references)
336 qclient->flags &= ~QSERVER_FLAG_IN_USE;
339 struct ChanUser *chanuser;
340 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
342 if(chanuser->flags & CHANUSERFLAG_OPPED)
343 tmpStr[tmpStrPos++] = '@';
344 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
345 tmpStr[tmpStrPos++] = '%';
346 if(chanuser->flags & CHANUSERFLAG_VOICED)
347 tmpStr[tmpStrPos++] = '+';
348 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
349 tmpStr[tmpStrPos++] = '<';
350 tmpStr[tmpStrPos] = '\0';
351 qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
353 qserver_put(qclient, "ACUE 1");
356 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
357 QSERVER_COMMAND_HEADER;
359 qserver_put(client, "E :Missing Parameter");
362 struct ClientSocket *bot;
363 if(!strcmp(argv[0], "1")) {
364 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
365 if(!stricmp(bot->user->nick, argv[1])) break;
368 struct ClientSocket *low_bot;
369 int botid = resolve_botalias(argv[1]);
371 botid = atoi(argv[1]);
372 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
373 if(bot->botid == botid) {
374 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
382 qserver_put(client, "R 0 :Bot not found");
385 putsock(bot, "%s", argv[2]);
386 qserver_put(client, "R 1");