ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.1.x/src/irc.c
Revision: 8123
Committed: Mon Apr 3 16:39:28 2017 UTC (6 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 19816 byte(s)
Log Message:
- irc.c:irc_init(): remove AI_PASSIVE flag from hints.ai_flags

File Contents

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

Properties

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