ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5684
Committed: Fri Mar 13 20:17:34 2015 UTC (9 years ago) by michael
Content type: text/x-csrc
File size: 21728 byte(s)
Log Message:
- irc.c: fixed compile error

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

Properties

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