/[svn]/hopm/branches/1.0.x/src/irc.c
ViewVC logotype

Contents of /hopm/branches/1.0.x/src/irc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5192 - (show annotations)
Mon Dec 29 14:58:50 2014 UTC (4 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 23215 byte(s)
- irc.c:irc_parse(): minor cleanups

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.26