ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 8183
Committed: Thu Apr 13 20:00:17 2017 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 20038 byte(s)
Log Message:
- Sort out unused header includes

File Contents

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

Properties

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