ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5279
Committed: Fri Jan 2 20:30:49 2015 UTC (9 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 21849 byte(s)
Log Message:
- Use 'const' and 'unsigned' whenever possible
- Removed pointless 0 assignments

File Contents

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

Properties

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