/*

Copyright (C) 2015 Olaf Till <i7tiol@t-online.de>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

*/

#include "parallel-gnutls.h"

#define BUFLEN 2048

#ifdef HAVE_LIBGNUTLS

// Username was given as argument to 'connect'. appasswd is optional.
octave_parallel_gnutls_srp_client_credentials::
octave_parallel_gnutls_srp_client_credentials (const char *user,
                                               char *apasswd)
: password (apasswd), pw_allocated (false)
{
  if (! password)
    password = getpass ("password: ");

  if (! strlen (password))
    {
      error ("password is empty");

      return;
    }

  if (! gnutls_srp_allocate_client_credentials
      ((gnutls_srp_client_credentials_t *) &cred))
    if (gnutls_srp_set_client_credentials
        ((gnutls_srp_client_credentials_t) cred, user, password))
      {
        free_credentials ();

        cred = NULL;
      }
}

// no username was given as argument to 'connect'
octave_parallel_gnutls_srp_client_credentials::
octave_parallel_gnutls_srp_client_credentials (std::string passwd_file)
  : password (NULL), pw_allocated (false)
{
  struct __bufguard
  {
    char *__b;
    __bufguard (char *__ib) : __b (__ib) { }
    ~__bufguard (void) { memset ((void *) __b, '\0', BUFLEN); delete[] __b; }
    char *__get (void) { return __b; }
  } __bg (new char[BUFLEN]);

  char *line = __bg.__get ();

  line[0] = '\0';

  octave_parallel_stream cpi
    (new octave_parallel_file_streambuf (passwd_file.c_str (), O_RDONLY, 0));

  if (! cpi.good ())
    {
      error ("could not open password file");

      return;
    }

  cpi.get_istream ().getline (line, BUFLEN);

  int len = strlen (line);

  if (cpi.get_istream ().fail () && len == BUFLEN - 1)
    {
      error ("line in password file too long");

      return;
    }

  char *p;

  if (! (p = strchr (line, ' ')))
    {
      error ("invalid line in password file");

      return;
    }

  *p = '\0';

  if (! strlen (line))
    {
      error ("no username in password file");

      return;
    }

  if (++p - line >= len)
    {
      error ("no password in password file");

      return;
    }

  if (! gnutls_srp_allocate_client_credentials
      ((gnutls_srp_client_credentials_t *) &cred))
    if (gnutls_srp_set_client_credentials
        ((gnutls_srp_client_credentials_t) cred, line, p))
      {
        free_credentials ();

        cred = NULL;
      }
    else
      {
        password = new char[strlen (p) + 1];

        pw_allocated = true;

        strcpy (password, p);
      }
}

#endif // HAVE_LIBGNUTLS
