ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 6148
Committed: Sun Jun 14 17:29:37 2015 UTC (8 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 21687 byte(s)
Log Message:
- Style corrections

File Contents

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

Properties

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