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