ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5252
Committed: Thu Jan 1 13:45:57 2015 UTC (9 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 21945 byte(s)
Log Message:
- irc.c:irc_send(): improved error reporting if send() fails

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

Properties

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