+ readbuf[len] = 0;
+ if (!array_cats( &My_Connections[Idx].rbuf, readbuf )) {
+ Log( LOG_ERR, "Could not append recieved data to input buffer (connn %d): %d bytes!", Idx, len );
+ Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
+ }
+ }
+
+ /* Update connection statistics */
+ My_Connections[Idx].bytes_in += len;
+
+ /* Update timestamp of last data received if this connection is
+ * registered as a user, server or service connection. Don't update
+ * otherwise, so users have at least Conf_PongTimeout seconds time to
+ * register with the IRC server -- see Check_Connections(). */
+ c = Client_GetFromConn(Idx);
+ if (c && (Client_Type(c) == CLIENT_USER
+ || Client_Type(c) == CLIENT_SERVER
+ || Client_Type(c) == CLIENT_SERVICE))
+ My_Connections[Idx].lastdata = time(NULL);
+
+ /* Look at the data in the (read-) buffer of this connection */
+ Handle_Buffer(Idx);
+} /* Read_Request */
+
+
+static bool
+Handle_Buffer( CONN_ID Idx )
+{
+ /* Handle Data in Connections Read-Buffer.
+ * Return true if a reuqest was handled, false otherwise (also returned on errors). */
+#ifndef STRICT_RFC
+ char *ptr1, *ptr2;
+#endif
+ char *ptr;
+ int len, delta;
+ bool result;
+#ifdef ZLIB
+ bool old_z;
+#endif
+
+ result = false;
+ for (;;) {
+ /* Check penalty */
+ if( My_Connections[Idx].delaytime > time( NULL )) return result;
+#ifdef ZLIB
+ /* unpack compressed data */
+ if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP ))
+ if( ! Unzip_Buffer( Idx )) return false;
+#endif
+
+ if (0 == array_bytes(&My_Connections[Idx].rbuf))
+ break;
+
+ if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) /* make sure buf is NULL terminated */
+ return false;
+
+ /* A Complete Request end with CR+LF, see RFC 2812. */
+ ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" );
+
+ if( ptr ) delta = 2; /* complete request */
+#ifndef STRICT_RFC
+ else {
+ /* Check for non-RFC-compliant request (only CR or LF)? Unfortunately,
+ * there are quite a few clients that do this (incl. "mIRC" :-( */
+ ptr1 = strchr( array_start(&My_Connections[Idx].rbuf), '\r' );
+ ptr2 = strchr( array_start(&My_Connections[Idx].rbuf), '\n' );
+ delta = 1;
+ if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
+ else if( ptr1 ) ptr = ptr1;
+ else if( ptr2 ) ptr = ptr2;
+ }
+#endif
+
+ if( ! ptr )
+ break;
+
+ /* End of request found */
+ *ptr = '\0';
+
+ len = ( ptr - (char*) array_start(&My_Connections[Idx].rbuf)) + delta;
+
+ if( len < 0 || len > ( COMMAND_LEN - 1 )) {
+ /* Request must not exceed 512 chars (incl. CR+LF!), see
+ * RFC 2812. Disconnect Client if this happens. */
+ Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!",
+ Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1 );
+ Conn_Close( Idx, NULL, "Request too long", true );
+ return false;
+ }
+
+ if (len <= 2) { /* request was empty (only '\r\n') */
+ array_moveleft(&My_Connections[Idx].rbuf, 1, delta); /* delta is either 1 or 2 */
+ break;
+ }
+#ifdef ZLIB
+ /* remember if stream is already compressed */
+ old_z = My_Connections[Idx].options & CONN_ZIP;
+#endif
+
+ My_Connections[Idx].msg_in++;
+ if (!Parse_Request(Idx, (char*)array_start(&My_Connections[Idx].rbuf) ))
+ return false;
+
+ result = true;
+
+ array_moveleft(&My_Connections[Idx].rbuf, 1, len);
+#ifdef DEBUG
+ Log(LOG_DEBUG,
+ "Connection %d: %d bytes left in read buffer.",
+ Idx, array_bytes(&My_Connections[Idx].rbuf));
+#endif
+#ifdef ZLIB
+ if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) &&
+ ( array_bytes(&My_Connections[Idx].rbuf) > 0 ))
+ {
+ /* The last Command activated Socket-Compression.
+ * Data that was read after that needs to be copied to Unzip-buf
+ * for decompression */
+ if( array_bytes(&My_Connections[Idx].rbuf)> ZREADBUFFER_LEN ) {
+ Log( LOG_ALERT, "Connection %d: No space left in unzip buf (need %u bytes)!",
+ Idx, array_bytes(&My_Connections[Idx].rbuf ));
+ return false;
+ }
+ if (!array_copy( &My_Connections[Idx].zip.rbuf, &My_Connections[Idx].rbuf ))
+ return false;
+
+ array_trunc(&My_Connections[Idx].rbuf);
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Moved already received data (%u bytes) to uncompression buffer.",
+ array_bytes(&My_Connections[Idx].zip.rbuf));
+#endif /* DEBUG */
+ }
+#endif /* ZLIB */
+ }
+
+ return result;
+} /* Handle_Buffer */
+
+
+static void
+Check_Connections( void )
+{
+ /* check if connections are alive. if not, play PING-PONG first.
+ * if this doesn't help either, disconnect client. */
+ CLIENT *c;
+ CONN_ID i;
+
+ for( i = 0; i < Pool_Size; i++ ) {
+ if( My_Connections[i].sock == NONE ) continue;
+
+ c = Client_GetFromConn( i );
+ if( c && (( Client_Type( c ) == CLIENT_USER ) || ( Client_Type( c ) == CLIENT_SERVER ) || ( Client_Type( c ) == CLIENT_SERVICE )))
+ {
+ /* connected User, Server or Service */
+ if( My_Connections[i].lastping > My_Connections[i].lastdata ) {
+ /* we already sent a ping */
+ if( My_Connections[i].lastping < time( NULL ) - Conf_PongTimeout ) {
+ /* Timeout */
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Connection %d: Ping timeout: %d seconds.", i, Conf_PongTimeout );
+#endif
+ Conn_Close( i, NULL, "Ping timeout", true );
+ }
+ }
+ else if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout ) {
+ /* we need to sent a PING */
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Connection %d: sending PING ...", i );
+#endif
+ My_Connections[i].lastping = time( NULL );
+ Conn_WriteStr( i, "PING :%s", Client_ID( Client_ThisServer( )));
+ }
+ }
+ else
+ {
+ /* The connection is not fully established yet, so
+ * we don't do the PING-PONG game here but instead
+ * disconnect the client after "a short time" if it's
+ * still not registered. */
+
+ if (My_Connections[i].lastdata <
+ time(NULL) - Conf_PongTimeout) {
+#ifdef DEBUG
+ Log(LOG_DEBUG,
+ "Unregistered connection %d timed out ...",
+ i);
+#endif
+ Conn_Close(i, NULL, "Timeout", false);
+ }
+ }
+ }
+} /* Check_Connections */
+
+
+static void
+Check_Servers( void )
+{
+ /* Check if we can establish further server links */
+
+ RES_STAT *s;
+ CONN_ID idx;
+ int i, n;
+
+ /* Search all connections, are there results from the resolver? */
+ for( idx = 0; idx < Pool_Size; idx++ ) {
+ if( My_Connections[idx].sock != SERVER_WAIT ) continue;
+
+ /* IP resolved? */
+ if( My_Connections[idx].res_stat == NULL ) New_Server( Conf_GetServer( idx ), idx );
+ }
+
+ /* Check all configured servers */
+ for( i = 0; i < MAX_SERVERS; i++ ) {
+ /* Valid outgoing server which isn't already connected or disabled? */
+ if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 ) ||
+ ( Conf_Server[i].conn_id > NONE ) || ( Conf_Server[i].flags & CONF_SFLAG_DISABLED ))
+ continue;
+
+ /* Is there already a connection in this group? */
+ if( Conf_Server[i].group > NONE ) {
+ for( n = 0; n < MAX_SERVERS; n++ ) {
+ if( n == i ) continue;
+ if(( Conf_Server[n].conn_id > NONE ) &&
+ ( Conf_Server[n].group == Conf_Server[i].group ))
+ break;
+ }
+ if (n < MAX_SERVERS) continue;
+ }
+
+ /* Check last connect attempt? */
+ if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue;
+
+ /* Okay, try to connect now */
+ Conf_Server[i].lasttry = time( NULL );
+
+ /* Search free connection structure */
+ for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
+ if( idx >= Pool_Size )
+ {
+ Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", Pool_Size );
+ return;
+ }
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Preparing connection %d for \"%s\" ...", idx, Conf_Server[i].host );
+#endif
+
+ /* Verbindungs-Struktur initialisieren */
+ Init_Conn_Struct( idx );
+ My_Connections[idx].sock = SERVER_WAIT;
+ Conf_Server[i].conn_id = idx;
+
+ /* Resolve Hostname. If this fails, try to use it as an IP address */
+ strlcpy( Conf_Server[i].ip, Conf_Server[i].host, sizeof( Conf_Server[i].ip ));
+ strlcpy( My_Connections[idx].host, Conf_Server[i].host, sizeof( My_Connections[idx].host ));
+ s = Resolve_Name( Conf_Server[i].host );
+
+ /* resolver process running? */
+ if( s ) My_Connections[idx].res_stat = s;
+ }
+} /* Check_Servers */
+
+
+static void
+New_Server( int Server, CONN_ID Idx )
+{
+ /* Establish new server link */
+
+ struct sockaddr_in new_addr;
+ struct in_addr inaddr;
+ int res, new_sock;
+ CLIENT *c;
+
+ assert( Server > NONE );
+ assert( Idx > NONE );
+
+ /* Did we get a valid IP address? */
+ if( ! Conf_Server[Server].ip[0] ) {
+ /* No. Free connection structure and abort: */
+ Log( LOG_ERR, "Can't connect to \"%s\": ip address unknown!", Conf_Server[Server].host );
+ Init_Conn_Struct( Idx );
+ Conf_Server[Server].conn_id = NONE;