ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5115
Committed: Wed Dec 24 22:17:42 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 23861 byte(s)
Log Message:
- irc.c:irc_init(): removed unused variables

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