ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5124
Committed: Thu Dec 25 17:12:13 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 23341 byte(s)
Log Message:
- irc.c:irc_read(): removed extraneous test for 'c' being either '\r' or '\n'.
  It's already dealt with cr/lf at this point.

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