ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 6167
Committed: Sat Jun 20 15:50:50 2015 UTC (10 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: hopm/trunk/src/irc.c
File size: 20560 byte(s)
Log Message:
- irc.c: reformatting; move COMMAND_TABLE into irc_parse()

File Contents

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

Properties

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