/* authinfo.c: 
 *
 ****************************************************************
 * Copyright (C) 2005 Canonical Ltd
 * Original Authors: James Blackwell
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/char/str.h"
#include "hackerlab/machine/types.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "libawk/relational.h"
#include "libfsutils/file-contents.h"
#include "po/gettext.h"
#include "libarch/authinfo.h"
#include "libarch/debug.h"

enum auth_fields
{
  AUTH_MACHINE = 0,
  AUTH_LOGIN   = 1,
  AUTH_PASS    = 2,
};

static t_uchar * arch_auth_authinfo_filename (void);
static t_uchar * arch_auth_read_auth_file (void);
static inline const t_uchar * find_non_whitespace (t_uchar const * const string);
static inline const t_uchar * find_whitespace (t_uchar const * const string);
static rel_table arch_auth_tokenize (t_uchar const * const password_list);

t_uchar *
arch_auth_username (t_uchar * machine)
{
  int row;
  t_uchar * username = NULL;
  t_uchar * passwords;
  rel_table password_table;

  passwords = arch_auth_read_auth_file();
  password_table = arch_auth_parse_auth_file(passwords);

  rel_for_each (password_table, row)
    {
      if (0 == str_cmp(machine, password_table[row][AUTH_MACHINE]))
        {
          username = str_save (0, password_table[row][AUTH_LOGIN]);
          break;
        }
    }
  rel_free_table (password_table);
  lim_free(0, passwords);

  return username;
}

t_uchar *
arch_auth_password (t_uchar * login, t_uchar * machine)
{
  int row;
  t_uchar * password = NULL;
  t_uchar * passwords;
  rel_table password_table;

  passwords = arch_auth_read_auth_file();
  password_table = arch_auth_parse_auth_file(passwords);

  rel_for_each (password_table, row)
    {
      if (0 == str_cmp(machine, password_table[row][AUTH_MACHINE]) &&
          0 == str_cmp(login, password_table[row][AUTH_LOGIN]))
        {
          password = str_save (0, password_table[row][AUTH_PASS]);
          break;
        }
    }
  rel_free_table (password_table);
  lim_free(0, passwords);

  return password;
}

rel_table
arch_auth_tokenize (t_uchar const * const password_list)
{
  rel_table tokens = NULL;

  const t_uchar * start;
  const t_uchar * end;

  start = password_list;
  end  = password_list + str_length(password_list);

  while (start < end)
    {
      t_uchar * token;
      const t_uchar * word_end;

      /* Get rid of starting whitespace. Then make sure
       * there is still data left
       */
      start = find_non_whitespace (start);
      if (start == end)
        break;

      /* We are at the start of a token. If we have a ", that means
       * tokenstart is one higher, and we snarf until the ending "
       * Otherwise, we snarf until the next whitespace.
       */

      if (*start == '"')
        {
          start++;
          word_end = str_chr_index (start, '"');
        }
      else
        word_end = find_whitespace (start);

      /* Uh oh. We hit the end of the string before the end of the token,
       * so the end of the token is the end
       */
      if (! word_end)
        word_end = end;
      
      /* Now we can save the token */
      token = str_save_n (0, start, (word_end) - start);
      rel_add_records(&tokens, rel_make_record(token, 0), 0);

      /* One last check. If we're at the end of the string, then 
       * adjust start thusly, so that we won't loop anymore. 
       * If not, then move start to the next unread data and
       * loop back for more.
       */

      if (word_end == end)
        start = end;
      else
        start = word_end + 1;

      lim_free(0, token);
    }
  return tokens;
}

rel_table
arch_auth_parse_auth_file (t_uchar const * const password_list)
{
  int rows;
  rel_table fields = NULL;
  rel_table parsed_passwords = NULL;


  fields = arch_auth_tokenize(password_list);
  
  rows = 0;
  while (rows + 3 < rel_n_records(fields))
    {
      if ((0 != str_casecmp("machine" , fields[rows+0][0])) ||
          (0 != str_casecmp("login"   , fields[rows+2][0])))
        {
          debug(dbg_authinfo, 6, _("Corrupt line in .authinfo\n"));
          /* be as fuzzy as possible in case of failure */
          rows += 1;
          continue;
        }
      if (rows + 5 < rel_n_records(fields) &&
          0 == str_casecmp("password", fields[rows+4][0])) 
        {
          rel_add_records(&parsed_passwords,
                          rel_make_record(fields[rows+1][0],
                                          fields[rows+3][0],
                                          fields[rows+5][0],
                                          0),0);
          rows += 6;
        } 
      else
        {
          // password hasn't been provided.
          // machine foo.com login john
          rel_add_records(&parsed_passwords,
                          rel_make_record(fields[rows+1][0],
                                          fields[rows+3][0],
                                          "", 0),0);
          rows += 4;
        }
    }
  
  if (rows != rel_n_records(fields))
    debug(dbg_authinfo, 1, _("Garbage at end of .authinfo file\n"));

  rel_free_table (fields);
  return parsed_passwords;
}

t_uchar *
arch_auth_read_auth_file ()
{
  t_uchar * passfile_contents = NULL;
  t_uchar * auth_file = arch_auth_authinfo_filename();

  if (0 == safe_access (auth_file, F_OK))
      passfile_contents = file_contents (auth_file);

  lim_free (0, auth_file);
  return passfile_contents;
}

t_uchar *
arch_auth_authinfo_filename ()
{
  t_uchar *filename = NULL;
  t_uchar *home = NULL;

  home = getenv("HOME");

  filename = file_name_in_vicinity(0, home, ".authinfo");

  return filename;
}

inline const t_uchar *
find_whitespace (t_uchar const * const string)
{
  const t_uchar * tok = string;

  while ( *tok != 0 && ! (*tok == '\n' || *tok == '\t' || *tok == ' '))
    tok++;
  return tok;
}

inline const t_uchar *
find_non_whitespace (t_uchar const * const string)
{
  const t_uchar * tok = string;

  while ( *tok != 0 && (*tok == '\n' || *tok == '\t' || *tok == ' '))
    tok++;
  return tok;
}

/* tag: James Blackwell Sun Apr 10 23:40:34 EDT 2005 (authinfo.c) */



syntax highlighted by Code2HTML, v. 0.9.1