ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5052
Committed: Mon Dec 22 11:56:03 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 25518 byte(s)
Log Message:
- Initial import of bopm 3.1.3

File Contents

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