ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5084
Committed: Mon Dec 22 19:57:43 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 25160 byte(s)
Log Message:
- Removed USE_VAR cruft

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     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 michael 5069 * Pass control to the IRC portion of HOPM to handle any awaiting IRC events.
140 michael 5052 *
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 michael 5077 if (!EmptyString(IRCItem->vhost))
275 michael 5052 {
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 = (struct ChannelConf *) node->data;
311 michael 5064 strlcat(IRC_CHANNELS, chan->name, sizeof(IRC_CHANNELS));
312 michael 5052
313     if(node->next)
314 michael 5064 strlcat(IRC_CHANNELS, ",", sizeof(IRC_CHANNELS));
315 michael 5052 }
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 michael 5072 void irc_send(const char *data, ...)
332 michael 5052 {
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 michael 5072 void irc_send_channels(const char *data, ...)
366 michael 5052 {
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 michael 5077 if (!EmptyString(IRCItem->password))
433 michael 5052 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 michael 5066 strlcpy(msg, IRC_RAW, sizeof(msg));
567 michael 5052
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 michael 5069 irc_send("PING :HOPM");
658 michael 5052 }
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 michael 5077 if (!EmptyString(IRCItem->nickserv))
802 michael 5052 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 michael 5083 if (!EmptyString(IRCItem->away))
812     irc_send("AWAY :%s", IRCItem->away);
813 michael 5052
814     /* Perform */
815     LIST_FOREACH(node, IRCItem->performs->head)
816     irc_send("%s", (char *) node->data);
817    
818     /* Join all listed channels. */
819     LIST_FOREACH(node, IRCItem->channels->head)
820     {
821     channel = (struct ChannelConf *) node->data;
822    
823 michael 5077 if (EmptyString(channel->name))
824 michael 5052 continue;
825    
826 michael 5077 if (!EmptyString(channel->key))
827 michael 5052 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 michael 5084 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 michael 5052 }
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 michael 5069 * parv[2] = target (hopm)
1059 michael 5052 * 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 michael 5069 * parv[2] = target (hopm)
1081 michael 5052 * 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 michael 5077 if (EmptyString(channel->invite))
1099 michael 5052 return;
1100    
1101     irc_send("%s", channel->invite);
1102     }
1103    
1104    
1105     /* m_kill
1106     *
1107     * parv[0] = source
1108     * parv[1] = numeric
1109 michael 5069 * parv[2] = target (hopm)
1110 michael 5052 * 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 michael 5084 /* Restart hopm to rehash */
1118     main_restart();
1119 michael 5052 }