ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
Revision: 5405
Committed: Tue Jan 20 19:14:40 2015 UTC (10 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 21711 byte(s)
Log Message:
- Added irc::notice configuration option (notice(s) to send to a newly connected client).

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

Properties

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