/*
 * Read a line from a descriptor with fgets 
 *
 * $Id$
 *
 */

#include "echoping.h"

int
readline (fs, ptr, maxlen, ln)
     FILE *fs;
     char *ptr;
     int maxlen;
     unsigned short ln;
{
  int n = 1;
  char *rc;
  int r;

  /* Reading with fgets or fread instead of read
     one-character-at-a-time is more than ten times faster, on a local
     server. */
  if (ln)
    {
      rc = fgets (ptr, maxlen + 1, fs);
      if (rc == NULL)
	{
	  if (timeout_flag)
	    return n;
	  return (-1);
	}
      n = strlen (rc);
      return n;
    }
  else
    {
      while (n < maxlen)
	{
	  r = fread (ptr, 1, maxlen, fs);
	  if (timeout_flag)
	    return r;
	  if (r == 0)
	    {
	      if (n == 1)
		return (0);	/* EOF, no data read */
	      else
		break;		/* EOF, some data was read */
	    }
	  n = n + r;
	}
    }
  return (n);
}

#ifdef OPENSSL

char SSL_buffer[MAXTOREAD];
int buf_ptr;
int buf_end;

int
SSL_readline (sslh, ptr, maxlen, ln)
     SSL *sslh;
     char *ptr;
     int maxlen;
     unsigned short ln;
{
  int rc = 0;
  int n = 0;
  int i, oi;
  if (ln)
    {
      /* Empty buffer */
      if (buf_end == 0)
	{
	  rc = SSL_read (sslh, SSL_buffer, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = rc;
	  buf_ptr = 0;
	}
      /* No more data in the buffer */
      else if (buf_ptr == buf_end)
	{
	  buf_ptr = 0;
	  rc = SSL_read (sslh, SSL_buffer, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = rc;
	}
      else if (SSL_buffer[buf_end] != '\n')
	{
	  /* We have a probleme here is the first SSL_read sent back
	     a text not finished by a \n. See www.SSL.de for an
	     example. We get more data. See bug #230384 */
	  rc = SSL_read (sslh, SSL_buffer + buf_end, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = buf_end + rc;
	}
      for (oi = buf_ptr, i = buf_ptr;
	   i <= buf_end && SSL_buffer[i] != '\n'; i++)
	{
	  *ptr++ = SSL_buffer[i];
	  buf_ptr++;
	}
      if (SSL_buffer[i] == '\n')
	buf_ptr++;
      *ptr = '\0';
      /* if (ln)
         printf ("SSL_readline returns %d (%s)\n", i - oi, SSL_buffer); */
      return (i - oi);
    }
  else
    {
      /* OpenSSL reads at most 4096 characters */
      rc = 1;			/* Just to avoid exiting too soon */
      while (n < maxlen && rc != 0)
	{
	  if ((buf_end == 0) || (buf_ptr > buf_end))
	    {
	      rc = SSL_read (sslh, ptr, maxlen);
	      buf_end = 0;
	      buf_ptr = 0;
	    }
	  else
	    {
	      for (i = buf_ptr; i < maxlen && i <= buf_end; i++)
		{
		  *ptr++ = SSL_buffer[i];
		  rc++;
		}
	      buf_ptr = i;
	    }
	  n = n + rc;
	}
      return n;
    }
}
#endif

#ifdef GNUTLS

char TLS_buffer[MAXTOREAD];
int buf_ptr;
int buf_end;

int
TLS_readline (session, ptr, maxlen, ln)
     gnutls_session session;
     char *ptr;
     int maxlen;
     unsigned short ln;
{
  int rc = 0;
  int n = 0;
  int i, oi;
  if (ln)
    {
      /* Empty buffer */
      if (buf_end == 0)
	{
	  rc = gnutls_record_recv (session, TLS_buffer, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = rc;
	  buf_ptr = 0;
	}
      /* No more data in the buffer */
      else if (buf_ptr == buf_end)
	{
	  buf_ptr = 0;
	  rc = gnutls_record_recv (session, TLS_buffer, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = rc;
	}
      else if (TLS_buffer[buf_end] != '\n')
	{
	  rc = gnutls_record_recv (session, TLS_buffer + buf_end, maxlen);
	  if (rc == -1)
	    return rc;
	  buf_end = buf_end + rc;
	}
      for (oi = buf_ptr, i = buf_ptr;
	   i <= buf_end && TLS_buffer[i] != '\n'; i++)
	{
	  *ptr++ = TLS_buffer[i];
	  buf_ptr++;
	}
      if (TLS_buffer[i] == '\n')
	buf_ptr++;
      *ptr = '\0';
      /* printf ("DEBUG: TLS_readline returns %d (%s)\n", i - oi, TLS_buffer); */
      return (i - oi);
    }
  else
    {
      rc = 1;			/* Just to avoid exiting too soon */
      while (n < maxlen && rc > 0)
	{
	  if ((buf_end == 0) || (buf_ptr > buf_end))
	    {
	      rc = gnutls_record_recv (session, ptr, maxlen);
	      buf_end = 0;
	      buf_ptr = 0;
	    }
	  else
	    {
	      for (i = buf_ptr; i < maxlen && i <= buf_end; i++)
		{
		  *ptr++ = TLS_buffer[i];
		  rc++;
		  /* printf ("DEBUG: Now %d chars read\n", rc); */
		}
	      buf_ptr = i;
	    }
	  if (rc > 0)
	    n = n + rc;
	  /* printf ("DEBUG: Now %d chars to send\n", n); */
	}
      return n;
    }
}
#endif
