]> jfr.im git - irc/ircd-hybrid/bopm.git/blame - src/irc.c
Fix a gcc3-ism.
[irc/ircd-hybrid/bopm.git] / src / irc.c
CommitLineData
a07879ed 1/* vim: set shiftwidth=3 softtabstop=3 expandtab: */
7cdaaf39 2
a07879ed 3/*
4 * Copyright (C) 2002 Erik Fears
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to
18 *
19 * The Free Software Foundation, Inc.
20 * 59 Temple Place - Suite 330
21 * Boston, MA 02111-1307, USA.
22 *
23 *
c185a5dd 24 */
25
7cdaaf39 26#include "setup.h"
27
28#include <stdio.h>
29#include <unistd.h>
30
31#ifdef STDC_HEADERS
32# include <stdlib.h>
33# include <string.h>
34#endif
35
36#ifdef HAVE_STRINGS_H
37# include <strings.h>
38#endif
39
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43#include <arpa/inet.h>
7cdaaf39 44
45#ifdef TIME_WITH_SYS_TIME
46# include <sys/time.h>
47# include <time.h>
48#else
49# ifdef HAVE_SYS_TIME_H
50# include <sys/time.h>
51# else
52# include <time.h>
53# endif
54#endif
55
56#include <errno.h>
57#include <stdarg.h>
a07879ed 58#include <regex.h>
7cdaaf39 59
c185a5dd 60#include "config.h"
7cdaaf39 61#include "irc.h"
62#include "log.h"
7cdaaf39 63#include "opercmd.h"
64#include "scan.h"
65#include "dnsbl.h"
66#include "stats.h"
67#include "extern.h"
68#include "options.h"
69#include "match.h"
70#include "compat.h"
3a533316 71#include "negcache.h"
a07879ed 72#include "malloc.h"
1eb2c721 73#include "main.h"
7cdaaf39 74
75static void irc_init(void);
76static void irc_connect(void);
77static void irc_reconnect(void);
78static void irc_read(void);
79static void irc_parse(void);
a07879ed 80
81static struct ChannelConf *get_channel(const char *);
82
83static struct UserInfo *userinfo_create(char *);
84static void userinfo_free(struct UserInfo *source);
85
86static void m_ping(char **, unsigned int, char *, struct UserInfo *);
87static void m_invite(char **, unsigned int, char *, struct UserInfo *);
88static void m_privmsg(char **, unsigned int, char *, struct UserInfo *);
89static void m_ctcp(char **, unsigned int, char *, struct UserInfo *);
90static void m_notice(char **, unsigned int, char *, struct UserInfo *);
91static void m_perform(char **, unsigned int, char *, struct UserInfo *);
92static void m_userhost(char **, unsigned int, char *, struct UserInfo *);
93static void m_cannot_join(char **, unsigned int, char *, struct UserInfo *);
1eb2c721 94static void m_kill(char **, unsigned int, char *, struct UserInfo *);
a07879ed 95
3a533316 96extern struct cnode *nc_head;
7cdaaf39 97
98/*
99 * Certain variables we don't want to allocate memory for over and over
100 * again so global scope is given.
101 */
102
a07879ed 103char IRC_RAW[MSGLENMAX]; /* Buffer to read data into */
104char IRC_SENDBUFF[MSGLENMAX]; /* Send buffer */
105char IRC_CHANNELS[MSGLENMAX]; /* Stores comma delim list of channels */
106int IRC_RAW_LEN = 0; /* Position of IRC_RAW */
7cdaaf39 107
1eb2c721 108int IRC_FD = 0; /* File descriptor for IRC client */
c185a5dd 109
a07879ed 110struct bopm_sockaddr IRC_SVR; /* Sock Address Struct for IRC server */
111struct bopm_ircaddr IRC_LOCAL; /* Sock Address Struct for Bind */
c185a5dd 112
a07879ed 113fd_set IRC_READ_FDSET; /* fd_set for IRC (read) data for select()*/
114struct timeval IRC_TIMEOUT; /* timeval struct for select() timeout */
c185a5dd 115
a07879ed 116time_t IRC_LAST = 0; /* Last full line of data from irc server*/
50747112 117time_t IRC_LASTRECONNECT = 0; /* Time of last reconnection */
1eb2c721 118
a07879ed 119/* Table should be ordered with most occuring (or priority)
120 commands at the top of the list. */
7cdaaf39 121
a07879ed 122static struct CommandHash COMMAND_TABLE[] = {
123 {"NOTICE", m_notice },
124 {"PRIVMSG", m_privmsg },
125 {"PING", m_ping },
126 {"INVITE", m_invite },
127 {"001", m_perform },
128 {"302", m_userhost },
129 {"471", m_cannot_join },
130 {"473", m_cannot_join },
131 {"474", m_cannot_join },
132 {"475", m_cannot_join },
1eb2c721 133 {"KILL", m_kill }
a07879ed 134 };
7cdaaf39 135
a07879ed 136/* irc_cycle
137 *
138 * Pass control to the IRC portion of BOPM to handle any awaiting IRC events.
139 *
140 * Parameters:
141 * None
142 *
143 * Return:
144 * None
145 *
7cdaaf39 146 */
147
148void irc_cycle(void)
a07879ed 149{
150 if (IRC_FD <= 0)
151 {
152 /* Initialise negative cache. */
153 if (OptionsItem->negcache > 0)
154 nc_init(&nc_head);
155
156 /* Resolve remote host. */
157 irc_init();
158
159 /* Connect to remote host. */
160 irc_connect();
50747112 161
162 return; /* In case connect() immediately failed */
163 }
a07879ed 164
165 IRC_TIMEOUT.tv_sec = 0;
166 /* Block .025 seconds to avoid excessive CPU use on select(). */
167 IRC_TIMEOUT.tv_usec = 25000;
168
169 FD_ZERO(&IRC_READ_FDSET);
170 FD_SET(IRC_FD, &IRC_READ_FDSET);
171
172 switch (select((IRC_FD + 1), &IRC_READ_FDSET, 0, 0, &IRC_TIMEOUT))
173 {
174 case -1:
175 return;
176 break;
177 case 0:
178 break;
179 default:
180 /* Check if IRC data is available. */
181 if (FD_ISSET(IRC_FD, &IRC_READ_FDSET))
182 irc_read();
183 break;
184 }
7cdaaf39 185}
186
187
a07879ed 188
189
190/* irc_init
191 *
192 * Resolve IRC host and perform other initialization.
193 *
194 * Parameters:
195 * None
196 *
197 * Return:
198 * None
7cdaaf39 199 *
200 */
201
202static void irc_init(void)
203{
a07879ed 204 node_t *node;
205 struct ChannelConf *chan;
206 struct bopm_sockaddr bsaddr;
5f8fa7e4 207 struct in_addr *irc_host;
a07879ed 208
209
210 if (IRC_FD)
211 close(IRC_FD);
212
213 memset(&IRC_SVR, 0, sizeof(IRC_SVR));
214 memset(&IRC_LOCAL, 0, sizeof(IRC_LOCAL));
215 memset(&bsaddr, 0, sizeof(struct bopm_sockaddr));
216
217 /* Resolve IRC host. */
5f8fa7e4 218 if ((irc_host = firedns_resolveip4(IRCItem->server)) == NULL)
a07879ed 219 {
0faee208 220 log_printf("IRC -> firedns_resolveip4(\"%s\"): %s", IRCItem->server,
5f8fa7e4 221 firedns_strerror(fdns_errno));
a07879ed 222 exit(EXIT_FAILURE);
223 }
224
225 IRC_SVR.sa4.sin_family = AF_INET;
226 IRC_SVR.sa4.sin_port = htons(IRCItem->port);
5f8fa7e4 227 IRC_SVR.sa4.sin_addr = *irc_host;
a07879ed 228
229 if (IRC_SVR.sa4.sin_addr.s_addr == INADDR_NONE)
230 {
0faee208 231 log_printf("IRC -> Unknown error resolving remote host (%s)",
a07879ed 232 IRCItem->server);
233 exit(EXIT_FAILURE);
234 }
235
a07879ed 236 /* Request file desc for IRC client socket */
1eb2c721 237 IRC_FD = socket(AF_INET, SOCK_STREAM, 0);
a07879ed 238
239 if (IRC_FD == -1)
240 {
241 switch(errno)
242 {
243 case EINVAL:
244 case EPROTONOSUPPORT:
0faee208 245 log_printf("IRC -> socket(): SOCK_STREAM is not "
a07879ed 246 "supported on this domain");
247 break;
248 case ENFILE:
0faee208 249 log_printf("IRC -> socket(): Not enough free file "
a07879ed 250 "descriptors to allocate IRC socket");
251 break;
252 case EMFILE:
0faee208 253 log_printf("IRC -> socket(): Process table overflow when "
a07879ed 254 "requesting file descriptor");
255 break;
256 case EACCES:
0faee208 257 log_printf("IRC -> socket(): Permission denied to create "
a07879ed 258 "socket of type SOCK_STREAM");
259 break;
260 case ENOMEM:
0faee208 261 log_printf("IRC -> socket(): Insufficient memory to "
a07879ed 262 "allocate socket");
263 break;
264 default:
0faee208 265 log_printf("IRC -> socket(): Unknown error allocating "
a07879ed 266 "socket");
267 break;
268 }
269 exit(EXIT_FAILURE);
270 }
271
272 /* Bind */
273 if (strlen(IRCItem->vhost) > 0)
274 {
275 int bindret = 0;
276 if (!inet_pton(AF_INET, IRCItem->vhost, &(IRC_LOCAL.in4.s_addr)))
277 {
0faee208 278 log_printf("IRC -> bind(): %s is an invalid address", IRCItem->vhost);
a07879ed 279 exit(EXIT_FAILURE);
280 }
281 bsaddr.sa4.sin_addr.s_addr = IRC_LOCAL.in4.s_addr;
282 bsaddr.sa4.sin_family = AF_INET;
283 bsaddr.sa4.sin_port = htons(0);
284
285 bindret = bind(IRC_FD, (struct sockaddr *) &(bsaddr.sa4), sizeof(bsaddr.sa4));
286
287 if (bindret)
288 {
289 switch(errno)
290 {
291 case EACCES:
0faee208 292 log_printf("IRC -> bind(): No access to bind to %s",
a07879ed 293 IRCItem->vhost);
294 break;
295 default:
0faee208 296 log_printf("IRC -> bind(): Error binding to %s (%d)",
a07879ed 297 IRCItem->vhost, errno);
298 break;
299 }
300 exit(EXIT_FAILURE);
301 }
302
303 }
304
305 /* Setup target list for irc_send_channels */
306 IRC_CHANNELS[0] = '\0';
307 LIST_FOREACH(node, IRCItem->channels->head)
308 {
309 chan = (struct ChannelConf *) node->data;
310 strncat(IRC_CHANNELS, chan->name, MSGLENMAX);
311
312 if(node->next)
313 strncat(IRC_CHANNELS, ",", MSGLENMAX);
314 }
315 IRC_CHANNELS[MSGLENMAX] = '\0';
7cdaaf39 316
7eaef52f 317
7cdaaf39 318}
319
320
a07879ed 321/* irc_send
322 *
323 * Send data to remote IRC host.
324 *
325 * Parameters:
326 * data: Format of data to send
327 * ...: varargs to format with
328 *
329 * Return: NONE
7cdaaf39 330 */
331
332
333void irc_send(char *data, ...)
334{
a07879ed 335 va_list arglist;
336 char data2[MSGLENMAX];
337 char tosend[MSGLENMAX];
338
339 va_start(arglist, data);
340 vsnprintf(data2, MSGLENMAX, data, arglist);
341 va_end(arglist);
342
343 if (OPT_DEBUG >= 2)
0faee208 344 log_printf("IRC SEND -> %s", data2);
a07879ed 345
346 snprintf(tosend, MSGLENMAX, "%s\n", data2);
347
348 if (send(IRC_FD, tosend, strlen(tosend), 0) == -1)
349 {
a07879ed 350 /* Return of -1 indicates error sending data; we reconnect. */
0faee208 351 log_printf("IRC -> Error sending data to server\n");
a07879ed 352 irc_reconnect();
353 }
7cdaaf39 354}
355
a07879ed 356/* irc_send
357 *
358 * Send privmsg to all channels.
359 *
360 * Parameters:
361 * data: Format of data to send
362 * ...: varargs to format with
363 *
364 * Return: NONE
7cdaaf39 365 */
366
a07879ed 367void irc_send_channels(char *data, ...)
7cdaaf39 368{
a07879ed 369 va_list arglist;
370 char data2[MSGLENMAX];
371 char tosend[MSGLENMAX];
372
373 va_start(arglist, data);
374 vsnprintf(data2, MSGLENMAX, data, arglist);
375 va_end(arglist);
376
377 snprintf(tosend, MSGLENMAX, "PRIVMSG %s :%s", IRC_CHANNELS, data2);
378
379 irc_send("%s", tosend);
7cdaaf39 380}
381
a07879ed 382
383
384
385/* irc_connect
386 *
387 * Connect to IRC server.
388 * XXX: FD allocation done here
389 *
390 * Parameters: NONE
391 * Return: NONE
392 *
7cdaaf39 393 */
394
395static void irc_connect(void)
396{
a07879ed 397 /* Connect to IRC server as client. */
398 if (connect(IRC_FD, (struct sockaddr *) &IRC_SVR,
399 sizeof(IRC_SVR)) == -1)
400 {
401 switch(errno)
402 {
403 case EISCONN:
404 /* Already connected */
405 return;
406 case ECONNREFUSED:
0faee208 407 log_printf("IRC -> connect(): Connection refused by (%s)",
a07879ed 408 IRCItem->server);
409 break;
410 case ETIMEDOUT:
0faee208 411 log_printf("IRC -> connect(): Timed out connecting to (%s)",
a07879ed 412 IRCItem->server);
413 break;
414 case ENETUNREACH:
0faee208 415 log_printf("IRC -> connect(): Network unreachable");
a07879ed 416 break;
417 case EALREADY:
418 /* Previous attempt not complete */
419 return;
420 default:
0faee208 421 log_printf("IRC -> connect(): Unknown error connecting to (%s)",
a07879ed 422 IRCItem->server);
423
424 if (OPT_DEBUG >= 1)
0faee208 425 log_printf("%s", strerror(errno));
a07879ed 426 }
50747112 427 /* Try to connect again */
428 irc_reconnect();
429 return;
a07879ed 430 }
431
432 irc_send("NICK %s", IRCItem->nick);
433
434 if(strlen(IRCItem->password) > 0)
435 irc_send("PASS %s", IRCItem->password);
436
437 irc_send("USER %s %s %s :%s",
438 IRCItem->username, IRCItem->username, IRCItem->username,
439 IRCItem->realname);
7cdaaf39 440}
441
442
a07879ed 443/* irc_reconnect
444 *
445 * Close connection to IRC server.
446 *
447 * Parameters: NONE
448 *
449 * Return: NONE
450 */
451
7cdaaf39 452static void irc_reconnect(void)
453{
7cdaaf39 454
50747112 455 time_t present;
456
457 time(&present);
458
459 /* Only try to reconnect every RECONNECT_INTERVAL seconds */
460 if((present - IRC_LASTRECONNECT) < RECONNECTINTERVAL)
461 {
462 /* Sleep to avoid excessive CPU */
463 sleep(1);
464 return;
465 }
466
467 time(&IRC_LASTRECONNECT);
468
a07879ed 469 if(IRC_FD > 0)
470 close(IRC_FD);
471
472 /* Set IRC_FD 0 for reconnection on next irc_cycle(). */
473 IRC_FD = 0;
7cdaaf39 474
0faee208 475 log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem->server);
7cdaaf39 476}
477
a07879ed 478
479
480/* irc_read
481 *
482 * irc_read is called my irc_cycle when new data is ready to be
483 * read from the irc server.
484 *
485 * Parameters: NONE
486 * Return: NONE
487 *
7cdaaf39 488 */
a07879ed 489
7cdaaf39 490static void irc_read(void)
491{
a07879ed 492 int len;
493 char c;
494
495 while ((len = read(IRC_FD, &c, 1)) > 0)
496 {
497 if (c == '\r')
498 continue;
499
500 if (c == '\n')
501 {
502 /* Null string. */
503 IRC_RAW[IRC_RAW_LEN] = '\0';
504 /* Parse line. */
505 irc_parse();
506 /* Reset counter. */
507 IRC_RAW_LEN = 0;
508 break;
509 }
510
511 if (c != '\r' && c != '\n' && c != '\0')
512 IRC_RAW[IRC_RAW_LEN++] = c;
513 }
514
50747112 515 if((len <= 0) && (errno != EAGAIN))
a07879ed 516 {
a07879ed 517 irc_reconnect();
518 IRC_RAW_LEN = 0;
519 return;
520 }
7cdaaf39 521}
522
a07879ed 523
524/* irc_parse
525 *
526 * irc_parse is called by irc_read when a full line of data
527 * is ready to be parsed.
528 *
529 * Parameters: NONE
530 * Return: NONE
531 *
7cdaaf39 532 */
533
a07879ed 534
7cdaaf39 535static void irc_parse(void)
536{
a07879ed 537 struct UserInfo *source_p;
538 char *pos;
0faee208 539 unsigned int i;
a07879ed 540
541 /*
542 parv stores the parsed token, parc is the count of the parsed
543 tokens
544
545 parv[0] is ALWAYS the source, and is the server name of the source
546 did not exist
547 */
548
549 static char *parv[17];
550 static unsigned int parc;
551 static char msg[MSGLENMAX]; /* Temporarily stores IRC msg to pass to handlers */
552
553 parc = 1;
554
555 if(IRC_RAW_LEN <= 0)
556 return;
557
558 if (OPT_DEBUG >= 2)
0faee208 559 log_printf("IRC READ -> %s", IRC_RAW);
a07879ed 560
561 time(&IRC_LAST);
562
563 /* Store a copy of IRC_RAW for the handlers (for functions that need PROOF) */
564 strcpy(msg, IRC_RAW);
565
566 /* parv[0] is always the source */
567 if(IRC_RAW[0] == ':')
568 parv[0] = IRC_RAW + 1;
569 else
570 {
571 parv[0] = IRCItem->server;
572 parv[parc++] = IRC_RAW;
573 }
574
575 pos = IRC_RAW;
576
577 while((pos = strchr(pos, ' ')) && parc <= 17)
578 {
579
580 /* Avoid excessive spaces and end of IRC_RAW */
581 if(*(pos + 1) == ' ' && *(pos + 1) == '\0')
582 {
583 pos++;
584 continue;
585 }
586
587 /* Anything after a : is considered the final string of the
588 message */
589 if(*(pos + 1) == ':')
590 {
591 parv[parc++] = pos + 2;
592 *pos = '\0';
593 break;
594 }
595
596 /* Set the next parv at this position and replace the space with a
597 \0 for the previous parv */
598 parv[parc++] = pos + 1;
599 *pos = '\0';
600 pos++;
601 }
602
603 /* Generate a UserInfo struct from the source */
604
605 source_p = userinfo_create(parv[0]);
606
607 /* Determine which command this is from the command table
608 and let the handler for that command take control */
609
610 for(i = 0; i < (sizeof(COMMAND_TABLE) / sizeof(struct CommandHash)); i++)
611 if(strcasecmp(COMMAND_TABLE[i].command, parv[1]) == 0)
612 {
613 (*COMMAND_TABLE[i].handler)(parv, parc, msg, source_p);
614 break;
615 }
616
617 userinfo_free(source_p);
7cdaaf39 618}
619
a07879ed 620
621
622
623/* irc_timer
624 *
625 * Functions to be performed every ~seconds.
626 *
627 * Parameters: NONE
628 * Return: NONE
629 *
7cdaaf39 630 */
631
a07879ed 632void irc_timer(void)
633{
634 time_t present, delta;
635
636 time(&present);
637
638 delta = present - IRC_LAST;
639
640 /* No data in NODATA_TIMEOUT minutes (set in options.h). */
641 if (delta >= NODATA_TIMEOUT)
642 {
0faee208 643 log_printf("IRC -> Timeout awaiting data from server.");
a07879ed 644 irc_reconnect();
645 /* Make sure we dont do this again for a while */
646 time(&IRC_LAST);
647 }
648 else if (delta >= NODATA_TIMEOUT / 2)
649 {
650 /*
651 * Generate some data so high ping times or bugs in certain
652 * ircds (*cough* unreal *cough*) don't cause uneeded
653 * reconnections
654 */
655 irc_send("PING :BOPM");
656 }
657
658}
659
660
7cdaaf39 661
c185a5dd 662
a07879ed 663/* get_channel
664 *
665 * Check if a channel is defined in our conf. If so return
666 * a pointer to it.
667 *
668 * Parameters:
669 * channel: channel to search conf for
670 *
671 * Return: Pointer to ChannelConf containing the channel
672 */
673
674static struct ChannelConf *get_channel(const char *channel)
675{
676 node_t *node;
677 struct ChannelConf *item;
678
679 LIST_FOREACH(node, IRCItem->channels->head)
680 {
681 item = node->data;
682
683 if(strcasecmp(item->name, channel) == 0)
684 return item;
685 }
686
687 return NULL;
7cdaaf39 688}
689
a07879ed 690
691/* userinfo_create
692 *
693 * Parse a nick!user@host into a UserInfo struct
694 * and return a pointer to the new struct.
695 *
696 * Parameters:
697 * source: nick!user@host to parse
698 *
699 * Return:
700 * pointer to new UserInfo struct, or NULL if parsing failed
701 *
7cdaaf39 702 */
703
a07879ed 704static struct UserInfo *userinfo_create(char *source)
705{
706 struct UserInfo *ret;
707
708 char *nick;
709 char *username;
710 char *hostname;
711 char *tmp;
712
713 int i, len;
714
715 nick = username = hostname = NULL;
716 tmp = DupString(source);
717 len = strlen(tmp);
718
719 nick = tmp;
720
721 for(i = 0; i < len; i++)
722 {
723 if(tmp[i] == '!')
724 {
725 tmp[i] = '\0';
726 username = tmp + i + 1;
727 }
728 if(tmp[i] == '@')
729 {
730 tmp[i] = '\0';
731 hostname = tmp + i + 1;
732 }
733 }
734
735 if(nick == NULL || username == NULL || hostname == NULL)
736 {
737 MyFree(tmp);
738 return NULL;
739 }
740
741 ret = MyMalloc(sizeof(struct UserInfo));
742
743 ret->irc_nick = DupString(nick);
744 ret->irc_username = DupString(username);
745 ret->irc_hostname = DupString(hostname);
746
747 MyFree(tmp);
748
749 return ret;
750};
751
752
753
754/* userinfo_free
755 *
756 * Free a UserInfo struct created with userinfo_create.
757 *
758 * Parameters:
759 * source: struct to free
760 *
761 * Return: None
762 *
763 */
764
765static void userinfo_free(struct UserInfo *source_p)
7cdaaf39 766{
a07879ed 767 if(source_p == NULL)
768 return;
769
770 MyFree(source_p->irc_nick);
771 MyFree(source_p->irc_username);
772 MyFree(source_p->irc_hostname);
773 MyFree(source_p);
7cdaaf39 774}
775
a07879ed 776
777
778/* m_perform
779 *
780 * actions to perform on IRC connection
781 *
782 * Parameters:
783 * parv[0] = source
784 * parv[1] = PING
785 * parv[2] = PING TS/Package
786 *
787 * source_p: UserInfo struct of the source user, or NULL if
788 * the source (parv[0]) is a server.
789 */
790
791static void m_perform(char **parv, unsigned int parc, char *msg, struct UserInfo *notused)
7cdaaf39 792{
a07879ed 793 node_t *node;
794 struct ChannelConf *channel;
795
606c6ecb 796 USE_VAR(parv);
797 USE_VAR(parc);
798 USE_VAR(msg);
799 USE_VAR(notused);
800
0faee208 801 log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port);
a07879ed 802
803 /* Identify to nickserv if needed */
804 if(strlen(IRCItem->nickserv))
805 irc_send("%s", IRCItem->nickserv);
806
807 /* Oper */
808 irc_send("OPER %s", IRCItem->oper);
809
810 /* Set modes */
811 irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode);
812
813 /* Set Away */
814 irc_send("AWAY :%s", IRCItem->away);
815
816 /* Perform */
817 LIST_FOREACH(node, IRCItem->performs->head)
7f82f570 818 irc_send("%s", (char *) node->data);
a07879ed 819
820 /* Join all listed channels. */
821 LIST_FOREACH(node, IRCItem->channels->head)
822 {
823 channel = (struct ChannelConf *) node->data;
824
825 if(strlen(channel->name) == 0)
826 continue;
827
828 if(strlen(channel->key) > 0)
829 irc_send("JOIN %s %s", channel->name, channel->key);
830 else
831 irc_send("JOIN %s", channel->name);
832 }
7cdaaf39 833}
834
a07879ed 835
836/* m_ping
837 *
838 * parv[0] = source
839 * parv[1] = PING
840 * parv[2] = PING TS/Package
841 *
842 * source_p: UserInfo struct of the source user, or NULL if
843 * the source (parv[0]) is a server.
7cdaaf39 844 */
a07879ed 845static void m_ping(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
7cdaaf39 846{
606c6ecb 847 USE_VAR(msg);
848 USE_VAR(source_p);
849
a07879ed 850 if(parc < 3)
851 return;
852
853 if(OPT_DEBUG >= 2)
0faee208 854 log_printf("IRC -> PING? PONG!");
a07879ed 855
856 irc_send("PONG %s", parv[2]);
7cdaaf39 857}
858
a07879ed 859
860
861/* m_invite
862 *
863 * parv[0] = source
864 * parv[1] = INVITE
865 * parv[2] = target
866 * parv[3] = channel
867 *
868 * source_p: UserInfo struct of the source user, or NULL if
869 * the source (parv[0]) is a server.
870 *
7cdaaf39 871 */
a07879ed 872
873static void m_invite(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
7cdaaf39 874{
a07879ed 875 struct ChannelConf *channel;
606c6ecb 876
877 USE_VAR(msg);
878 USE_VAR(source_p);
a07879ed 879
880 if(parc < 4)
881 return;
882
0faee208 883 log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
a07879ed 884
885 if((channel = get_channel(parv[3])) == NULL)
886 return;
887
888 irc_send("JOIN %s %s", channel->name, channel->key);
7cdaaf39 889}
890
a07879ed 891
892
893
894/* m_privmsg
895 *
896 * parv[0] = source
897 * parv[1] = PRIVMSG
898 * parv[2] = target (channel or user)
899 * parv[3] = message
900 *
901 * source_p: UserInfo struct of the source user, or NULL if
902 * the source (parv[0]) is a server.
903 *
7cdaaf39 904 */
a07879ed 905
906static void m_privmsg(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
7cdaaf39 907{
a07879ed 908 struct ChannelConf *channel;
e29db411 909 size_t nick_len;
a07879ed 910
911 if(source_p == NULL)
912 return;
913
914 if(parc < 4)
915 return;
916
917 /* CTCP */
0faee208 918 if(parv[3][0] == '\001')
ecce9af9 919 m_ctcp(parv, parc, msg, source_p);
a07879ed 920
921 /* Only interested in privmsg to channels */
922 if(parv[2][0] != '#' && parv[2][0] != '&')
923 return;
924
925 /* Get a target */
926 if((channel = get_channel(parv[2])) == NULL)
927 return;
928
e29db411 929 /* Find a suitable length to compare with */
930 nick_len = strcspn(parv[3], " :,");
931 if(nick_len < 3 && strlen(IRCItem->nick) >= 3)
932 nick_len = 3;
933
a07879ed 934 /* message is a command */
e29db411 935 if(strncasecmp(parv[3], IRCItem->nick, nick_len) == 0 ||
d6eb13f3 936 strncasecmp(parv[3], "!all", 4) == 0)
a07879ed 937 {
938 /* XXX command_parse will alter parv[3]. */
939 command_parse(parv[3], msg, channel, source_p);
940 }
7cdaaf39 941}
942
943
944
a07879ed 945
946
947/* m_ctcp
948 * parv[0] = source
949 * parv[1] = PRIVMSG
950 * parv[2] = target (channel or user)
951 * parv[3] = message
952 *
953 * source_p: UserInfo struct of the source user, or NULL if
954 * the source (parv[0]) is a server.
955 *
7cdaaf39 956 */
a07879ed 957
958static void m_ctcp(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
7cdaaf39 959{
606c6ecb 960 USE_VAR(parc);
961 USE_VAR(msg);
962
a07879ed 963 if(strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
0e6c5668 964 {
965 irc_send("NOTICE %s :\001VERSION Blitzed Open Proxy Monitor %s\001",
966 source_p->irc_nick, VERSION);
967 }
7cdaaf39 968}
969
a07879ed 970
971
972
973
974/* m_notice
975 *
976 * parv[0] = source
977 * parv[1] = NOTICE
978 * parv[2] = target
979 * parv[3] = message
980 *
981 *
982 * source_p: UserInfo struct of the source user, or NULL if
983 * the source (parv[0]) is a server.
984 *
7cdaaf39 985 */
a07879ed 986
987static void m_notice(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
7cdaaf39 988{
a07879ed 989
990
991 static regex_t *preg = NULL;
992 regmatch_t pmatch[5];
993
994 static char errmsg[256];
995 int errnum, i;
996
997 char *user[4];
998
999 if(parc < 4)
1000 return;
1001
1002 /* Not interested in notices from users */
1003 if(source_p != NULL)
1004 return;
1005
1006 /* Compile the regular expression if it has not been already */
1007 if(preg == NULL)
1008 {
1009 preg = MyMalloc(sizeof(regex_t));
1010
1011 if((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)) != 0)
1012 {
1013
1014 regerror(errnum, preg, errmsg, 256);
0faee208 1015 log_printf("IRC REGEX -> Error when compiling regular expression");
1016 log_printf("IRC REGEX -> %s", errmsg);
a07879ed 1017
1018 MyFree(preg);
1019 preg = NULL;
1020 return;
1021 }
1022 }
1023
1024 /* Match the expression against the possible connection notice */
1025 if(regexec(preg, parv[3], 5, pmatch, 0) != 0)
1026 return;
1027
1028 if(OPT_DEBUG > 0)
0faee208 1029 log_printf("IRC REGEX -> Regular expression caught connection notice. Parsing.");
a07879ed 1030
1031 if(pmatch[4].rm_so == -1)
1032 {
0faee208 1033 log_printf("IRC REGEX -> pmatch[4].rm_so is -1 while parsing??? Aborting.");
a07879ed 1034 return;
1035 }
1036
1037 /*
1038 Offsets for data in the connection notice:
1039
1040 NICKNAME: pmatch[1].rm_so TO pmatch[1].rm_eo
1041 USERNAME: pmatch[2].rm_so TO pmatch[2].rm_eo
1042 HOSTNAME: pmatch[3].rm_so TO pmatch[3].rm_eo
1043 IP : pmatch[4].rm_so TO pmatch[4].rm_eo
1044
1045 */
1046
1047 for(i = 0; i < 4; i++)
1048 {
1049 user[i] = (parv[3] + pmatch[i + 1].rm_so);
1050 *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
1051 }
1052
1053 if(OPT_DEBUG > 0)
0faee208 1054 log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
a07879ed 1055 user[0], user[1], user[2], user[3]);
1056
1057 /*FIXME (reminder) In the case of any rehash to the regex, preg MUST be freed first.
1058 regfree(preg);
1059 */
1060
1061 /* Pass this information off to scan.c */
1062 scan_connect(user, msg);
1063 /* Record the connect for stats purposes */
1064 stats_connect();
7cdaaf39 1065}
1066
a07879ed 1067/* m_userhost
1068 *
1069 * parv[0] = source
1070 * parv[1] = USERHOST
1071 * parv[2] = target (bopm)
1072 * parv[3] = :nick=(flags)user@host
1073 *
1074 *
1075 * source_p: UserInfo struct of the source user, or NULL if
1076 * the source (parv[0]) is a server.
1077 *
7cdaaf39 1078 */
a07879ed 1079
0e6c5668 1080static void m_userhost(char **parv, unsigned int parc, char *msg,
1081 struct UserInfo *source_p)
7cdaaf39 1082{
606c6ecb 1083 USE_VAR(msg);
1084 USE_VAR(source_p);
1085
a07879ed 1086 if(parc < 4)
1087 return;
1088
1089 command_userhost(parv[3]);
7cdaaf39 1090}
a07879ed 1091
1092/* m_cannot_join
1093 *
1094 * parv[0] = source
1095 * parv[1] = numeric
1096 * parv[2] = target (bopm)
1097 * parv[3] = channel
1098 * parv[4] = error text
1099 *
1100 */
1101
0e6c5668 1102static void m_cannot_join(char **parv, unsigned int parc, char *msg,
1103 struct UserInfo *source_p)
a07879ed 1104{
1105 struct ChannelConf *channel;
1106
606c6ecb 1107 USE_VAR(msg);
1108 USE_VAR(source_p);
1109
a07879ed 1110 if(parc < 5)
1111 return;
1112
1113 /* Is it one of our channels? */
1114 if((channel = get_channel(parv[3])) == NULL)
1115 return;
1116
1117 if(strlen(channel->invite) == 0)
1118 return;
1119
1120 irc_send("%s", channel->invite);
1121}
1122
1eb2c721 1123
1124/* m_kill
1125 *
1126 * parv[0] = source
1127 * parv[1] = numeric
1128 * parv[2] = target (bopm)
1129 * parv[3] = channel
1130 * parv[4] = error text
1131 *
1132 */
1133
1134static void m_kill(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
1135{
0e6c5668 1136 USE_VAR(parv);
1137 USE_VAR(parc);
1138 USE_VAR(msg);
1139 USE_VAR(source_p);
606c6ecb 1140
1141 /* Restart bopm to rehash */
1142 main_restart();
1eb2c721 1143}