1 |
/* DALnet (4.4.13-) protocol module for IRC Services. |
2 |
* |
3 |
* IRC Services is copyright (c) 1996-2009 Andrew Church. |
4 |
* E-mail: <achurch@achurch.org> |
5 |
* Parts written by Andrew Kempe and others. |
6 |
* This program is free but copyrighted software; see the file GPL.txt for |
7 |
* details. |
8 |
*/ |
9 |
|
10 |
#include "services.h" |
11 |
#include "modules.h" |
12 |
#include "conffile.h" |
13 |
#include "language.h" |
14 |
#include "messages.h" |
15 |
|
16 |
/*************************************************************************/ |
17 |
|
18 |
static char *NetworkDomain = NULL; |
19 |
|
20 |
/*************************************************************************/ |
21 |
/************************** User/channel modes ***************************/ |
22 |
/*************************************************************************/ |
23 |
|
24 |
struct modedata_init { |
25 |
uint8 mode; |
26 |
ModeData data; |
27 |
}; |
28 |
|
29 |
static const struct modedata_init new_usermodes[] = { |
30 |
{'g', {0x00000008}}, /* Receive globops */ |
31 |
{'h', {0x00000010}}, /* Helpop */ |
32 |
}; |
33 |
|
34 |
static const struct modedata_init new_chanmodes[] = { |
35 |
}; |
36 |
|
37 |
static const struct modedata_init new_chanusermodes[] = { |
38 |
}; |
39 |
|
40 |
static void init_modes(void) |
41 |
{ |
42 |
int i; |
43 |
|
44 |
for (i = 0; i < lenof(new_usermodes); i++) |
45 |
usermodes[new_usermodes[i].mode] = new_usermodes[i].data; |
46 |
for (i = 0; i < lenof(new_chanmodes); i++) |
47 |
chanmodes[new_chanmodes[i].mode] = new_chanmodes[i].data; |
48 |
for (i = 0; i < lenof(new_chanusermodes); i++) |
49 |
chanusermodes[new_chanusermodes[i].mode] = new_chanusermodes[i].data; |
50 |
|
51 |
mode_setup(); |
52 |
}; |
53 |
|
54 |
/*************************************************************************/ |
55 |
/************************* IRC message receiving *************************/ |
56 |
/*************************************************************************/ |
57 |
|
58 |
static void m_nick(char *source, int ac, char **av) |
59 |
{ |
60 |
if (*source) { |
61 |
/* Old user changing nicks. */ |
62 |
if (ac != 2) { |
63 |
module_log_debug(1, "NICK message: wrong number of parameters" |
64 |
" (%d) for source `%s'", ac, source); |
65 |
} else { |
66 |
do_nick(source, ac, av); |
67 |
} |
68 |
return; |
69 |
} |
70 |
|
71 |
/* New user. */ |
72 |
|
73 |
if (ac != 7) { |
74 |
module_log_debug(1, "NICK message: wrong number of parameters (%d)" |
75 |
" for new user", ac); |
76 |
return; |
77 |
} |
78 |
do_nick(source, ac, av); |
79 |
} |
80 |
|
81 |
/*************************************************************************/ |
82 |
|
83 |
static Message dalnet_messages[] = { |
84 |
{ "AKILL", NULL }, |
85 |
{ "GLOBOPS", NULL }, |
86 |
{ "GNOTICE", NULL }, |
87 |
{ "GOPER", NULL }, |
88 |
{ "NICK", m_nick }, |
89 |
{ "RAKILL", NULL }, |
90 |
{ "SILENCE", NULL }, |
91 |
{ "SQLINE", NULL }, |
92 |
{ NULL } |
93 |
}; |
94 |
|
95 |
/*************************************************************************/ |
96 |
/************************** IRC message sending **************************/ |
97 |
/*************************************************************************/ |
98 |
|
99 |
/* Send a NICK command for a new user. */ |
100 |
|
101 |
static void do_send_nick(const char *nick, const char *user, const char *host, |
102 |
const char *server, const char *name, |
103 |
const char *modes) |
104 |
{ |
105 |
send_cmd(NULL, "NICK %s 1 %ld %s %s %s :%s", nick, (long)time(NULL), |
106 |
user, host, server, name); |
107 |
if (modes) |
108 |
send_cmd(nick, "MODE %s +%s", nick, modes); |
109 |
} |
110 |
|
111 |
/*************************************************************************/ |
112 |
|
113 |
/* Send a NICK command to change an existing user's nick. */ |
114 |
|
115 |
static void do_send_nickchange(const char *nick, const char *newnick) |
116 |
{ |
117 |
send_cmd(nick, "NICK %s %ld", newnick, (long)time(NULL)); |
118 |
} |
119 |
|
120 |
/*************************************************************************/ |
121 |
|
122 |
/* Send a command to change a user's "real name". */ |
123 |
|
124 |
static void do_send_namechange(const char *nick, const char *newname) |
125 |
{ |
126 |
/* Not supported by this protocol. */ |
127 |
} |
128 |
|
129 |
/*************************************************************************/ |
130 |
|
131 |
/* Send a SERVER command, and anything else needed at the beginning of the |
132 |
* connection. |
133 |
*/ |
134 |
|
135 |
static void do_send_server(void) |
136 |
{ |
137 |
send_cmd(NULL, "PASS :%s", RemotePassword); |
138 |
send_cmd(NULL, "SERVER %s 1 :%s", ServerName, ServerDesc); |
139 |
} |
140 |
|
141 |
/*************************************************************************/ |
142 |
|
143 |
/* Send a SERVER command for a remote (juped) server. */ |
144 |
|
145 |
static void do_send_server_remote(const char *server, const char *reason) |
146 |
{ |
147 |
send_cmd(NULL, "SERVER %s 2 :%s", server, reason); |
148 |
} |
149 |
|
150 |
/*************************************************************************/ |
151 |
|
152 |
/* Send a WALLOPS (really a GLOBOPS). */ |
153 |
|
154 |
static void do_wallops(const char *source, const char *fmt, ...) |
155 |
{ |
156 |
va_list args; |
157 |
char buf[BUFSIZE]; |
158 |
|
159 |
va_start(args, fmt); |
160 |
vsnprintf(buf, sizeof(buf), fmt, args); |
161 |
va_end(args); |
162 |
send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf); |
163 |
} |
164 |
|
165 |
/*************************************************************************/ |
166 |
|
167 |
/* Send a NOTICE to all users on the network. */ |
168 |
|
169 |
static void do_notice_all(const char *source, const char *fmt, ...) |
170 |
{ |
171 |
va_list args; |
172 |
char msgbuf[BUFSIZE]; |
173 |
|
174 |
va_start(args, fmt); |
175 |
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); |
176 |
va_end(args); |
177 |
if (NetworkDomain) { |
178 |
send_cmd(source, "NOTICE $*.%s :%s", NetworkDomain, msgbuf); |
179 |
} else { |
180 |
/* Go through all common top-level domains. If you have others, |
181 |
* add them here. */ |
182 |
send_cmd(source, "NOTICE $*.com :%s", msgbuf); |
183 |
send_cmd(source, "NOTICE $*.net :%s", msgbuf); |
184 |
send_cmd(source, "NOTICE $*.org :%s", msgbuf); |
185 |
send_cmd(source, "NOTICE $*.edu :%s", msgbuf); |
186 |
} |
187 |
} |
188 |
|
189 |
/*************************************************************************/ |
190 |
|
191 |
/* Send a command which modifies channel status. */ |
192 |
|
193 |
static void do_send_channel_cmd(const char *source, const char *fmt, ...) |
194 |
{ |
195 |
va_list args; |
196 |
|
197 |
va_start(args, fmt); |
198 |
vsend_cmd(source, fmt, args); |
199 |
va_end(args); |
200 |
} |
201 |
|
202 |
/*************************************************************************/ |
203 |
/******************************* Callbacks *******************************/ |
204 |
/*************************************************************************/ |
205 |
|
206 |
static int do_set_topic(const char *source, Channel *c, const char *topic, |
207 |
const char *setter, time_t t) |
208 |
{ |
209 |
if (c->topic_time && t >= c->topic_time) |
210 |
t = c->topic_time - 1; /* Force topic change */ |
211 |
if (setter) |
212 |
return 0; |
213 |
c->topic_time = t; |
214 |
send_cmd(source, "TOPIC %s %s %ld :%s", c->name, c->topic_setter, |
215 |
(long)c->topic_time, c->topic ? c->topic : ""); |
216 |
return 1; |
217 |
} |
218 |
|
219 |
/*************************************************************************/ |
220 |
|
221 |
static int do_send_akill(const char *username, const char *host, |
222 |
time_t expires, const char *who, const char *reason) |
223 |
{ |
224 |
send_cmd(ServerName, "AKILL %s %s :%s", host, username, reason); |
225 |
return 1; |
226 |
} |
227 |
|
228 |
/*************************************************************************/ |
229 |
|
230 |
static int do_cancel_akill(const char *username, const char *host) |
231 |
{ |
232 |
send_cmd(ServerName, "RAKILL %s %s", host, username); |
233 |
return 1; |
234 |
} |
235 |
|
236 |
/*************************************************************************/ |
237 |
/***************************** Module stuff ******************************/ |
238 |
/*************************************************************************/ |
239 |
|
240 |
ConfigDirective module_config[] = { |
241 |
{ "NetworkDomain", { { CD_STRING, 0, &NetworkDomain } } }, |
242 |
{ NULL } |
243 |
}; |
244 |
|
245 |
/*************************************************************************/ |
246 |
|
247 |
static int do_load_module(Module *mod, const char *modname) |
248 |
{ |
249 |
if (strcmp(modname, "operserv/akill") == 0) { |
250 |
if (!add_callback(mod, "send_akill", do_send_akill)) |
251 |
module_log("Unable to add send_akill callback"); |
252 |
if (!add_callback(mod, "cancel_akill", do_cancel_akill)) |
253 |
module_log("Unable to add cancel_akill callback"); |
254 |
} |
255 |
return 0; |
256 |
} |
257 |
|
258 |
/*************************************************************************/ |
259 |
|
260 |
static int do_unload_module(Module *mod) |
261 |
{ |
262 |
return 0; |
263 |
} |
264 |
|
265 |
/*************************************************************************/ |
266 |
|
267 |
int init_module(void) |
268 |
{ |
269 |
protocol_name = "DALnet"; |
270 |
protocol_version = "4.4.13-"; |
271 |
protocol_features = 0; |
272 |
protocol_nickmax = 30; |
273 |
|
274 |
if (!register_messages(dalnet_messages)) { |
275 |
module_log("Unable to register messages"); |
276 |
exit_module(1); |
277 |
return 0; |
278 |
} |
279 |
|
280 |
if (!add_callback(NULL, "load module", do_load_module) |
281 |
|| !add_callback(NULL, "unload module", do_unload_module) |
282 |
|| !add_callback(NULL, "set topic", do_set_topic) |
283 |
) { |
284 |
module_log("Unable to add callbacks"); |
285 |
exit_module(1); |
286 |
return 0; |
287 |
} |
288 |
|
289 |
init_modes(); |
290 |
|
291 |
irc_lowertable['['] = '['; |
292 |
irc_lowertable['\\'] = '\\'; |
293 |
irc_lowertable[']'] = ']'; |
294 |
valid_chan_table['+'] = 3; |
295 |
valid_chan_table[':'] = 0; |
296 |
|
297 |
send_nick = do_send_nick; |
298 |
send_nickchange = do_send_nickchange; |
299 |
send_namechange = do_send_namechange; |
300 |
send_server = do_send_server; |
301 |
send_server_remote = do_send_server_remote; |
302 |
wallops = do_wallops; |
303 |
notice_all = do_notice_all; |
304 |
send_channel_cmd = do_send_channel_cmd; |
305 |
pseudoclient_modes = ""; |
306 |
enforcer_modes = ""; |
307 |
pseudoclient_oper = 0; |
308 |
|
309 |
mapstring(OPER_BOUNCY_MODES, OPER_BOUNCY_MODES_U_LINE); |
310 |
|
311 |
return 1; |
312 |
} |
313 |
|
314 |
/*************************************************************************/ |
315 |
|
316 |
int exit_module(int shutdown) |
317 |
{ |
318 |
if (!shutdown) { |
319 |
/* Do not allow removal */ |
320 |
return 0; |
321 |
} |
322 |
|
323 |
remove_callback(NULL, "set topic", do_set_topic); |
324 |
remove_callback(NULL, "unload module", do_unload_module); |
325 |
remove_callback(NULL, "load module", do_load_module); |
326 |
unregister_messages(dalnet_messages); |
327 |
return 1; |
328 |
} |
329 |
|
330 |
/*************************************************************************/ |
331 |
|
332 |
/* |
333 |
* Local variables: |
334 |
* c-file-style: "stroustrup" |
335 |
* c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
336 |
* indent-tabs-mode: nil |
337 |
* End: |
338 |
* |
339 |
* vim: expandtab shiftwidth=4: |
340 |
*/ |