/* $Id: sfskeyctl.C,v 1.15 2001/08/24 23:03:01 ericp Exp $ */

/*
 *
 * Copyright (C) 1999 David Mazieres (dm@uun.org)
 *
 * 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 2, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */


#include "sfskey.h"

void
sfskey_add (int argc, char **argv)
{
  time_t expire = 0;

  int ch;
  while ((ch = getopt (argc, argv, "t:")) != -1)
    switch (ch) {
    case 't':
      {
	rxx hmrx ("^((\\d+):)?(\\d+)?$");
	int hrs = 0, min = 0;
	if (!hmrx.search (optarg)
	    || (hmrx[3] && !convertint (hmrx[3], &min))
	    || (hmrx[2] && (!convertint (hmrx[2], &hrs) || min > 60))
	    || min < 0 || hrs < 0)
	  usage ();
	expire = 3600 * hrs + 60 * min;
	if (expire)
	  expire += time (NULL);
	break;
      }
    default:
      usage ();
      break;
    }

  agent_setsock ();
  str keyname;
  if (optind == argc)
    keyname = defkey ();
  else if (optind + 1 == argc)
    keyname = argv[optind];
  else
    usage ();

  cagent ();
  sfskey k;
  ptr<sfscon> sc;
  if (str err = keyfetch (&k, keyname, &sc))
    fatal << err << "\n";

  sfs_addkey_arg arg;
  arg.p = k.key->p;
  arg.q = k.key->q;
  arg.expire = expire;
  arg.comment = k.keyname;
  bool res;
  if (clnt_stat err = cagent ()->scall (AGENTCTL_ADDKEY, &arg, &res))
    fatal << "agent: " << err << "\n";
  else if (!res)
    warn << "agent refused private key\n";
  if (sc) {
    sfsagent_symlink_arg arg;
    arg.name = sc->servinfo.host.hostname;
    arg.contents = sc->path;
    cagent ()->scall (AGENTCTL_SYMLINK, &arg, NULL);
  }
  exit (0);
}

void
sfskey_sesskill (int argc, char **argv)
{
  if (getopt (argc, argv, "") != -1 || optind + 1 != argc)
    usage ();
  sfs_hostname arg = argv[optind];
  bool res;
  if (clnt_stat err = cagent ()->scall (AGENTCTL_KILLSESS, &arg, &res))
    fatal << "agent: " << err << "\n";
  if (res)
    exit (0);
  else
    fatal << "no rexsessions connected to " << argv[optind] << "\n";
}

void
sfskey_sesslist (int argc, char **argv)
{
  nularg (argc, argv);
  rex_sessvec sv;
  if (clnt_stat err = cagent ()->scall (AGENTCTL_LISTSESS, NULL, &sv))
    fatal << "agent: " << err << "\n";

  
  strbuf list;
  list <<
    "Connection to:                   Created from:        Agent forwarded?\n";

  for (size_t i = 0; i < sv.size (); i++) {
    str agentstatus = sv[i].agentforwarded ? "yes\n" : "no\n";

    list << sv[i].to << "    " << sv[i].created_from << "      "
	 << agentstatus;
  }

  make_sync (1);
  list.tosuio ()->output (1);
  exit (0);
}

void
sfskey_list (int argc, char **argv)
{
  bool opt_l = false, opt_q = false;
  int ch;
  while ((ch = getopt (argc, argv, "lq")) != -1)
    switch (ch) {
    case 'l':
      opt_l = true;
      break;
    case 'q':
      opt_q = true;
      break;
    default:
      usage ();
      break;
    }
  if (optind < argc)
    usage ();

  sfs_keylist kl;
  if (clnt_stat err = cagent ()->scall (AGENTCTL_DUMPKEYS, NULL, &kl))
    fatal << "agent: " << err << "\n";

  sfs_time now = time (NULL);
  strbuf list;

  if (!opt_q)
    list.fmt ("%-40s  %9s%s\n", "NAME", "EXPIRE",
	      opt_l ? "  KEY" : "");
  for (sfs_keylistelm *e = kl; e; e = e->next) {
    list.fmt ("%-40s", e->comment.cstr ());
    if (!e->expire)
      list.fmt ("  %9s", "never");
    else {
      sfs_time life = e->expire < 0 ? 0 : e->expire - now;
      list.fmt ("  % 3" U64F "d:%02" U64F "d'%02" U64F "d",
		life / 3600, life / 60 % 60, life % 60);
    }
    if (opt_l)
      list << "  0x" << e->key.getstr (16);
    list << "\n";
  }

  make_sync (1);
  list.tosuio ()->output (1);
  exit (0);
}

void
sfskey_clear (int argc, char **argv)
{
  nularg (argc, argv);
  if (clnt_stat err = cagent ()->scall (AGENTCTL_REMALLKEYS, NULL, NULL))
    fatal << "agent: " << err << "\n";
  exit (0);
}

void
sfskey_delete (int argc, char **argv)
{
  if (getopt (argc, argv, "") != -1 || optind + 1 != argc)
    usage ();
  sfs_remkey_arg arg (SFS_REM_COMMENT);
  *arg.comment = argv[optind];
  bool res;
  if (clnt_stat err = cagent ()->scall (AGENTCTL_REMKEY, &arg, &res))
    fatal << "agent: " << err << "\n";
  else if (!res)
    fatal << "agent: could not delete key\n";
  exit (0);
}

void
sfskey_reset (int argc, char **argv)
{
  nularg (argc, argv);
  if (clnt_stat err = cagent ()->scall (AGENTCTL_RESET, NULL, NULL))
    fatal << "agent: " << err << "\n";
  exit (0);
}
