ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 5274
Committed: Thu Jan 1 20:00:33 2015 UTC (10 years, 7 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 21818 byte(s)
Log Message:
- Renamed MyMalloc() to xcalloc()

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

Properties

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