1 /*
2 * ctcp.c:handles the client-to-client protocol(ctcp).
3 *
4 * Written By Michael Sandrof
5 * Copyright(c) 1990, 1995 Michael Sandroff and others
6 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
7 *
8 * Serious cleanup by jfn (August 1996)
9 */
10
11
12 #include "irc.h"
13 static char cvsrevision[] = "$Id: ctcp.c 432 2013-11-07 03:00:24Z tcava $";
14 CVS_REVISION(ctcp_c)
15 #include "struct.h"
16
17 #include <pwd.h>
18
19
20 #ifdef HAVE_UNAME
21 # include <sys/utsname.h>
22 #endif
23
24 #include <stdarg.h>
25
26 #include "encrypt.h"
27 #include "ctcp.h"
28 #include "dcc.h"
29 #include "commands.h"
30 #include "flood.h"
31 #include "hook.h"
32 #include "if.h"
33 #include "ignore.h"
34 #include "ircaux.h"
35 #include "lastlog.h"
36 #include "list.h"
37 #include "names.h"
38 #include "output.h"
39 #include "parse.h"
40 #include "server.h"
41 #include "status.h"
42 #include "vars.h"
43 #include "window.h"
44 #include "cdcc.h"
45 #include "misc.h"
46 #include "userlist.h"
47 #include "hash2.h"
48
49 #ifdef WANT_TCL
50 #include "tcl_bx.h"
51 #endif
52
53 #define MAIN_SOURCE
54 #include "modval.h"
55
56 /*
57 * ctcp_entry: the format for each ctcp function. note that the function
58 * described takes 4 parameters, a pointer to the ctcp entry, who the message
59 * was from, who the message was to (nickname, channel, etc), and the rest of
60 * the ctcp message. it can return null, or it can return a malloced string
61 * that will be inserted into the oringal message at the point of the ctcp.
62 * if null is returned, nothing is added to the original message
63 */
64
65 /* forward declarations for the built in CTCP functions */
66 static char *do_sed (CtcpEntry *, char *, char *, char *);
67 static char *do_version (CtcpEntry *, char *, char *, char *);
68 static char *do_clientinfo (CtcpEntry *, char *, char *, char *);
69 static char *do_ping (CtcpEntry *, char *, char *, char *);
70 static char *do_echo (CtcpEntry *, char *, char *, char *);
71 static char *do_userinfo (CtcpEntry *, char *, char *, char *);
72 static char *do_finger (CtcpEntry *, char *, char *, char *);
73 static char *do_time (CtcpEntry *, char *, char *, char *);
74 static char *do_atmosphere (CtcpEntry *, char *, char *, char *);
75 static char *do_dcc (CtcpEntry *, char *, char *, char *);
76 static char *do_utc (CtcpEntry *, char *, char *, char *);
77 static char *do_dcc_reply (CtcpEntry *, char *, char *, char *);
78 static char *do_ping_reply (CtcpEntry *, char *, char *, char *);
79 static char *do_bdcc (CtcpEntry *, char *, char *, char *);
80 static char *do_cinvite (CtcpEntry *, char *, char *, char *);
81 static char *do_whoami (CtcpEntry *, char *, char *, char *);
82 static char *do_ctcpops (CtcpEntry *, char *, char *, char *);
83 static char *do_ctcpunban (CtcpEntry *, char *, char *, char *);
84 static char *do_botlink (CtcpEntry *, char *, char *, char *);
85 static char *do_ctcp_uptime (CtcpEntry *, char *, char *, char *);
86 static char *do_ctcpident (CtcpEntry *, char *, char *, char *);
87
88 static CtcpEntry ctcp_cmd[] =
89 {
90 { "SED", CTCP_SED, CTCP_INLINE | CTCP_NOLIMIT,
91 "contains simple_encrypted_data",
92 do_sed, do_sed },
93 { "UTC", CTCP_UTC, CTCP_INLINE | CTCP_NOLIMIT,
94 "substitutes the local timezone",
95 do_utc, do_utc },
96 { "ACTION", CTCP_ACTION, CTCP_SPECIAL | CTCP_NOLIMIT,
97 "contains action descriptions for atmosphere",
98 do_atmosphere, do_atmosphere },
99
100 { "DCC", CTCP_DCC, CTCP_SPECIAL,
101 "requests a direct_client_connection",
102 do_dcc, do_dcc_reply },
103
104 { "CDCC", CTCP_CDCC, CTCP_SPECIAL | CTCP_TELLUSER,
105 "checks cdcc info for you",
106 do_bdcc, NULL },
107 { "BDCC", CTCP_CDCC1, CTCP_SPECIAL | CTCP_TELLUSER,
108 "checks cdcc info for you",
109 do_bdcc, NULL },
110 { "XDCC", CTCP_CDCC2, CTCP_SPECIAL | CTCP_TELLUSER,
111 "checks cdcc info for you",
112 do_bdcc, NULL },
113
114 { "VERSION", CTCP_VERSION, CTCP_REPLY | CTCP_TELLUSER,
115 "shows client type, version and environment",
116 do_version, NULL },
117
118 { "CLIENTINFO", CTCP_CLIENTINFO,CTCP_REPLY | CTCP_TELLUSER,
119 "gives information about available CTCP commands",
120 do_clientinfo, NULL },
121 { "USERINFO", CTCP_USERINFO, CTCP_REPLY | CTCP_TELLUSER,
122 "returns user settable information",
123 do_userinfo, NULL },
124 { "ERRMSG", CTCP_ERRMSG, CTCP_REPLY | CTCP_TELLUSER,
125 "returns error messages",
126 do_echo, NULL },
127 { "FINGER", CTCP_FINGER, CTCP_REPLY | CTCP_TELLUSER,
128 "shows real name, login name and idle time of user",
129 do_finger, NULL },
130 { "TIME", CTCP_TIME, CTCP_REPLY | CTCP_TELLUSER,
131 "tells you the time on the user's host",
132 do_time, NULL },
133 { "PING", CTCP_PING, CTCP_REPLY | CTCP_TELLUSER,
134 "returns the arguments it receives",
135 do_ping, do_ping_reply },
136 { "ECHO", CTCP_ECHO, CTCP_REPLY | CTCP_TELLUSER,
137 "returns the arguments it receives",
138 do_echo, NULL },
139
140 { "INVITE", CTCP_INVITE, CTCP_SPECIAL,
141 "invite to channel specified",
142 do_cinvite, NULL },
143 { "WHOAMI", CTCP_WHOAMI, CTCP_SPECIAL,
144 "user list information",
145 do_whoami, NULL },
146 { "OP", CTCP_OPS, CTCP_SPECIAL,
147 "ops the person if on userlist",
148 do_ctcpops, NULL },
149 { "OPS", CTCP_OPS, CTCP_SPECIAL,
150 "ops the person if on userlist",
151 do_ctcpops, NULL },
152 { "UNBAN", CTCP_UNBAN, CTCP_SPECIAL,
153 "unbans the person from channel",
154 do_ctcpunban, NULL },
155 { "IDENT", CTCP_IDENT, CTCP_SPECIAL,
156 "change userhost of userlist",
157 do_ctcpident, NULL },
158 { "XLINK", CTCP_BOTLINK, CTCP_SPECIAL,
159 "x-filez rule",
160 do_botlink, NULL },
161
162 { "UPTIME", CTCP_UPTIME, CTCP_SPECIAL,
163 "my uptime",
164 do_ctcp_uptime, NULL },
165
166 { NULL, CTCP_CUSTOM, CTCP_REPLY | CTCP_TELLUSER,
167 NULL,
168 NULL, NULL }
169 };
170
171 #ifdef WANT_DLL
172 CtcpEntryDll *dll_ctcp = NULL;
173 #endif
174
175
176 /* CDE do ops and unban logging */
177
178 static char *ctcp_type[] =
179 {
180 "PRIVMSG",
181 "NOTICE"
182 };
183
184 /* This is set to one if we parsed an SED */
185 int sed = 0;
186
187 /*
188 * in_ctcp_flag is set to true when IRCII is handling a CTCP request. This
189 * is used by the ctcp() sending function to force NOTICEs to be used in any
190 * CTCP REPLY
191 */
192 int in_ctcp_flag = 0;
193
194 #define CTCP_HANDLER(x) \
195 static char * x (CtcpEntry *ctcp, char *from, char *to, char *cmd)
196
197 /**************************** CTCP PARSERS ****************************/
198
199 /********** INLINE EXPANSION CTCPS ***************/
200
201
202 #ifdef WANT_USERLIST
print_ctcp(char * from,char * uh,char * to,char * str,char * cmd)203 void print_ctcp(char *from, char *uh, char *to, char *str, char *cmd)
204 {
205 put_it("%s", convert_output_format(fget_string_var(is_channel(to)?FORMAT_CTCP_CLOAK_FUNC_FSET:FORMAT_CTCP_CLOAK_FUNC_USER_FSET),
206 "%s %s %s %s %s %s",update_clock(GET_TIME), from, uh, to, str, *cmd? cmd : empty_string));
207 }
208
log_denied(char * type,char * from,char * uh,char * to,char * cmd)209 void log_denied(char *type, char *from, char *uh, char *to, char *cmd)
210 {
211 logmsg(LOG_CTCP, from, 0, "%s %s %s [%s]", type, "! Access Denied from ", uh, cmd);
212 }
213 #endif
214
CTCP_HANDLER(do_ctcpident)215 CTCP_HANDLER(do_ctcpident)
216 {
217 #if defined(WANT_USERLIST)
218 UserList *ThisNick = NULL;
219 char *nick, *passwd = NULL;
220 char *channel = "*";
221 int ok = 0;
222 print_ctcp(from, FromUserHost, to, "IDENT ", cmd);
223 if (is_channel(to))
224 return NULL;
225 nick = next_arg(cmd, &cmd);
226 passwd = next_arg(cmd, &cmd);
227 if (cmd && *cmd)
228 channel = next_arg(cmd, &cmd);
229 ThisNick = lookup_userlevelc(nick, "*", channel, passwd);
230 if (nick && passwd && ThisNick && ThisNick->password)
231 {
232 if (!checkpass(passwd, ThisNick->password))
233 {
234 char *bang = NULL;
235 char *u, *h;
236 ok = 1;
237 bang = LOCAL_COPY(FromUserHost);
238 u = bang;
239 if ((h = strchr(bang, '@')))
240 *h++ = 0;
241 if (!h || !*h)
242 return NULL;
243 malloc_sprintf(&ThisNick->host, "*%s@%s", clear_server_flags(u), cluster(h));
244 }
245 }
246 if (!ok && !get_int_var(CLOAK_VAR))
247 log_denied("IDENT", from, FromUserHost, to, cmd);
248 else if (ok || (ThisNick && (ThisNick->flags & ADD_CTCP)))
249 {
250 if (get_int_var(SEND_CTCP_MSG_VAR))
251 send_to_server("NOTICE %s :UserHost updated to %s", from, FromUserHost);
252 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "IDENT", from, FromUserHost);
253 }
254 #endif
255 return NULL;
256 }
257
258
259
260
261 /* parse a remote ctcp CDCC command */
CTCP_HANDLER(do_bdcc)262 CTCP_HANDLER(do_bdcc)
263 {
264 #ifdef WANT_CDCC
265 int i;
266 char *secure = NULL;
267 extern pack *offerlist;
268 extern remote_cmd remote[];
269 char *rest, *arg, *temp = NULL;
270
271 if ((check_ignore(from, FromUserHost, to, IGNORE_CDCC, NULL) == IGNORED))
272 return NULL;
273
274 if (!offerlist || !get_int_var(CDCC_VAR))
275 return NULL;
276
277 if ((secure = get_string_var(CDCC_SECURITY_VAR)))
278 {
279 UserList *tmp;
280 char *pass = NULL;
281 /* workaround for var.c which had a int for a var */
282 if (*secure == '0' && strlen(secure) == 1)
283 goto got_good_pass1;
284 if (cmd && *cmd)
285 pass = strrchr(cmd, ' ');
286 if (pass && *pass)
287 {
288 pass++;
289 if (*pass && !my_stricmp(pass, secure))
290 {
291 *pass-- = 0;
292 goto got_good_pass1;
293 }
294 }
295 #if defined(WANT_USERLIST)
296 if (!(tmp = lookup_userlevelc("*", FromUserHost, "*", NULL)) || !(tmp->flags & ADD_DCC))
297 return NULL;
298 #else
299 return NULL;
300 #endif
301 }
302
303 got_good_pass1:
304 temp = LOCAL_COPY(cmd);
305 arg = next_arg(temp, &temp);
306 if (!arg)
307 return NULL;
308 rest = temp;
309 for (i = 0; *remote[i].name; i++)
310 {
311 if (!my_stricmp(arg, remote[i].name))
312 {
313 remote[i].function(from, rest);
314 return NULL;
315 }
316 }
317 send_to_server("NOTICE %s :try /ctcp %s cdcc help", from, get_server_nickname(from_server));
318 #endif
319 return NULL;
320 }
321
CTCP_HANDLER(do_botlink)322 CTCP_HANDLER(do_botlink)
323 {
324 #if !defined(BITCHX_LITE)
325 #ifdef WANT_USERLIST
326 char *nick = NULL, *password = NULL, *port = NULL;
327 nick = next_arg(cmd, &cmd);
328 password = next_arg(cmd, &cmd);
329 port = next_arg(cmd, &cmd);
330 print_ctcp(from, FromUserHost, to, "XLINK ", cmd);
331 if (nick && password)
332 {
333 char *t = NULL;
334 UserList *n = NULL;
335 if (get_string_var(BOT_PASSWD_VAR) || (n = lookup_userlevelc(nick, FromUserHost, "*", password)))
336 {
337 char *pass;
338 if (!n)
339 pass = get_string_var(BOT_PASSWD_VAR);
340 else
341 pass = n->password;
342 if (pass && !my_stricmp(pass, password))
343 {
344 if (port)
345 malloc_sprintf(&t, "%s -p %s -e %s", nick, port, password);
346 else
347 malloc_sprintf(&t, "%s -e %s", nick, password);
348 dcc_chat("BOT", t);
349 new_free(&t);
350 set_int_var(BOT_MODE_VAR, 1);
351 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s [%s]", "XLINK", from, FromUserHost, to, cmd?cmd:empty_string);
352 } else
353 log_denied("XLINK", from, FromUserHost, to, cmd);
354 } else
355 log_denied("XLINK", from, FromUserHost, to, cmd);
356 }
357 else
358 {
359 log_denied("XLINK", from, FromUserHost, to, cmd);
360 return m_sprintf("Invalid Bot Link request %s %s %s", nick?nick:"null", password?password:"-", port?port:"*");
361 }
362 #endif
363 #endif
364
365 return NULL;
366 }
367
CTCP_HANDLER(do_cinvite)368 CTCP_HANDLER(do_cinvite)
369 {
370 #ifdef WANT_USERLIST
371 UserList *tmp;
372 char *channel;
373 char *password = NULL;
374 ChannelList *chan;
375 int serv = from_server;
376 print_ctcp(from, FromUserHost, to, "Invite to ", cmd);
377 channel = next_arg(cmd, &cmd);
378 if (cmd && *cmd)
379 password = next_arg(cmd, &cmd);
380
381 if (is_channel(to) || !channel || (channel && *channel && !is_channel(channel)))
382 return NULL;
383
384 tmp = lookup_userlevelc("*", FromUserHost, channel, password);
385 chan = prepare_command(&serv, channel, PC_SILENT);
386 if (chan && tmp && (tmp->flags & ADD_INVITE) && (check_channel_match(tmp->channels, channel)))
387 {
388 if (tmp->password && !password)
389 {
390 log_denied("INVITE", from, FromUserHost, to, cmd);
391 return NULL;
392 }
393 if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
394 {
395 if (chan->key)
396 my_send_to_server(serv, "NOTICE %s :\002Ctcp-inviting you to %s. Key is [%s]\002", from, channel, chan->key);
397 else
398 my_send_to_server(serv, "NOTICE %s :\002Ctcp-inviting you to %s\002", from, channel);
399 my_send_to_server(serv, "INVITE %s %s", from, channel);
400 logmsg(LOG_CTCP, from, 0, "Successful INVITE from %s!%s to %s", from, FromUserHost, channel);
401 }
402 else
403 {
404 if (get_int_var(SEND_CTCP_MSG_VAR))
405 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
406 log_denied("INVITE", from, FromUserHost, to, cmd);
407 }
408 }
409 else if (!get_int_var(CLOAK_VAR) || (tmp && (tmp->flags & ADD_CTCP)))
410 {
411 if (!chan)
412 {
413 if (get_int_var(SEND_CTCP_MSG_VAR))
414 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on that channel", from, version);
415 log_denied("INVITE", from, FromUserHost, to, cmd);
416 }
417 else
418 {
419 if (get_int_var(SEND_CTCP_MSG_VAR))
420 my_send_to_server(serv, "NOTICE %s :\002%s\002: Access Denied", from, version);
421 log_denied("INVITE", from, FromUserHost, to, cmd);
422 }
423 }
424 else
425 log_denied("INVITE", from, FromUserHost, to, cmd);
426 #endif
427 return NULL;
428 }
429
CTCP_HANDLER(do_whoami)430 CTCP_HANDLER(do_whoami)
431 {
432 #ifdef WANT_USERLIST
433 UserList *Nick = NULL;
434 print_ctcp(from, FromUserHost, to, "WhoAmI", cmd);
435 if (is_channel(to))
436 return NULL;
437
438 Nick = lookup_userlevelc("*", FromUserHost, "*", NULL);
439 if (Nick && Nick->flags)
440 {
441 send_to_server("NOTICE %s :\002%s\002: Userlevel - %s ",from, version, convert_flags_to_str(Nick->flags));
442 send_to_server("NOTICE %s :\002%s\002: Host Mask - %s Channels Allowed - %s %s",
443 from, version, Nick->host, Nick->channels, Nick->password?"Password Required":empty_string);
444 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s", "WHOAMI", from, FromUserHost, to);
445 }
446 else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
447 {
448 send_to_server("NOTICE %s :\002%s\002: Access Denied", from, version);
449 if (get_int_var(SEND_CTCP_MSG_VAR))
450 log_denied("WHOAMI", from, FromUserHost, to, cmd);
451 } else if (get_int_var(SEND_CTCP_MSG_VAR))
452 log_denied("WHOAMI", from, FromUserHost, to, cmd);
453 #endif
454 return NULL;
455 }
456
CTCP_HANDLER(do_ctcp_uptime)457 CTCP_HANDLER(do_ctcp_uptime)
458 {
459 #ifdef WANT_USERLIST
460 UserList *Nick = NULL;
461 print_ctcp(from, FromUserHost, to, "Uptime", cmd);
462 Nick = lookup_userlevelc("*", FromUserHost, "*", NULL);
463 if (Nick)
464 {
465 send_to_server("NOTICE %s :\002%s\002: Current Uptime is %s", from, version, convert_time(now-start_time));
466 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s to %s", "UPTIME", from, FromUserHost, to);
467 } else if (get_int_var(SEND_CTCP_MSG_VAR))
468 log_denied("UPTIME", from, FromUserHost, to, cmd);
469 #endif
470 return NULL;
471 }
472
CTCP_HANDLER(do_ctcpops)473 CTCP_HANDLER(do_ctcpops)
474 {
475 #ifdef WANT_USERLIST
476 UserList *Nick = NULL;
477 char *channel;
478 char *password = NULL;
479 ChannelList *chan;
480 int serv = from_server;
481 print_ctcp(from, FromUserHost, to, "Ops on", cmd);
482
483 if (is_channel(to))
484 return NULL;
485 channel = next_arg(cmd, &cmd);
486 if (!channel || !*channel)
487 return NULL;
488 if (cmd && *cmd)
489 password = next_arg(cmd, &cmd);
490 Nick = lookup_userlevelc("*", FromUserHost, channel, password);
491 chan = prepare_command(&serv, channel, PC_SILENT);
492 if (chan && get_cset_int_var(chan->csets, USERLIST_CSET) && Nick)
493 {
494 if (Nick->flags & ADD_OPS)
495 {
496 if (Nick->password && !password)
497 {
498 log_denied("OPS", from, FromUserHost, to, cmd);
499 return NULL;
500 }
501 if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
502 {
503 my_send_to_server(serv, "MODE %s +o %s", channel, from);
504 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "OPS", from, FromUserHost);
505 }
506 else
507 {
508 if (get_int_var(SEND_CTCP_MSG_VAR))
509 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
510 log_denied("OPS", from, FromUserHost, to, cmd);
511 }
512 }
513 else if (Nick->flags & ADD_VOICE)
514 {
515 if (im_on_channel(channel, from_server) && is_chanop(channel, get_server_nickname(from_server)))
516 {
517 my_send_to_server(serv, "MODE %s +v %s", channel, from);
518 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s", "VOICE", from, FromUserHost);
519 }
520 else
521 {
522 if (get_int_var(SEND_CTCP_MSG_VAR))
523 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
524 log_denied("OPS", from, FromUserHost, to, cmd);
525 }
526 }
527 else
528 {
529 if ((!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP))) && get_int_var(SEND_CTCP_MSG_VAR))
530 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel?channel:empty_string);
531 log_denied("OPS", from, FromUserHost, to, cmd);
532 }
533 }
534 else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
535 {
536 if (get_int_var(SEND_CTCP_MSG_VAR))
537 my_send_to_server(serv, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel?channel:empty_string);
538 log_denied("OPS", from, FromUserHost, to, cmd);
539 }
540 #endif
541 return NULL;
542 }
543
CTCP_HANDLER(do_ctcpunban)544 CTCP_HANDLER(do_ctcpunban)
545 {
546 #ifdef WANT_USERLIST
547 UserList *Nick = NULL;
548 char *channel;
549 char *password = NULL;
550 char ban[BIG_BUFFER_SIZE];
551 ChannelList *chan;
552 int server;
553
554 print_ctcp(from, FromUserHost, to, "UnBan on ", cmd);
555
556 if (is_channel(to))
557 return NULL;
558
559 channel = next_arg(cmd, &cmd);
560 if (!channel || !*channel)
561 return NULL;
562 if (cmd && *cmd)
563 password = next_arg(cmd, &cmd);
564
565 Nick = lookup_userlevelc("*", FromUserHost, channel, password);
566 chan = prepare_command(&server, channel, PC_SILENT);
567
568 if (chan && get_cset_int_var(chan->csets, USERLIST_CSET) && Nick && (Nick->flags & ADD_UNBAN))
569 {
570 BanList *b = NULL;
571 if (Nick->password && !password)
572 {
573 log_denied("UNBAN", from, FromUserHost, to, cmd);
574 return NULL;
575 }
576 sprintf(ban, "%s!%s", from, FromUserHost);
577 if (chan && chan->have_op)
578 {
579 if ((b = ban_is_on_channel(ban, chan)))
580 {
581 my_send_to_server(server, "MODE %s -b %s", channel, b->ban);
582 logmsg(LOG_CTCP, from, 0, "Successful %s from %s!%s on %s", "UNBAN", from, FromUserHost, channel);
583 }
584 else
585 {
586 if (get_int_var(SEND_CTCP_MSG_VAR))
587 my_send_to_server(server, "NOTICE %s :\002%s\002: you %s are not banned on %s", from, version, ban, channel);
588 log_denied("OPS", from, FromUserHost, to, cmd);
589 }
590 }
591 else
592 {
593 my_send_to_server(server, "NOTICE %s :\002%s\002: I'm not on %s, or I'm not opped", from, version, channel);
594 log_denied("OPS", from, FromUserHost, to, cmd);
595 }
596 }
597 else if (!get_int_var(CLOAK_VAR) || (Nick && (Nick->flags & ADD_CTCP)))
598 {
599 if (!chan)
600 my_send_to_server(server, "NOTICE %s :\002%s\002: I'm not on that channel", from, version);
601 else
602 my_send_to_server(server, "NOTICE %s :\002%s\002: Access Denied", from, version);
603 log_denied("OPS", from, FromUserHost, to, cmd);
604 }
605 #endif
606 return NULL;
607 }
608
609
610
611 /*
612 * do_sed: Performs the Simple Encrypted Data trasfer for ctcp. Returns in a
613 * malloc string the decryped message (if a key is set for that user) or the
614 * text "[ENCRYPTED MESSAGE]"
615 */
CTCP_HANDLER(do_sed)616 CTCP_HANDLER(do_sed)
617 {
618 char *key = NULL,
619 *crypt_who;
620 char *ret = NULL, *ret2 = NULL;
621
622 if (*from == '=')
623 crypt_who = from;
624 if (my_stricmp(to, get_server_nickname(from_server)))
625 crypt_who = to;
626 else
627 crypt_who = from;
628
629 if ((key = is_crypted(crypt_who)))
630 ret = decrypt_msg(cmd, key);
631
632 if (!key || !ret)
633 malloc_strcpy(&ret2, "[ENCRYPTED MESSAGE]");
634 else
635 {
636 /*
637 * There might be a CTCP message in there,
638 * so we see if we can find it.
639 */
640 ret2 = m_strdup(do_ctcp(from, to, ret));
641 sed = 1;
642 }
643
644 new_free(&ret);
645 return ret2;
646 }
647
CTCP_HANDLER(do_utc)648 CTCP_HANDLER(do_utc)
649 {
650
651 if (get_int_var(CLOAK_VAR))
652 return m_strdup(empty_string);
653 if (!cmd || !*cmd)
654 return m_strdup(empty_string);
655
656 return m_strdup(my_ctime(my_atol(cmd)));
657 }
658
659
660 /*
661 * do_atmosphere: does the CTCP ACTION command --- done by lynX
662 * Changed this to make the default look less offensive to people
663 * who don't like it and added a /on ACTION. This is more in keeping
664 * with the design philosophy behind IRCII
665 */
CTCP_HANDLER(do_atmosphere)666 CTCP_HANDLER(do_atmosphere)
667 {
668 const char *old_message_from;
669 unsigned long old_message_level;
670 int ac_reply;
671 char *ptr1 = cmd;
672
673 if (!cmd || !*cmd)
674 return NULL;
675
676 if ((ac_reply = check_auto_reply(cmd)))
677 addtabkey(from,"msg", 1);
678
679 save_display_target(&old_message_from, &old_message_level);
680 logmsg(LOG_ACTION, from, 0, "%s %s", to, cmd);
681
682 if (is_channel(to))
683 {
684 int r = 0;
685 ChannelList *chan = NULL;
686 chan = lookup_channel(to, from_server, CHAN_NOUNLINK);
687 do_logchannel(LOG_CTCP, chan, "%s %s %s %s", from, FromUserHost, to, cmd);
688 #ifdef WANT_USERLIST
689 r = (lookup_userlevelc("*", FromUserHost, to, NULL)) ? 1 : 0;
690 #endif
691 set_display_target(to, LOG_ACTION);
692 if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
693 {
694 char *s;
695 s = fget_string_var((ac_reply && r)?FORMAT_ACTION_USER_AR_FSET :
696 ac_reply ? FORMAT_ACTION_OTHER_AR_FSET :
697 r ? FORMAT_ACTION_USER_FSET :FORMAT_ACTION_OTHER_FSET);
698 if (is_current_channel(to, from_server, 0))
699 {
700 s = fget_string_var((r && ac_reply)?FORMAT_ACTION_USER_AR_FSET:
701 (ac_reply) ? FORMAT_ACTION_AR_FSET:
702 r ? FORMAT_ACTION_USER_FSET : FORMAT_ACTION_CHANNEL_FSET);
703 put_it("%s", convert_output_format(s, "%s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ptr1));
704 }
705 else
706 put_it("%s", convert_output_format(s, "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ptr1));
707 }
708 }
709 else
710 {
711 set_display_target(from, LOG_ACTION);
712 if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
713 put_it("%s", convert_output_format(fget_string_var(ac_reply?FORMAT_ACTION_AR_FSET:FORMAT_ACTION_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ptr1));
714 }
715
716 restore_display_target(old_message_from, old_message_level);
717 return NULL;
718 }
719
720 /*
721 * do_dcc: Records data on an incoming DCC offer. Makes sure it's a
722 * user->user CTCP, as channel DCCs don't make any sense whatsoever
723 */
CTCP_HANDLER(do_dcc)724 CTCP_HANDLER(do_dcc)
725 {
726 char *type;
727 char *description = NULL;
728 char *inetaddr = NULL;
729 char *port = NULL;
730 char *size = NULL;
731 char *extra_flags = NULL;
732 if (my_stricmp(to, get_server_nickname(from_server)))
733 return NULL;
734 if (!(type = next_arg(cmd, &cmd)))
735 return NULL;
736 #if 1
737 if (!(description = new_next_arg(cmd, &cmd)) || !*description)
738 return NULL;
739 if (!(inetaddr = next_arg(cmd, &cmd)) ||
740 !(port = next_arg(cmd, &cmd)))
741 return NULL;
742
743 size = next_arg(cmd, &cmd);
744 extra_flags = next_arg(cmd, &cmd);
745 #else
746 size = last_arg(&cmd);
747 port = last_arg(&cmd);
748 inetaddr = last_arg(&cmd);
749 if (!size || !port || !inetaddr || !description)
750 return NULL;
751 #endif
752 register_dcc_type(from, type, description, inetaddr, port, size, extra_flags, FromUserHost, NULL);
753 return NULL;
754 }
755
756 /*************** REPLY-GENERATING CTCPS *****************/
757
758 /*
759 * do_clientinfo: performs the CLIENTINFO CTCP. If cmd is empty, returns the
760 * list of all CTCPs currently recognized by IRCII. If an arg is supplied,
761 * it returns specific information on that CTCP. If a matching CTCP is not
762 * found, an ERRMSG ctcp is returned
763 */
CTCP_HANDLER(do_clientinfo)764 CTCP_HANDLER(do_clientinfo)
765 {
766 int i;
767 #ifdef WANT_DLL
768 CtcpEntryDll *dll = NULL;
769 #endif
770
771 if (get_int_var(CLOAK_VAR))
772 return NULL;
773 if (cmd && *cmd)
774 {
775 #ifdef WANT_DLL
776 for (dll = dll_ctcp; dll; dll = dll->next)
777 {
778 if (!my_stricmp(cmd, dll->name))
779 {
780 send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
781 "%s %s",
782 dll->name, dll->desc?dll->desc:"none");
783 return NULL;
784 }
785 }
786 #endif
787 for (i = 0; i < NUMBER_OF_CTCPS; i++)
788 {
789 if (!my_stricmp(cmd, ctcp_cmd[i].name))
790 {
791 send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
792 "%s %s",
793 ctcp_cmd[i].name, ctcp_cmd[i].desc);
794 return NULL;
795 }
796 }
797 send_ctcp(CTCP_NOTICE, from, CTCP_ERRMSG,
798 "%s: %s is not a valid function",
799 ctcp_cmd[CTCP_CLIENTINFO].name, cmd);
800 }
801 else
802 {
803 char buffer[BIG_BUFFER_SIZE];
804
805 *buffer = '\0';
806 for (i = 0; i < NUMBER_OF_CTCPS; i++)
807 {
808 strlcat(buffer, ctcp_cmd[i].name, sizeof buffer);
809 strlcat(buffer, space, sizeof buffer);
810 }
811 #ifdef WANT_DLL
812 for (dll = dll_ctcp; dll; dll = dll->next)
813 {
814 strlcat(buffer, dll->name, sizeof buffer);
815 strlcat(buffer, space, sizeof buffer);
816 }
817 #endif
818 send_ctcp(CTCP_NOTICE, from, CTCP_CLIENTINFO,
819 "%s :Use CLIENTINFO <COMMAND> to get more specific information",
820 buffer);
821 }
822 return NULL;
823 }
824
825 /* do_version: does the CTCP VERSION command */
CTCP_HANDLER(do_version)826 CTCP_HANDLER(do_version)
827 {
828 char *tmp;
829 char *version_reply = NULL;
830 extern char tcl_versionstr[];
831 /*
832 * The old way seemed lame to me... let's show system name and
833 * release information as well. This will surely help out
834 * experts/gurus answer newbie questions. -- Jake [WinterHawk] Khuon
835 *
836 * For the paranoid, UNAME_HACK hides the gory details of your OS.
837 */
838
839
840 #if defined(HAVE_UNAME) && !defined(UNAME_HACK)
841 struct utsname un;
842 char *the_unix,
843 *the_version;
844
845 if (get_int_var(AUTOKICK_ON_VERSION_VAR))
846 {
847 char *channel = get_current_channel_by_refnum(0);
848 if (channel)
849 {
850 ChannelList *chan;
851 if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
852 {
853 NickList *nick;
854 if ((nick = find_nicklist_in_channellist(from, chan, 0)) && !isme(from))
855 send_to_server("KICK %s %s :%s", channel, from, "/VER is lame");
856 }
857 }
858 return NULL;
859 }
860 if (get_int_var(CLOAK_VAR))
861 return NULL;
862 if (uname(&un) < 0)
863 {
864 the_version = empty_string;
865 the_unix = "unknown";
866 }
867 else
868 {
869 the_version = un.release;
870 the_unix = un.sysname;
871 }
872 malloc_strcpy(&version_reply, stripansicodes(convert_output_format(fget_string_var(FORMAT_VERSION_FSET), "%s %s %s %s %s", irc_version, internal_version, the_unix, the_version, tcl_versionstr)));
873 send_ctcp(CTCP_NOTICE, from, CTCP_VERSION, "%s :%s", version_reply,
874 #else
875 if (get_int_var(AUTOKICK_ON_VERSION_VAR))
876 {
877 char *channel = get_current_channel_by_refnum(0);
878 if (channel)
879 {
880 ChannelList *chan;
881 if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
882 {
883 NickList *nick;
884 if ((nick = find_nicklist_in_channellist(from, chan, 0)))
885 send_to_server("KICK %s %s :%s", channel, from, "/VER is lame");
886 }
887 }
888 return NULL;
889 }
890 if (get_int_var(CLOAK_VAR))
891 return NULL;
892 malloc_strcpy(&version_reply, stripansicodes(convert_output_format(fget_string_var(FORMAT_VERSION_FSET), "%s %s %s %s %s", irc_version, internal_version, "*IX", "�", tcl_versionstr)));
893 send_ctcp(CTCP_NOTICE, from, CTCP_VERSION, "%s :%s", version_reply,
894 #endif
895 (tmp = get_string_var(CLIENTINFO_VAR)) ? tmp : IRCII_COMMENT);
896 new_free(&version_reply);
897 return NULL;
898 }
899
900 /* do_time: does the CTCP TIME command --- done by Veggen */
CTCP_HANDLER(do_time)901 CTCP_HANDLER(do_time)
902 {
903
904
905 if (get_int_var(CLOAK_VAR))
906 return NULL;
907 send_ctcp(CTCP_NOTICE, from, CTCP_TIME,
908 "%s", my_ctime(now));
909 return NULL;
910 }
911
912 /* do_userinfo: does the CTCP USERINFO command */
CTCP_HANDLER(do_userinfo)913 CTCP_HANDLER(do_userinfo)
914 {
915
916
917 if (get_int_var(CLOAK_VAR))
918 return NULL;
919 send_ctcp(CTCP_NOTICE, from, CTCP_USERINFO,
920 "%s", get_string_var(USERINFO_VAR));
921 return NULL;
922 }
923
924 /*
925 * do_echo: does the CTCP ERRMSG and CTCP ECHO commands. Does
926 * not send an error for ERRMSG and if the CTCP was sent to a channel.
927 */
CTCP_HANDLER(do_echo)928 CTCP_HANDLER(do_echo)
929 {
930
931
932 if (get_int_var(CLOAK_VAR))
933 return NULL;
934 if (!is_channel(to))
935 {
936 if (strlen(cmd) > 60)
937 {
938 yell("WARNING ctcp echo request longer than 60 chars. truncating");
939 cmd[60] = 0;
940 }
941 send_ctcp(CTCP_NOTICE, from, ctcp->id, "%s", cmd);
942 }
943 return NULL;
944 }
945
CTCP_HANDLER(do_ping)946 CTCP_HANDLER(do_ping)
947 {
948
949
950 if (get_int_var(CLOAK_VAR) == 2)
951 return NULL;
952 send_ctcp(CTCP_NOTICE, from, CTCP_PING, "%s", cmd ? cmd : empty_string);
953 return NULL;
954 }
955
956
957 /*
958 * Does the CTCP FINGER reply
959 */
CTCP_HANDLER(do_finger)960 CTCP_HANDLER(do_finger)
961 {
962 struct passwd *pwd;
963 time_t diff;
964 char *tmp;
965 char *ctcpuser,
966 *ctcpfinger;
967 const char *my_host;
968
969
970 if (get_int_var(CLOAK_VAR))
971 return NULL;
972 if ((my_host = get_server_userhost(from_server)) && strchr(my_host, '@'))
973 my_host = strchr(my_host, '@') + 1;
974 else
975 my_host = hostname;
976
977 diff = now - idle_time;
978
979 if (!(pwd = getpwuid(getuid())))
980 return NULL;
981
982 #ifndef GECOS_DELIMITER
983 #define GECOS_DELIMITER ','
984 #endif
985
986 if ((tmp = strchr(pwd->pw_gecos, GECOS_DELIMITER)) != NULL)
987 *tmp = '\0';
988
989 /*
990 * Three optionsn for handling CTCP replies
991 * + Fascist Bastard Way -- normal, non-hackable fashion
992 * + Winterhawk way (default) -- allows hacking through IRCUSER and
993 * IRCFINGER environment variables
994 * + hop way -- returns a blank always
995 */
996 /*
997 * It would be pretty pointless to allow for customisable
998 * usernames if they can track via IRCNAME from the
999 * /etc/passwd file... We therefore need to either disable
1000 * CTCP_FINGER or also make it customisable. Let's do the
1001 * latter because it invokes less suspicion in the long run
1002 * -- Jake [WinterHawk] Khuon
1003 */
1004 if (!(ctcpuser = getenv("IRCUSER")))
1005 ctcpuser = pwd->pw_name;
1006 if (!(ctcpfinger = getenv("IRCFINGER")))
1007 ctcpfinger = pwd->pw_gecos;
1008
1009 send_ctcp(CTCP_NOTICE, from, CTCP_FINGER,
1010 "%s (%s@%s) Idle %ld second%s",
1011 ctcpfinger, ctcpuser, my_host, diff, plural(diff));
1012 return NULL;
1013 }
1014
1015
1016 /*
1017 * If we recieve a CTCP DCC REJECT in a notice, then we want to remove
1018 * the offending DCC request
1019 */
CTCP_HANDLER(do_dcc_reply)1020 CTCP_HANDLER(do_dcc_reply)
1021 {
1022 char *subcmd = NULL;
1023 char *type = NULL;
1024
1025 if (is_channel(to))
1026 return NULL;
1027
1028 if (cmd && *cmd)
1029 subcmd = next_arg(cmd, &cmd);
1030 if (cmd && *cmd)
1031 type = next_arg(cmd, &cmd);
1032
1033 if (subcmd && type && cmd && !strcmp(subcmd, "REJECT"))
1034 dcc_reject (from, type, cmd);
1035
1036 return NULL;
1037 }
1038
1039
1040 /*
1041 * Handles CTCP PING replies.
1042 */
CTCP_HANDLER(do_ping_reply)1043 CTCP_HANDLER(do_ping_reply)
1044 {
1045 char *sec, *usec = NULL;
1046 struct timeval t;
1047 time_t tsec = 0, tusec = 0, orig;
1048
1049 if (!cmd || !*cmd)
1050 return NULL; /* This is a fake -- cant happen. */
1051
1052 orig = my_atol(cmd);
1053
1054 get_time(&t);
1055 if (orig < start_time || orig > t.tv_sec)
1056 return NULL;
1057
1058 /* We've already checked 'cmd' here, so its safe. */
1059 sec = cmd;
1060 tsec = t.tv_sec - my_atol(sec);
1061
1062 if ((usec = strchr(sec, ' ')))
1063 {
1064 *usec++ = 0;
1065 tusec = t.tv_usec - my_atol(usec);
1066 }
1067
1068 /*
1069 * 'cmd', a variable passed in from do_notice_ctcp()
1070 * points to a buffer which is MUCH larger than the
1071 * string 'cmd' points at. So this is safe, even
1072 * if it looks "unsafe".
1073 */
1074 sprintf(cmd, "%5.3f seconds", (float)(tsec + (tusec / 1000000.0)));
1075 return NULL;
1076 }
1077
1078
1079 /************************************************************************/
1080 /*
1081 * do_ctcp: a re-entrant form of a CTCP parser. The old one was lame,
1082 * so i took a hatchet to it so it didnt suck.
1083 */
do_ctcp(char * from,char * to,char * str)1084 extern char *do_ctcp (char *from, char *to, char *str)
1085 {
1086 int flag;
1087
1088 char local_ctcp_buffer [BIG_BUFFER_SIZE + 1],
1089 the_ctcp [IRCD_BUFFER_SIZE + 1],
1090 last [IRCD_BUFFER_SIZE + 1];
1091 char *ctcp_command,
1092 *ctcp_argument;
1093 int i;
1094 char *ptr = NULL;
1095 int allow_ctcp_reply = 1;
1096
1097 #ifdef WANT_DLL
1098 CtcpEntryDll *dll = NULL;
1099 #endif
1100 int delim_char = charcount(str, CTCP_DELIM_CHAR);
1101
1102 if (delim_char < 2)
1103 return str; /* No CTCPs. */
1104
1105 if (delim_char > 8)
1106 allow_ctcp_reply = 0; /* Historical limit of 4 CTCPs */
1107
1108
1109 flag = check_ignore(from, FromUserHost, to, IGNORE_CTCPS, NULL);
1110
1111 in_ctcp_flag++;
1112 strlcpy(local_ctcp_buffer, str, sizeof local_ctcp_buffer - 2);
1113
1114 for (;;strlcat(local_ctcp_buffer, last, sizeof local_ctcp_buffer - 2))
1115 {
1116 split_CTCP(local_ctcp_buffer, the_ctcp, last);
1117
1118 if (!*the_ctcp)
1119 break; /* all done! */
1120 /*
1121 * Apply some integrety rules:
1122 * -- If we've already replied to a CTCP, ignore it.
1123 * -- If user is ignoring sender, ignore it.
1124 * -- If we're being flooded, ignore it.
1125 * -- If CTCP was a global msg, ignore it.
1126 */
1127
1128 /*
1129 * Yes, this intentionally ignores "unlimited" CTCPs like
1130 * UTC and SED. Ultimately, we have to make sure that
1131 * CTCP expansions dont overrun any buffers that might
1132 * contain this string down the road. So by allowing up to
1133 * 4 CTCPs, we know we cant overflow -- but if we have more
1134 * than 40, it might overflow, and its probably a spam, so
1135 * no need to shed tears over ignoring them. Also makes
1136 * the sanity checking much simpler.
1137 */
1138 if (!allow_ctcp_reply)
1139 continue;
1140
1141 /*
1142 * Check to see if the user is ignoring person.
1143 */
1144
1145 if (flag == IGNORED)
1146 {
1147 allow_ctcp_reply = 0;
1148 continue;
1149 }
1150
1151 ctcp_command = the_ctcp;
1152 ctcp_argument = strchr(the_ctcp, ' ');
1153 if (ctcp_argument)
1154 *ctcp_argument++ = 0;
1155 else
1156 ctcp_argument = empty_string;
1157
1158 /* Set up the window level/logging */
1159 if (im_on_channel(to, from_server))
1160 set_display_target(to, LOG_CTCP);
1161 else
1162 set_display_target(from, LOG_CTCP);
1163
1164 /* Global messages -- just drop the CTCP */
1165 if (*to == '$' || (*to == '#' && !lookup_channel(to, from_server, 0)))
1166 {
1167 allow_ctcp_reply = 0;
1168 continue;
1169 }
1170 #ifdef WANT_DLL
1171 /* Find the correct CTCP and run it. */
1172 for (dll = dll_ctcp; dll; dll = dll->next)
1173 if (!strcmp(dll->name, ctcp_command))
1174 break;
1175 #endif
1176 for (i = 0; i < NUMBER_OF_CTCPS; i++)
1177 if (!strcmp(ctcp_command, ctcp_cmd[i].name))
1178 break;
1179
1180 /* Set up the window level/logging */
1181 if (im_on_channel(to, from_server))
1182 set_display_target(to, LOG_CTCP);
1183 else
1184 set_display_target(NULL, LOG_CTCP);
1185
1186 #ifdef WANT_DLL
1187 if (!dll && ctcp_cmd[i].id == CTCP_ACTION)
1188 check_flooding(from, CTCP_ACTION_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1189 else if (!dll && ctcp_cmd[i].id == CTCP_DCC)
1190 check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1191 #else
1192 if (ctcp_cmd[i].id == CTCP_ACTION)
1193 check_flooding(from, CTCP_ACTION_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1194 else if (ctcp_cmd[i].id == CTCP_DCC)
1195 check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1196 #endif
1197 else
1198 {
1199 check_flooding(from, CTCP_FLOOD, ctcp_argument, is_channel(to)?to:NULL);
1200 if (get_int_var(NO_CTCP_FLOOD_VAR) && (now - get_server_last_ctcp_time(from_server) < get_int_var(CTCP_DELAY_VAR)))
1201 {
1202 if (get_int_var(FLOOD_WARNING_VAR))
1203 put_it("%s", convert_output_format(fget_string_var(FORMAT_FLOOD_FSET), "%s %s %s %s %s", update_clock(GET_TIME),ctcp_command,from, FromUserHost, to));
1204 set_server_last_ctcp_time(from_server, time(NULL));
1205 allow_ctcp_reply = 0;
1206 continue;
1207 }
1208 }
1209 /* Did the CTCP search work? */
1210 #ifdef WANT_DLL
1211 if (i == NUMBER_OF_CTCPS && !dll)
1212 #else
1213 if (i == NUMBER_OF_CTCPS)
1214 #endif
1215 {
1216 /*
1217 * Offer it to the user.
1218 * Maybe they know what to do with it.
1219 */
1220 #ifdef WANT_TCL
1221 if (check_tcl_ctcp(from, FromUserHost, from, to, ctcp_command, ctcp_argument))
1222 continue;
1223 #endif
1224
1225 if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument) && allow_ctcp_reply)
1226 {
1227 if (get_int_var(CTCP_VERBOSE_VAR))
1228 {
1229 #ifdef WANT_USERLIST
1230 if (lookup_userlevelc("*", FromUserHost, "*", NULL))
1231 put_it("%s", convert_output_format(fget_string_var(get_int_var(CLOAK_VAR)? FORMAT_CTCP_CLOAK_UNKNOWN_USER_FSET:FORMAT_CTCP_UNKNOWN_USER_FSET),
1232 "%s %s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1233 else
1234 #endif
1235 put_it("%s", convert_output_format(fget_string_var(get_int_var(CLOAK_VAR)? FORMAT_CTCP_CLOAK_UNKNOWN_FSET:FORMAT_CTCP_UNKNOWN_FSET),
1236 "%s %s %s %s %s %s",update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1237 }
1238
1239 add_last_type(&last_ctcp[0], 1, from, FromUserHost, to, ctcp_command);
1240 }
1241 allow_ctcp_reply = 0;
1242 continue;
1243 }
1244
1245 #ifdef WANT_TCL
1246 check_tcl_ctcp(from, FromUserHost, from, to, ctcp_command, ctcp_argument);
1247 #endif
1248
1249 #ifdef WANT_DLL
1250 if (dll)
1251 ptr = (dll->func) (dll, from, to, ctcp_argument);
1252 else
1253 #endif
1254 ptr = ctcp_cmd[i].func(ctcp_cmd + i, from, to, ctcp_argument);
1255
1256 #ifdef WANT_DLL
1257 if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT) || (dll && !(dll->flag & CTCP_NOLIMIT)))
1258 #else
1259 if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT))
1260 #endif
1261 {
1262 set_server_last_ctcp_time(from_server, time(NULL));
1263 allow_ctcp_reply = 0;
1264 }
1265
1266 /*
1267 * We've only gotten to this point if its a valid CTCP
1268 * query and we decided to parse it.
1269 */
1270
1271 /* If its an inline CTCP paste it back in */
1272 #ifdef WANT_DLL
1273 if ((ctcp_cmd[i].flag & CTCP_INLINE) || (dll && (dll->flag & CTCP_INLINE)))
1274 strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1275 #else
1276 if ((ctcp_cmd[i].flag & CTCP_INLINE))
1277 strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1278 #endif
1279 /* If its interesting, tell the user. */
1280 #ifdef WANT_DLL
1281 if ((ctcp_cmd[i].flag & CTCP_TELLUSER) || (dll && (dll->flag & CTCP_TELLUSER)))
1282 #else
1283 if ((ctcp_cmd[i].flag & CTCP_TELLUSER))
1284 #endif
1285 {
1286 if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument))
1287 {
1288 if (get_int_var(CTCP_VERBOSE_VAR))
1289 #ifdef WANT_USERLIST
1290 put_it("%s", convert_output_format(fget_string_var((!lookup_userlevelc("*",FromUserHost, "*", NULL))? get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_FSET:FORMAT_CTCP_FSET:get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_USER_FSET:FORMAT_CTCP_USER_FSET),
1291 "%s %s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1292 #else
1293 put_it("%s", convert_output_format(fget_string_var((get_int_var(CLOAK_VAR)?FORMAT_CTCP_CLOAK_FSET:FORMAT_CTCP_FSET)),
1294 "%s %s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, ctcp_command, *ctcp_argument? ctcp_argument : empty_string));
1295 #endif
1296 add_last_type(&last_ctcp[0], 1, from, FromUserHost, to, ctcp_command);
1297 }
1298 }
1299
1300 new_free(&ptr);
1301 }
1302
1303 /* Reset the window level/logging */
1304 reset_display_target();
1305
1306 in_ctcp_flag--;
1307 strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE);
1308 return str;
1309 }
1310
1311
1312
1313 /*
1314 * do_notice_ctcp: a re-entrant form of a CTCP reply parser.
1315 */
do_notice_ctcp(char * from,char * to,char * str)1316 extern char *do_notice_ctcp (char *from, char *to, char *str)
1317 {
1318 int flag;
1319 char local_ctcp_buffer [BIG_BUFFER_SIZE + 1],
1320 the_ctcp [IRCD_BUFFER_SIZE + 1],
1321 last [IRCD_BUFFER_SIZE + 1];
1322 char *ctcp_command,
1323 *ctcp_argument;
1324 int i;
1325 char *ptr;
1326 char *tbuf = NULL;
1327 int allow_ctcp_reply = 1;
1328
1329 #ifdef WANT_DLL
1330 CtcpEntryDll *dll = NULL;
1331 #endif
1332
1333 int delim_char = charcount(str, CTCP_DELIM_CHAR);
1334
1335 if (delim_char < 2)
1336 return str; /* No CTCPs. */
1337 if (delim_char > 8)
1338 allow_ctcp_reply = 0; /* Ignore all the CTCPs. */
1339
1340 flag = check_ignore(from, FromUserHost, to, IGNORE_CTCPS, NULL);
1341 if (!in_ctcp_flag)
1342 in_ctcp_flag = -1;
1343
1344 tbuf = stripansi(str);
1345 strlcpy(local_ctcp_buffer, tbuf, sizeof local_ctcp_buffer - 2);
1346 new_free(&tbuf);
1347
1348 for (;;strlcat(local_ctcp_buffer, last, sizeof local_ctcp_buffer - 2))
1349 {
1350 split_CTCP(local_ctcp_buffer, the_ctcp, last);
1351 if (!*the_ctcp)
1352 break; /* all done! */
1353
1354 if (!allow_ctcp_reply)
1355 continue;
1356
1357 if (flag == IGNORED)
1358 {
1359 allow_ctcp_reply = 0;
1360 continue;
1361 }
1362
1363 /* Global messages -- just drop the CTCP */
1364 if (*to == '$' || (*to == '#' && !lookup_channel(to, from_server, 0)))
1365 {
1366 allow_ctcp_reply = 0;
1367 continue;
1368 }
1369
1370 ctcp_command = the_ctcp;
1371 ctcp_argument = strchr(the_ctcp, ' ');
1372 if (ctcp_argument)
1373 *ctcp_argument++ = 0;
1374 else
1375 ctcp_argument = empty_string;
1376
1377 #ifdef WANT_DLL
1378 /* Find the correct CTCP and run it. */
1379 for (dll = dll_ctcp; dll; dll = dll->next)
1380 if (!strcmp(dll->name, ctcp_command))
1381 break;
1382 #endif
1383 /* Find the correct CTCP and run it. */
1384 for (i = 0; i < NUMBER_OF_CTCPS; i++)
1385 if (!strcmp(ctcp_command, ctcp_cmd[i].name))
1386 break;
1387
1388 /*
1389 * If we've already parsed one, and there is a limit
1390 * on this CTCP, then just punt it.
1391 */
1392 #ifdef WANT_DLL
1393 if (i < NUMBER_OF_CTCPS && !dll && ctcp_cmd[i].repl)
1394 #else
1395 if (i < NUMBER_OF_CTCPS && ctcp_cmd[i].repl)
1396 #endif
1397 {
1398 if ((ptr = ctcp_cmd[i].repl(ctcp_cmd + i, from, to, ctcp_argument)))
1399 {
1400 strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1401 new_free(&ptr);
1402 continue;
1403 }
1404 }
1405 #ifdef WANT_DLL
1406 if (dll && dll->repl)
1407 {
1408 if ((ptr = dll->repl(dll, from, to, ctcp_argument)))
1409 {
1410 strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer);
1411 new_free(&ptr);
1412 continue;
1413 }
1414 }
1415 #endif
1416 #ifdef WANT_TCL
1417 check_tcl_ctcr(from, FromUserHost, from, to, ctcp_command, ctcp_argument?ctcp_argument:empty_string);
1418 #endif
1419 /* Set up the window level/logging */
1420 set_display_target(from, LOG_CTCP);
1421 /* Toss it at the user. */
1422 if (do_hook(CTCP_REPLY_LIST, "%s %s %s", from, ctcp_command, ctcp_argument))
1423 {
1424 put_it("%s", convert_output_format(fget_string_var(FORMAT_CTCP_REPLY_FSET),"%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, ctcp_command, ctcp_argument));
1425 add_last_type(&last_ctcp_reply[0], 1, from, FromUserHost, ctcp_command, ctcp_argument);
1426 }
1427
1428 allow_ctcp_reply = 0;
1429 }
1430
1431 if (in_ctcp_flag == -1)
1432 in_ctcp_flag = 0;
1433 /* Reset the window level/logging */
1434 reset_display_target();
1435
1436 strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE);
1437 return str;
1438 }
1439
1440
1441
1442 /* in_ctcp: simply returns the value of the ctcp flag */
in_ctcp(void)1443 extern int in_ctcp (void) { return (in_ctcp_flag); }
1444
1445
1446
1447 /*
1448 * This is no longer directly sends information to its target.
1449 * As part of a larger attempt to consolidate all data transmission
1450 * into send_text, this function was modified so as to use send_text().
1451 * This function can send both direct CTCP requests, as well as the
1452 * appropriate CTCP replies. By its use of send_text(), it can send
1453 * CTCPs to DCC CHAT and irc nickname peers, and handles encryption
1454 * transparantly. This greatly reduces the logic, complexity, and
1455 * possibility for error in this function.
1456 */
send_ctcp(int type,char * to,int datatag,char * format,...)1457 extern void send_ctcp (int type, char *to, int datatag, char *format, ...)
1458 {
1459 char putbuf [BIG_BUFFER_SIZE + 1],
1460 *putbuf2;
1461 int len;
1462
1463 if ((len = IRCD_BUFFER_SIZE - (12 + strlen(to))) < 0)
1464 return;
1465
1466 if (len < strlen(ctcp_cmd[datatag].name) + 3)
1467 return;
1468
1469 putbuf2 = alloca(len);
1470
1471 if (format)
1472 {
1473 va_list args;
1474 va_start(args, format);
1475 vsnprintf(putbuf, BIG_BUFFER_SIZE, format, args);
1476 va_end(args);
1477
1478 do_hook(SEND_CTCP_LIST, "%s %s %s %s",
1479 ctcp_type[type], to,
1480 ctcp_cmd[datatag].name, putbuf);
1481 snprintf(putbuf2, len, "%c%s %s%c",
1482 CTCP_DELIM_CHAR,
1483 ctcp_cmd[datatag].name, putbuf,
1484 CTCP_DELIM_CHAR);
1485 }
1486 else
1487 {
1488 do_hook(SEND_CTCP_LIST, "%s %s %s",
1489 ctcp_type[type], to,
1490 ctcp_cmd[datatag].name);
1491 snprintf(putbuf2, len, "%c%s%c",
1492 CTCP_DELIM_CHAR,
1493 ctcp_cmd[datatag].name,
1494 CTCP_DELIM_CHAR);
1495 }
1496
1497 putbuf2[len - 2] = CTCP_DELIM_CHAR;
1498 putbuf2[len - 1] = 0;
1499 send_text(to, putbuf2, ctcp_type[type], 0, 0);
1500 }
1501
1502
1503 /*
1504 * quote_it: This quotes the given string making it sendable via irc. A
1505 * pointer to the length of the data is required and the data need not be
1506 * null terminated (it can contain nulls). Returned is a malloced, null
1507 * terminated string.
1508 */
ctcp_quote_it(char * str,int len)1509 extern char *ctcp_quote_it (char *str, int len)
1510 {
1511 char buffer[BIG_BUFFER_SIZE + 1];
1512 char *ptr;
1513 int i;
1514
1515 ptr = buffer;
1516 for (i = 0; i < len; i++)
1517 {
1518 switch (str[i])
1519 {
1520 case CTCP_DELIM_CHAR: *ptr++ = CTCP_QUOTE_CHAR;
1521 *ptr++ = 'a';
1522 break;
1523 case '\n': *ptr++ = CTCP_QUOTE_CHAR;
1524 *ptr++ = 'n';
1525 break;
1526 case '\r': *ptr++ = CTCP_QUOTE_CHAR;
1527 *ptr++ = 'r';
1528 break;
1529 case CTCP_QUOTE_CHAR: *ptr++ = CTCP_QUOTE_CHAR;
1530 *ptr++ = CTCP_QUOTE_CHAR;
1531 break;
1532 case '\0': *ptr++ = CTCP_QUOTE_CHAR;
1533 *ptr++ = '0';
1534 break;
1535 default: *ptr++ = str[i];
1536 break;
1537 }
1538 }
1539 *ptr = '\0';
1540 return m_strdup(buffer);
1541 }
1542
1543 /*
1544 * ctcp_unquote_it: This takes a null terminated string that had previously
1545 * been quoted using ctcp_quote_it and unquotes it. Returned is a malloced
1546 * space pointing to the unquoted string. NOTE: a trailing null is added for
1547 * convenied, but the returned data may contain nulls!. The len is modified
1548 * to contain the size of the data returned.
1549 */
ctcp_unquote_it(char * str,int * len)1550 extern char *ctcp_unquote_it (char *str, int *len)
1551 {
1552 char *buffer;
1553 char *ptr;
1554 char c;
1555 int i,
1556 new_size = 0;
1557
1558 buffer = (char *) new_malloc((sizeof(char) * *len) + 1);
1559 ptr = buffer;
1560 i = 0;
1561 while (i < *len)
1562 {
1563 if ((c = str[i++]) == CTCP_QUOTE_CHAR)
1564 {
1565 switch (c = str[i++])
1566 {
1567 case CTCP_QUOTE_CHAR:
1568 *ptr++ = CTCP_QUOTE_CHAR;
1569 break;
1570 case 'a':
1571 *ptr++ = CTCP_DELIM_CHAR;
1572 break;
1573 case 'n':
1574 *ptr++ = '\n';
1575 break;
1576 case 'r':
1577 *ptr++ = '\r';
1578 break;
1579 case '0':
1580 *ptr++ = '\0';
1581 break;
1582 default:
1583 *ptr++ = c;
1584 break;
1585 }
1586 }
1587 else
1588 *ptr++ = c;
1589 new_size++;
1590 }
1591 *ptr = '\0';
1592 *len = new_size;
1593 return (buffer);
1594 }
1595
get_ctcp_val(char * str)1596 int get_ctcp_val (char *str)
1597 {
1598 int i;
1599
1600 for (i = 0; i < NUMBER_OF_CTCPS; i++)
1601 if (!strcmp(str, ctcp_cmd[i].name))
1602 return i;
1603
1604 /*
1605 * This is *dangerous*, but it works. The only place that
1606 * calls this function is edit.c:ctcp(), and it immediately
1607 * calls send_ctcp(). So the pointer that is being passed
1608 * to us is globally allocated at a level higher then ctcp().
1609 * so it wont be bogus until some time after ctcp() returns,
1610 * but at that point, we dont care any more.
1611 */
1612 ctcp_cmd[CTCP_CUSTOM].name = str;
1613 return CTCP_CUSTOM;
1614 }
1615
1616
1617
1618 /*
1619 * XXXX -- some may call this a hack, but if youve got a better
1620 * way to handle this job, id love to use it.
1621 */
BX_split_CTCP(char * raw_message,char * ctcp_dest,char * after_ctcp)1622 void BX_split_CTCP(char *raw_message, char *ctcp_dest, char *after_ctcp)
1623 {
1624 char *ctcp_start, *ctcp_end;
1625
1626 *ctcp_dest = *after_ctcp = 0;
1627 ctcp_start = strchr(raw_message, CTCP_DELIM_CHAR);
1628 if (!ctcp_start)
1629 return; /* No CTCPs present. */
1630
1631 *ctcp_start++ = 0;
1632 ctcp_end = strchr(ctcp_start, CTCP_DELIM_CHAR);
1633 if (!ctcp_end)
1634 {
1635 *--ctcp_start = CTCP_DELIM_CHAR;
1636 return; /* Thats _not_ a CTCP. */
1637 }
1638
1639 *ctcp_end++ = 0;
1640 strlcpy(ctcp_dest, ctcp_start, IRCD_BUFFER_SIZE - 2);
1641 strlcpy(after_ctcp, ctcp_end, IRCD_BUFFER_SIZE - 2);
1642
1643 return; /* All done! */
1644 }
1645