ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5358
Committed: Sun Jan 11 18:51:07 2015 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 21841 byte(s)
Log Message:
- irc.c:irc_init(): get rid of 'bindret'

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

Properties

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