ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5066
Committed: Mon Dec 22 14:32:01 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 25517 byte(s)
Log Message:
- irc.c:irc_parse(): replaced strcpy() with strlcpy()

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 strlcat(IRC_CHANNELS, chan->name, sizeof(IRC_CHANNELS));
313
314 if(node->next)
315 strlcat(IRC_CHANNELS, ",", sizeof(IRC_CHANNELS));
316 }
317 }
318
319
320 /* irc_send
321 *
322 * Send data to remote IRC host.
323 *
324 * Parameters:
325 * data: Format of data to send
326 * ...: varargs to format with
327 *
328 * Return: NONE
329 */
330
331
332 void irc_send(char *data, ...)
333 {
334 va_list arglist;
335 char data2[MSGLENMAX];
336 char tosend[MSGLENMAX];
337
338 va_start(arglist, data);
339 vsnprintf(data2, MSGLENMAX, data, arglist);
340 va_end(arglist);
341
342 if (OPT_DEBUG >= 2)
343 log_printf("IRC SEND -> %s", data2);
344
345 snprintf(tosend, MSGLENMAX, "%s\n", data2);
346
347 if (send(IRC_FD, tosend, strlen(tosend), 0) == -1)
348 {
349 /* Return of -1 indicates error sending data; we reconnect. */
350 log_printf("IRC -> Error sending data to server\n");
351 irc_reconnect();
352 }
353 }
354
355 /* irc_send
356 *
357 * Send privmsg to all channels.
358 *
359 * Parameters:
360 * data: Format of data to send
361 * ...: varargs to format with
362 *
363 * Return: NONE
364 */
365
366 void irc_send_channels(char *data, ...)
367 {
368 va_list arglist;
369 char data2[MSGLENMAX];
370 char tosend[MSGLENMAX];
371
372 va_start(arglist, data);
373 vsnprintf(data2, MSGLENMAX, data, arglist);
374 va_end(arglist);
375
376 snprintf(tosend, MSGLENMAX, "PRIVMSG %s :%s", IRC_CHANNELS, data2);
377
378 irc_send("%s", tosend);
379 }
380
381
382
383
384 /* irc_connect
385 *
386 * Connect to IRC server.
387 * XXX: FD allocation done here
388 *
389 * Parameters: NONE
390 * Return: NONE
391 *
392 */
393
394 static void irc_connect(void)
395 {
396 /* Connect to IRC server as client. */
397 if (connect(IRC_FD, (struct sockaddr *) &IRC_SVR,
398 sizeof(IRC_SVR)) == -1)
399 {
400 switch(errno)
401 {
402 case EISCONN:
403 /* Already connected */
404 return;
405 case ECONNREFUSED:
406 log_printf("IRC -> connect(): Connection refused by (%s)",
407 IRCItem->server);
408 break;
409 case ETIMEDOUT:
410 log_printf("IRC -> connect(): Timed out connecting to (%s)",
411 IRCItem->server);
412 break;
413 case ENETUNREACH:
414 log_printf("IRC -> connect(): Network unreachable");
415 break;
416 case EALREADY:
417 /* Previous attempt not complete */
418 return;
419 default:
420 log_printf("IRC -> connect(): Unknown error connecting to (%s)",
421 IRCItem->server);
422
423 if (OPT_DEBUG >= 1)
424 log_printf("%s", strerror(errno));
425 }
426 /* Try to connect again */
427 irc_reconnect();
428 return;
429 }
430
431 irc_send("NICK %s", IRCItem->nick);
432
433 if(strlen(IRCItem->password) > 0)
434 irc_send("PASS %s", IRCItem->password);
435
436 irc_send("USER %s %s %s :%s",
437 IRCItem->username, IRCItem->username, IRCItem->username,
438 IRCItem->realname);
439
440 time(&IRC_LAST);
441 }
442
443
444 /* irc_reconnect
445 *
446 * Close connection to IRC server.
447 *
448 * Parameters: NONE
449 *
450 * Return: NONE
451 */
452
453 static void irc_reconnect(void)
454 {
455
456 time_t present;
457
458 time(&present);
459
460 /* Only try to reconnect every RECONNECT_INTERVAL seconds */
461 if((present - IRC_LASTRECONNECT) < RECONNECTINTERVAL)
462 {
463 /* Sleep to avoid excessive CPU */
464 sleep(1);
465 return;
466 }
467
468 time(&IRC_LASTRECONNECT);
469
470 if(IRC_FD > 0)
471 close(IRC_FD);
472
473 /* Set IRC_FD 0 for reconnection on next irc_cycle(). */
474 IRC_FD = 0;
475
476 log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem->server);
477 }
478
479
480
481 /* irc_read
482 *
483 * irc_read is called my irc_cycle when new data is ready to be
484 * read from the irc server.
485 *
486 * Parameters: NONE
487 * Return: NONE
488 *
489 */
490
491 static void irc_read(void)
492 {
493 int len;
494 char c;
495
496 while ((len = read(IRC_FD, &c, 1)) > 0)
497 {
498 if (c == '\r')
499 continue;
500
501 if (c == '\n')
502 {
503 /* Null string. */
504 IRC_RAW[IRC_RAW_LEN] = '\0';
505 /* Parse line. */
506 irc_parse();
507 /* Reset counter. */
508 IRC_RAW_LEN = 0;
509 break;
510 }
511
512 if (c != '\r' && c != '\n' && c != '\0')
513 IRC_RAW[IRC_RAW_LEN++] = c;
514 }
515
516 if((len <= 0) && (errno != EAGAIN))
517 {
518 if(OPT_DEBUG >= 2)
519 log_printf("irc_read -> errno=%d len=%d", errno, len);
520 irc_reconnect();
521 IRC_RAW_LEN = 0;
522 return;
523 }
524 }
525
526
527 /* irc_parse
528 *
529 * irc_parse is called by irc_read when a full line of data
530 * is ready to be parsed.
531 *
532 * Parameters: NONE
533 * Return: NONE
534 *
535 */
536
537
538 static void irc_parse(void)
539 {
540 struct UserInfo *source_p;
541 char *pos;
542 unsigned int i;
543
544 /*
545 parv stores the parsed token, parc is the count of the parsed
546 tokens
547
548 parv[0] is ALWAYS the source, and is the server name of the source
549 did not exist
550 */
551
552 static char *parv[17];
553 static unsigned int parc;
554 static char msg[MSGLENMAX]; /* Temporarily stores IRC msg to pass to handlers */
555
556 parc = 1;
557
558 if(IRC_RAW_LEN <= 0)
559 return;
560
561 if (OPT_DEBUG >= 2)
562 log_printf("IRC READ -> %s", IRC_RAW);
563
564 time(&IRC_LAST);
565
566 /* Store a copy of IRC_RAW for the handlers (for functions that need PROOF) */
567 strlcpy(msg, IRC_RAW, sizeof(msg));
568
569 /* parv[0] is always the source */
570 if(IRC_RAW[0] == ':')
571 parv[0] = IRC_RAW + 1;
572 else
573 {
574 parv[0] = IRCItem->server;
575 parv[parc++] = IRC_RAW;
576 }
577
578 pos = IRC_RAW;
579
580 while((pos = strchr(pos, ' ')) && parc <= 17)
581 {
582
583 /* Avoid excessive spaces and end of IRC_RAW */
584 if(*(pos + 1) == ' ' && *(pos + 1) == '\0')
585 {
586 pos++;
587 continue;
588 }
589
590 /* Anything after a : is considered the final string of the
591 message */
592 if(*(pos + 1) == ':')
593 {
594 parv[parc++] = pos + 2;
595 *pos = '\0';
596 break;
597 }
598
599 /* Set the next parv at this position and replace the space with a
600 \0 for the previous parv */
601 parv[parc++] = pos + 1;
602 *pos = '\0';
603 pos++;
604 }
605
606 /* Generate a UserInfo struct from the source */
607
608 source_p = userinfo_create(parv[0]);
609
610 /* Determine which command this is from the command table
611 and let the handler for that command take control */
612
613 for(i = 0; i < (sizeof(COMMAND_TABLE) / sizeof(struct CommandHash)); i++)
614 if(strcasecmp(COMMAND_TABLE[i].command, parv[1]) == 0)
615 {
616 (*COMMAND_TABLE[i].handler)(parv, parc, msg, source_p);
617 break;
618 }
619
620 userinfo_free(source_p);
621 }
622
623
624
625
626 /* irc_timer
627 *
628 * Functions to be performed every ~seconds.
629 *
630 * Parameters: NONE
631 * Return: NONE
632 *
633 */
634
635 void irc_timer(void)
636 {
637 time_t present, delta;
638
639 time(&present);
640
641 delta = present - IRC_LAST;
642
643 /* No data in NODATA_TIMEOUT minutes (set in options.h). */
644 if (delta >= NODATA_TIMEOUT)
645 {
646 log_printf("IRC -> Timeout awaiting data from server.");
647 irc_reconnect();
648 /* Make sure we dont do this again for a while */
649 time(&IRC_LAST);
650 }
651 else if (delta >= NODATA_TIMEOUT / 2)
652 {
653 /*
654 * Generate some data so high ping times or bugs in certain
655 * ircds (*cough* unreal *cough*) don't cause uneeded
656 * reconnections
657 */
658 irc_send("PING :BOPM");
659 }
660
661 }
662
663
664
665
666 /* get_channel
667 *
668 * Check if a channel is defined in our conf. If so return
669 * a pointer to it.
670 *
671 * Parameters:
672 * channel: channel to search conf for
673 *
674 * Return: Pointer to ChannelConf containing the channel
675 */
676
677 static struct ChannelConf *get_channel(const char *channel)
678 {
679 node_t *node;
680 struct ChannelConf *item;
681
682 LIST_FOREACH(node, IRCItem->channels->head)
683 {
684 item = node->data;
685
686 if(strcasecmp(item->name, channel) == 0)
687 return item;
688 }
689
690 return NULL;
691 }
692
693
694 /* userinfo_create
695 *
696 * Parse a nick!user@host into a UserInfo struct
697 * and return a pointer to the new struct.
698 *
699 * Parameters:
700 * source: nick!user@host to parse
701 *
702 * Return:
703 * pointer to new UserInfo struct, or NULL if parsing failed
704 *
705 */
706
707 static struct UserInfo *userinfo_create(char *source)
708 {
709 struct UserInfo *ret;
710
711 char *nick;
712 char *username;
713 char *hostname;
714 char *tmp;
715
716 int i, len;
717
718 nick = username = hostname = NULL;
719 tmp = DupString(source);
720 len = strlen(tmp);
721
722 nick = tmp;
723
724 for(i = 0; i < len; i++)
725 {
726 if(tmp[i] == '!')
727 {
728 tmp[i] = '\0';
729 username = tmp + i + 1;
730 }
731 if(tmp[i] == '@')
732 {
733 tmp[i] = '\0';
734 hostname = tmp + i + 1;
735 }
736 }
737
738 if(nick == NULL || username == NULL || hostname == NULL)
739 {
740 MyFree(tmp);
741 return NULL;
742 }
743
744 ret = MyMalloc(sizeof *ret);
745
746 ret->irc_nick = DupString(nick);
747 ret->irc_username = DupString(username);
748 ret->irc_hostname = DupString(hostname);
749
750 MyFree(tmp);
751
752 return ret;
753 };
754
755
756
757 /* userinfo_free
758 *
759 * Free a UserInfo struct created with userinfo_create.
760 *
761 * Parameters:
762 * source: struct to free
763 *
764 * Return: None
765 *
766 */
767
768 static void userinfo_free(struct UserInfo *source_p)
769 {
770 if(source_p == NULL)
771 return;
772
773 MyFree(source_p->irc_nick);
774 MyFree(source_p->irc_username);
775 MyFree(source_p->irc_hostname);
776 MyFree(source_p);
777 }
778
779
780
781 /* m_perform
782 *
783 * actions to perform on IRC connection
784 *
785 * Parameters:
786 * parv[0] = source
787 * parv[1] = PING
788 * parv[2] = PING TS/Package
789 *
790 * source_p: UserInfo struct of the source user, or NULL if
791 * the source (parv[0]) is a server.
792 */
793
794 static void m_perform(char **parv, unsigned int parc, char *msg, struct UserInfo *notused)
795 {
796 node_t *node;
797 struct ChannelConf *channel;
798
799 USE_VAR(parv);
800 USE_VAR(parc);
801 USE_VAR(msg);
802 USE_VAR(notused);
803
804 log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port);
805
806 /* Identify to nickserv if needed */
807 if(strlen(IRCItem->nickserv))
808 irc_send("%s", IRCItem->nickserv);
809
810 /* Oper */
811 irc_send("OPER %s", IRCItem->oper);
812
813 /* Set modes */
814 irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode);
815
816 /* Set Away */
817 irc_send("AWAY :%s", IRCItem->away);
818
819 /* Perform */
820 LIST_FOREACH(node, IRCItem->performs->head)
821 irc_send("%s", (char *) node->data);
822
823 /* Join all listed channels. */
824 LIST_FOREACH(node, IRCItem->channels->head)
825 {
826 channel = (struct ChannelConf *) node->data;
827
828 if(strlen(channel->name) == 0)
829 continue;
830
831 if(strlen(channel->key) > 0)
832 irc_send("JOIN %s %s", channel->name, channel->key);
833 else
834 irc_send("JOIN %s", channel->name);
835 }
836 }
837
838
839 /* m_ping
840 *
841 * parv[0] = source
842 * parv[1] = PING
843 * parv[2] = PING TS/Package
844 *
845 * source_p: UserInfo struct of the source user, or NULL if
846 * the source (parv[0]) is a server.
847 */
848 static void m_ping(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
849 {
850 USE_VAR(msg);
851 USE_VAR(source_p);
852
853 if(parc < 3)
854 return;
855
856 if(OPT_DEBUG >= 2)
857 log_printf("IRC -> PING? PONG!");
858
859 irc_send("PONG %s", parv[2]);
860 }
861
862
863
864 /* m_invite
865 *
866 * parv[0] = source
867 * parv[1] = INVITE
868 * parv[2] = target
869 * parv[3] = channel
870 *
871 * source_p: UserInfo struct of the source user, or NULL if
872 * the source (parv[0]) is a server.
873 *
874 */
875
876 static void m_invite(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
877 {
878 struct ChannelConf *channel;
879
880 USE_VAR(msg);
881 USE_VAR(source_p);
882
883 if(parc < 4)
884 return;
885
886 log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
887
888 if((channel = get_channel(parv[3])) == NULL)
889 return;
890
891 irc_send("JOIN %s %s", channel->name, channel->key);
892 }
893
894
895
896
897 /* m_privmsg
898 *
899 * parv[0] = source
900 * parv[1] = PRIVMSG
901 * parv[2] = target (channel or user)
902 * parv[3] = message
903 *
904 * source_p: UserInfo struct of the source user, or NULL if
905 * the source (parv[0]) is a server.
906 *
907 */
908
909 static void m_privmsg(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
910 {
911 struct ChannelConf *channel;
912 size_t nick_len;
913
914 if(source_p == NULL)
915 return;
916
917 if(parc < 4)
918 return;
919
920 /* CTCP */
921 if(parv[3][0] == '\001')
922 m_ctcp(parv, parc, msg, source_p);
923
924 /* Only interested in privmsg to channels */
925 if(parv[2][0] != '#' && parv[2][0] != '&')
926 return;
927
928 /* Get a target */
929 if((channel = get_channel(parv[2])) == NULL)
930 return;
931
932 /* Find a suitable length to compare with */
933 nick_len = strcspn(parv[3], " :,");
934 if(nick_len < 3 && strlen(IRCItem->nick) >= 3)
935 nick_len = 3;
936
937 /* message is a command */
938 if(strncasecmp(parv[3], IRCItem->nick, nick_len) == 0 ||
939 strncasecmp(parv[3], "!all", 4) == 0)
940 {
941 /* XXX command_parse will alter parv[3]. */
942 command_parse(parv[3], msg, channel, source_p);
943 }
944 }
945
946
947
948
949
950 /* m_ctcp
951 * parv[0] = source
952 * parv[1] = PRIVMSG
953 * parv[2] = target (channel or user)
954 * parv[3] = message
955 *
956 * source_p: UserInfo struct of the source user, or NULL if
957 * the source (parv[0]) is a server.
958 *
959 */
960
961 static void m_ctcp(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
962 {
963 USE_VAR(parc);
964 USE_VAR(msg);
965
966 if(strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
967 {
968 irc_send("NOTICE %s :\001VERSION Blitzed Open Proxy Monitor %s\001",
969 source_p->irc_nick, VERSION);
970 }
971 }
972
973
974
975
976
977 /* m_notice
978 *
979 * parv[0] = source
980 * parv[1] = NOTICE
981 * parv[2] = target
982 * parv[3] = message
983 *
984 *
985 * source_p: UserInfo struct of the source user, or NULL if
986 * the source (parv[0]) is a server.
987 *
988 */
989
990 static void m_notice(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
991 {
992
993
994 static regex_t *preg = NULL;
995 regmatch_t pmatch[5];
996
997 static char errmsg[256];
998 int errnum, i;
999
1000 char *user[4];
1001
1002 if(parc < 4)
1003 return;
1004
1005 /* Not interested in notices from users */
1006 if(source_p != NULL)
1007 return;
1008
1009 /* Compile the regular expression if it has not been already */
1010 if(preg == NULL)
1011 {
1012 preg = MyMalloc(sizeof *preg);
1013
1014 if((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)) != 0)
1015 {
1016
1017 regerror(errnum, preg, errmsg, 256);
1018 log_printf("IRC REGEX -> Error when compiling regular expression");
1019 log_printf("IRC REGEX -> %s", errmsg);
1020
1021 MyFree(preg);
1022 preg = NULL;
1023 return;
1024 }
1025 }
1026
1027 /* Match the expression against the possible connection notice */
1028 if(regexec(preg, parv[3], 5, pmatch, 0) != 0)
1029 return;
1030
1031 if(OPT_DEBUG > 0)
1032 log_printf("IRC REGEX -> Regular expression caught connection notice. Parsing.");
1033
1034 if(pmatch[4].rm_so == -1)
1035 {
1036 log_printf("IRC REGEX -> pmatch[4].rm_so is -1 while parsing??? Aborting.");
1037 return;
1038 }
1039
1040 /*
1041 Offsets for data in the connection notice:
1042
1043 NICKNAME: pmatch[1].rm_so TO pmatch[1].rm_eo
1044 USERNAME: pmatch[2].rm_so TO pmatch[2].rm_eo
1045 HOSTNAME: pmatch[3].rm_so TO pmatch[3].rm_eo
1046 IP : pmatch[4].rm_so TO pmatch[4].rm_eo
1047
1048 */
1049
1050 for(i = 0; i < 4; i++)
1051 {
1052 user[i] = (parv[3] + pmatch[i + 1].rm_so);
1053 *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
1054 }
1055
1056 if(OPT_DEBUG > 0)
1057 log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
1058 user[0], user[1], user[2], user[3]);
1059
1060 /*FIXME (reminder) In the case of any rehash to the regex, preg MUST be freed first.
1061 regfree(preg);
1062 */
1063
1064 /* Pass this information off to scan.c */
1065 scan_connect(user, msg);
1066 /* Record the connect for stats purposes */
1067 stats_connect();
1068 }
1069
1070 /* m_userhost
1071 *
1072 * parv[0] = source
1073 * parv[1] = USERHOST
1074 * parv[2] = target (bopm)
1075 * parv[3] = :nick=(flags)user@host
1076 *
1077 *
1078 * source_p: UserInfo struct of the source user, or NULL if
1079 * the source (parv[0]) is a server.
1080 *
1081 */
1082
1083 static void m_userhost(char **parv, unsigned int parc, char *msg,
1084 struct UserInfo *source_p)
1085 {
1086 USE_VAR(msg);
1087 USE_VAR(source_p);
1088
1089 if(parc < 4)
1090 return;
1091
1092 command_userhost(parv[3]);
1093 }
1094
1095 /* m_cannot_join
1096 *
1097 * parv[0] = source
1098 * parv[1] = numeric
1099 * parv[2] = target (bopm)
1100 * parv[3] = channel
1101 * parv[4] = error text
1102 *
1103 */
1104
1105 static void m_cannot_join(char **parv, unsigned int parc, char *msg,
1106 struct UserInfo *source_p)
1107 {
1108 struct ChannelConf *channel;
1109
1110 USE_VAR(msg);
1111 USE_VAR(source_p);
1112
1113 if(parc < 5)
1114 return;
1115
1116 /* Is it one of our channels? */
1117 if((channel = get_channel(parv[3])) == NULL)
1118 return;
1119
1120 if(strlen(channel->invite) == 0)
1121 return;
1122
1123 irc_send("%s", channel->invite);
1124 }
1125
1126
1127 /* m_kill
1128 *
1129 * parv[0] = source
1130 * parv[1] = numeric
1131 * parv[2] = target (bopm)
1132 * parv[3] = channel
1133 * parv[4] = error text
1134 *
1135 */
1136
1137 static void m_kill(char **parv, unsigned int parc, char *msg, struct UserInfo *source_p)
1138 {
1139 USE_VAR(parv);
1140 USE_VAR(parc);
1141 USE_VAR(msg);
1142 USE_VAR(source_p);
1143
1144 /* Restart bopm to rehash */
1145 main_restart();
1146 }