ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5115
Committed: Wed Dec 24 22:17:42 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 23861 byte(s)
Log Message:
- irc.c:irc_init(): removed unused variables

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