/* 
 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
 * Copyright (c) 1990,1993 Regents of The University of Michigan.
 * All Rights Reserved.  See COPYRIGHT.
 *
 * modified from main.c. this handles afp options.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/param.h>
#include <syslog.h>

#include <atalk/paths.h>
#include "globals.h"
#include "status.h"
#include "auth.h"

#include <atalk/compat.h>

#ifndef MIN
#define MIN(a, b)  ((a) < (b) ? (a) : (b))
#endif

#define OPTIONS "dn:f:s:uc:g:ACKGP:pDS:TL:F:t"
#define LENGTH 512

/* return an option. this uses an internal array, so it's necessary
 * to duplicate it if you want to hold it for long. this is probably
 * non-optimal. */
static char *getoption(char *buf, const char *option)
{
  static char string[LENGTH + 1];
  char *end;
  int len;

  if (option && (buf = strstr(buf, option)))
    buf = strpbrk(buf, " \t");

  while (buf && isspace(*buf))
    buf++;
      
  if (!buf)
    return NULL;

  /* search for any quoted stuff */
  if (*buf == '"' && (end = strchr(buf + 1, '"'))) { 
    buf++;
    len = MIN(end - buf, LENGTH);
  } else if (end = strpbrk(buf, " \t\n")) /* option or eoln */
    len = MIN(end - buf, LENGTH);
  else
    len = MIN(strlen(buf), LENGTH);
  
  strncpy(string, buf, len);
  string[len] = '\0';
  return string;
}

/* get rid of any allocated afp_option buffers. */
void afp_options_free(struct afp_options *opt, 
		      const struct afp_options *save)
{
  if (opt->defaultvol && (opt->defaultvol != save->defaultvol))
    free(opt->defaultvol);
  if (opt->systemvol && (opt->systemvol != save->systemvol))
    free(opt->systemvol);
  if (opt->loginmesg && (opt->loginmesg != save->loginmesg))
    free(opt->loginmesg);
  if (opt->guest && (opt->guest != save->guest)) 
    free(opt->guest);
  if (opt->server && (opt->server != save->server))
    free(opt->server);
  if (opt->address && (opt->address != save->address))
    free(opt->address);
  if (opt->uampath && (opt->uampath != save->uampath))
    free(opt->uampath);
  if (opt->nlspath && (opt->nlspath != save->nlspath))
    free(opt->nlspath);
}

/* initialize options */
void afp_options_init(struct afp_options *options)
{
  memset(options, 0, sizeof(struct afp_options));
  options->connections = 5;
  options->pidfile = _PATH_AFPDLOCK;
  options->defaultvol = _PATH_AFPDDEFVOL;
  options->systemvol = _PATH_AFPDSYSVOL;
  options->configfile = _PATH_AFPDCONF;
  options->nlspath = _PATH_AFPDNLSPATH;
  options->uampath = _PATH_AFPDUAMPATH;
  options->guest = "nobody";
  options->loginmesg = "";
  options->transports = AFPTRANS_ALL;
  options->authbits = AU_ALL;
  options->passwdfile = _NAME_AFPDPWFILE;
  options->tickleval = 30;
}

/* parse an afpd.conf line. i'm doing it this way because it's
 * easy. it is, however, massively hokey. sample afpd.conf:
 * server:AFPServer@zone -loginmesg "blah blah blah" -nodsi 
 * "private machine"@zone2 -noguest -port 11012
 * server2 -nocleartxt -nodsi
 *
 * NOTE: this ignores unknown options 
 */
