ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 5726
Committed: Tue Mar 24 18:04:06 2015 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 21538 byte(s)
Log Message:
- Removed some irrelevant comments

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

Properties

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