ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5876
Committed: Wed Apr 29 11:25:48 2015 UTC (10 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 21653 byte(s)
Log Message:
- Removed trailing whitespaces

File Contents

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

Properties

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