int afp_options_parseline(char *buf, struct afp_options *options)
{
  char *c, *opt;
  
  /* handle server */
  if (*buf != '-' && (c = getoption(buf, NULL)) && (opt = strdup(c)))
    options->server = opt;

  /* parse toggles */
  if (strstr(buf, " -nodebug"))
    options->debug = 0;

  if (strstr(buf, " -nouservolfirst"))
    options->uservolfirst = 0;
  if (strstr(buf, " -uservolfirst"))
    options->uservolfirst = 1;
  if (strstr(buf, " -nouservol"))
    options->nouservol = 1;
  if (strstr(buf, " -uservol"))
    options->nouservol = 0;

  /* passwd bits */
  if (strstr(buf, " -nosavepassword"))
    options->passwdbits |= PASSWD_NOSAVE;
  if (strstr(buf, " -savepassword"))
    options->passwdbits &= ~PASSWD_NOSAVE;
  if (strstr(buf, " -nosetpassword"))
    options->passwdbits &= ~PASSWD_SET;
  if (strstr(buf, " -setpassword"))
    options->passwdbits |= PASSWD_SET;
  
  /* uams */
  if (strstr(buf, " -noauthall"))
    options->authbits = AU_NONE;
  if (strstr(buf, " -authall"))
    options->authbits = AU_ALL;
  if (strstr(buf, " -nocleartxt"))
    options->authbits &= ~AU_CLRTXT;
  if (strstr(buf, " -cleartxt"))
    options->authbits |= AU_CLRTXT;
  if (strstr(buf, " -noafskrb"))
    options->authbits &= ~AU_AFSKRB;
  if (strstr(buf, " -afskrb"))
    options->authbits |= AU_AFSKRB;
  if (strstr(buf, " -nokrbiv"))
    options->authbits &= ~AU_KRBIV;
  if (strstr(buf, " -krbiv"))
    options->authbits |= AU_KRBIV;
  if (strstr(buf, " -noguest"))
    options->authbits &= ~AU_GUEST;
  if (strstr(buf, " -guest"))
    options->authbits |= AU_GUEST;
  if (strstr(buf, " -randnum"))
    options->authbits |= AU_RANDNUM;
  if (strstr(buf, " -norandnum"))
    options->authbits &= ~AU_RANDNUM;
  if (strstr(buf, " -rand2num"))
    options->authbits |= AU_2WAYRANDNUM;
  if (strstr(buf, " -norand2num"))
    options->authbits &= ~AU_2WAYRANDNUM;

  /* transports */
  if (strstr(buf, " -transall"))
    options->transports = AFPTRANS_ALL;
  if (strstr(buf, " -notransall"))
    options->transports = AFPTRANS_NONE;
  if (strstr(buf, " -tcp"))
    options->transports |= AFPTRANS_TCP;
  if (strstr(buf, " -notcp"))
    options->transports &= ~AFPTRANS_TCP;
  if (strstr(buf, " -ddp"))
    options->transports |= AFPTRANS_DDP;
  if (strstr(buf, " -noddp"))
    options->transports &= ~AFPTRANS_DDP;

  /* figure out options w/ values. currently, this will ignore the setting
   * if memory is lacking. */
  if ((c = getoption(buf, "-defaultvol")) && (opt = strdup(c)))
    options->defaultvol = opt;
  if ((c = getoption(buf, "-systemvol")) && (opt = strdup(c)))
    options->systemvol = opt;
  if ((c = getoption(buf, "-loginmesg")) && (opt = strdup(c)))
    options->loginmesg = opt;
  if ((c = getoption(buf, "-guestname")) && (opt = strdup(c)))
    options->guest = opt;
  if ((c = getoption(buf, "-address")) && (opt = strdup(c)))
    options->address = opt;
  if (c = getoption(buf, "-port"))
    options->port = atoi(c);
  if (c = getoption(buf, "-tickleval"))
    options->tickleval = atoi(c);
  if ((c = getoption(buf, "-uampath")) && (opt = strdup(c)))
    options->uampath = opt;
  if ((c = getoption(buf, "-nlspath")) && (opt = strdup(c)))
    options->nlspath = opt;

  return 1;
}

int afp_options_parse(int ac, char **av, struct afp_options *options)
{
  extern char *optarg;
  extern int optind;
  
  char *p;
  int c, err = 0;

  if (gethostname(options->hostname, sizeof(options->hostname )) < 0 ) {
    perror( "gethostname" );
    return 0;
  }
    if (( p = strchr(options->hostname, '.' )) != 0 ) {
	*p = '\0';
    }

    if (( p = strrchr( av[ 0 ], '/' )) == NULL ) {
	p = av[ 0 ];
    } else {
	p++;
    }

    while (( c = getopt( ac, av, OPTIONS )) != EOF ) {
	switch ( c ) {
	case 'd' :
	    options->debug++;
	    break;
	case 'n' :
	    options->server = optarg;
	    break;
	case 'f' :
	    options->defaultvol = optarg;
	    break;
	case 's' :
	    options->systemvol = optarg;
	    break;
	case 'u' :
	    options->uservolfirst++;
	    break;
	case 'c' :
	    options->connections = atoi( optarg );
	    break;
	case 'g' :
	    options->guest = optarg;
	    break;

	case 'A' :
	    options->authbits &= ~AU_AFSKRB;
	    break;
	case 'C' :
	    options->authbits &= ~AU_CLRTXT;
	    break;
	case 'K' :
	    options->authbits &= ~AU_KRBIV;
	    break;
	case 'G' :
            options->authbits &= ~AU_GUEST;
	    break;

	case 'P' :
	    options->pidfile = optarg;
	    break;

	case 'p':
	    options->passwdbits |= PASSWD_NOSAVE;
	    break;
	case 't':
  	    options->passwdbits |= PASSWD_SET;
	    break;

	case 'D':
	    options->transports &= ~AFPTRANS_DDP;
	    break;
	case 'S':
	    options->port = atoi(optarg);
	    break;
	case 'T':
	    options->transports &= ~AFPTRANS_TCP;
	    break;
	case 'L':
	    options->loginmesg = optarg;
	    break;
	case 'F':
	    options->configfile = optarg;
	    break;
	default :
	    err++;
	}
    }
    if ( err || optind != ac ) {
	fprintf( stderr,
		"Usage:\t%s [ -dGKCApDTt ] [ -n nbpname ] [ -f defvols ] \
[ -P pidfile ] [ -s sysvols ] \n", p );
	fprintf( stderr,
		"\t[ -u ] [ -c maxconn ] [ -g guest ] \
[ -S port ] [ -L loginmesg ] [ -F configfile ]\n" );
	return 0;
    }

#ifdef ultrix
    openlog( p, LOG_PID );
#else ultrix
    openlog( p, LOG_NDELAY|LOG_PID, LOG_DAEMON );
#endif ultrix

    return 1;
}
