/[svn]/hopm/trunk/src/irc.c
ViewVC logotype

Annotation of /hopm/trunk/src/irc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28