ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5114
Committed: Wed Dec 24 22:12:05 2014 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 23905 byte(s)
Log Message:
- Style corrections

File Contents

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