ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5359
Committed: Sun Jan 11 18:51:17 2015 UTC (9 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 21841 byte(s)
Log Message:
- irc.c:irc_init(): get rid of 'bindret'

File Contents

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

Properties

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