/[svn]/hopm/trunk/src/irc.c
ViewVC logotype

Contents of /hopm/trunk/src/irc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5363 - (show annotations)
Mon Jan 12 19:19:11 2015 UTC (5 years, 6 months ago) by michael
File MIME type: text/x-chdr
File size: 21936 byte(s)
- irc.c: added basic IPv6 support allowing HOPM to bind and connect to IPv6 addresses

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28