ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5170
Committed: Fri Dec 26 20:53:09 2014 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 23254 byte(s)
Log Message:
- Continue to use inet_pton() until we add full ipv6 support, but at least
  replace all occurrences of inet_aton() with inet_pton()

File Contents

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

Properties

Name Value
svn:eol-style native
svn:keywords Id