ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5333
Committed: Wed Jan 7 20:45:06 2015 UTC (9 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 21736 byte(s)
Log Message:
- Move malloc.c to memory.c

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

Properties

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