ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 5198
Committed: Mon Dec 29 16:53:16 2014 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 23219 byte(s)
Log Message:
- Made NODATA_TIMEOUT a configuration option

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

Properties

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