ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5210
Committed: Mon Dec 29 19:52:01 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 23116 byte(s)
Log Message:
- Removed configure header test for strings.h; removed strings.h header includes

File Contents

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

Properties

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