]> jfr.im git - irc/evilnet/x3.git/blame - src/mod-qserver.c
Minor typo in previous commit where returning 0 when it should have been 1 from opser...
[irc/evilnet/x3.git] / src / mod-qserver.c
CommitLineData
1136f709 1/* Direct Query Server module for srvx 1.x
2 * Copyright 2006 Michael Poole <mdpoole@troilus.org>
3 *
4 * This file is part of srvx.
5 *
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
be2c97a5 8 * the Free Software Foundation; either version 3 of the License, or
1136f709 9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21#include "conf.h"
22#include "hash.h"
23#include "ioset.h"
24#include "log.h"
25#include "modcmd.h"
26#include "proto.h"
27
28const char *qserver_module_deps[] = { NULL };
29
30struct qserverClient {
31 struct userNode *user;
32 struct io_fd *fd;
33 unsigned int id;
34 unsigned int password_ok : 1;
35};
36
37static struct log_type *qserver_log;
38static struct io_fd *qserver_listener;
39static struct qserverClient **qserver_clients;
40static dict_t qserver_dict;
41static unsigned int qserver_nbots;
42
43static struct {
44 const char *password;
45} conf;
46
47static void
48qserver_privmsg(struct userNode *user, struct userNode *target, const char *text, UNUSED_ARG(int server_qualified))
49{
50 struct qserverClient *client;
51
52 client = dict_find(qserver_dict, target->nick, NULL);
53 assert(client->user == target);
54 ioset_printf(client->fd, "%s P :%s\n", user->nick, text);
55}
56
57static void
58qserver_notice(struct userNode *user, struct userNode *target, const char *text, UNUSED_ARG(int server_qualified))
59{
60 struct qserverClient *client;
61
62 client = dict_find(qserver_dict, target->nick, NULL);
63 assert(client->user == target);
64 ioset_printf(client->fd, "%s N :%s\n", user->nick, text);
65}
66
67static void
68qserver_readable(struct io_fd *fd)
69{
70 struct qserverClient *client;
71 struct service *service;
72 char *argv[MAXNUMPARAMS];
73 unsigned int argc;
74 size_t len;
75 int res;
76 char tmpline[MAXLEN];
77
78 client = fd->data;
79 assert(client->fd == fd);
80 res = ioset_line_read(fd, tmpline, sizeof(tmpline));
81 if (res < 0)
82 return;
83 else if (res == 0) {
84 ioset_close(fd, 1);
85 return;
86 }
87 len = strlen(tmpline);
88 while (tmpline[len - 1] == '\r' || tmpline[len - 1] == '\n')
89 tmpline[--len] = '\0';
90 argc = split_line(tmpline, false, ArrayLength(argv), argv);
91 if (argc < 3) {
92 ioset_printf(fd, "MISSING_ARGS\n");
93 return;
94 }
95 if (!strcmp(argv[1], "PASS")
96 && conf.password
97 && !strcmp(argv[2], conf.password)) {
98 client->password_ok = 1;
99 } else if ((client->password_ok || !conf.password)
100 && (service = service_find(argv[1])) != NULL) {
101 ioset_printf(fd, "%s S\n", argv[0]);
102 svccmd_invoke_argv(client->user, service, NULL, argc - 2, argv + 2, 1);
103 ioset_printf(fd, "%s E\n", argv[0]);
104 } else {
105 ioset_printf(fd, "%s X %s\n", argv[0], argv[1]);
106 }
107}
108
109static void
110qserver_destroy_fd(struct io_fd *fd)
111{
112 struct qserverClient *client;
113
114 client = fd->data;
115 assert(client->fd == fd);
116 dict_remove(qserver_dict, client->user->nick);
117 DelUser(client->user, NULL, 0, "client disconnected");
118 qserver_clients[client->id] = NULL;
119 free(client);
120}
121
122static void
123qserver_accept(UNUSED_ARG(struct io_fd *listener), struct io_fd *fd)
124{
125 struct qserverClient *client;
126 struct sockaddr_storage ss;
127 socklen_t sa_len;
128 unsigned int ii;
129 unsigned int jj;
130 int res;
131 char nick[NICKLEN+1];
132 char host[HOSTLEN+1];
133 char ip[HOSTLEN+1];
134
135 client = calloc(1, sizeof(*client));
136 fd->data = client;
137 fd->line_reads = 1;
138 fd->readable_cb = qserver_readable;
139 fd->destroy_cb = qserver_destroy_fd;
140
141 for (ii = 0; ii < qserver_nbots; ++ii)
142 if (qserver_clients[ii] == NULL)
143 break;
144 if (ii == qserver_nbots) {
145 qserver_nbots += 8;
146 qserver_clients = realloc(qserver_clients, qserver_nbots * sizeof(qserver_clients[0]));
147 for (jj = ii; jj < qserver_nbots; ++jj)
148 qserver_clients[jj] = NULL;
149 }
150 client->id = ii;
151 client->fd = fd;
152 qserver_clients[client->id] = client;
153 snprintf(nick, sizeof(nick), " QServ%04d", client->id);
154 safestrncpy(host, "srvx.dummy.user", sizeof(host));
155 safestrncpy(ip, "0.0.0.0", sizeof(ip));
156 sa_len = sizeof(ss);
157 res = getpeername(fd->fd, (struct sockaddr*)&ss, &sa_len);
158 if (res == 0) {
159 getnameinfo((struct sockaddr*)&ss, sa_len, ip, sizeof(host), NULL, 0, NI_NUMERICHOST);
160 if (getnameinfo((struct sockaddr*)&ss, sa_len, host, sizeof(host), NULL, 0, 0) != 0)
161 safestrncpy(host, ip, sizeof(host));
162 }
163 client->user = AddLocalUser(nick, nick+1, host, "qserver dummy user", "*+oi");
164 irc_pton(&client->user->ip, NULL, ip);
165 dict_insert(qserver_dict, client->user->nick, client);
166
167 reg_privmsg_func(client->user, qserver_privmsg);
168 reg_notice_func(client->user, qserver_notice);
169}
170
171static void
172qserver_conf_read(void)
173{
174 struct addrinfo hints;
175 struct addrinfo *ai;
176 dict_t node;
177 const char *str1;
178 const char *str2;
179 int res;
180
181 ioset_close(qserver_listener, 1);
182 qserver_listener = NULL;
183 node = conf_get_data("modules/qserver", RECDB_OBJECT);
184 if (!node)
185 return;
186 str1 = database_get_data(node, "bind_address", RECDB_QSTRING);
187 if (!str1)
188 str1 = database_get_data(node, "address", RECDB_QSTRING);
189 str2 = database_get_data(node, "port", RECDB_QSTRING);
190 if (!str2)
191 return;
192 memset(&hints, 0, sizeof(hints));
193 hints.ai_flags = AI_PASSIVE;
194 hints.ai_socktype = SOCK_STREAM;
195 res = getaddrinfo(str1, str2, &hints, &ai);
196 if (res) {
197 log_module(qserver_log, LOG_ERROR, "Unable to find address [%s]:%s: %s", str1 ? str1 : "", str2, gai_strerror(res));
198 } else if (!(qserver_listener = ioset_listen(ai->ai_addr, ai->ai_addrlen, NULL, qserver_accept))) {
199 log_module(qserver_log, LOG_ERROR, "Unable to listen on [%s]:%s", str1 ? str1 : "", str2);
200 }
201 conf.password = database_get_data(node, "password", RECDB_QSTRING);
202 freeaddrinfo(ai);
203}
204
205void
30874d66 206qserver_cleanup(UNUSED_ARG(void *extra))
1136f709 207{
208 unsigned int ii;
209
210 ioset_close(qserver_listener, 1);
211 for (ii = 0; ii < qserver_nbots; ++ii)
212 if (qserver_clients[ii])
213 DelUser(qserver_clients[ii]->user, NULL, 0, "module finalizing");
214 dict_delete(qserver_dict);
215}
216
217int
218qserver_init(void)
219{
220 qserver_log = log_register_type("QServer", "file:qserver.log");
221 conf_register_reload(qserver_conf_read);
222 qserver_dict = dict_new();
30874d66 223 reg_exit_func(qserver_cleanup, NULL);
1136f709 224 return 1;
225}
226
227int
228qserver_finalize(void)
229{
230 return 1;
231}