ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/irc.c
(Generate patch)

Comparing hopm/trunk/src/irc.c (file contents):
Revision 8178 by michael, Thu Apr 13 14:55:40 2017 UTC vs.
Revision 9727 by michael, Mon Nov 16 10:29:12 2020 UTC

# Line 1 | Line 1
1   /*
2   *  Copyright (c) 2002-2003 Erik Fears
3 < *  Copyright (c) 2014-2017 ircd-hybrid development team
3 > *  Copyright (c) 2014-2020 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
# Line 30 | Line 30
30   #include <netinet/in.h>
31   #include <arpa/inet.h>
32   #include <poll.h>
33 #include <sys/time.h>
33   #include <time.h>
35
34   #include <errno.h>
35   #include <stdarg.h>
36   #include <regex.h>
37   #include <assert.h>
38 + #ifdef HAVE_LIBCRYPTO
39 + #include <openssl/ssl.h>
40 + #include <openssl/x509v3.h>
41 + #include <openssl/err.h>
42 + #endif
43  
44   #include "config.h"
45   #include "irc.h"
# Line 51 | Line 54
54   #include "negcache.h"
55   #include "memory.h"
56   #include "main.h"
54 #include "serno.h"
57  
58  
59   /*
# Line 63 | Line 65 | static unsigned int IRC_RAW_LEN;
65   static int          IRC_FD = -1;         /* File descriptor for IRC client         */
66  
67   static struct sockaddr_storage IRC_SVR;  /* Sock Address Struct for IRC server     */
68 < static socklen_t svr_addrlen;
68 > static socklen_t IRC_SVR_LEN;
69 > static char IRC_SVR_STR[INET6_ADDRSTRLEN];
70   static time_t IRC_LAST;                  /* Last full line of data from irc server */
71   static time_t IRC_LASTRECONNECT;         /* Time of last reconnection              */
72  
73 + #ifdef HAVE_LIBCRYPTO
74 + static SSL_CTX *ssl_ctx;
75 + static SSL *ssl_handle;
76 + #endif
77 +
78  
79   /* get_channel
80   *
# Line 83 | Line 91 | get_channel(const char *name)
91   {
92    node_t *node;
93  
94 <  LIST_FOREACH(node, IRCItem->channels->head)
94 >  LIST_FOREACH(node, IRCItem.channels.head)
95    {
96      struct ChannelConf *item = node->data;
97  
# Line 111 | Line 119 | m_perform(char *parv[], unsigned int par
119   {
120    node_t *node;
121  
122 <  log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port);
122 >  log_printf("IRC -> Connected to %s[%s]:%i", IRC_SVR_STR, IRCItem.server, IRCItem.port);
123  
124    /* Identify to nickserv if needed */
125 <  if (!EmptyString(IRCItem->nickserv))
126 <    irc_send("%s", IRCItem->nickserv);
125 >  if (!EmptyString(IRCItem.nickserv))
126 >    irc_send("%s", IRCItem.nickserv);
127  
128    /* Oper */
129 <  irc_send("OPER %s", IRCItem->oper);
129 >  if (!EmptyString(IRCItem.oper))
130 >    irc_send("OPER %s", IRCItem.oper);
131  
132    /* Set modes */
133 <  irc_send("MODE %s %s", IRCItem->nick, IRCItem->mode);
133 >  if (!EmptyString(IRCItem.mode))
134 >    irc_send("MODE %s %s", IRCItem.nick, IRCItem.mode);
135  
136    /* Set Away */
137 <  if (!EmptyString(IRCItem->away))
138 <    irc_send("AWAY :%s", IRCItem->away);
137 >  if (!EmptyString(IRCItem.away))
138 >    irc_send("AWAY :%s", IRCItem.away);
139  
140    /* Perform */
141 <  LIST_FOREACH(node, IRCItem->performs->head)
141 >  LIST_FOREACH(node, IRCItem.performs.head)
142      irc_send("%s", node->data);
143  
144    /* Join all listed channels. */
145 <  LIST_FOREACH(node, IRCItem->channels->head)
145 >  LIST_FOREACH(node, IRCItem.channels.head)
146    {
147      const struct ChannelConf *channel = node->data;
148  
# Line 180 | Line 190 | m_ping(char *parv[], unsigned int parc,
190   static void
191   m_invite(char *parv[], unsigned int parc, const char *msg, const char *source_p)
192   {
183  const struct ChannelConf *channel = NULL;
184
193    if (parc < 4)
194      return;
195  
196    log_printf("IRC -> Invited to %s by %s", parv[3], parv[0]);
197  
198 <  if ((channel = get_channel(parv[3])) == NULL)
198 >  const struct ChannelConf *channel = get_channel(parv[3]);
199 >  if (channel == NULL)
200      return;
201  
202    irc_send("JOIN %s %s", channel->name, channel->key);
# Line 206 | Line 215 | static void
215   m_ctcp(char *parv[], unsigned int parc, const char *msg, const char *source_p)
216   {
217    if (strncasecmp(parv[3], "\001VERSION\001", 9) == 0)
218 <    irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s(%s)\001",
219 <             source_p, VERSION, SERIALNUM);
218 >    irc_send("NOTICE %s :\001VERSION Hybrid Open Proxy Monitor %s\001",
219 >             source_p, VERSION);
220   }
221  
222   /* m_privmsg
# Line 223 | Line 232 | m_ctcp(char *parv[], unsigned int parc,
232   static void
233   m_privmsg(char *parv[], unsigned int parc, const char *msg, const char *source_p)
234   {
226  const struct ChannelConf *channel = NULL;
227
235    if (source_p == NULL)
236      return;
237  
# Line 243 | Line 250 | m_privmsg(char *parv[], unsigned int par
250      return;
251  
252    /* Get a target */
253 <  if ((channel = get_channel(parv[2])) == NULL)
253 >  const struct ChannelConf *channel = get_channel(parv[2]);
254 >  if (channel == NULL)
255      return;
256  
257    int hit = strncasecmp(parv[3], "!all ", 5) == 0;
258    if (hit == 0)
259    {
260 <    size_t nick_len = strlen(IRCItem->nick);
260 >    size_t nick_len = strlen(IRCItem.nick);
261  
262 <    if (strncasecmp(parv[3], IRCItem->nick, nick_len) == 0)
263 <      hit = *(parv[3] + nick_len) == ' ';
262 >    if (strncasecmp(parv[3], IRCItem.nick, nick_len) == 0)
263 >      hit = *(parv[3] + nick_len) == ' ' ||
264 >            *(parv[3] + nick_len) == ',' ||
265 >            *(parv[3] + nick_len) == ':';
266    }
267  
268    if (hit)
269      /* XXX command_parse will alter parv[3]. */
270 <    command_parse(parv[3], channel, source_p);
270 >    command_parse(parv[3], channel->name, source_p);
271   }
272  
273   /* m_notice
# Line 292 | Line 302 | m_notice(char *parv[], unsigned int parc
302    {
303      preg = xcalloc(sizeof(*preg));
304  
305 <    if ((errnum = regcomp(preg, IRCItem->connregex, REG_ICASE | REG_EXTENDED)))
305 >    if ((errnum = regcomp(preg, IRCItem.connregex, REG_ICASE | REG_EXTENDED)))
306      {
307        char errmsg[256];
308  
# Line 336 | Line 346 | m_notice(char *parv[], unsigned int parc
346      log_printf("IRC REGEX -> Parsed %s!%s@%s [%s] from connection notice.",
347                 user[0], user[1], user[2], user[3]);
348  
349 <  LIST_FOREACH(node, IRCItem->notices->head)
349 >  LIST_FOREACH(node, IRCItem.notices.head)
350      irc_send("NOTICE %s :%s", user[0], node->data);
351  
352    /* Pass this information off to scan.c */
# Line 377 | Line 387 | m_userhost(char *parv[], unsigned int pa
387   static void
388   m_cannot_join(char *parv[], unsigned int parc, const char *msg, const char *source_p)
389   {
380  const struct ChannelConf *channel = NULL;
381
390    if (parc < 5)
391      return;
392  
393    /* Is it one of our channels? */
394 <  if ((channel = get_channel(parv[3])) == NULL)
394 >  const struct ChannelConf *channel = get_channel(parv[3]);
395 >  if (channel == NULL)
396      return;
397  
398    if (EmptyString(channel->invite))
# Line 461 | Line 470 | userinfo_create(const char *source)
470   static void
471   irc_init(void)
472   {
473 <  const void *address = NULL;
473 >  int n;
474 >  const void *address;
475 >  struct addrinfo hints, *res = NULL;
476  
477    assert(IRC_FD == -1);
478  
479    memset(&IRC_SVR, 0, sizeof(IRC_SVR));
480  
481 +  if (!EmptyString(IRCItem.bind))
482 +  {
483 +    memset(&hints, 0, sizeof(hints));
484 +
485 +    hints.ai_family = AF_UNSPEC;
486 +    hints.ai_socktype = SOCK_STREAM;
487 +    hints.ai_flags = AI_NUMERICHOST;
488 +
489 +    n = getaddrinfo(IRCItem.bind, NULL, &hints, &res);
490 +    if (n)
491 +    {
492 +      log_printf("IRC -> getaddrinfo() error: %s", gai_strerror(n));
493 +      exit(EXIT_FAILURE);
494 +    }
495 +  }
496 +
497    /* Resolve IRC host. */
498 <  if ((address = firedns_resolveip6(IRCItem->server)))
498 >  if ((res == NULL || res->ai_family == AF_INET6) && (address = firedns_resolveip6(IRCItem.server)))
499    {
500      struct sockaddr_in6 *in = (struct sockaddr_in6 *)&IRC_SVR;
501  
502 <    svr_addrlen = sizeof(*in);
502 >    IRC_SVR_LEN = sizeof(*in);
503      IRC_SVR.ss_family = AF_INET6;
504 <    in->sin6_port = htons(IRCItem->port);
504 >    in->sin6_port = htons(IRCItem.port);
505      memcpy(&in->sin6_addr, address, sizeof(in->sin6_addr));
506    }
507 <  else if ((address = firedns_resolveip4(IRCItem->server)))
507 >  else if ((res == NULL || res->ai_family == AF_INET) && (address = firedns_resolveip4(IRCItem.server)))
508    {
509      struct sockaddr_in *in = (struct sockaddr_in *)&IRC_SVR;
510  
511 <    svr_addrlen = sizeof(*in);
511 >    IRC_SVR_LEN = sizeof(*in);
512      IRC_SVR.ss_family = AF_INET;
513 <    in->sin_port = htons(IRCItem->port);
513 >    in->sin_port = htons(IRCItem.port);
514      memcpy(&in->sin_addr, address, sizeof(in->sin_addr));
515    }
516    else
517    {
518 <    log_printf("IRC -> firedns_resolveip(\"%s\"): %s", IRCItem->server,
518 >    log_printf("IRC -> Error resolving host '%s': %s", IRCItem.server,
519                 firedns_strerror(firedns_errno));
520      exit(EXIT_FAILURE);
521    }
522  
523 +  n = getnameinfo((const struct sockaddr *)&IRC_SVR, IRC_SVR_LEN, IRC_SVR_STR,
524 +                  sizeof(IRC_SVR_STR), NULL, 0, NI_NUMERICHOST);
525 +  if (n)
526 +  {
527 +    log_printf("IRC -> getnameinfo() error: %s", gai_strerror(n));
528 +    exit(EXIT_FAILURE);
529 +  }
530 +
531    /* Request file desc for IRC client socket */
532    IRC_FD = socket(IRC_SVR.ss_family, SOCK_STREAM, 0);
533  
# Line 503 | Line 538 | irc_init(void)
538    }
539  
540    /* Bind */
541 <  if (!EmptyString(IRCItem->vhost))
541 >  if (res)
542    {
543 <    struct addrinfo hints, *res;
544 <    int n;
545 <
546 <    memset(&hints, 0, sizeof(hints));
543 >    if (bind(IRC_FD, res->ai_addr, res->ai_addrlen))
544 >    {
545 >      log_printf("IRC -> error binding to %s: %s", IRCItem.bind, strerror(errno));
546 >      exit(EXIT_FAILURE);
547 >    }
548  
549 <    hints.ai_family = AF_UNSPEC;
550 <    hints.ai_socktype = SOCK_STREAM;
515 <    hints.ai_flags = AI_NUMERICHOST;
549 >    freeaddrinfo(res);
550 >  }
551  
552 <    if ((n = getaddrinfo(IRCItem->vhost, NULL, &hints, &res)))
552 >  if (IRCItem.tls)
553 >  {
554 > #ifdef HAVE_LIBCRYPTO
555 >    /* Initialize SSL */
556 >    static int tls_init = 0;
557 >    if (tls_init == 0)
558      {
559 <      log_printf("IRC -> error binding to %s: %s", IRCItem->vhost, gai_strerror(n));
560 <      exit(EXIT_FAILURE);
559 >      tls_init = 1;
560 >
561 >      ssl_ctx = SSL_CTX_new(TLS_client_method());
562 >      if (ssl_ctx == NULL)
563 >      {
564 >        log_printf("IRC -> unable to create SSL context");
565 >        exit(EXIT_FAILURE);
566 >      }
567 >
568 >      if (!EmptyString(IRCItem.rsa_private_key_file) &&
569 >          !EmptyString(IRCItem.tls_certificate_file))
570 >      {
571 >        if (SSL_CTX_use_certificate_chain_file(ssl_ctx, IRCItem.tls_certificate_file) != 1)
572 >        {
573 >          log_printf("IRC -> couldn't load client certificate from %s: %s",
574 >                     IRCItem.tls_certificate_file, ERR_error_string(ERR_get_error(), NULL));
575 >          exit(EXIT_FAILURE);
576 >        }
577 >
578 >        if (SSL_CTX_use_PrivateKey_file(ssl_ctx, IRCItem.rsa_private_key_file, SSL_FILETYPE_PEM) != 1)
579 >        {
580 >          log_printf("IRC -> couldn't load private key from %s: %s",
581 >                     IRCItem.rsa_private_key_file, ERR_error_string(ERR_get_error(), NULL));
582 >          exit(EXIT_FAILURE);
583 >        }
584 >
585 >        if (SSL_CTX_check_private_key(ssl_ctx) != 1)
586 >        {
587 >          log_printf("IRC -> Private key does not match the client certificate: %s",
588 >                     ERR_error_string(ERR_get_error(), NULL));
589 >          exit(EXIT_FAILURE);
590 >        }
591 >      }
592 >
593 >      SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION);
594 >      SSL_CTX_set_default_verify_paths(ssl_ctx);
595      }
596 <    else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen))
596 >
597 >    ssl_handle = SSL_new(ssl_ctx);
598 >    SSL_set_fd(ssl_handle, IRC_FD);
599 >
600 >    if (IRCItem.tls_hostname_verification)
601      {
602 <      log_printf("IRC -> error binding to %s: %s", IRCItem->vhost, strerror(errno));
603 <      exit(EXIT_FAILURE);
602 >      SSL_set_hostflags(ssl_handle, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
603 >
604 >      if (SSL_set1_host(ssl_handle, IRCItem.server) == 0)
605 >      {
606 >        log_printf("IRC -> unable to set expected DNS hostname");
607 >        /* OpenSSL is unable to verify the server hostname at this point, so we exit. */
608 >        exit(EXIT_FAILURE);
609 >      }
610      }
611  
612 <    freeaddrinfo(res);
612 >    SSL_set_verify(ssl_handle, SSL_VERIFY_PEER, NULL);
613 > #else
614 >    log_printf("IRC -> HOPM is not compiled with OpenSSL support");
615 >    exit(EXIT_FAILURE);
616 > #endif
617    }
618   }
619  
620 < /* irc_reconnect
620 > /* irc_close
621   *
622   *    Close connection to IRC server.
623   *
# Line 538 | Line 626 | irc_init(void)
626   * Return: NONE
627   */
628   static void
629 < irc_reconnect(void)
629 > irc_close(void)
630   {
543  time_t present;
544
545  time(&present);
546
547  /* Only try to reconnect every IRCItem->reconnectinterval seconds */
548  if ((present - IRC_LASTRECONNECT) < IRCItem->reconnectinterval)
549  {
550    /* Sleep to avoid excessive CPU */
551    sleep(1);
552    return;
553  }
554
555  time(&IRC_LASTRECONNECT);
556
631    if (IRC_FD > -1)
632    {
633 + #ifdef HAVE_LIBCRYPTO
634 +    if (ssl_handle)
635 +    {
636 +      SSL_shutdown(ssl_handle);
637 +      SSL_free(ssl_handle);
638 +      ssl_handle = NULL;
639 +    }
640 + #endif
641 +
642      close(IRC_FD);
643      IRC_FD = -1;  /* Set IRC_FD -1 for reconnection on next irc_cycle(). */
644    }
645  
646 <  log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem->server);
646 >  log_printf("IRC -> Connection to (%s) failed, reconnecting.", IRCItem.server);
647   }
648  
649   /* irc_connect
# Line 574 | Line 657 | irc_reconnect(void)
657   static void
658   irc_connect(void)
659   {
660 +  time_t present;
661 +
662 +  time(&present);
663 +
664 +  /* Only try to reconnect every IRCItem.reconnectinterval seconds */
665 +  if ((present - IRC_LASTRECONNECT) < IRCItem.reconnectinterval)
666 +  {
667 +    /* Sleep to avoid excessive CPU */
668 +    sleep(1);
669 +    return;
670 +  }
671 +
672 +  time(&IRC_LASTRECONNECT);
673 +  time(&IRC_LAST);
674 +
675 +  irc_init();
676 +
677 +  log_printf("IRC -> Attempting to connect to %s[%s]:%i", IRC_SVR_STR, IRCItem.server, IRCItem.port);
678 +
679    /* Connect to IRC server as client. */
680 <  if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, svr_addrlen) == -1)
680 >  if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, IRC_SVR_LEN) == -1)
681    {
682      log_printf("IRC -> connect(): error connecting to %s: %s",
683 <               IRCItem->server, strerror(errno));
683 >               IRCItem.server, strerror(errno));
684  
685 <    if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */)
686 <      return;
585 <
586 <    /* Try to connect again */
587 <    irc_reconnect();
685 >    /* Close socket and try to connect again */
686 >    irc_close();
687      return;
688    }
689  
690 <  irc_send("NICK %s", IRCItem->nick);
690 > #ifdef HAVE_LIBCRYPTO
691 >  if (ssl_handle)
692 >  {
693 >    int ret = SSL_connect(ssl_handle);
694 >    if (ret != 1)
695 >    {
696 >      const char *error = ERR_error_string(ERR_get_error(), NULL);
697 >      log_printf("IRC -> connect(): error performing TLS handshake with %s: %s",
698 >                 IRCItem.server, error);
699 >
700 >      /* Close socket and try to connect again */
701 >      irc_close();
702 >      return;
703 >    }
704 >  }
705 > #endif
706 >
707 >  irc_send("NICK %s", IRCItem.nick);
708  
709 <  if (!EmptyString(IRCItem->password))
710 <    irc_send("PASS %s", IRCItem->password);
709 >  if (!EmptyString(IRCItem.password))
710 >    irc_send("PASS %s", IRCItem.password);
711  
712    irc_send("USER %s %s %s :%s",
713 <           IRCItem->username,
714 <           IRCItem->username,
715 <           IRCItem->username,
716 <           IRCItem->realname);
713 >           IRCItem.username,
714 >           IRCItem.username,
715 >           IRCItem.username,
716 >           IRCItem.realname);
717    time(&IRC_LAST);
718   }
719  
# Line 622 | Line 738 | irc_parse(void)
738     * source did not exist
739     */
740    char        *parv[17];
741 +  static const unsigned int parv_size = sizeof(parv) / sizeof(parv[0]);
742    unsigned int parc = 1;
743    char         msg[MSGLENMAX];  /* Temporarily stores IRC msg to pass to handlers */
744  
# Line 667 | Line 784 | irc_parse(void)
784      parv[0] = IRC_RAW + 1;
785    else
786    {
787 <    parv[0] = IRCItem->server;
787 >    parv[0] = IRCItem.server;
788      parv[parc++] = IRC_RAW;
789    }
790  
791    pos = IRC_RAW;
792  
793 <  while ((pos = strchr(pos, ' ')) && parc <= 17)
793 >  while ((pos = strchr(pos, ' ')) && parc < parv_size)
794    {
795      /* Avoid excessive spaces and end of IRC_RAW */
796      if (*(pos + 1) == ' ' || *(pos + 1) == '\0')
# Line 727 | Line 844 | irc_read(void)
844    ssize_t len;
845    char c;
846  
847 <  while ((len = read(IRC_FD, &c, 1)) > 0)
847 >  while (1)
848    {
849 + #ifdef HAVE_LIBCRYPTO
850 +    if (ssl_handle)
851 +      len = SSL_read(ssl_handle, &c, 1);
852 +    else
853 + #endif
854 +      len = recv(IRC_FD, &c, 1, 0);
855 +
856 +    if (len <= 0)
857 +      break;
858 +
859      if (c == '\r')
860        continue;
861  
# Line 742 | Line 869 | irc_read(void)
869  
870        /* Reset counter. */
871        IRC_RAW_LEN = 0;
872 <      break;
872 >      return;
873      }
874  
875      if (c != '\0')
# Line 754 | Line 881 | irc_read(void)
881      if (errno != EINTR)
882        log_printf("IRC -> Error reading data from server: %s", strerror(errno));
883  
884 <    irc_reconnect();
884 >    irc_close();
885      IRC_RAW_LEN = 0;
759    return;
886    }
887   }
888  
# Line 778 | Line 904 | irc_cycle(void)
904    if (IRC_FD == -1)
905    {
906      /* Initialize negative cache. */
907 <    if (OptionsItem->negcache)
907 >    if (OptionsItem.negcache)
908        negcache_init();
909  
784    /* Resolve remote host. */
785    irc_init();
786
910      /* Connect to remote host. */
911      irc_connect();
912      return;  /* In case connect() immediately failed */
# Line 803 | Line 926 | irc_cycle(void)
926        if (pfd.revents & POLLIN)
927          irc_read();
928        else if (pfd.revents & (POLLERR | POLLHUP))
929 <        irc_reconnect();
929 >        irc_close();
930  
931        break;
932    }
# Line 824 | Line 947 | irc_send(const char *data, ...)
947   {
948    va_list arglist;
949    char buf[MSGLENMAX];
827  size_t len = 0;
950  
951    va_start(arglist, data);
952 <  len = vsnprintf(buf, sizeof(buf), data, arglist);
952 >  ssize_t len = vsnprintf(buf, sizeof(buf), data, arglist);
953    va_end(arglist);
954  
955    if (OPT_DEBUG >= 2)
# Line 839 | Line 961 | irc_send(const char *data, ...)
961    buf[len++] = '\r';
962    buf[len++] = '\n';
963  
964 <  if (send(IRC_FD, buf, len, 0) == -1)
964 >  ssize_t sent;
965 > #ifdef HAVE_LIBCRYPTO
966 >  if (ssl_handle)
967 >    sent = SSL_write(ssl_handle, buf, len);
968 >  else
969 > #endif
970 >    sent = send(IRC_FD, buf, len, 0);
971 >
972 >  if (sent != len)
973    {
974      /* Return of -1 indicates error sending data; we reconnect. */
975      log_printf("IRC -> Error sending data to server: %s", strerror(errno));
976 <    irc_reconnect();
976 >    irc_close();
977    }
978   }
979  
# Line 868 | Line 998 | irc_send_channels(const char *data, ...)
998    vsnprintf(buf, sizeof(buf), data, arglist);
999    va_end(arglist);
1000  
1001 <  LIST_FOREACH(node, IRCItem->channels->head)
1001 >  LIST_FOREACH(node, IRCItem.channels.head)
1002    {
1003      const struct ChannelConf *chan = node->data;
1004  
# Line 892 | Line 1022 | irc_timer(void)
1022  
1023    delta = present - IRC_LAST;
1024  
1025 <  /* No data in IRCItem->readtimeout seconds */
1026 <  if (delta >= IRCItem->readtimeout)
1025 >  /* No data in IRCItem.readtimeout seconds */
1026 >  if (delta >= IRCItem.readtimeout)
1027    {
1028      log_printf("IRC -> Timeout awaiting data from server.");
1029 <    irc_reconnect();
1029 >    irc_close();
1030  
1031      /* Make sure we don't do this again for a while */
1032      time(&IRC_LAST);
1033    }
1034 <  else if (delta >= IRCItem->readtimeout / 2)
1034 >  else if (delta >= IRCItem.readtimeout / 2)
1035    {
1036      /*
1037       * Generate some data so high ping times don't cause uneeded

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)