1 /* dircproxy
2 * Copyright (C) 2000-2003 Scott James Remnant <scott at netsplit dot com>
3 *
4 * Copyright (C) 2004-2008 Francois Harvey <contact at francoisharvey dot ca>
5 *
6 * Copyright (C) 2008-2009 Noel Shrum <noel dot w8tvi at gmail dot com>
7 * Francois Harvey <contact at francoisharvey dot ca>
8 *
9 *
10 * irc_client.c
11 * - Handling of clients connected to the proxy
12 * - Functions to send data to the client in the correct protocol format
13 * --
14 * @(#) $Id: irc_client.c,v 1.96 2004/04/24 09:34:37 fharvey Exp $
15 *
16 * This file is distributed according to the GNU General Public
17 * License. For full details, read the top of 'main.c' or the
18 * file called COPYING that was distributed with this code.
19 */
20
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <time.h>
28
29 #include <dircproxy.h>
30
31 #ifdef HAVE_CRYPT_H
32 # include <crypt.h>
33 #else /* HAVE_CRYPT_H */
34 # include <unistd.h>
35 #endif /* HAVE_CRYPT_H */
36
37 #include "sprintf.h"
38 #include "net.h"
39 #include "dns.h"
40 #include "timers.h"
41 #include "dcc_net.h"
42 #include "irc_log.h"
43 #include "irc_net.h"
44 #include "irc_prot.h"
45 #include "irc_string.h"
46 #include "irc_server.h"
47 #include "irc_client.h"
48 #include "logo.h"
49
50 /* forward declarations */
51 static void _ircclient_connected2(struct ircproxy *, void *, const char *,
52 const char *);
53 static void _ircclient_data(struct ircproxy *, int);
54 static void _ircclient_error(struct ircproxy *, int, int);
55 static int _ircclient_detach(struct ircproxy *, const char *);
56 static int _ircclient_gotmsg(struct ircproxy *, const char *);
57 static int _ircclient_authenticate(struct ircproxy *, const char *);
58 static void _ircclient_resetnick(struct ircproxy *, void *);
59 static int _ircclient_got_details(struct ircproxy *, const char *,
60 const char *, const char *, const char *);
61 static int _ircclient_motd(struct ircproxy *);
62 static void _ircclient_timedout(struct ircproxy *, void *);
63 static int _ircclient_send_dccreject(struct ircproxy *, const char *,
64 const char *);
65 int _ircclient_handle_privmsg(struct ircproxy *, struct ircmessage);
66 void _ircclient_handle_recall(struct ircproxy *, struct ircmessage);
67 void _ircclient_handle_users(struct ircproxy *, struct ircmessage);
68 void _ircclient_handle_kill(struct ircproxy *, struct ircmessage);
69 void _ircclient_handle_notify(struct ircproxy *, struct ircmessage);
70 int _ircclient_handle_jump(struct ircproxy *, struct ircmessage);
71 void _ircclient_handle_status(struct ircproxy *, struct ircmessage);
72 void _ircclient_handle_help(struct ircproxy *, struct ircmessage);
73
74 /* New user mode bits */
75 #define RFC2812_MODE_W 0x04
76 #define RFC2812_MODE_I 0x08
77
78 /* Time/date format for strftime(3) */
79 #define START_TIMEDATE_FORMAT "%a, %d %b %Y %H:%M:%S %z"
80
81 /* Define MIN() */
82 #ifndef MIN
83 #define MIN(x, y) ((x) < (y) ? (x) : (y))
84 #endif /* MIN */
85
86 /* Called when a new client has connected */
ircclient_connected(struct ircproxy * p)87 int ircclient_connected(struct ircproxy *p) {
88 char ip[DNS_MAX_HOSTLEN];
89
90 ircclient_send_notice(p, "Looking up your hostname...");
91
92 net_ntop(&p->client_addr, ip, sizeof(ip));
93 dns_hostfromaddr(p, 0, ip, (dns_fun_t) _ircclient_connected2);
94
95 return 0;
96 }
97
98 /* Called once a client DNS lookup has completed */
_ircclient_connected2(struct ircproxy * p,void * data,const char * ip,const char * name)99 static void _ircclient_connected2(struct ircproxy *p, void *data,
100 const char *ip, const char *name) {
101 p->client_host = x_strdup(name);
102 if (!p->hostname)
103 p->hostname = x_strdup(name);
104 ircclient_send_notice(p, "Got your hostname.");
105
106 p->client_status |= IRC_CLIENT_CONNECTED;
107 net_hook(p->client_sock, SOCK_NORMAL, (void *)p,
108 ACTIVITY_FUNCTION(_ircclient_data),
109 ERROR_FUNCTION(_ircclient_error));
110
111 debug("Client connected from %s", p->client_host);
112
113 timer_new((void *)p, "client_auth", g.client_timeout,
114 TIMER_FUNCTION(_ircclient_timedout), (void *)0);
115 }
116
117 /* Called when a client sends us stuff. */
_ircclient_data(struct ircproxy * p,int sock)118 static void _ircclient_data(struct ircproxy *p, int sock) {
119 char *str;
120
121 if (sock != p->client_sock) {
122 error("Unexpected socket %d in _ircclient_data, expected %d", sock,
123 p->client_sock);
124 net_close(&sock);
125 return;
126 }
127
128 str = 0;
129 while (!p->dead && (p->client_status & IRC_CLIENT_CONNECTED)
130 && net_gets(p->client_sock, &str, "\r\n") > 0) {
131 debug(">> '%s'", str);
132 _ircclient_gotmsg(p, str);
133 free(str);
134 }
135 }
136
137 /* Called on client disconnection or error */
_ircclient_error(struct ircproxy * p,int sock,int bad)138 static void _ircclient_error(struct ircproxy *p, int sock, int bad) {
139 if (sock != p->client_sock) {
140 error("Unexpected socket %d in _ircclient_error, expected %d", sock,
141 p->client_sock);
142 net_close(&sock);
143 return;
144 }
145
146 if (bad) {
147 debug("Socket error");
148 } else {
149 debug("Client disconnect");
150 }
151
152 _ircclient_detach(p, 0);
153 }
154
155 /* Called to detach an irc client */
_ircclient_detach(struct ircproxy * p,const char * message)156 static int _ircclient_detach(struct ircproxy *p, const char *message) {
157 if (p->die_on_close) {
158 debug("Killing proxy");
159
160 if (message) {
161 ircserver_send_command(p, "QUIT", ":%s", message);
162 } else if (p->conn_class && p->conn_class->quit_message) {
163 ircserver_send_command(p, "QUIT", ":%s", p->conn_class->quit_message);
164 } else {
165 ircserver_send_command(p, "QUIT", ":Leaving IRC - %s %s",
166 PACKAGE, VERSION);
167 }
168 ircserver_close_sock(p);
169
170 p->conn_class = 0;
171 ircclient_close(p);
172
173 } else {
174 debug("Detaching proxy");
175 if (p->client_status == IRC_CLIENT_ACTIVE)
176 irclog_log(p, IRC_LOG_CLIENT, IRC_LOGFILE_ALL, PACKAGE,
177 "You disconnected");
178
179 /* Drop modes */
180 if ((p->client_status == IRC_CLIENT_ACTIVE)
181 && p->conn_class->drop_modes) {
182 char *mode;
183
184 mode = x_sprintf("-%s", p->conn_class->drop_modes);
185 debug("Auto-mode-change '%s'", mode);
186
187 ircclient_change_mode(p, mode);
188 if (p->server_status == IRC_SERVER_ACTIVE)
189 ircserver_send_command(p, "MODE", "%s %s", p->nickname, mode);
190
191 free(mode);
192 }
193
194 /* Send detach message to all channels we're on */
195 if ((p->server_status == IRC_SERVER_ACTIVE)
196 && (p->client_status == IRC_CLIENT_ACTIVE)) {
197 if (p->conn_class->detach_message) {
198 struct ircchannel *c;
199 int slashme;
200 char *msg;
201
202 msg = p->conn_class->detach_message;
203 if ((strlen(msg) >= 5) && !strncasecmp(msg, "/me ", 4)) {
204 /* Starts with /me */
205 slashme = 1;
206 msg += 4;
207 } else {
208 slashme = 0;
209 }
210
211 c = p->channels;
212 while (c) {
213 if (!c->inactive && !c->unjoined) {
214 if (slashme) {
215 ircserver_send_command(p, "PRIVMSG", "%s :\001ACTION %s\001",
216 c->name, msg);
217 } else {
218 ircserver_send_command(p, "PRIVMSG", "%s :%s", c->name, msg);
219 }
220 }
221 c = c->next;
222 }
223 }
224 }
225
226 /* Leave channels until they come back */
227 if ((p->server_status == IRC_SERVER_ACTIVE)
228 && (p->client_status == IRC_CLIENT_ACTIVE)) {
229 if (p->conn_class->channel_leave_on_detach) {
230 struct ircchannel *c;
231
232 c = p->channels;
233 while (c) {
234 struct ircchannel *t;
235
236 t = c;
237 c = c->next;
238
239 /* Leave the channel and decide whether to delete it or rejoin */
240 if (!t->inactive && !t->unjoined) {
241 ircserver_send_command(p, "PART", ":%s", t->name);
242 if (p->conn_class->channel_rejoin_on_attach) {
243 t->unjoined = 1;
244 } else {
245 ircnet_delchannel(p, t->name);
246 }
247 }
248 }
249 }
250 }
251
252 /* Set away message */
253 if ((p->server_status == IRC_SERVER_ACTIVE)
254 && (p->client_status == IRC_CLIENT_ACTIVE)) {
255 if (message) {
256 ircserver_send_command(p, "AWAY", ":%s", message);
257 } else if (!p->awaymessage && p->conn_class->away_message) {
258 ircserver_send_command(p, "AWAY", ":%s", p->conn_class->away_message);
259 }
260 }
261
262 /* Change Nickname */
263 if ((p->client_status == IRC_CLIENT_ACTIVE)
264 && p->conn_class->detach_nickname) {
265 char *nick, *ptr;
266
267 nick = x_strdup(p->conn_class->detach_nickname);
268 ptr = strchr(nick, '*');
269 if (ptr) {
270 char *newnick;
271
272 *(ptr++) = 0;
273 newnick = x_sprintf("%s%s%s", nick, p->nickname, ptr);
274 free(nick);
275 nick = newnick;
276 }
277 debug("Auto-nick-change '%s'", nick);
278
279 /* We need to remember what the setnickname is now so when the client
280 comes back we can reset it again. So put it in oldnickname. */
281 if (p->oldnickname)
282 free(p->oldnickname);
283 p->oldnickname = p->setnickname;
284 p->setnickname = 0;
285
286 ircclient_change_nick(p, nick);
287
288 free(nick);
289 }
290
291 /* Open private_log */
292 if ((p->client_status == IRC_CLIENT_ACTIVE)
293 && p->conn_class->private_log_enabled
294 && !p->conn_class->private_log_always) {
295 if (irclog_open(p, p->nickname))
296 ircclient_send_notice(p, "(warning) Unable to log private messages");
297 }
298
299 /* Open server log */
300 if ((p->client_status == IRC_CLIENT_ACTIVE)
301 && p->conn_class->server_log_enabled
302 && !p->conn_class->server_log_always) {
303 if (irclog_open(p, 0))
304 ircclient_send_notice(p, "(warning) Unable to log server messages");
305 }
306
307 /* Open channel logs */
308 if ((p->client_status == IRC_CLIENT_ACTIVE)
309 && p->conn_class->chan_log_enabled
310 && !p->conn_class->chan_log_always) {
311 struct ircchannel *c;
312
313 c = p->channels;
314 while (c) {
315 if (irclog_open(p, c->name))
316 ircclient_send_notice(p, "(warning) Unable to log channel: %s",
317 c->name);
318 c = c->next;
319 }
320 }
321
322 /* Close the socket */
323 ircclient_close(p);
324 }
325
326 return 0;
327 }
328
329 /* Called when we get an irc protocol data from a client */
_ircclient_gotmsg(struct ircproxy * p,const char * str)330 static int _ircclient_gotmsg(struct ircproxy *p, const char *str) {
331 struct ircmessage msg;
332
333 if (ircprot_parsemsg(str, &msg) == -1)
334 return -1;
335
336 debug("c=%02x, s=%02x", p->client_status, p->server_status);
337
338 if (!(p->client_status & IRC_CLIENT_AUTHED)) {
339 /* Accept PASS, NICK and USER commands only until we've authenticated */
340 if (!irc_strcasecmp(msg.cmd, "PASS")) {
341 if (msg.numparams >= 1) {
342 if (p->password)
343 free(p->password);
344 p->password = x_strdup(msg.params[0]);
345 p->client_status |= IRC_CLIENT_GOTPASS;
346 } else {
347 ircclient_send_numeric(p, 461, ":Not enough parameters");
348 }
349
350 } else if (!irc_strcasecmp(msg.cmd, "NICK")) {
351 if (msg.numparams >= 1) {
352 if (!(p->client_status & IRC_CLIENT_GOTNICK)
353 || strcmp(p->nickname, msg.params[0]))
354 ircclient_change_nick(p, msg.params[0]);
355 } else {
356 ircclient_send_numeric(p, 431, ":No nickname given");
357 }
358
359 } else if (!irc_strcasecmp(msg.cmd, "USER")) {
360 if (msg.numparams >= 4) {
361 if (!(p->client_status & IRC_CLIENT_GOTUSER))
362 _ircclient_got_details(p, msg.params[0], msg.params[1],
363 msg.params[2], msg.params[3]);
364 } else {
365 ircclient_send_numeric(p, 461, ":Not enough parameters");
366 }
367
368 } else if (!(p->client_status & IRC_CLIENT_GOTPASS)) {
369 ircclient_send_notice(p, "Please send /QUOTE PASS <password> to login");
370
371 } else {
372 ircclient_send_notice(p, "Please send /QUOTE NICK and /QUOTE USER");
373 }
374
375 } else if (!(p->client_status & IRC_CLIENT_GOTNICK)) {
376 /* We've lost the nickname */
377 if (!irc_strcasecmp(msg.cmd, "NICK")) {
378 if (msg.numparams >= 1) {
379 ircclient_change_nick(p, msg.params[0]);
380 } else {
381 ircclient_send_numeric(p, 431, ":No nickname given");
382 }
383
384 } else {
385 ircclient_send_notice(p, "Please send a /NICK command");
386 }
387
388 } else {
389 /* The server MUST be active to use most of the commands. The only
390 exception is /DIRCPROXY. */
391
392 if (p->server_status == IRC_SERVER_ACTIVE) {
393 /* By default we squelch everything, but the else clause turns this off.
394 Effectively it means that all handled commands are not passed to the
395 server unless you set squelch to 0 */
396 int squelch = 1;
397
398 if (!irc_strcasecmp(msg.cmd, "PASS")) {
399 /* Ignore PASS */
400 } else if (!irc_strcasecmp(msg.cmd, "USER")) {
401 /* Ignore USER */
402 } else if (!irc_strcasecmp(msg.cmd, "DIRCPROXY")) {
403 /* Ignore DIRCPROXY (handled in a minute) */
404 } else if (!irc_strcasecmp(msg.cmd, "QUIT")) {
405 /* User wants to detach */
406 ircnet_announce_status(p);
407 ircclient_send_error(p, "Detached from %s %s", PACKAGE, VERSION);
408 _ircclient_detach(p, 0);
409 ircprot_freemsg(&msg);
410 return 0;
411
412 } else if (!irc_strcasecmp(msg.cmd, "PONG")) {
413 /* Ignore PONG */
414
415 } else if (!irc_strcasecmp(msg.cmd, "NICK")) {
416 /* User changing their nickname */
417 if (msg.numparams >= 1) {
418 ircclient_change_nick(p, msg.params[0]);
419 } else {
420 ircclient_send_numeric(p, 431, ":No nickname given");
421 }
422
423 } else if (!irc_strcasecmp(msg.cmd, "AWAY")) {
424 /* User marking themselves as away or back */
425 squelch = 0;
426
427 /* ircII sends an empty parameter to mark back *grr* */
428 if ((msg.numparams >= 1) && strlen(msg.params[0])) {
429 free(p->awaymessage);
430 p->awaymessage = x_strdup(msg.params[0]);
431 } else {
432 free(p->awaymessage);
433 p->awaymessage = 0;
434 }
435
436 } else if (!irc_strcasecmp(msg.cmd, "MOTD")) {
437 /* User requesting the message of the day from the server */
438 p->allow_motd = 1;
439 squelch = 0;
440
441 } else if (!irc_strcasecmp(msg.cmd, "PING")) {
442 /* User requesting a ping from the server */
443 p->allow_pong = 1;
444 squelch = 0;
445
446 } else if (!irc_strcasecmp(msg.cmd, "PRIVMSG")) {
447 /* All PRIVMSGs go to the server unless we fiddle */
448 squelch = _ircclient_handle_privmsg(p, msg);
449
450 } else if (!irc_strcasecmp(msg.cmd, "NOTICE")) {
451 /* Notices from us get logged */
452 if (msg.numparams >= 2) {
453 char *str;
454
455 ircprot_stripctcp(msg.params[1], &str, 0);
456
457 if (str && strlen(str)) {
458 char *tmp;
459
460 tmp = x_sprintf("%s!%s@%s", p->nickname, p->username,
461 p->hostname);
462 irclog_log(p, IRC_LOG_NOTICE, msg.params[0], tmp, "%s", str);
463 free(tmp);
464 }
465 free(str);
466 }
467
468 if (p->conn_class->idle_maxtime)
469 ircserver_resetidle(p);
470 squelch = 0;
471
472 } else {
473 squelch = 0;
474 }
475
476 /* Send command up to server? (We know there is one at this point) */
477 if (!squelch)
478 net_send(p->server_sock, "%s\r\n", msg.orig);
479
480 } else if (irc_strcasecmp(msg.cmd, "DIRCPROXY")) {
481 /* Command didn't (and won't be) handled. We better stick to the
482 RFC and send a RPL_TRYAGAIN back. */
483 ircclient_send_numeric(p, 263, "%s :Please wait a while and try again.",
484 msg.cmd);
485 }
486
487 /* /DIRCPROXY can be used at *any* time, if it ever sends anything to the
488 server it has to do it explicitly (no automatic sending) and has to
489 check there is a server there */
490 if (!irc_strcasecmp(msg.cmd, "DIRCPROXY")) {
491 if (msg.numparams >= 1) {
492 if (!irc_strcasecmp(msg.params[0], "RECALL")) {
493 _ircclient_handle_recall(p, msg);
494
495 } else if (p->conn_class->allow_persist
496 && !irc_strcasecmp(msg.params[0], "PERSIST")) {
497 /* User wants a die_on_close proxy to persist */
498 if (p->die_on_close) {
499 if (p->conn_class->disconnect_on_detach) {
500 /* Its die_on_close because of configuration, can't dedicate! */
501 p->die_on_close = 0;
502 ircnet_announce_dedicated(p);
503 } else if (!ircnet_dedicate(p)) {
504 /* Okay, it was inetd - we can dedicate this */
505 p->die_on_close = 0;
506 } else {
507 ircclient_send_notice(p, "Could not persist");
508 }
509 } else {
510 ircnet_announce_dedicated(p);
511 }
512 } else if (!irc_strcasecmp(msg.params[0], "GET")) {
513 /* User want to get a configuration item */
514 if (p->conn_class->allow_dynamic >= 1) {
515 // todo
516 } else {
517 ircclient_send_notice(p, "You are not authorized to use GET command");
518 }
519 } else if (!irc_strcasecmp(msg.params[0], "SET")) {
520 /* User want to set a configuration item */
521 if (p->conn_class->allow_dynamic == 2) {
522 // todo
523 } else {
524 ircclient_send_notice(p, "You are not authorized to use SET command");
525 }
526 } else if (!irc_strcasecmp(msg.params[0], "RELOAD")) {
527 /* User wants to reload the configuration file */
528 ircclient_send_notice(p, "RELOAD in progress");
529 reload();
530
531 } else if (!irc_strcasecmp(msg.params[0], "DETACH")) {
532 /* User wants to detach and can't be bothered to use /QUIT */
533 ircnet_announce_status(p);
534 ircclient_send_error(p, "Detached from %s %s", PACKAGE, VERSION);
535
536 /* Optional AWAY message can be supplied */
537 if ((msg.numparams >= 2) && strlen(msg.paramstarts[1])) {
538 _ircclient_detach(p, msg.paramstarts[1]);
539 } else {
540 _ircclient_detach(p, 0);
541 }
542 ircprot_freemsg(&msg);
543 return 0;
544
545 } else if (!irc_strcasecmp(msg.params[0], "QUIT")) {
546 /* User wants to detach and end their proxy session */
547
548 if (IS_SERVER_READY(p)) {
549 /* Optional QUIT message can be supplied */
550 if ((msg.numparams >= 2) && strlen(msg.paramstarts[1])) {
551 ircserver_send_command(p, "QUIT", ":%s", msg.paramstarts[1]);
552 } else if (p->conn_class->quit_message) {
553 ircserver_send_command(p, "QUIT", ":%s",
554 p->conn_class->quit_message);
555 } else {
556 ircserver_send_command(p, "QUIT", ":Leaving IRC - %s %s",
557 PACKAGE, VERSION);
558 }
559 }
560
561 ircserver_close_sock(p);
562 p->conn_class = 0;
563 ircclient_close(p);
564 ircprot_freemsg(&msg);
565 return 0;
566
567 } else if (!irc_strcasecmp(msg.params[0], "MOTD")) {
568 /* Display message of the day file */
569 _ircclient_motd(p);
570
571 } else if (p->conn_class->allow_die
572 && !irc_strcasecmp(msg.params[0], "DIE")) {
573 /* User wants to kill us :( */
574 ircclient_send_notice(p, "I'm melting!");
575 stop();
576
577 } else if (p->conn_class->allow_users
578 && !irc_strcasecmp(msg.params[0], "USERS")) {
579 _ircclient_handle_users(p, msg);
580
581 } else if (p->conn_class->allow_kill
582 && !irc_strcasecmp(msg.params[0], "KILL")) {
583 _ircclient_handle_kill(p, msg);
584
585 } else if (p->conn_class->allow_notify
586 && !irc_strcasecmp(msg.params[0], "NOTIFY")) {
587 _ircclient_handle_notify(p, msg);
588
589 } else if (!irc_strcasecmp(msg.params[0], "SERVERS")) {
590 struct strlist *s;
591 int i;
592
593 s = p->conn_class->servers;
594 i = 0;
595
596 /* User wants a server list */
597 if (s) {
598 ircclient_send_notice(p, "You can connect to:");
599 } else {
600 ircclient_send_notice(p, "No servers");
601 }
602
603 while (s) {
604 ircclient_send_notice(p, "-%s %2d. %s",
605 (s == p->conn_class->next_server ? ">" : " "),
606 ++i, s->str);
607 s = s->next;
608 }
609
610 } else if (p->conn_class->allow_jump
611 && (!irc_strcasecmp(msg.params[0], "JUMP")
612 || !irc_strcasecmp(msg.params[0], "CONNECT"))) {
613 if (_ircclient_handle_jump(p, msg))
614 return 0;
615
616 } else if (p->conn_class->allow_host
617 && !irc_strcasecmp(msg.params[0], "HOST")) {
618 /* User wants to change their hostname */
619 free(p->conn_class->local_address);
620 p->conn_class->local_address = 0;
621
622 if (msg.numparams >= 2) {
623 if (irc_strcasecmp(msg.params[1], "none"))
624 p->conn_class->local_address = x_strdup(msg.params[1]);
625
626 } else if (p->conn_class->orig_local_address) {
627 p->conn_class->local_address =
628 x_strdup(p->conn_class->orig_local_address);
629 }
630
631 ircserver_connectagain(p);
632
633 /* We have no server now, so need to get out of here */
634 ircprot_freemsg(&msg);
635 return 0;
636
637 } else if (!irc_strcasecmp(msg.params[0], "STATUS")) {
638 _ircclient_handle_status(p, msg);
639
640 } else if (!irc_strcasecmp(msg.params[0], "HELP")) {
641 /* User needs a little help */
642 _ircclient_handle_help(p, msg);
643
644 } else {
645 /* Invalid command */
646 ircclient_send_numeric(p, 421, "%s :Unknown DIRCPROXY command",
647 msg.params[0]);
648
649 }
650 } else {
651 ircclient_send_numeric(p, 461, ":Not enough parameters");
652 }
653 }
654 }
655
656 /* Do we have enough information to authenticate them? */
657 if (!(p->client_status & IRC_CLIENT_AUTHED)
658 && (p->client_status & IRC_CLIENT_GOTPASS)
659 && (p->client_status & IRC_CLIENT_GOTNICK)
660 && (p->client_status & IRC_CLIENT_GOTUSER))
661 {
662 _ircclient_authenticate(p, p->password);
663 free(p->password);
664 p->password = 0;
665 p->client_status &= ~(IRC_CLIENT_GOTPASS);
666 }
667
668 /* Do we have enough information to connect to a server? */
669 if (IS_CLIENT_READY(p) && !p->dead) {
670 if (p->server_status != IRC_SERVER_ACTIVE) {
671 if (!(p->server_status & IRC_SERVER_CREATED)) {
672 if (p->conn_class && p->conn_class->server_autoconnect) {
673 ircserver_connect(p);
674 } else {
675 ircclient_send_notice(p, "Please send /DIRCPROXY JUMP "
676 "<hostname>[:[port][:[password]]] to choose a "
677 "server");
678
679 /* This won't delete an existing timer */
680 timer_new((void *)p, "client_connect", g.connect_timeout,
681 TIMER_FUNCTION(_ircclient_timedout), (void *)1);
682 }
683 } else if (!IS_SERVER_READY(p)) {
684 ircclient_send_notice(p, "Connection to server is in progress...");
685 }
686 } else if (!(p->client_status & IRC_CLIENT_SENTWELCOME)) {
687 ircclient_welcome(p);
688 }
689 }
690
691 ircprot_freemsg(&msg);
692 return 0;
693 }
694
695 /* Got a password */
_ircclient_authenticate(struct ircproxy * p,const char * password)696 static int _ircclient_authenticate(struct ircproxy *p, const char *password) {
697 struct ircconnclass *cc;
698
699 cc = connclasses;
700 while (cc) {
701 #ifdef ENCRYPTED_PASSWORDS
702 char *cmp;
703
704 cmp = crypt(password, cc->password);
705
706 if (!strcmp(cc->password, cmp)) {
707 #else
708 if (!strcmp(cc->password, password)) {
709 #endif
710 if (cc->masklist) {
711 struct strlist *m;
712 const char *ip;
713 char buf[40];
714
715 ip = net_ntop(&p->client_addr, buf, sizeof(buf));
716
717 m = cc->masklist;
718 while (m) {
719 if (strcasematch(ip, m->str) || strcasematch(p->client_host, m->str))
720 break;
721
722 m = m->next;
723 }
724
725 /* We got a matching masklist, so this one's ok */
726 if (m)
727 break;
728 } else {
729 break;
730 }
731 }
732
733 cc = cc->next;
734 }
735
736 if (cc) {
737 struct ircproxy *tmp_p;
738
739 tmp_p = ircnet_fetchclass(cc);
740 if (tmp_p && (tmp_p->client_status & IRC_CLIENT_CONNECTED)) {
741 if (tmp_p->conn_class->disconnect_existing) {
742 debug("Already connected, disconnecting existing");
743
744 ircclient_send_error(tmp_p, "Collided with new user");
745 ircclient_close(tmp_p);
746
747 if (tmp_p->dead) {
748 debug("Kicked off client, and they died");
749 tmp_p = 0;
750 }
751 } else {
752 debug("Already connected, disconnecting incoming");
753 ircclient_send_error(p, "Already connected");
754 ircclient_close(p);
755 return -1;
756 }
757 }
758
759 /* Check again, in case killing existing user killed the proxy */
760 if (tmp_p) {
761 debug("Attaching new client to old server session");
762
763 tmp_p->client_sock = p->client_sock;
764 tmp_p->client_status |= IRC_CLIENT_CONNECTED | IRC_CLIENT_AUTHED;
765 tmp_p->client_addr = p->client_addr;
766 net_hook(tmp_p->client_sock, SOCK_NORMAL, (void *)tmp_p,
767 ACTIVITY_FUNCTION(_ircclient_data),
768 ERROR_FUNCTION(_ircclient_error));
769
770 /* If the connecting client doesn't agree with the proxy about its
771 nickname, then correct it. */
772 if (strcmp(p->nickname, tmp_p->nickname))
773 ircclient_send_selfcmd(p, "NICK", ":%s", tmp_p->nickname);
774
775 /* If we've got to restore a different nickname, then do that now */
776 if (tmp_p->oldnickname && strcmp(tmp_p->oldnickname, tmp_p->nickname))
777 ircclient_change_nick(tmp_p, tmp_p->oldnickname);
778
779 /* We don't need this anymore */
780 free(tmp_p->oldnickname);
781 tmp_p->oldnickname = 0;
782
783 /* Notify nickserv */
784 if (tmp_p->conn_class->nickserv_password)
785 ircserver_send_command(tmp_p, "PRIVMSG", " %s :IDENTIFY %s", "NICKSERV",tmp_p->conn_class->nickserv_password);
786
787 /* Unset any away message if we set one */
788 if (!tmp_p->awaymessage && (tmp_p->server_status == IRC_SERVER_ACTIVE)
789 && tmp_p->conn_class->away_message)
790 ircserver_send_command(tmp_p, "AWAY", "");
791
792 /* Rejoin any channels we parted */
793 if ((tmp_p->server_status == IRC_SERVER_ACTIVE) && tmp_p->channels) {
794 struct ircchannel *c;
795
796 c = tmp_p->channels;
797 while (c) {
798 if (c->unjoined) {
799 if (c->key) {
800 ircserver_send_command(tmp_p, "JOIN", "%s :%s", c->name, c->key);
801 } else {
802 ircserver_send_command(tmp_p, "JOIN", ":%s", c->name);
803 }
804 }
805
806 c = c->next;
807 }
808 }
809
810 /* Send attach message to all channels we're on */
811 if (tmp_p->server_status == IRC_SERVER_ACTIVE) {
812 if (tmp_p->conn_class->attach_message) {
813 struct ircchannel *c;
814 int slashme;
815 char *msg;
816
817 msg = tmp_p->conn_class->attach_message;
818 if ((strlen(msg) >= 5) && !strncasecmp(msg, "/me ", 4)) {
819 /* Starts with /me */
820 slashme = 1;
821 msg += 4;
822 } else {
823 slashme = 0;
824 }
825
826 c = tmp_p->channels;
827 while (c) {
828 if (!c->inactive) {
829 if (slashme) {
830 ircserver_send_command(tmp_p, "PRIVMSG",
831 "%s :\001ACTION %s\001", c->name, msg);
832 } else {
833 ircserver_send_command(tmp_p, "PRIVMSG", "%s :%s",
834 c->name, msg);
835 }
836 }
837 c = c->next;
838 }
839 }
840 }
841
842 if ((tmp_p->server_status == IRC_SERVER_ACTIVE)
843 && !(tmp_p->client_status & IRC_CLIENT_SENTWELCOME))
844 ircclient_welcome(tmp_p);
845
846 p->client_status = IRC_CLIENT_NONE;
847 p->client_sock = -1;
848 p->dead = 1;
849
850 } else {
851 struct strlist *s;
852
853 p->conn_class = cc;
854 p->client_status |= IRC_CLIENT_AUTHED;
855 time(&(p->start));
856
857 if (p->conn_class->disconnect_on_detach)
858 p->die_on_close = 1;
859
860 /* Okay, they've authed for the first time, make the log directory
861 here */
862 if (p->conn_class->chan_log_enabled
863 || p->conn_class->private_log_enabled
864 || p->conn_class->server_log_enabled) {
865 if (irclog_maketempdir(p))
866 ircclient_send_notice(p, "(warning) Unable to create log "
867 "directory, logging disabled");
868 }
869
870 /* Initialise the private message log */
871 irclog_init(p, "");
872
873 /* Open a log file if we're always logging */
874 if (p->conn_class->private_log_enabled
875 && p->conn_class->private_log_always) {
876 if (irclog_open(p, ""))
877 ircclient_send_notice(p, "(warning) Unable to log private messages");
878 }
879
880 /* Initialise the server message log */
881 irclog_init(p, 0);
882
883 /* Open a log file if we're always logging */
884 if (p->conn_class->server_log_enabled
885 && p->conn_class->server_log_always) {
886 if (irclog_open(p, 0))
887 ircclient_send_notice(p, "(warning) Unable to log server messages");
888 }
889
890 /* Join initial channels */
891 s = p->conn_class->channels;
892 while (s) {
893 struct ircchannel *c;
894 char *name, *key;
895
896 name = x_strdup(s->str);
897 key = strchr(name, ' ');
898 if (key)
899 *(key++) = 0;
900
901 ircnet_addchannel(p, name);
902 c = ircnet_fetchchannel(p, name);
903 if (c) {
904 c->inactive = 1;
905 if (key)
906 c->key = x_strdup(key);
907 }
908
909 free(name);
910
911 s = s->next;
912 }
913
914 /* Set initial modes */
915 if (p->conn_class->initial_modes)
916 ircclient_change_mode(p, p->conn_class->initial_modes);
917
918 /* Notify nickserv */
919 // currently broken i will look in next revision
920 /* if (p->conn_class->nickserv_password) */
921 /* ircserver_send_command(p, "PRIVMSG", " %s :IDENTIFY %s", "NICKSERV",p->conn_class->nickserv_password); */
922 }
923
924 return 0;
925 }
926
927 ircclient_send_numeric(p, 464, ":You are not permitted to use this proxy");
928 ircclient_send_error(p, "Permission Denied");
929 ircclient_close(p);
930 return -1;
931 }
932
933 /* Request a nickname change */
934 int ircclient_change_nick(struct ircproxy *p, const char *newnick) {
935 /* If a server is ready to accept a NICK command, send it */
936 if (IS_SERVER_READY(p)) {
937 debug("Requesting nick change from '%s' to '%s'",
938 (p->nickname ? p->nickname : ""), newnick);
939 ircserver_send_command(p, "NICK", ":%s", newnick);
940 }
941
942 /* If we have a nickname already then the server will confirm that, otherwise
943 we should remember it ourselves */
944 if (p->client_status & IRC_CLIENT_GOTNICK) {
945 debug("Server will change it for us");
946 p->expecting_nick = 1;
947
948 return 0;
949 } else {
950 int ret;
951
952 /* Because we're not expecting a server confirmation, then we better
953 do the confirm for the client ourselves */
954 if ((p->client_status & IRC_CLIENT_CONNECTED) &&
955 (p->client_status & IRC_CLIENT_AUTHED))
956 ircclient_send_selfcmd(p, "NICK", ":%s", newnick);
957
958 /* Make the change in the wings */
959 ret = ircclient_nick_changed(p, newnick);
960 ircclient_setnickname(p);
961 ircclient_checknickname(p);
962
963 return ret;
964 }
965 }
966
967 /* Nickname has now definitly been changed */
968 int ircclient_nick_changed(struct ircproxy *p, const char *newnick) {
969 if (p->nickname)
970 debug("nickname WAS '%s'", p->nickname);
971 free(p->nickname);
972
973 p->nickname = x_strdup(newnick);
974 p->client_status |= IRC_CLIENT_GOTNICK;
975 debug("nickname NOW '%s'", p->nickname);
976
977 return 0;
978 }
979
980 /* Make the current nickname the set one */
981 int ircclient_setnickname(struct ircproxy *p) {
982 /* Update setnickname too */
983 if (p->setnickname)
984 free(p->setnickname);
985 p->setnickname = x_strdup(p->nickname);
986 debug("Changed setnickname to '%s'", p->setnickname);
987
988 return 0;
989 }
990
991 /* Check whether we need to restore the nickname later */
992 int ircclient_checknickname(struct ircproxy *p) {
993 if (p->conn_class && p->conn_class->nick_keep
994 && strcmp(p->nickname, p->setnickname))
995 timer_new((void *)p, "client_resetnick", NICK_GUARD_TIME,
996 TIMER_FUNCTION(_ircclient_resetnick), (void *)0);
997
998 return 0;
999 }
1000
1001 /* Change the nickname to something we generate ourselves */
1002 int ircclient_generate_nick(struct ircproxy *p, const char *tried) {
1003 char *c, *nick;
1004 int ret;
1005
1006 c = nick = (char *)malloc(strlen(tried) + 2);
1007 strcpy(nick, tried);
1008 c += strlen(nick) - 1;
1009
1010 /* We add -'s until we can't, then we move back through them cycling them
1011 0..9 then finally _ until the whole nickname is _________. Once that
1012 happens we just use 'dircproxy' and do it all over again */
1013 if (strlen(nick) < 9) {
1014 *(++c) = '-';
1015 *(++c) = 0;
1016 } else {
1017 while (c >= nick) {
1018 if (*c == '-') {
1019 *c = '0';
1020 break;
1021 } else if ((*c >= '0') && (*c < '9')) {
1022 (*c)++;
1023 break;
1024 } else if (*c == '9') {
1025 *c = '_';
1026 break;
1027 } else if (*c == '_') {
1028 c--;
1029 } else {
1030 *c = '-';
1031 break;
1032 }
1033 }
1034
1035 if (c < nick) {
1036 free(nick);
1037 nick = x_strdup(FALLBACK_NICKNAME);
1038 }
1039 }
1040
1041 /* Ask the server to change the nickname */
1042 if (IS_SERVER_READY(p)) {
1043 debug("Requesting nick change from '%s' to '%s'",
1044 (p->nickname ? p->nickname : ""), nick);
1045 ircserver_send_command(p, "NICK", ":%s", nick);
1046 }
1047
1048 /* If we don't have a nickname yet, make the change ourselves */
1049 if (!(p->client_status & IRC_CLIENT_GOTNICK)) {
1050 /* We know that there is no client connected, otherwise this would
1051 never have been called, so no point sending a nickname to the client.
1052
1053 Just change it in our memory */
1054 ret = ircclient_nick_changed(p, nick);
1055 ircclient_checknickname(p);
1056 } else {
1057 debug("Server will change it for us");
1058 }
1059
1060 free(nick);
1061 return 0;
1062 }
1063
1064 /* Timer hook to restore a lost nickname */
1065 static void _ircclient_resetnick(struct ircproxy *p, void *data) {
1066 /* We don't have a server anymore, setnickname will be restored on
1067 connection attempt */
1068 if (!IS_SERVER_READY(p))
1069 return;
1070
1071 /* Is it worth doing this? */
1072 if (!strcmp(p->nickname, p->setnickname))
1073 return;
1074
1075 /* Ask the server to change the nickname */
1076 debug("Attempting to restore nickname to '%s'", p->setnickname);
1077 ircclient_change_nick(p, p->setnickname);
1078 }
1079
1080 /* Got some details */
1081 static int _ircclient_got_details(struct ircproxy *p, const char *newusername,
1082 const char *newmode, const char *unused,
1083 const char *newrealname) {
1084 int mode;
1085
1086 if (!p->username)
1087 p->username = x_strdup(newusername);
1088
1089 if (!p->realname)
1090 p->realname = x_strdup(newrealname);
1091
1092 /* RFC2812 states that the second parameter to USER is a numeric stating
1093 what default modes to set. This disagrees with RFC1459. We follow
1094 the newer one if we can, as the old hostname/servername combo were
1095 useless and ignored anyway. */
1096 mode = atoi(newmode);
1097 if (mode & RFC2812_MODE_W)
1098 ircclient_change_mode(p, "+w");
1099 if (mode & RFC2812_MODE_I)
1100 ircclient_change_mode(p, "+w");
1101
1102 /* Okay we have the username now */
1103 p->client_status |= IRC_CLIENT_GOTUSER;
1104
1105 return 0;
1106 }
1107
1108 /* Got a personal mode change */
1109 int ircclient_change_mode(struct ircproxy *p, const char *change) {
1110 char *ptr, *str;
1111 int add = 1;
1112
1113 ptr = str = x_strdup(change);
1114 debug("Mode change from '%s', '%s'", (p->modes ? p->modes : ""), str);
1115
1116 while (*ptr) {
1117 switch (*ptr) {
1118 case '+':
1119 add = 1;
1120 break;
1121 case '-':
1122 add = 0;
1123 break;
1124 default:
1125 if (add) {
1126 if (!p->modes || !strchr(p->modes, *ptr)) {
1127 if (p->modes) {
1128 p->modes = (char *)realloc(p->modes, strlen(p->modes) + 2);
1129 } else {
1130 p->modes = (char *)malloc(2);
1131 p->modes[0] = 0;
1132 }
1133 p->modes[strlen(p->modes) + 1] = 0;
1134 p->modes[strlen(p->modes)] = *ptr;
1135 }
1136 } else if (p->modes) {
1137 char *pos;
1138
1139 pos = strchr(p->modes, *ptr);
1140 if (pos) {
1141 char *tmp;
1142
1143 tmp = p->modes;
1144 p->modes = (char *)malloc(strlen(p->modes));
1145 *(pos++) = 0;
1146 strcpy(p->modes, tmp);
1147 strcpy(p->modes + strlen(p->modes), pos);
1148 free(tmp);
1149
1150 if (!strlen(p->modes)) {
1151 free(p->modes);
1152 p->modes = 0;
1153 }
1154 }
1155 }
1156 }
1157
1158 ptr++;
1159 }
1160
1161 debug(" now '%s'", (p->modes ? p->modes : ""));
1162 free(str);
1163 return 0;
1164 }
1165
1166 /* Close the client socket */
1167 int ircclient_close(struct ircproxy *p) {
1168 timer_del((void *)p, "client_auth");
1169 timer_del((void *)p, "client_connect");
1170
1171 net_close(&(p->client_sock));
1172 p->client_sock = -1;
1173 p->client_status &= ~(IRC_CLIENT_CONNECTED | IRC_CLIENT_AUTHED
1174 | IRC_CLIENT_SENTWELCOME);
1175
1176 /* No connection class, or no nick or user? Die! */
1177 if (!p->conn_class || !(p->client_status & IRC_CLIENT_GOTNICK)
1178 || !(p->client_status & IRC_CLIENT_GOTUSER)) {
1179 if (p->server_status & IRC_SERVER_CREATED) {
1180 ircserver_send_command(p, "QUIT", ":I shouldn't really be here - %s %s",
1181 PACKAGE, VERSION);
1182 ircserver_close_sock(p);
1183 }
1184 p->dead = 1;
1185 }
1186
1187 return p->dead;
1188 }
1189
1190 /* send message of the day to the user */
1191 static int _ircclient_motd(struct ircproxy *p) {
1192 FILE *motd_file;
1193
1194 if (p->conn_class->motd_file) {
1195 motd_file = fopen(p->conn_class->motd_file, "r");
1196 if (!motd_file)
1197 syscall_fail("fopen", p->conn_class->motd_file, 0);
1198 } else {
1199 motd_file = (FILE *)0;
1200 }
1201
1202 /* Check whether to do anything, and send appropriate numerics */
1203 if (!p->conn_class->motd_logo && !p->conn_class->motd_stats && !motd_file) {
1204 if (p->conn_class->motd_file) {
1205 ircclient_send_numeric(p, 422, ":MOTD File is missing");
1206 } else {
1207 ircclient_send_numeric(p, 422, ":No MOTD");
1208 }
1209 return 0;
1210 } else {
1211 ircclient_send_numeric(p, 375, ":- %s Message of the Day -", PACKAGE);
1212 }
1213
1214 /* Send the pretty dircproxy logo */
1215 if (p->conn_class->motd_logo) {
1216 char *ver;
1217 int line;
1218
1219 line = 0;
1220 while (logo[line]) {
1221 ircclient_send_numeric(p, 372, ":- %s", logo[line]);
1222 line++;
1223 }
1224
1225 ver = x_sprintf(verstr, VERSION);
1226 ircclient_send_numeric(p, 372, ":- %s", ver);
1227 ircclient_send_numeric(p, 372, ":-");
1228 free(ver);
1229 }
1230
1231 /* Send from file */
1232 if (motd_file) {
1233 char buff[512];
1234
1235 while (fgets(buff, 512, motd_file)) {
1236 char *ptr;
1237
1238 ptr = buff + strlen(buff);
1239 while ((ptr >= buff) && (!ptr || strchr(" \t\r\n", *ptr))) *(ptr--) = 0;
1240 ircclient_send_numeric(p, 372, ":- %s", buff);
1241 }
1242
1243 ircclient_send_numeric(p, 372, ":-");
1244 }
1245
1246 /* Send some stats */
1247 if (p->conn_class->motd_stats) {
1248 /* Private messages */
1249 if (p->private_log.filename) {
1250 char *s;
1251
1252 if (p->conn_class->private_log_recall == -1) {
1253 s = x_strdup(p->private_log.nlines ? "all" : "none");
1254 } else if (p->conn_class->private_log_recall == 0) {
1255 s = x_strdup("none");
1256 } else if (p->conn_class->private_log_recall == p->private_log.nlines) {
1257 s = x_strdup("all");
1258 } else {
1259 s = x_sprintf("%ld", p->conn_class->private_log_recall);
1260 }
1261
1262 ircclient_send_numeric(p, 372, ":- %ld private message%s "
1263 "(%s will be sent)", p->private_log.nlines,
1264 (p->private_log.nlines == 1 ? "" : "s"), s);
1265 ircclient_send_numeric(p, 372, ":-");
1266
1267 free(s);
1268 }
1269
1270 /* Server messages */
1271 if (p->server_log.filename) {
1272 char *s;
1273
1274 if (p->conn_class->server_log_recall == -1) {
1275 s = x_strdup(p->server_log.nlines ? "all" : "none");
1276 } else if (p->conn_class->server_log_recall == 0) {
1277 s = x_strdup("none");
1278 } else if (p->conn_class->server_log_recall == p->server_log.nlines) {
1279 s = x_strdup("all");
1280 } else {
1281 s = x_sprintf("%ld", p->conn_class->server_log_recall);
1282 }
1283
1284 ircclient_send_numeric(p, 372, ":- %ld server message%s "
1285 "(%s will be sent)", p->server_log.nlines,
1286 (p->server_log.nlines == 1 ? "" : "s"), s);
1287 ircclient_send_numeric(p, 372, ":-");
1288
1289 free(s);
1290 }
1291
1292
1293 /* Channels they were on */
1294 if (p->channels) {
1295 struct ircchannel *c;
1296
1297 c = p->channels;
1298 while (c) {
1299 if (c->inactive) {
1300 if (c->log.nlines) {
1301 ircclient_send_numeric(p, 372, ":- was on %s but removed by force",
1302 c->name);
1303 } else {
1304 ircclient_send_numeric(p, 372, ":- yet to join %s", c->name);
1305 }
1306 } else if (c->unjoined) {
1307 ircclient_send_numeric(p, 372, ":- was on %s, yet to rejoin",
1308 c->name);
1309 } else if (c->log.filename) {
1310 char *s;
1311
1312 if (p->conn_class->chan_log_recall == -1) {
1313 s = x_strdup(c->log.nlines ? "all" : "none");
1314 } else if (p->conn_class->chan_log_recall == 0) {
1315 s = x_strdup("none");
1316 } else if (p->conn_class->chan_log_recall == c->log.nlines) {
1317 s = x_strdup("all");
1318 } else {
1319 s = x_sprintf("%ld", MIN(c->log.nlines,
1320 p->conn_class->chan_log_recall));
1321 }
1322
1323 ircclient_send_numeric(p, 372, ":- %s. %ld line%s logged. "
1324 "(%s will be sent)", c->name, c->log.nlines,
1325 (c->log.nlines == 1 ? "" : "s"), s);
1326
1327 free(s);
1328 } else {
1329 ircclient_send_numeric(p, 372, ":- %s (not logged)", c->name);
1330 }
1331 c = c->next;
1332 }
1333 ircclient_send_numeric(p, 372, ":-");
1334 }
1335 }
1336
1337 /* Done */
1338 ircclient_send_numeric(p, 376, ":End of /MOTD command");
1339 if (motd_file)
1340 fclose(motd_file);
1341
1342 return 1;
1343 }
1344
1345 /* send welcome headers to the user */
1346 int ircclient_welcome(struct ircproxy *p) {
1347 char tbuf[40];
1348
1349 strftime(tbuf, sizeof(tbuf), START_TIMEDATE_FORMAT, localtime(&(p->start)));
1350
1351 ircclient_send_numeric(p, 1, ":Welcome to the Internet Relay Network %s",
1352 p->nickname);
1353 ircclient_send_numeric(p, 2, ":Your host is %s running %s via %s %s",
1354 p->servername,
1355 (p->serverver ? p->serverver : "(unknown)"),
1356 PACKAGE, VERSION);
1357 ircclient_send_numeric(p, 3, ":This proxy has been running since %s", tbuf);
1358 if (p->serverver)
1359 ircclient_send_numeric(p, 4, "%s %s %s %s",
1360 p->servername, p->serverver,
1361 p->serverumodes, p->servercmodes);
1362 struct strlist *s = p->serversupported;
1363 while (s) {
1364 ircclient_send_numeric(p, 5, "%s", s->str);
1365 s = s->next;
1366 }
1367
1368 _ircclient_motd(p);
1369
1370 if (p->modes)
1371 ircclient_send_selfcmd(p, "MODE", "%s +%s", p->nickname, p->modes);
1372
1373 if (p->awaymessage) {
1374 /* Ack. There's no reason for a client to expect AWAY from a server,
1375 so we cheat and send a 306, reminding them what their away message
1376 was in the text. This might not trick the client either, but hey,
1377 I can't do anything about that. */
1378 ircclient_send_numeric(p, 306, ":%s: %s",
1379 "You left yourself away. Your message was",
1380 p->awaymessage);
1381 }
1382
1383 /* Recall other log file */
1384 if (p->conn_class->server_log_enabled) {
1385 irclog_autorecall(p, 0);
1386 if (!p->conn_class->server_log_always)
1387 irclog_close(p, 0);
1388 }
1389
1390 /* Recall channel log files, and get channel topic and members from server */
1391 if (p->channels) {
1392 struct ircchannel *c;
1393
1394 c = p->channels;
1395 while (c) {
1396 if (!c->inactive && !c->unjoined) {
1397 ircclient_send_selfcmd(p, "JOIN", ":%s", c->name);
1398 ircserver_send_command(p, "TOPIC", ":%s", c->name);
1399 ircserver_send_command(p, "NAMES", ":%s", c->name);
1400
1401 if (p->conn_class->chan_log_enabled) {
1402 irclog_autorecall(p, c->name);
1403 if (!p->conn_class->chan_log_always)
1404 irclog_close(p, c->name);
1405 }
1406 }
1407
1408 c = c->next;
1409 }
1410 }
1411
1412 /* Recall private log file */
1413 if (p->conn_class->private_log_enabled) {
1414 irclog_autorecall(p, p->nickname);
1415 if (!p->conn_class->private_log_always)
1416 irclog_close(p, p->nickname);
1417 }
1418
1419 irclog_log(p, IRC_LOG_CLIENT, IRC_LOGFILE_ALL, PACKAGE, "You connected");
1420 ircnet_announce_status(p);
1421
1422 p->client_status |= IRC_CLIENT_SENTWELCOME;
1423 return 0;
1424 }
1425
1426 /* Timer hook when something's timed out */
1427 static void _ircclient_timedout(struct ircproxy *p, void *data) {
1428 int connect;
1429
1430 /* These are always called after the timeout if the client's still
1431 connected, check the event they were looking for has happened */
1432 connect = (int)data;
1433 if (connect && (p->server_status & IRC_SERVER_CREATED)) {
1434 /* Connecting to server, and a socket has been created to do it */
1435 debug("Server has been chosen");
1436 return;
1437 } else if (!connect && IS_CLIENT_READY(p)) {
1438 /* Authorization, and client is ready to accept data */
1439 debug("They are authorized");
1440 return;
1441 }
1442
1443 /* Timeout! */
1444 debug("Timed out");
1445 ircclient_send_error(p, "%s Timeout", (connect ? "Connect" : "Login"));
1446 ircclient_close(p);
1447 }
1448
1449 /* send a numeric to the user */
1450 int ircclient_send_numeric(struct ircproxy *p, short numeric,
1451 const char *format, ...) {
1452 va_list ap;
1453 char *msg;
1454 int ret;
1455
1456 va_start(ap, format);
1457 msg = x_vsprintf(format, ap);
1458 va_end(ap);
1459
1460 ret = net_send(p->client_sock, ":%s %03d %s %s\r\n",
1461 (p->servername ? p->servername : PACKAGE), numeric,
1462 (p->nickname ? p->nickname : "*"), msg);
1463 debug("<- ':%s %03d %s %s'", (p->servername ? p->servername : PACKAGE),
1464 numeric, (p->nickname ? p->nickname : "*"), msg);
1465
1466 free(msg);
1467 return ret;
1468 }
1469
1470 /* send a notice to the user */
1471 int ircclient_send_notice(struct ircproxy *p, const char *format, ...) {
1472 va_list ap;
1473 char *msg;
1474 int ret;
1475
1476 va_start(ap, format);
1477 msg = x_vsprintf(format, ap);
1478 va_end(ap);
1479
1480 ret = net_send(p->client_sock, ":%s %s %s :%s\r\n", PACKAGE, "NOTICE",
1481 (p->nickname ? p->nickname : "AUTH"), msg);
1482 debug("<- ':%s %s %s :%s'", PACKAGE, "NOTICE",
1483 (p->nickname ? p->nickname : "AUTH"), msg);
1484
1485 free(msg);
1486 return ret;
1487 }
1488
1489 /* send a notice to a channel */
1490 int ircclient_send_channotice(struct ircproxy *p, const char *channel,
1491 const char *format, ...) {
1492 va_list ap;
1493 char *msg;
1494 int ret;
1495
1496 va_start(ap, format);
1497 msg = x_vsprintf(format, ap);
1498 va_end(ap);
1499
1500 ret = net_send(p->client_sock, ":%s %s %s :%s\r\n",
1501 (p->servername ? p->servername : PACKAGE), "NOTICE",
1502 channel, msg);
1503 debug("<- ':%s %s %s :%s'", (p->servername ? p->servername : PACKAGE),
1504 "NOTICE", channel, msg);
1505
1506 free(msg);
1507 return ret;
1508 }
1509
1510 /* send a command to the user from the server */
1511 int ircclient_send_command(struct ircproxy *p, const char *command,
1512 const char *format, ...) {
1513 va_list ap;
1514 char *msg;
1515 int ret;
1516
1517 va_start(ap, format);
1518 msg = x_vsprintf(format, ap);
1519 va_end(ap);
1520
1521 ret = net_send(p->client_sock, ":%s %s %s\r\n",
1522 (p->servername ? p->servername : PACKAGE), command, msg);
1523 debug("<- ':%s %s %s'", (p->servername ? p->servername : PACKAGE),
1524 command, msg);
1525
1526 free(msg);
1527 return ret;
1528 }
1529
1530 /* send a command to the user making it look like its from them */
1531 int ircclient_send_selfcmd(struct ircproxy *p, const char *command,
1532 const char *format, ...) {
1533 char *msg, *prefix;
1534 va_list ap;
1535 int ret;
1536
1537 va_start(ap, format);
1538 msg = x_vsprintf(format, ap);
1539 va_end(ap);
1540
1541 if (p->nickname && p->username && p->hostname) {
1542 prefix = x_sprintf(":%s!%s@%s ", p->nickname, p->username, p->hostname);
1543 } else if (p->nickname) {
1544 prefix = x_sprintf(":%s ", p->nickname);
1545 } else {
1546 prefix = (char *)malloc(1);
1547 prefix[0] = 0;
1548 }
1549
1550 ret = net_send(p->client_sock, "%s%s %s\r\n", prefix, command, msg);
1551 debug("<- '%s%s %s'", prefix, command, msg);
1552
1553 free(prefix);
1554 free(msg);
1555 return ret;
1556 }
1557
1558 /* send an error to the user */
1559 int ircclient_send_error(struct ircproxy *p, const char *format, ...) {
1560 char *msg, *nick, *user, *host;
1561 va_list ap;
1562 int ret;
1563
1564 va_start(ap, format);
1565 msg = x_vsprintf(format, ap);
1566 va_end(ap);
1567
1568 nick = p->nickname ? p->nickname : "";
1569 user = p->username ? p->username : "user";
1570 host = p->hostname ? p->hostname : "host";
1571
1572 ret = net_send(p->client_sock, "%s :%s: %s[%s@%s] (%s)\r\n",
1573 "ERROR", "Closing Link", nick, user, host, msg);
1574 debug("<- '%s :%s: %s[%s@%s] (%s)'", "ERROR", "Closing Link",
1575 nick, user, host, msg);
1576
1577 free(msg);
1578 return ret;
1579 }
1580
1581 /* Send a DCC reject message */
1582 static int _ircclient_send_dccreject(struct ircproxy *p, const char *msg,
1583 const char *reason) {
1584 int ret = 1;
1585
1586 if (p && p->conn_class && p->conn_class->dcc_proxy_sendreject &&
1587 (p->client_status == IRC_CLIENT_ACTIVE)) {
1588 if (reason) {
1589 ret = net_send(p->client_sock, "%s (%s: %s)\001\r\n", msg,
1590 PACKAGE, reason);
1591 debug("<- '%s (%s: %s)\001'", msg, PACKAGE, reason);
1592 } else {
1593 ret = net_send(p->client_sock, "%s\001\r\n", msg);
1594 debug("<- '%s\001'", msg);
1595 }
1596 }
1597
1598 return ret;
1599 }
1600
1601 /* /DIRCPROXY STATUS handler */
1602 void _ircclient_handle_status(struct ircproxy *p, struct ircmessage msg) {
1603 struct ircchannel *c;
1604 struct strlist *s;
1605
1606 ircclient_send_notice(p, "%s %s status:", PACKAGE, VERSION);
1607 ircclient_send_notice(p, "- Nickname on server: %s", p->nickname);
1608 ircclient_send_notice(p, "- Nickname to guard: %s", p->setnickname);
1609 ircclient_send_notice(p, "- Username for server: %s", p->username);
1610 ircclient_send_notice(p, "- Hostname for server: %s", p->hostname);
1611 ircclient_send_notice(p, "- Real name for server: %s", p->realname);
1612 ircclient_send_notice(p, "-");
1613
1614 ircclient_send_notice(p, "- Client status: %s",
1615 IS_CLIENT_READY(p) ? "Ready" : "");
1616 if (p->client_status != IRC_CLIENT_ACTIVE) {
1617 if (p->client_status & IRC_CLIENT_CONNECTED)
1618 ircclient_send_notice(p, "- Connected");
1619 if (p->client_status & IRC_CLIENT_GOTPASS)
1620 ircclient_send_notice(p, "- Received password");
1621 if (p->client_status & IRC_CLIENT_GOTNICK)
1622 ircclient_send_notice(p, "- Received nickname");
1623 if (p->client_status & IRC_CLIENT_GOTUSER)
1624 ircclient_send_notice(p, "- Received user information");
1625 if (p->client_status & IRC_CLIENT_AUTHED)
1626 ircclient_send_notice(p, "- Authorised");
1627 if (p->client_status & IRC_CLIENT_SENTWELCOME)
1628 ircclient_send_notice(p, "- Welcomed");
1629 }
1630 ircclient_send_notice(p, "-");
1631
1632 ircclient_send_notice(p, "- Server status: %s",
1633 IS_SERVER_READY(p) ? "Ready" : "");
1634 if (p->server_status != IRC_SERVER_ACTIVE) {
1635 if (p->server_status & IRC_SERVER_CREATED)
1636 ircclient_send_notice(p, "- Created");
1637 if (p->server_status & IRC_SERVER_SEEN)
1638 ircclient_send_notice(p, "- Seen");
1639 if (p->server_status & IRC_SERVER_CONNECTED)
1640 ircclient_send_notice(p, "- Connected");
1641 if (p->server_status & IRC_SERVER_INTRODUCED)
1642 ircclient_send_notice(p, "- Introduced ourselves");
1643 if (p->server_status & IRC_SERVER_GOTWELCOME)
1644 ircclient_send_notice(p, "- Have been welcomed");
1645 }
1646 ircclient_send_notice(p, "-");
1647
1648 ircclient_send_notice(p, "- Servers. Current marked by '->'");
1649 s = p->conn_class->servers;
1650 while (s) {
1651 ircclient_send_notice(p, "-%s %s",
1652 (s == p->conn_class->next_server ? ">" : " "),
1653 s->str);
1654 s = s->next;
1655 }
1656 ircclient_send_notice(p, "-");
1657
1658 ircclient_send_notice(p, "- Channels");
1659 c = p->channels;
1660 while (c) {
1661 ircclient_send_notice(p, "- %s%s%s%s%s%s",
1662 c->name,
1663 c->key ? " (key: " : "",
1664 c->key ? c->key : "",
1665 c->key ? ")" : "",
1666 c->inactive ? " (removed by force)" : "",
1667 c->unjoined ? " (left on detach)" : "");
1668 c = c->next;
1669 }
1670 ircclient_send_notice(p, "-");
1671
1672 ircclient_send_notice(p, "- Advanced:");
1673 ircclient_send_notice(p, "- Allow MOTD count: %d", p->allow_motd);
1674 ircclient_send_notice(p, "- Allow PONG count: %d", p->allow_pong);
1675 ircclient_send_notice(p, "- 411 Squelch count: %d", p->squelch_411);
1676 ircclient_send_notice(p, "- Expecting NICK count: %d",
1677 p->expecting_nick);
1678
1679 if (p->squelch_modes)
1680 ircclient_send_notice(p, "- Squelching mode changes:");
1681 s = p->squelch_modes;
1682 while (s) {
1683 ircclient_send_notice(p, "- %s", s->str);
1684 s = s->next;
1685 }
1686 }
1687
1688 /* /DIRCPROXY JUMP handler */
1689 int _ircclient_handle_jump(struct ircproxy *p, struct ircmessage msg) {
1690 struct strlist *server;
1691
1692 /* User wants to jump to a new server */
1693 if (msg.numparams >= 2) {
1694 struct strlist *s;
1695 int i;
1696
1697 /* Check the server list to see whether its a plain jump */
1698 server = 0;
1699 s = p->conn_class->servers;
1700 i = 0;
1701 while (s) {
1702 if ((atoi(msg.params[1]) == ++i)
1703 || !irc_strcasecmp(msg.params[1], s->str)) {
1704 server = s;
1705 break;
1706 }
1707
1708 s = s->next;
1709 }
1710
1711 } else {
1712 /* User wants to jump to the next server */
1713 server = 0;
1714 if (p->conn_class->next_server)
1715 server = p->conn_class->next_server->next;
1716 if (!server)
1717 server = p->conn_class->servers;
1718 }
1719
1720 /* Allocate new server if jump_new */
1721 if (!server && p->conn_class->allow_jump_new
1722 && (msg.numparams >= 2)) {
1723 debug("New server");
1724
1725 server = (struct strlist *)malloc(sizeof(struct strlist));
1726 server->str = x_strdup(msg.params[1]);
1727 server->next = 0;
1728
1729 if (p->conn_class->servers) {
1730 struct strlist *ss;
1731
1732 ss = p->conn_class->servers;
1733 while (ss->next)
1734 ss = ss->next;
1735
1736 ss->next = server;
1737 } else {
1738 p->conn_class->servers = server;
1739 }
1740
1741 } else if (!server) {
1742 ircclient_send_numeric(p, 402, "No such server, "
1743 "use /DIRCPROXY SERVERS to see them");
1744 }
1745
1746 if (server) {
1747 debug("Jumping to %s", server->str);
1748
1749 p->conn_class->next_server = server;
1750 ircserver_connectagain(p);
1751
1752 /* We have no server now, so need to get out of here */
1753 ircprot_freemsg(&msg);
1754 return 1;
1755 } else {
1756 return 0;
1757 }
1758 }
1759
1760 /* /DIRCPROXY KILL handler */
1761 void _ircclient_handle_kill(struct ircproxy *p, struct ircmessage msg) {
1762 struct ircproxy *proxy;
1763
1764 /* User wants to kill a user */
1765 if (msg.numparams >= 2) {
1766 struct ircconnclass *c;
1767 struct ircproxy *cp;
1768 int i;
1769
1770 /* Check the user list */
1771 proxy = 0;
1772 c = connclasses;
1773 i = 0;
1774 while (c) {
1775 cp = ircnet_fetchclass(c);
1776 if (!cp) {
1777 c = c->next;
1778 continue;
1779 }
1780
1781 if ((atoi(msg.params[1]) == ++i)
1782 || (cp->client_host
1783 && !irc_strcasecmp(msg.params[1], cp->client_host))
1784 || (cp->servername
1785 && !irc_strcasecmp(msg.params[1], cp->servername))
1786 || (cp->nickname
1787 && !irc_strcasecmp(msg.params[1], cp->nickname))) {
1788 proxy = cp;
1789 break;
1790 }
1791
1792 c = c->next;
1793 }
1794
1795 if (proxy && (proxy == p)) {
1796 ircclient_send_notice(p, "Use /DIRCPROXY QUIT to kill yourself");
1797 } else if (proxy) {
1798 if (IS_SERVER_READY(proxy)) {
1799 ircserver_send_command(proxy, "QUIT",
1800 ":Killed by adminstrator - %s %s",
1801 PACKAGE, VERSION);
1802 }
1803 if (IS_CLIENT_READY(proxy)) {
1804 ircclient_send_error(proxy, "Killed by administrator");
1805 }
1806
1807 ircserver_close_sock(proxy);
1808 proxy->conn_class = 0;
1809 ircclient_close(proxy);
1810
1811 } else {
1812 ircclient_send_numeric(p, 401, "No such user, "
1813 "use /DIRCPROXY USERS to see them");
1814 }
1815
1816 } else {
1817 ircclient_send_numeric(p, 461, ":Not enough parameters");
1818 }
1819 }
1820
1821 /* /DIRCPROXY NOTIFY handler */
1822 void _ircclient_handle_notify(struct ircproxy *p, struct ircmessage msg)
1823 {
1824 struct ircproxy *proxy;
1825 /* User wants to kill a user */
1826 if (msg.numparams >= 2) {
1827 struct ircconnclass *c;
1828 struct ircproxy *cp;
1829 int i;
1830
1831 /* Check the user list */
1832 proxy = 0;
1833 c = connclasses;
1834 i = 0;
1835 while (c) {
1836 cp = ircnet_fetchclass(c);
1837 if (!cp) {
1838 c = c->next;
1839 continue;
1840 }
1841 if ((atoi(msg.params[1]) == ++i)
1842 || (cp->client_host
1843 && !irc_strcasecmp(msg.params[1], cp->client_host))
1844 || (cp->servername
1845 && !irc_strcasecmp(msg.params[1], cp->servername))
1846 || (cp->nickname
1847 && !irc_strcasecmp(msg.params[1], cp->nickname))) {
1848 proxy = cp;
1849 break;
1850 }
1851 c = c->next;
1852 }
1853
1854 if (proxy) {
1855 net_send(proxy->client_sock, ":dircproxy!dircproxy@localhost NOTICE %s :%s\r\n",cp->nickname, msg.paramstarts[2]);
1856 } else {
1857 ircclient_send_numeric(p, 401, "No such user, use /DIRCPROXY USERS to see them");
1858 }
1859 }
1860
1861 }
1862
1863
1864 /* /DIRCPROXY USERS handler */
1865 void _ircclient_handle_users(struct ircproxy *p, struct ircmessage msg) {
1866 struct ircconnclass *c;
1867 struct ircproxy *cp;
1868 int i;
1869
1870 c = connclasses;
1871 i = 0;
1872
1873 ircclient_send_notice(p, "Connection classes:");
1874
1875 while (c) {
1876 cp = ircnet_fetchclass(c);
1877 if (!cp) {
1878 c = c->next;
1879 continue;
1880 }
1881
1882 ircclient_send_notice(p, "-%s %2d. %s -> %s (%s)",
1883 (cp == p ? ">" : " "), ++i,
1884 cp->client_host ? cp->client_host : "(none)",
1885 cp->servername ? cp->servername : "(none)",
1886 cp->nickname ? cp->nickname : "no nickname");
1887 c = c->next;
1888 }
1889 }
1890
1891 /* /DIRCPROXY RECALL handler */
1892 void _ircclient_handle_recall(struct ircproxy *p, struct ircmessage msg) {
1893 char *src, *filter;
1894 long start, lines;
1895
1896 /* User wants to recall stuff from log files */
1897 src = filter = 0;
1898 start = -1;
1899 lines = 0;
1900
1901 if (msg.numparams >= 4) {
1902 src = msg.params[1];
1903 start = atol(msg.params[2]);
1904 lines = atol(msg.params[3]);
1905 } else if (msg.numparams >= 3) {
1906 if (!irc_strcasecmp(msg.params[2], "ALL")) {
1907 src = msg.params[1];
1908 lines = -1;
1909 } else if (strspn(msg.params[1], "0123456789")
1910 == strlen(msg.params[1])) {
1911 start = atol(msg.params[1]);
1912 lines = atol(msg.params[2]);
1913 } else {
1914 src = msg.params[1];
1915 lines = atol(msg.params[2]);
1916 }
1917 } else if (msg.numparams >= 2) {
1918 if (!irc_strcasecmp(msg.params[1], "ALL")) {
1919 lines = -1;
1920 } else {
1921 lines = atol(msg.params[1]);
1922 }
1923 } else {
1924 ircclient_send_numeric(p, 461, ":Not enough parameters");
1925 }
1926
1927 if (src && !irc_strcasecmp(src, "SERVER")) {
1928 src = 0;
1929 } else if (src) {
1930 struct ircchannel *c;
1931
1932 c = ircnet_fetchchannel(p, src);
1933 if (!c) {
1934 filter = src;
1935 src = p->nickname;
1936 }
1937 } else {
1938 src = p->nickname;
1939 }
1940
1941 irclog_recall(p, src, start, lines, filter);
1942 }
1943
1944 /* PRIVMSG handler */
1945 int _ircclient_handle_privmsg(struct ircproxy *p, struct ircmessage msg) {
1946 int squelch = 0;
1947
1948 if (msg.numparams >= 2) {
1949 struct strlist *list, *s;
1950 char *str;
1951
1952 ircprot_stripctcp(msg.params[1], &str, &list);
1953
1954 /* Privmsgs from us get logged */
1955 if (str && strlen(str)) {
1956 char *tmp;
1957
1958 tmp = x_sprintf("%s!%s@%s", p->nickname, p->username,
1959 p->hostname);
1960 irclog_log(p, IRC_LOG_MSG, msg.params[0], tmp, "%s", str);
1961 free(tmp);
1962 }
1963 free(str);
1964
1965 /* Handle CTCP */
1966 str = x_strdup(msg.params[1]);
1967 s = list;
1968 while (s) {
1969 struct ctcpmessage cmsg;
1970 struct strlist *n;
1971 char *unquoted;
1972 int r;
1973
1974 n = s->next;
1975 r = ircprot_parsectcp(s->str, &cmsg);
1976 unquoted = s->str;
1977 free(s);
1978 s = n;
1979 if (r == -1) {
1980 free(unquoted);
1981 continue;
1982 }
1983
1984 if (!strcmp(cmsg.cmd, "ACTION")) {
1985 char *tmp;
1986
1987 tmp = x_sprintf("%s!%s@%s", p->nickname, p->username,
1988 p->hostname);
1989 if (cmsg.paramstarts)
1990 irclog_log(p, IRC_LOG_ACTION, msg.params[0], tmp, "%s", cmsg.paramstarts[0]);
1991 else
1992 irclog_log(p, IRC_LOG_ACTION, msg.params[0], tmp, NULL);
1993 free(tmp);
1994
1995 } else if (!strcmp(cmsg.cmd, "DCC")
1996 && p->conn_class->dcc_proxy_outgoing) {
1997 struct sockaddr_in vis_addr;
1998 int len;
1999
2000 /* We need our local address to do anything DCC related */
2001 len = sizeof(struct sockaddr_in);
2002 if (getsockname(p->server_sock, (struct sockaddr *)&vis_addr,
2003 &len)) {
2004 syscall_fail("getsockname", "", 0);
2005
2006 } else if ((cmsg.numparams >= 4)
2007 && (!irc_strcasecmp(cmsg.params[0], "CHAT")
2008 || !irc_strcasecmp(cmsg.params[0], "SEND"))) {
2009 char *tmp, *ptr, *dccmsg, *rejmsg;
2010 struct in_addr l_addr, r_addr;
2011 int l_port, r_port, t_port;
2012 char *rest = 0;
2013 int type = 0;
2014
2015 /* Find out what type of DCC request this is */
2016 if (!irc_strcasecmp(cmsg.params[0], "CHAT")) {
2017 type = DCC_CHAT;
2018 } else if (!irc_strcasecmp(cmsg.params[0], "SEND")) {
2019 if (p->conn_class->dcc_send_fast) {
2020 type = DCC_SEND_FAST;
2021 } else {
2022 type = DCC_SEND_SIMPLE;
2023 }
2024 }
2025
2026 /* Check whether there's a tunnel port */
2027 t_port = 0;
2028 if (p->conn_class->dcc_tunnel_outgoing)
2029 t_port = dns_portfromserv(p->conn_class->dcc_tunnel_outgoing);
2030
2031 /* Eww, host order, how the hell does this even work
2032 between machines of a different byte order? */
2033 if (!t_port) {
2034 r_addr.s_addr = strtoul(cmsg.params[2], (char **)NULL, 10);
2035 r_port = atoi(cmsg.params[3]);
2036 } else {
2037 r_addr.s_addr = INADDR_LOOPBACK;
2038 r_port = ntohs(t_port);
2039 }
2040 l_addr.s_addr = ntohl(vis_addr.sin_addr.s_addr);
2041 if (cmsg.numparams >= 5)
2042 rest = cmsg.paramstarts[4];
2043
2044 /* Strip out this CTCP from the message, replacing it in
2045 a moment with dccmsg */
2046 tmp = x_sprintf("\001%s\001", unquoted);
2047 ptr = strstr(str, tmp);
2048 dccmsg = 0;
2049
2050 /* Save this in case we need it later */
2051 rejmsg = x_sprintf(":%s NOTICE %s :\001DCC REJECT %s %s",
2052 msg.params[0], p->nickname,
2053 cmsg.params[0], cmsg.params[1]);
2054
2055 /* Set up a dcc proxy */
2056 if (ptr && !dccnet_new(type, p->conn_class->dcc_proxy_timeout,
2057 p->conn_class->dcc_proxy_ports,
2058 p->conn_class->dcc_proxy_ports_sz,
2059 &l_port, r_addr, r_port, 0, 0,
2060 DCCN_FUNCTION(_ircclient_send_dccreject),
2061 p, rejmsg, 0)) {
2062 char *me_tmp;
2063
2064 dccmsg = x_sprintf("\001DCC %s %s %lu %u%s%s\001",
2065 cmsg.params[0], cmsg.params[1],
2066 l_addr.s_addr, l_port,
2067 (rest ? " " : ""), (rest ? rest : ""));
2068
2069 me_tmp = x_sprintf("%s!%s@%s", p->nickname, p->username,
2070 p->hostname);
2071 irclog_log(p, IRC_LOG_CTCP, msg.params[0], me_tmp,
2072 "Sent DCC %s Request", cmsg.params[0]);
2073 free(me_tmp);
2074
2075 } else if (ptr) {
2076 dccmsg = x_strdup("");
2077 _ircclient_send_dccreject(p, rejmsg,
2078 "Couldn't establish proxy");
2079 }
2080
2081 /* Don't need this now */
2082 free(rejmsg);
2083
2084 /* Cut out the old CTCP and replace with dccmsg */
2085 if (ptr) {
2086 char *oldstr;
2087
2088 *ptr = 0;
2089 ptr += strlen(tmp);
2090
2091 oldstr = str;
2092 str = x_sprintf("%s%s%s", oldstr, dccmsg, ptr);
2093
2094 free(oldstr);
2095 free(dccmsg);
2096 }
2097
2098 free(tmp);
2099
2100 } else {
2101 /* Unknown DCC */
2102 if (cmsg.numparams > 0)
2103 debug("Unknown or Unimplemented DCC request - %s", cmsg.params[0]);
2104 }
2105
2106 } else {
2107 char *tmp;
2108
2109 tmp = x_sprintf("%s!%s@%s", p->nickname, p->username,
2110 p->hostname);
2111 if (cmsg.numparams > 0)
2112 irclog_log(p, IRC_LOG_CTCP, msg.params[0], tmp, "Sent CTCP %s", cmsg.params[0]);
2113 free(tmp);
2114 }
2115
2116 ircprot_freectcp(&cmsg);
2117 free(unquoted);
2118 }
2119
2120 /* Send str */
2121 if (strlen(str))
2122 net_send(p->server_sock, ":%s PRIVMSG %s :%s\r\n",
2123 (msg.src.orig ? msg.src.orig : p->nickname),
2124 msg.params[0], str);
2125 squelch = 1;
2126 free(str);
2127 }
2128
2129 if (p->conn_class->idle_maxtime)
2130 ircserver_resetidle(p);
2131
2132 return squelch;
2133 }
2134
2135 /* /DIRCPROXY HELP handler */
2136 void _ircclient_handle_help(struct ircproxy *p, struct ircmessage msg) {
2137 char **help_page;
2138
2139 help_page = 0;
2140
2141 if ((msg.numparams >= 2) && strlen(msg.params[1])) {
2142 if (!irc_strcasecmp(msg.params[1], "RECALL")) {
2143 help_page = command_help[I_HELP_RECALL];
2144 } else if (p->conn_class->allow_persist
2145 && !irc_strcasecmp(msg.params[1], "PERSIST")) {
2146 help_page = command_help[I_HELP_PERSIST];
2147 } else if (!irc_strcasecmp(msg.params[1], "RELOAD")) {
2148 help_page = command_help[I_HELP_RELOAD];
2149 } else if (!irc_strcasecmp(msg.params[1], "DETACH")) {
2150 help_page = command_help[I_HELP_DETACH];
2151 } else if (!irc_strcasecmp(msg.params[1], "QUIT")) {
2152 help_page = command_help[I_HELP_QUIT];
2153 } else if (!irc_strcasecmp(msg.params[1], "MOTD")) {
2154 help_page = command_help[I_HELP_MOTD];
2155 } else if (p->conn_class->allow_die
2156 && !irc_strcasecmp(msg.params[1], "DIE")) {
2157 help_page = command_help[I_HELP_DIE];
2158 } else if (!irc_strcasecmp(msg.params[1], "SERVERS")) {
2159 help_page = command_help[I_HELP_SERVERS];
2160 } else if (p->conn_class->allow_jump
2161 && !irc_strcasecmp(msg.params[1], "JUMP")) {
2162 help_page = (p->conn_class->allow_jump_new
2163 ? command_help[I_HELP_JUMP_NEW] : command_help[I_HELP_JUMP]);
2164 } else if (p->conn_class->allow_host
2165 && !irc_strcasecmp(msg.params[1], "HOST")) {
2166 help_page = command_help[I_HELP_HOST];
2167 } else if (!irc_strcasecmp(msg.params[1], "STATUS")) {
2168 help_page = command_help[I_HELP_STATUS];
2169 } else if (!irc_strcasecmp(msg.params[1], "USERS")) {
2170 help_page = command_help[I_HELP_USERS];
2171 } else if (!irc_strcasecmp(msg.params[1], "KILL")) {
2172 help_page = command_help[I_HELP_KILL];
2173 } else if (!irc_strcasecmp(msg.params[1], "NOTIFY")) {
2174 help_page = command_help[I_HELP_NOTIFY];
2175 } else if (!irc_strcasecmp(msg.params[1], "HELP")) {
2176 help_page = command_help[I_HELP_HELP];
2177 } else {
2178 help_page = command_help[I_HELP_INDEX];
2179 }
2180
2181 } else {
2182 help_page = command_help[I_HELP_INDEX];
2183 }
2184
2185 if (help_page) {
2186 int i;
2187
2188 i = 0;
2189 ircclient_send_notice(p, "%s %s help", PACKAGE, VERSION);
2190 while (help_page[i]) {
2191 ircclient_send_notice(p, "- %s", help_page[i]);
2192 i++;
2193 }
2194
2195 if (help_page == command_help[I_HELP_INDEX]) {
2196 ircclient_send_notice(p, "- HELP "
2197 "(help on /dircproxy commands)");
2198 ircclient_send_notice(p, "- MOTD "
2199 "(show dircproxy message of the day)");
2200 ircclient_send_notice(p, "- STATUS "
2201 "(show dircproxy status information)");
2202 ircclient_send_notice(p, "- RECALL "
2203 "(recall text from log files)");
2204 ircclient_send_notice(p, "- GET "
2205 "(Get the value of a configuration item)");
2206 ircclient_send_notice(p, "- SET "
2207 "(Set the value of a configuration item)");
2208 ircclient_send_notice(p, "- RELOAD "
2209 "(reload configuration file)");
2210 ircclient_send_notice(p, "- DETACH "
2211 "(detach from dircproxy)");
2212 if (p->conn_class->allow_persist)
2213 ircclient_send_notice(p, "- PERSIST "
2214 "(keep session after detach)");
2215 ircclient_send_notice(p, "- QUIT "
2216 "(end dircproxy session)");
2217 if (p->conn_class->allow_die)
2218 ircclient_send_notice(p, "- DIE "
2219 "(terminate dircproxy)");
2220 if (p->conn_class->allow_users)
2221 ircclient_send_notice(p, "- USERS "
2222 "(show users using dircproxy)");
2223 if (p->conn_class->allow_kill)
2224 ircclient_send_notice(p, "- KILL "
2225 "(terminate a user's session)");
2226 if (p->conn_class->allow_notify)
2227 ircclient_send_notice(p, "- NOTIFY "
2228 "(send a notice to a user's session");
2229 ircclient_send_notice(p, "- SERVERS "
2230 "(show servers list)");
2231 if (p->conn_class->allow_jump)
2232 ircclient_send_notice(p, "- JUMP "
2233 "(jump to a different server)");
2234 if (p->conn_class->allow_host)
2235 ircclient_send_notice(p, "- HOST "
2236 "(change your visible hostname)");
2237
2238 i = 0;
2239 while (command_help[I_HELP_INDEX_END][i]) {
2240 ircclient_send_notice(p, "- %s", command_help[I_HELP_INDEX_END][i]);
2241 i++;
2242 }
2243 }
2244
2245 ircclient_send_notice(p, "-");
2246 }
2247 }
2248