ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5364
Committed: Mon Jan 12 19:56:33 2015 UTC (9 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 21405 byte(s)
Log Message:
- irc.c: cleaned up irc_connect()

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
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 log_printf("IRC -> connect(): error connecting to %s: %s",
319 IRCItem->server, strerror(errno));
320
321 if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */)
322 return;
323
324 /* Try to connect again */
325 irc_reconnect();
326 return;
327 }
328
329 irc_send("NICK %s", IRCItem->nick);
330
331 if (!EmptyString(IRCItem->password))
332 irc_send("PASS %s", IRCItem->password);
333
334 irc_send("USER %s %s %s :%s",
335 IRCItem->username,
336 IRCItem->username,
337 IRCItem->username,
338 IRCItem->realname);
339 time(&IRC_LAST);
340 }
341
342 /* irc_reconnect
343 *
344 * Close connection to IRC server.
345 *
346 * Parameters: NONE
347 *
348 * Return: NONE
349 */
350 static void
351 irc_reconnect(void)
352 {
353 time_t present;
354
355 time(&present);
356
357 /* Only try to reconnect every RECONNECT_INTERVAL seconds */
358 if ((present - IRC_LASTRECONNECT) < RECONNECTINTERVAL)
359 {
360 /* Sleep to avoid excessive CPU */
361 sleep(1);
362 return;
363 }
364
365 time(&IRC_LASTRECONNECT);
366
367 if (IRC_FD > 0)
368 close(IRC_FD);
369
370 /* Set IRC_FD 0 for reconnection on next irc_cycle(). */
371 IRC_FD = 0;
372
373 log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem->server);
374 }
375
376 /* irc_read
377 *
378 * irc_read is called my irc_cycle when new data is ready to be
379 * read from the irc server.
380 *
381 * Parameters: NONE
382 * Return: NONE
383 */
384 static void
385 irc_read(void)
386 {
387 int len;
388 char c;
389
390 while ((len = read(IRC_FD, &c, 1)) > 0)
391 {
392 if (c == '\r')
393 continue;
394
395 if (c == '\n')
396 {
397 /* Null string. */
398 IRC_RAW[IRC_RAW_LEN] = '\0';
399
400 /* Parse line. */
401 irc_parse();
402
403 /* Reset counter. */
404 IRC_RAW_LEN = 0;
405 break;
406 }
407
408 if (c != '\0')
409 IRC_RAW[IRC_RAW_LEN++] = c;
410 }
411
412 if ((len <= 0) && (errno != EAGAIN))
413 {
414 if (OPT_DEBUG >= 2)
415 log_printf("irc_read -> errno=%d len=%d", errno, len);
416
417 irc_reconnect();
418 IRC_RAW_LEN = 0;
419 return;
420 }
421 }
422
423 /* irc_parse
424 *
425 * irc_parse is called by irc_read when a full line of data
426 * is ready to be parsed.
427 *
428 * Parameters: NONE
429 * Return: NONE
430 */
431 static void
432 irc_parse(void)
433 {
434 struct UserInfo *source_p;
435 char *pos;
436
437 /*
438 * parv stores the parsed token, parc is the count of the parsed
439 * tokens
440 *
441 * parv[0] is ALWAYS the source, and is the server name of the source
442 * did not exist
443 */
444 char *parv[17];
445 unsigned int parc = 1;
446 char msg[MSGLENMAX]; /* Temporarily stores IRC msg to pass to handlers */
447
448 if (IRC_RAW_LEN == 0)
449 return;
450
451 if (OPT_DEBUG >= 2)
452 log_printf("IRC READ -> %s", IRC_RAW);
453
454 time(&IRC_LAST);
455
456 /* Store a copy of IRC_RAW for the handlers (for functions that need PROOF) */
457 strlcpy(msg, IRC_RAW, sizeof(msg));
458
459 /* parv[0] is always the source */
460 if (IRC_RAW[0] == ':')
461 parv[0] = IRC_RAW + 1;
462 else
463 {
464 parv[0] = IRCItem->server;
465 parv[parc++] = IRC_RAW;
466 }
467
468 pos = IRC_RAW;
469
470 while ((pos = strchr(pos, ' ')) && parc <= 17)
471 {
472 /* Avoid excessive spaces and end of IRC_RAW */
473 if (*(pos + 1) == ' ' || *(pos + 1) == '\0')
474 {
475 pos++;
476 continue;
477 }
478
479 /* Anything after a : is considered the final string of the message */
480 if (*(pos + 1) == ':')
481 {
482 parv[parc++] = pos + 2;
483 *pos = '\0';
484 break;
485 }
486
487 /*
488 * Set the next parv at this position and replace the space with a
489 * \0 for the previous parv
490 */
491 parv[parc++] = pos + 1;
492 *pos = '\0';
493 pos++;
494 }
495
496 /* Generate a UserInfo struct from the source */
497 source_p = userinfo_create(parv[0]);
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 cmd->handler(parv, parc, msg, source_p);
508 break;
509 }
510 }
511
512 userinfo_free(source_p);
513 }
514
515 /* irc_timer
516 *
517 * Functions to be performed every ~seconds.
518 *
519 * Parameters: NONE
520 * Return: NONE
521 */
522 void
523 irc_timer(void)
524 {
525 time_t present, delta;
526
527 time(&present);
528
529 delta = present - IRC_LAST;
530
531 /* No data in IRCItem->readtimeout seconds */
532 if (delta >= IRCItem->readtimeout)
533 {
534 log_printf("IRC -> Timeout awaiting data from server.");
535 irc_reconnect();
536
537 /* Make sure we don't do this again for a while */
538 time(&IRC_LAST);
539 }
540 else if (delta >= IRCItem->readtimeout / 2)
541 {
542 /*
543 * Generate some data so high ping times don't cause uneeded
544 * reconnections
545 */
546 irc_send("PING :HOPM");
547 }
548 }
549
550 /* get_channel
551 *
552 * Check if a channel is defined in our conf. If so return
553 * a pointer to it.
554 *
555 * Parameters:
556 * channel: channel to search conf for
557 *
558 * Return: Pointer to ChannelConf containing the channel
559 */
560 static struct ChannelConf *
561 get_channel(const char *channel)
562 {
563 node_t *node;
564
565 LIST_FOREACH(node, IRCItem->channels->head)
566 {
567 struct ChannelConf *item = node->data;
568
569 if (strcasecmp(item->name, channel) == 0)
570 return item;
571 }
572
573 return NULL;
574 }
575
576 /* userinfo_create
577 *
578 * Parse a nick!user@host into a UserInfo struct
579 * and return a pointer to the new struct.
580 *
581 * Parameters:
582 * source: nick!user@host to parse
583 *
584 * Return:
585 * pointer to new UserInfo struct, or NULL if parsing failed
586 */
587 static struct UserInfo *
588 userinfo_create(char *source)
589 {
590 struct UserInfo *ret;
591 char *nick;
592 char *username;
593 char *hostname;
594 char *tmp;
595 int i, len;
596
597 nick = username = hostname = NULL;
598 tmp = xstrdup(source);
599 len = strlen(tmp);
600 nick = tmp;
601
602 for (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 (nick == NULL || username == NULL || hostname == NULL)
618 {
619 MyFree(tmp);
620 return NULL;
621 }
622
623 ret = xcalloc(sizeof *ret);
624 ret->irc_nick = xstrdup(nick);
625 ret->irc_username = xstrdup(username);
626 ret->irc_hostname = xstrdup(hostname);
627
628 MyFree(tmp);
629
630 return ret;
631 };
632
633 /* userinfo_free
634 *
635 * Free a UserInfo struct created with userinfo_create.
636 *
637 * Parameters:
638 * source: struct to free
639 *
640 * Return: None
641 */
642 static void
643 userinfo_free(struct UserInfo *source_p)
644 {
645 if (source_p == NULL)
646 return;
647
648 MyFree(source_p->irc_nick);
649 MyFree(source_p->irc_username);
650 MyFree(source_p->irc_hostname);
651 MyFree(source_p);
652 }
653
654 /* m_perform
655 *
656 * actions to perform on IRC connection
657 *
658 * Parameters:
659 * parv[0] = source
660 * parv[1] = PING
661 * parv[2] = PING TS/Package
662 *
663 * source_p: UserInfo struct of the source user, or NULL if
664 * the source (parv[0]) is a server.
665 */
666 static void
667 m_perform(char *parv[], unsigned int parc, char *msg, const struct UserInfo *notused)
668 {
669 node_t *node;
670
671 log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port);
672
673 /* Identify to nickserv if needed */
674 if (!EmptyString(IRCItem->nickserv))
675 irc_send("%s", IRCItem->nickserv);
676
677 /* Oper */
678 irc_send("OPER %s", IRCItem->oper);
679
680 /* Set modes */
681 irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode);
682
683 /* Set Away */
684 if (!EmptyString(IRCItem->away))
685 irc_send("AWAY :%s", IRCItem->away);
686
687 /* Perform */
688 LIST_FOREACH(node, IRCItem->performs->head)
689 irc_send("%s", node->data);
690
691 /* Join all listed channels. */
692 LIST_FOREACH(node, IRCItem->channels->head)
693 {
694 const struct ChannelConf *channel = node->data;
695
696 if (EmptyString(channel->name))
697 continue;
698
699 if (!EmptyString(channel->key))
700 irc_send("JOIN %s %s", channel->name, channel->key);
701 else
702 irc_send("JOIN %s", channel->name);
703 }
704 }
705
706 /* m_ping
707 *
708 * parv[0] = source
709 * parv[1] = PING
710 * parv[2] = PING TS/Package
711 *
712 * source_p: UserInfo struct of the source user, or NULL if
713 * the source (parv[0]) is a server.
714 */
715 static void
716 m_ping(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
717 {
718 if (parc < 3)
719 return;
720
721 if (OPT_DEBUG >= 2)
722 log_printf("IRC -> PING? PONG!");
723
724 irc_send("PONG %s", parv[2]);
725 }
726
727 /* m_invite
728 *
729 * parv[0] = source
730 * parv[1] = INVITE
731 * parv[2] = target
732 * parv[3] = channel
733 *
734 * source_p: UserInfo struct of the source user, or NULL if
735 * the source (parv[0]) is a server.
736 */
737 static void
738 m_invite(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
739 {
740 struct ChannelConf *channel = NULL;
741
742 if (parc < 4)
743 return;
744
745 log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
746
747 if ((channel = get_channel(parv[3])) == NULL)
748 return;
749
750 irc_send("JOIN %s %s", channel->name, channel->key);
751 }
752
753 /* m_privmsg
754 *
755 * parv[0] = source
756 * parv[1] = PRIVMSG
757 * parv[2] = target (channel or user)
758 * parv[3] = message
759 *
760 * source_p: UserInfo struct of the source user, or NULL if
761 * the source (parv[0]) is a server.
762 */
763 static void
764 m_privmsg(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
765 {
766 struct ChannelConf *channel = NULL;
767 size_t nick_len;
768
769 if (source_p == NULL)
770 return;
771
772 if (parc < 4)
773 return;
774
775 /* CTCP */
776 if (parv[3][0] == '\001')
777 m_ctcp(parv, parc, msg, source_p);
778
779 /* Only interested in privmsg to channels */
780 if (parv[2][0] != '#' && parv[2][0] != '&')
781 return;
782
783 /* Get a target */
784 if ((channel = get_channel(parv[2])) == NULL)
785 return;
786
787 /* Find a suitable length to compare with */
788 nick_len = strcspn(parv[3], " :,");
789
790 if (nick_len < 3 && strlen(IRCItem->nick) >= 3)
791 nick_len = 3;
792
793 /* message is a command */
794 if (strncasecmp(parv[3], IRCItem->nick, nick_len) == 0 ||
795 strncasecmp(parv[3], "!all", 4) == 0)
796 {
797 /* XXX command_parse will alter parv[3]. */
798 command_parse(parv[3], channel, source_p);
799 }
800 }
801
802 /* m_ctcp
803 * parv[0] = source
804 * parv[1] = PRIVMSG
805 * parv[2] = target (channel or user)
806 * parv[3] = message
807 *
808 * source_p: UserInfo struct of the source user, or NULL if
809 * the source (parv[0]) is a server.
810 *
811 */
812 static void
813 m_ctcp(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
814 {
815 if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
816 irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001",
817 source_p->irc_nick, VERSION);
818 }
819
820 /* m_notice
821 *
822 * parv[0] = source
823 * parv[1] = NOTICE
824 * parv[2] = target
825 * parv[3] = message
826 *
827 *
828 * source_p: UserInfo struct of the source user, or NULL if
829 * the source (parv[0]) is a server.
830 *
831 */
832 static void
833 m_notice(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
834 {
835 static regex_t *preg = NULL;
836 regmatch_t pmatch[5];
837 int errnum;
838 const char *user[4];
839
840 /* Not interested in notices from users */
841 if (source_p)
842 return;
843
844 if (parc < 4)
845 return;
846
847 /* Compile the regular expression if it has not been already */
848 if (preg == NULL)
849 {
850 preg = xcalloc(sizeof *preg);
851
852 if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)))
853 {
854 char errmsg[256];
855
856 regerror(errnum, preg, errmsg, sizeof(errmsg));
857 log_printf("IRC REGEX -> Error when compiling regular expression");
858 log_printf("IRC REGEX -> %s", errmsg);
859
860 MyFree(preg);
861 preg = NULL;
862 return;
863 }
864 }
865
866 /* Match the expression against the possible connection notice */
867 if (regexec(preg, parv[3], 5, pmatch, 0))
868 return;
869
870 if (OPT_DEBUG > 0)
871 log_printf("IRC REGEX -> Regular expression caught connection notice. Parsing.");
872
873 if (pmatch[4].rm_so == -1)
874 {
875 log_printf("IRC REGEX -> pmatch[4].rm_so is -1 while parsing??? Aborting.");
876 return;
877 }
878
879 /*
880 * Offsets for data in the connection notice:
881 *
882 * NICKNAME: pmatch[1].rm_so TO pmatch[1].rm_eo
883 * USERNAME: pmatch[2].rm_so TO pmatch[2].rm_eo
884 * HOSTNAME: pmatch[3].rm_so TO pmatch[3].rm_eo
885 * IP : pmatch[4].rm_so TO pmatch[4].rm_eo
886 */
887 for (unsigned int i = 0; i < 4; ++i)
888 {
889 user[i] = (parv[3] + pmatch[i + 1].rm_so);
890 *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
891 }
892
893 if (OPT_DEBUG > 0)
894 log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
895 user[0], user[1], user[2], user[3]);
896
897 /*FIXME (reminder) In the case of any rehash to the regex, preg MUST be freed first.
898 regfree(preg);
899 */
900
901 /* Pass this information off to scan.c */
902 scan_connect(user, msg);
903
904 /* Record the connect for stats purposes */
905 stats_connect();
906 }
907
908 /* m_userhost
909 *
910 * parv[0] = source
911 * parv[1] = USERHOST
912 * parv[2] = target (hopm)
913 * parv[3] = :nick=(flags)user@host
914 *
915 *
916 * source_p: UserInfo struct of the source user, or NULL if
917 * the source (parv[0]) is a server.
918 *
919 */
920 static void
921 m_userhost(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
922 {
923 if (parc < 4)
924 return;
925
926 command_userhost(parv[3]);
927 }
928
929 /* m_cannot_join
930 *
931 * parv[0] = source
932 * parv[1] = numeric
933 * parv[2] = target (hopm)
934 * parv[3] = channel
935 * parv[4] = error text
936 *
937 */
938 static void
939 m_cannot_join(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
940 {
941 const struct ChannelConf *channel = NULL;
942
943 if (parc < 5)
944 return;
945
946 /* Is it one of our channels? */
947 if ((channel = get_channel(parv[3])) == NULL)
948 return;
949
950 if (EmptyString(channel->invite))
951 return;
952
953 irc_send("%s", channel->invite);
954 }
955
956 /* m_kill
957 *
958 * parv[0] = source
959 * parv[1] = numeric
960 * parv[2] = target (hopm)
961 * parv[3] = channel
962 * parv[4] = error text
963 *
964 */
965 static void
966 m_kill(char *parv[], unsigned int parc, char *msg, const struct UserInfo *source_p)
967 {
968 /* Restart hopm to rehash */
969 main_restart();
970 }

Properties

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