ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 5279
Committed: Fri Jan 2 20:30:49 2015 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 21849 byte(s)
Log Message:
- Use 'const' and 'unsigned' whenever possible
- Removed pointless 0 assignments

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

Properties

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