ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5091
Committed: Tue Dec 23 19:59:18 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 25105 byte(s)
Log Message:
- Removed pointless casts

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