ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/irc.c
Revision: 5251
Committed: Thu Jan 1 13:40:00 2015 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 21926 byte(s)
Log Message:
- irc.c:irc_init(): improve and simplify error reporting if socket()/bind() fails

File Contents

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

Properties

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