ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5106
Committed: Wed Dec 24 12:47:21 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 24752 byte(s)
Log Message:
- irc.c: rewrite irc_send_channels()

File Contents

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