/[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 5169 - (show annotations)
Fri Dec 26 19:32:28 2014 UTC (7 years, 6 months ago) by michael
File MIME type: text/x-chdr
File size: 23583 byte(s)
- Use sizeof(struct in_addr) instead of res->ai_addrlen

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

Properties

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

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