ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5135
Committed: Thu Dec 25 18:51:51 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 23250 byte(s)
Log Message:
- propset svn:eol-style native

File Contents

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

Properties

Name Value
svn:eol-style native
svn:keywords Id