ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5691
Committed: Sat Mar 14 19:02:51 2015 UTC (10 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 21685 byte(s)
Log Message:
- irc.c: cleaned up userinfo_create()

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(const 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 const 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(const char *source)
591 {
592 struct UserInfo *ret;
593 char *nick = NULL;
594 char *username = NULL;
595 char *hostname = NULL;
596 char tmp[MSGLENMAX];
597 size_t i, len;
598
599 len = strlcpy(tmp, source, sizeof(tmp));
600 nick = tmp;
601
602 for (i = 0; i < len; ++i)
603 {
604 if (tmp[i] == '!')
605 {
606 tmp[i] = '\0';
607 username = tmp + i + 1;
608 }
609
610 if (tmp[i] == '@')
611 {
612 tmp[i] = '\0';
613 hostname = tmp + i + 1;
614 }
615 }
616
617 if (username == NULL || hostname == NULL)
618 return NULL;
619
620 ret = xcalloc(sizeof *ret);
621 ret->irc_nick = xstrdup(nick);
622 ret->irc_username = xstrdup(username);
623 ret->irc_hostname = xstrdup(hostname);
624
625 return ret;
626 };
627
628 /* userinfo_free
629 *
630 * Free a UserInfo struct created with userinfo_create.
631 *
632 * Parameters:
633 * source: struct to free
634 *
635 * Return: None
636 */
637 static void
638 userinfo_free(struct UserInfo *source_p)
639 {
640 if (source_p == NULL)
641 return;
642
643 xfree(source_p->irc_nick);
644 xfree(source_p->irc_username);
645 xfree(source_p->irc_hostname);
646 xfree(source_p);
647 }
648
649 /* m_perform
650 *
651 * actions to perform on IRC connection
652 *
653 * Parameters:
654 * parv[0] = source
655 * parv[1] = PING
656 * parv[2] = PING TS/Package
657 *
658 * source_p: UserInfo struct of the source user, or NULL if
659 * the source (parv[0]) is a server.
660 */
661 static void
662 m_perform(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *notused)
663 {
664 node_t *node;
665
666 log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port);
667
668 /* Identify to nickserv if needed */
669 if (!EmptyString(IRCItem->nickserv))
670 irc_send("%s", IRCItem->nickserv);
671
672 /* Oper */
673 irc_send("OPER %s", IRCItem->oper);
674
675 /* Set modes */
676 irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode);
677
678 /* Set Away */
679 if (!EmptyString(IRCItem->away))
680 irc_send("AWAY :%s", IRCItem->away);
681
682 /* Perform */
683 LIST_FOREACH(node, IRCItem->performs->head)
684 irc_send("%s", node->data);
685
686 /* Join all listed channels. */
687 LIST_FOREACH(node, IRCItem->channels->head)
688 {
689 const struct ChannelConf *channel = node->data;
690
691 if (EmptyString(channel->name))
692 continue;
693
694 if (!EmptyString(channel->key))
695 irc_send("JOIN %s %s", channel->name, channel->key);
696 else
697 irc_send("JOIN %s", channel->name);
698 }
699 }
700
701 /* m_ping
702 *
703 * parv[0] = source
704 * parv[1] = PING
705 * parv[2] = PING TS/Package
706 *
707 * source_p: UserInfo struct of the source user, or NULL if
708 * the source (parv[0]) is a server.
709 */
710 static void
711 m_ping(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
712 {
713 if (parc < 3)
714 return;
715
716 if (OPT_DEBUG >= 2)
717 log_printf("IRC -> PING? PONG!");
718
719 irc_send("PONG %s", parv[2]);
720 }
721
722 /* m_invite
723 *
724 * parv[0] = source
725 * parv[1] = INVITE
726 * parv[2] = target
727 * parv[3] = channel
728 *
729 * source_p: UserInfo struct of the source user, or NULL if
730 * the source (parv[0]) is a server.
731 */
732 static void
733 m_invite(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
734 {
735 const struct ChannelConf *channel = NULL;
736
737 if (parc < 4)
738 return;
739
740 log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
741
742 if ((channel = get_channel(parv[3])) == NULL)
743 return;
744
745 irc_send("JOIN %s %s", channel->name, channel->key);
746 }
747
748 /* m_privmsg
749 *
750 * parv[0] = source
751 * parv[1] = PRIVMSG
752 * parv[2] = target (channel or user)
753 * parv[3] = message
754 *
755 * source_p: UserInfo struct of the source user, or NULL if
756 * the source (parv[0]) is a server.
757 */
758 static void
759 m_privmsg(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
760 {
761 const struct ChannelConf *channel = NULL;
762 size_t nick_len;
763
764 if (source_p == NULL)
765 return;
766
767 if (parc < 4)
768 return;
769
770 /* CTCP */
771 if (parv[3][0] == '\001')
772 m_ctcp(parv, parc, msg, source_p);
773
774 /* Only interested in privmsg to channels */
775 if (parv[2][0] != '#' && parv[2][0] != '&')
776 return;
777
778 /* Get a target */
779 if ((channel = get_channel(parv[2])) == NULL)
780 return;
781
782 /* Find a suitable length to compare with */
783 nick_len = strcspn(parv[3], " :,");
784
785 if (nick_len < 3 && strlen(IRCItem->nick) >= 3)
786 nick_len = 3;
787
788 /* message is a command */
789 if (strncasecmp(parv[3], IRCItem->nick, nick_len) == 0 ||
790 strncasecmp(parv[3], "!all", 4) == 0)
791 {
792 /* XXX command_parse will alter parv[3]. */
793 command_parse(parv[3], channel, source_p);
794 }
795 }
796
797 /* m_ctcp
798 * parv[0] = source
799 * parv[1] = PRIVMSG
800 * parv[2] = target (channel or user)
801 * parv[3] = message
802 *
803 * source_p: UserInfo struct of the source user, or NULL if
804 * the source (parv[0]) is a server.
805 *
806 */
807 static void
808 m_ctcp(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
809 {
810 if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
811 irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001",
812 source_p->irc_nick, VERSION);
813 }
814
815 /* m_notice
816 *
817 * parv[0] = source
818 * parv[1] = NOTICE
819 * parv[2] = target
820 * parv[3] = message
821 *
822 *
823 * source_p: UserInfo struct of the source user, or NULL if
824 * the source (parv[0]) is a server.
825 *
826 */
827 static void
828 m_notice(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
829 {
830 static regex_t *preg = NULL;
831 regmatch_t pmatch[5];
832 int errnum;
833 const char *user[4];
834 const node_t *node;
835
836 /* Not interested in notices from users */
837 if (source_p)
838 return;
839
840 if (parc < 4)
841 return;
842
843 /* Compile the regular expression if it has not been already */
844 if (preg == NULL)
845 {
846 preg = xcalloc(sizeof *preg);
847
848 if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)))
849 {
850 char errmsg[256];
851
852 regerror(errnum, preg, errmsg, sizeof(errmsg));
853 log_printf("IRC REGEX -> Error when compiling regular expression");
854 log_printf("IRC REGEX -> %s", errmsg);
855
856 xfree(preg);
857 preg = NULL;
858 return;
859 }
860 }
861
862 /* Match the expression against the possible connection notice */
863 if (regexec(preg, parv[3], 5, pmatch, 0))
864 return;
865
866 if (OPT_DEBUG > 0)
867 log_printf("IRC REGEX -> Regular expression caught connection notice. Parsing.");
868
869 if (pmatch[4].rm_so == -1)
870 {
871 log_printf("IRC REGEX -> pmatch[4].rm_so is -1 while parsing??? Aborting.");
872 return;
873 }
874
875 /*
876 * Offsets for data in the connection notice:
877 *
878 * NICKNAME: pmatch[1].rm_so TO pmatch[1].rm_eo
879 * USERNAME: pmatch[2].rm_so TO pmatch[2].rm_eo
880 * HOSTNAME: pmatch[3].rm_so TO pmatch[3].rm_eo
881 * IP : pmatch[4].rm_so TO pmatch[4].rm_eo
882 */
883 for (unsigned int i = 0; i < 4; ++i)
884 {
885 user[i] = (parv[3] + pmatch[i + 1].rm_so);
886 *(parv[3] + pmatch[i + 1].rm_eo) = '\0';
887 }
888
889 if (OPT_DEBUG > 0)
890 log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
891 user[0], user[1], user[2], user[3]);
892
893 /*FIXME (reminder) In the case of any rehash to the regex, preg MUST be freed first.
894 regfree(preg);
895 */
896
897 LIST_FOREACH(node, IRCItem->notices->head)
898 irc_send("NOTICE %s :%s", user[0], node->data);
899
900 /* Pass this information off to scan.c */
901 scan_connect(user, msg);
902
903 /* Record the connect for stats purposes */
904 stats_connect();
905 }
906
907 /* m_userhost
908 *
909 * parv[0] = source
910 * parv[1] = USERHOST
911 * parv[2] = target (hopm)
912 * parv[3] = :nick=(flags)user@host
913 *
914 *
915 * source_p: UserInfo struct of the source user, or NULL if
916 * the source (parv[0]) is a server.
917 *
918 */
919 static void
920 m_userhost(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
921 {
922 if (parc < 4)
923 return;
924
925 command_userhost(parv[3]);
926 }
927
928 /* m_cannot_join
929 *
930 * parv[0] = source
931 * parv[1] = numeric
932 * parv[2] = target (hopm)
933 * parv[3] = channel
934 * parv[4] = error text
935 *
936 */
937 static void
938 m_cannot_join(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
939 {
940 const struct ChannelConf *channel = NULL;
941
942 if (parc < 5)
943 return;
944
945 /* Is it one of our channels? */
946 if ((channel = get_channel(parv[3])) == NULL)
947 return;
948
949 if (EmptyString(channel->invite))
950 return;
951
952 irc_send("%s", channel->invite);
953 }
954
955 /* m_kill
956 *
957 * parv[0] = source
958 * parv[1] = numeric
959 * parv[2] = target (hopm)
960 * parv[3] = channel
961 * parv[4] = error text
962 *
963 */
964 static void
965 m_kill(char *parv[], unsigned int parc, const char *msg, const struct UserInfo *source_p)
966 {
967 /* Restart hopm to rehash */
968 main_restart();
969 }

Properties

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