/*
 * options.c - handles option processing for PPP.
 *
 * Copyright (c) 1989 Carnegie Mellon University.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by Carnegie Mellon University.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *	11/19/96  FAR -- Corrected bug which caused GK's graphical editor 
 *						to edit the wrong values
 *
 *	Modifications added 6/16/96 to support GateKeeper.app
 *	Copyright (c) 1996
 *		
 *			by	Felipe A. Rodriguez
 *
 *	GateKeeper code is supplied "as is" the author makes no warranty as  
 *	to its suitability for any purpose.  This code is free and may be 
 *	distributed in accordance with the terms of the:
 *		
 *			GNU GENERAL PUBLIC LICENSE
 *			Version 2, June 1991
 *			copyright (C) 1989, 1991 Free Software Foundation, Inc.
 * 			675 Mass Ave, Cambridge, MA 02139, USA
 *
 */


//#ifndef lint
//char rcsid[] = "$Id: options.c,v 1.22 1995/06/30 01:52:24 paulus Exp $";
//#endif

#import <objc/Object.h>
#import <appkit/Application.h>
#import <appkit/nextstd.h>
#import "options.h"
#import "Coordinator.h"
#import "OptionsEditor.h"


#define	S_IRUSR	_S_IRUSR		/* read permission, */
#define NGROUPS_MAX	16     		/* Number of simultaneous    */  
	                       		/* supplementary group IDs   */
			      				/* per process.              */
#define S_IRGRP	0000040		/* read permission, group */
#define S_IROTH	0000004		/* read permission, other */
#define MAXWORDLEN	1024	/* max length of word in file (incl null) */
#define MAXARGS		1		/* max # args to a command */
#define MAXNAMELEN	256		/* max length of hostname or name for auth */
#define MAXSECRETLEN	256	/* max length of password or secret */

#import <stdio.h>
#import <errno.h>
#import <ctype.h>
#import <unistd.h>
#import <limits.h>
#import <stdlib.h>
#import <termios.h>
#import <syslog.h>
#import <string.h>
#import <netdb.h>
#import <pwd.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <sys/param.h>		/* for MAXPATHLEN and BSD4_4, if defined */
#import <netinet/in.h>


typedef unsigned u_int32_t;

#ifndef GIDSET_TYPE
#define GIDSET_TYPE	int
#endif

/*
 * Option variables and default values.
 */
int	debug = 0;		/* Debug flag */
int	default_device = 1;	/* Using /dev/tty or equivalent */
char devnam[MAXPATHLEN] = "/dev/tty";	/* Device name */
int	crtscts = 0;		/* Use hardware flow control */
int	modem = 1;		/* Use modem control lines */
int	inspeed = 0;		/* Input/Output speed requested */
int	lockflag = 0;		/* Create lock file to lock the serial dev */
int	nodetach = 0;		/* Don't detach from controlling tty */
int	defaultroute = 0;	/* assign default route through interface */
int	proxyarp = 0;		/* Set up proxy ARP entry for peer */
    FILE *f;


//*****************************************************************************
//
// 		Prototypes for implemented functions 
//
//			GateKeeper supports graphical editing of these parameters
//
//*****************************************************************************

static int setspeed (char *arg);
static int setlock (void);
static int clearlock (void);
static int setdefaultroute (void);
static int cleardefaultroute (void);
static int setdebug (void);
static int cleardebug (void);
static int setd (void);
static int cleard (void);
static int setcrtscts (void);
static int clearcrtscts (void);
static int setdevname(char *cp);


#define __P(x)	()					// redefine in order to get a clean 
									// compile under NeXT

//*****************************************************************************
//
// 		Prototypes for placeholders 
//
//			GateKeeper does not support graphical editing of these parameters
//
//*****************************************************************************

static int setkdebug __P((char **));
static int setpassive __P((void));
static int setsilent __P((void));
static int noopt __P((void));
static int setnovj __P((void));
static int setnovjccomp __P((void));
static int setvjslots __P((char **));
static int reqpap __P((void));
static int nopap __P((void));
static int setupapfile __P((char **));
static int nochap __P((void));
static int reqchap __P((void));
static int noaccomp __P((void));
static int noasyncmap __P((void));
static int noip __P((void));
static int nomagicnumber __P((void));
static int setasyncmap __P((char **));
static int setescape __P((char **));
static int setmru __P((char **));
static int setmtu __P((char **));
static int setcbcp __P((char **));
static int nomru __P((void));
static int nopcomp __P((void));
static int setconnector __P((char **));
static int setdisconnector __P((char **));
static int setwelcomer __P((char **));
static int setmaxconnect __P((char **));
static int setdomain __P((char **));
static int setnetmask __P((char **));
static int setnocrtscts __P((void));
static int setxonxoff __P((void));
static int setnodetach __P((void));
static int setmodem __P((void));
static int setlocal __P((void));
static int setname __P((char **));
static int setuser __P((char **));
static int setremote __P((char **));
static int setauth __P((void));
static int setnoauth __P((void));
static int readfile __P((char **));
static int callfile __P((char **));
static int setnodefaultroute __P((void));
static int setproxyarp __P((void));
static int setnoproxyarp __P((void));
static int setpersist __P((void));
static int setnopersist __P((void));
static int setdologin __P((void));
static int setusehostname __P((void));
static int setnoipdflt __P((void));
static int setlcptimeout __P((char **));
static int setlcpterm __P((char **));
static int setlcpconf __P((char **));
static int setlcpfails __P((char **));
static int setipcptimeout __P((char **));
static int setipcpterm __P((char **));
static int setipcpconf __P((char **));
static int setipcpfails __P((char **));
static int setpaptimeout __P((char **));
static int setpapreqs __P((char **));
static int setpapreqtime __P((char **));
static int setchaptimeout __P((char **));
static int setchapchal __P((char **));
static int setchapintv __P((char **));
static int setipcpaccl __P((void));
static int setipcpaccr __P((void));
static int setlcpechointv __P((char **));
static int setlcpechofails __P((char **));
static int noccp __P((void));
static int setbsdcomp __P((char **));
static int setnobsdcomp __P((void));
static int setdeflate __P((char **));
static int setnodeflate __P((void));
static int setdemand __P((void));
static int setpred1comp __P((void));
static int setnopred1comp __P((void));
static int setipparam __P((char **));
static int setpapcrypt __P((void));
static int setidle __P((char **));
static int setholdoff __P((char **));
static int setdnsaddr __P((char **));
static int resetipxproto __P((void));
static int setipxproto __P((void));
static int setipxanet __P((void));
static int setipxalcl __P((void));
static int setipxarmt __P((void));
static int setipxnetwork __P((char **));
static int setipxnode __P((char **));
static int setipxrouter __P((char **));
static int setipxname __P((char **));
static int setipxcptimeout __P((char **));
static int setipxcpterm __P((char **));
static int setipxcpconf __P((char **));
static int setipxcpfails __P((char **));



static int hitArray[7];		// used in determining whether an option flag
							// method was called while scanning options file 


/*
 * Valid arguments.
 */
static struct cmd {
    char *cmd_name;
    int num_args;
    int (*cmd_func)();
} cmds[] = {
			// implemented functions
    {"-d", 0, setd},	/* Increase debugging level */
    {"@-d", 0, cleard},	/* Increase debugging level */
    {"debug", 0, setdebug},	/* Increase debugging level */
    {"@debug", 0, cleardebug},	/* Increase debugging level */
    {"crtscts", 0, setcrtscts},		/* set h/w flow control */
    {"-crtscts", 0, clearcrtscts}, 	/* clear h/w flow control */
    {"@crtscts", 0, clearcrtscts}, 	/* clear h/w flow control */
    {"lock", 0, setlock},	/* Lock serial device (with lock file) */
    {"@lock", 0, clearlock},	/* Lock serial device (with lock file) */
    {"defaultroute", 0, setdefaultroute}, /* Add default route */
    {"@defaultroute", 0, cleardefaultroute}, /* Add default route */
    {"mtu", 1, setmtu},						/* Set mtu */

			// placeholder functions
    {"-all", 0, noopt},		/* Don't request/allow any options (useless) */
    {"noaccomp", 0, noaccomp},	/* Disable Address/Control compression */
    {"-ac", 0, noaccomp},	/* Disable Address/Control compress */
    {"default-asyncmap", 0, noasyncmap}, /* Disable asyncmap negoatiation */
    {"-am", 0, noasyncmap},	/* Disable asyncmap negotiation */
    {"-as", 1, setasyncmap},	/* set the desired async map */
    {"nodetach", 0, setnodetach}, /* Don't detach from controlling tty */
    {"-detach", 0, setnodetach}, /* don't fork */
    {"noip", 0, noip},		/* Disable IP and IPCP */
    {"-ip", 0, noip},		/* Disable IP and IPCP */
    {"nomagic", 0, nomagicnumber}, /* Disable magic number negotiation */
    {"-mn", 0, nomagicnumber},	/* Disable magic number negotiation */
    {"default-mru", 0, nomru},	/* Disable MRU negotiation */
    {"-mru", 0, nomru},		/* Disable mru negotiation */
    {"-p", 0, setpassive},	/* Set passive mode */
    {"nopcomp", 0, nopcomp},	/* Disable protocol field compression */
    {"-pc", 0, nopcomp},	/* Disable protocol field compress */
    {"+ua", 1, setupapfile},	/* Get PAP user and password from file */
    {"require-pap", 0, reqpap},	/* Require PAP authentication from peer */
    {"+pap", 0, reqpap},	/* Require PAP auth from peer */
    {"refuse-pap", 0, nopap},	/* Don't agree to auth to peer with PAP */
    {"-pap", 0, nopap},		/* Don't allow UPAP authentication with peer */
    {"require-chap", 0, reqchap}, /* Require CHAP authentication from peer */
    {"+chap", 0, reqchap},	/* Require CHAP authentication from peer */
    {"refuse-chap", 0, nochap},	/* Don't agree to auth to peer with CHAP */
    {"-chap", 0, nochap},	/* Don't allow CHAP authentication with peer */
    {"novj", 0, setnovj},	/* Disable VJ compression */
    {"-vj", 0, setnovj},	/* disable VJ compression */
    {"novjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
    {"-vjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
    {"vj-max-slots", 1, setvjslots}, /* Set maximum VJ header slots */
    {"asyncmap", 1, setasyncmap}, /* set the desired async map */
    {"escape", 1, setescape},	/* set chars to escape on transmission */
    {"connect", 1, setconnector}, /* A program to set up a connection */
    {"disconnect", 1, setdisconnector},	/* program to disconnect serial dev. */
    {"welcome", 1, setwelcomer},/* Script to welcome client */
    {"maxconnect", 1, setmaxconnect},  /* specify a maximum connect time */
    {"nocrtscts", 0, setnocrtscts}, /* clear h/w flow control */
    {"-crtscts", 0, setnocrtscts}, /* clear h/w flow control */
    {"xonxoff", 0, setxonxoff},	/* set s/w flow control */
    {"kdebug", 1, setkdebug},	/* Enable kernel-level debugging */
    {"domain", 1, setdomain},	/* Add given domain name to hostname*/
    {"mru", 1, setmru},		/* Set MRU value for negotiation */
    {"mtu", 1, setmtu},		/* Set our MTU */
    {"callback", 1, setcbcp},	/* Ask for callback */
    {"netmask", 1, setnetmask},	/* set netmask */
    {"passive", 0, setpassive},	/* Set passive mode */
    {"silent", 0, setsilent},	/* Set silent mode */
    {"modem", 0, setmodem},	/* Use modem control lines */
    {"local", 0, setlocal},	/* Don't use modem control lines */
    {"name", 1, setname},	/* Set local name for authentication */
    {"user", 1, setuser},	/* Set name for auth with peer */
    {"usehostname", 0, setusehostname},	/* Must use hostname for auth. */
    {"remotename", 1, setremote}, /* Set remote name for authentication */
    {"auth", 0, setauth},	/* Require authentication from peer */
    {"noauth", 0, setnoauth},	/* Don't require peer to authenticate */
    {"file", 1, readfile},	/* Take options from a file */
    {"call", 1, callfile},	/* Take options from a privileged file */
    {"nodefaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
    {"-defaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
    {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
    {"noproxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
    {"-proxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
    {"persist", 0, setpersist},	/* Keep on reopening connection after close */
    {"nopersist", 0, setnopersist},  /* Turn off persist option */
    {"demand", 0, setdemand},	/* Dial on demand */
    {"login", 0, setdologin},	/* Use system password database for UPAP */
    {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
    {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
    {"lcp-echo-interval", 1, setlcpechointv}, /* time for lcp echo events */
    {"lcp-restart", 1, setlcptimeout}, /* Set timeout for LCP */
    {"lcp-max-terminate", 1, setlcpterm}, /* Set max #xmits for term-reqs */
    {"lcp-max-configure", 1, setlcpconf}, /* Set max #xmits for conf-reqs */
    {"lcp-max-failure", 1, setlcpfails}, /* Set max #conf-naks for LCP */
    {"ipcp-restart", 1, setipcptimeout}, /* Set timeout for IPCP */
    {"ipcp-max-terminate", 1, setipcpterm}, /* Set max #xmits for term-reqs */
    {"ipcp-max-configure", 1, setipcpconf}, /* Set max #xmits for conf-reqs */
    {"ipcp-max-failure", 1, setipcpfails}, /* Set max #conf-naks for IPCP */
    {"pap-restart", 1, setpaptimeout},	/* Set retransmit timeout for PAP */
    {"pap-max-authreq", 1, setpapreqs}, /* Set max #xmits for auth-reqs */
    {"pap-timeout", 1, setpapreqtime},	/* Set time limit for peer PAP auth. */
    {"chap-restart", 1, setchaptimeout}, /* Set timeout for CHAP */
    {"chap-max-challenge", 1, setchapchal}, /* Set max #xmits for challenge */
    {"chap-interval", 1, setchapintv}, /* Set interval for rechallenge */
    {"ipcp-accept-local", 0, setipcpaccl}, /* Accept peer's address for us */
    {"ipcp-accept-remote", 0, setipcpaccr}, /* Accept peer's address for it */
    {"noccp", 0, noccp},		/* Disable CCP negotiation */
    {"-ccp", 0, noccp},			/* Disable CCP negotiation */
    {"bsdcomp", 1, setbsdcomp},		/* request BSD-Compress */
    {"nobsdcomp", 0, setnobsdcomp},	/* don't allow BSD-Compress */
    {"-bsdcomp", 0, setnobsdcomp},	/* don't allow BSD-Compress */
    {"deflate", 1, setdeflate},		/* request Deflate compression */
    {"nodeflate", 0, setnodeflate},	/* don't allow Deflate compression */
    {"-deflate", 0, setnodeflate},	/* don't allow Deflate compression */
    {"predictor1", 0, setpred1comp},	/* request Predictor-1 */
    {"nopredictor1", 0, setnopred1comp},/* don't allow Predictor-1 */
    {"-predictor1", 0, setnopred1comp},	/* don't allow Predictor-1 */
    {"ipparam", 1, setipparam},		/* set ip script parameter */
    {"papcrypt", 0, setpapcrypt},	/* PAP passwords encrypted */
    {"idle", 1, setidle},		/* idle time limit (seconds) */
    {"holdoff", 1, setholdoff},		/* set holdoff time (seconds) */
    {"ms-dns", 1, setdnsaddr},		/* DNS address for the peer's use */
    {"noipx",  0, resetipxproto},	/* Disable IPXCP (and IPX) */
    {"-ipx",   0, resetipxproto},	/* Disable IPXCP (and IPX) */
    {"ipx-network",          1, setipxnetwork}, /* IPX network number */
    {"ipxcp-accept-network", 0, setipxanet},    /* Accept peer netowrk */
    {"ipx-node",             1, setipxnode},    /* IPX node number */
    {"ipxcp-accept-local",   0, setipxalcl},    /* Accept our address */
    {"ipxcp-accept-remote",  0, setipxarmt},    /* Accept peer's address */
    {"ipx-routing",          1, setipxrouter},  /* IPX routing proto number */
    {"ipx-router-name",      1, setipxname},    /* IPX router name */
    {"ipxcp-restart",        1, setipxcptimeout}, /* Set timeout for IPXCP */
    {"ipxcp-max-terminate",  1, setipxcpterm},  /* max #xmits for term-reqs */
    {"ipxcp-max-configure",  1, setipxcpconf},  /* max #xmits for conf-reqs */
    {"ipxcp-max-failure",    1, setipxcpfails}, /* max #conf-naks for IPXCP */
    {"ipx",		     0, setipxproto},	/* Enable IPXCP (and IPX) */
    {"+ipx",		     0, setipxproto},	/* Enable IPXCP (and IPX) */
   {NULL, 0, NULL}
};


/*
 * Read a word from a file.
 * Words are delimited by white-space or by quotes (" or ').
 * Quotes, white-space and \ may be escaped with \.
 * \<newline> is ignored.
 */

int
getword(f, word, newlinep, filename)
    FILE *f;
    char *word;
    int *newlinep;
    const char *filename;
{
    int c, len, escape;
    int quoted, comment;
    int value, digit, got, n;

#define isoctal(c) ((c) >= '0' && (c) < '8')

    *newlinep = 0;
    len = 0;
    escape = 0;
    comment = 0;

    /*
     * First skip white-space and comments.
     */
    for (;;) {
	c = getc(f);
	if (c == EOF)
	    break;

	/*
	 * A newline means the end of a comment; backslash-newline
	 * is ignored.  Note that we cannot have escape && comment.
	 */
	if (c == '\n') {
	    if (!escape) {
		*newlinep = 1;
		comment = 0;
	    } else
		escape = 0;
	    continue;
	}


	/*
	 * Possible one of our flags or keywords.
	 */
	if (comment && (c == '@'))
	    break;

	/*
	 * Ignore characters other than newline in a comment.
	 */
	if (comment)
	    continue;


	/*
	 * If this character is escaped, we have a word start.
	 */
	if (escape)
	    break;

	/*
	 * If this is the escape character, look at the next character.
	 */
	if (c == '\\') {
	    escape = 1;
	    continue;
	}

	/*
	 * If this is the start of a comment, ignore the rest of the line.
	 */
	if (c == '#') {
	    comment = 1;
	    continue;
	}

	/*
	 * A non-whitespace character is the start of a word.
	 */
	if (!isspace(c))
	    break;
    }

    /*
     * Save the delimiter for quoted strings.
     */
    if (!escape && (c == '"' || c == '\'')) {
        quoted = c;
	c = getc(f);
    } else
        quoted = 0;

    /*
     * Process characters until the end of the word.
     */
    while (c != EOF) {
	if (escape) {
	    /*
	     * This character is escaped: backslash-newline is ignored,
	     * various other characters indicate particular values
	     * as for C backslash-escapes.
	     */
	    escape = 0;
	    if (c == '\n') {
	        c = getc(f);
		continue;
	    }

	    got = 0;
	    switch (c) {
	    case 'a':
		value = '\a';
		break;
	    case 'b':
		value = '\b';
		break;
	    case 'f':
		value = '\f';
		break;
	    case 'n':
		value = '\n';
		break;
	    case 'r':
		value = '\r';
		break;
	    case 's':
		value = ' ';
		break;
	    case 't':
		value = '\t';
		break;

	    default:
		if (isoctal(c)) {
		    /*
		     * \ddd octal sequence
		     */
		    value = 0;
		    for (n = 0; n < 3 && isoctal(c); ++n) {
			value = (value << 3) + (c & 07);
			c = getc(f);
		    }
		    got = 1;
		    break;
		}

		if (c == 'x') {
		    /*
		     * \x<hex_string> sequence
		     */
		    value = 0;
		    c = getc(f);
		    for (n = 0; n < 2 && isxdigit(c); ++n) {
			digit = toupper(c) - '0';
			if (digit > 10)
			    digit += '0' + 10 - 'A';
			value = (value << 4) + digit;
			c = getc (f);
		    }
		    got = 1;
		    break;
		}

		/*
		 * Otherwise the character stands for itself.
		 */
		value = c;
		break;
	    }

	    /*
	     * Store the resulting character for the escape sequence.
	     */
	    if (len < MAXWORDLEN-1)
		word[len] = value;
	    ++len;

	    if (!got)
		c = getc(f);
	    continue;

	}

	/*
	 * Not escaped: see if we've reached the end of the word.
	 */
	if (quoted) {
	    if (c == quoted)
		break;
	} else {
	    if (isspace(c) || c == '#') {
		ungetc (c, f);
		break;
	    }
	}

	/*
	 * Backslash starts an escape sequence.
	 */
	if (c == '\\') {
	    escape = 1;
	    c = getc(f);
	    continue;
	}

	/*
	 * An ordinary character: store it in the word and get another.
	 */
	if (len < MAXWORDLEN-1)
	    word[len] = c;
	++len;

	c = getc(f);
    }

    /*
     * End of the word: check for errors.
     */
    if (c == EOF) {
	if (ferror(f)) {
	    if (errno == 0)
		errno = EIO;
	    perror(filename);
	    return 0;
	}
	/*
	 * If len is zero, then we didn't find a word before the
	 * end of the file.
	 */
	if (len == 0)
	    return 0;
    }

    /*
     * Warn if the word was too long, and append a terminating null.
     */
    if (len >= MAXWORDLEN) {
	perror("warning: word in options file is too long");
	len = MAXWORDLEN - 1;
    }
    word[len] = 0;

    return 1;

#undef isoctal

}

/*
 * options_from_file - Read a string of options from a file,
 * and interpret them.
 */
int
options_from_file(filename, must_exist, check_prot)
    const char *filename;
    int must_exist;
    int check_prot;
{
    int i, newline, ret;
    struct cmd *cmdp;
    char *argv[MAXARGS];
    char args[MAXARGS][MAXWORDLEN];
    char cmd[MAXWORDLEN];

	for (i = 0; i < 6; i++) 		// zero out hit array each invocation
 		{hitArray[i] = 0;}		// used in detecting whether func was called

	if ((f = fopen(filename, "r+")) == NULL) {
	if (!must_exist && errno == ENOENT)
	    return 1;
	perror(filename);
	return 0;
    }
    if (check_prot && !readable(fileno(f))) {
	fprintf(stderr, "%s: access denied\n", filename);
	fclose(f);
	return 0;
    }

    while (getword(f, cmd, &newline, filename)) {
	/*
	 * First see if it's a command.
	 */
	for (cmdp = cmds; cmdp->cmd_name; cmdp++)
	    if (!strcmp(cmd, cmdp->cmd_name))
		break;

	if (cmdp->cmd_name != NULL) {
	    for (i = 0; i < cmdp->num_args; ++i) {
		if (!getword(f, args[i], &newline, filename)) {
		    fprintf(stderr,
			    "In file %s: too few parameters for command %s\n",
			    filename, cmd);
		    fclose(f);
			f = NULL;
		    return 0;
		}
		argv[i] = args[i];
	    }
	    if (!(*cmdp->cmd_func)(argv)) {
		fclose(f);
		f = NULL;
		return 0;
	    }

	} else {
	    /*
	     * Maybe a tty name, speed or IP address?
	     */
	    ret = setdevname(cmd);
		ret = setspeed(cmd);
		}
	}
	if(!hitArray[4] && [oDelegate shouldSave])
		{
		fputs("\n/dev/cua  \n", f);
		[oDelegate setDevName:"/dev/cua"];
		}
	if(!hitArray[5] && [oDelegate shouldSave])		// speed not found in file
		{
		fputs("\n57600  \n", f);					// save in options file
		[oDelegate setSpeed:"57600"];				// show setting in GUI
		}
	if(!hitArray[0] && [oDelegate defaultRoute] && [oDelegate shouldSave])
		fputs("\ndefaultroute  \n", f);
	if(!hitArray[1] && [oDelegate lockFlag] && [oDelegate shouldSave])
		fputs("\nlock  \n", f);
	if(!hitArray[2] && [oDelegate crtscts] && [oDelegate shouldSave])
		fputs("\ncrtscts  \n", f);
	if(!hitArray[3] && [oDelegate debug] && [oDelegate shouldSave])
		fputs("\ndebug  \n", f);

	if(f)
		fclose(f);
		f = NULL;

    return 1;
}

/*
 * readable - check if a file is readable by the real user.
 */
int
readable(fd)
    int fd;
{
    uid_t uid;
    int ngroups, i;
    struct stat sbuf;
    GIDSET_TYPE groups[NGROUPS_MAX];

    uid = getuid();
    if (uid == 0)
	return 1;
    if (fstat(fd, &sbuf) != 0)
	return 0;
    if (sbuf.st_uid == uid)
	return sbuf.st_mode & S_IRUSR;
    if (sbuf.st_gid == getgid())
	return sbuf.st_mode & S_IRGRP;
    ngroups = getgroups(NGROUPS_MAX, groups);
    for (i = 0; i < ngroups; ++i)
	if (sbuf.st_gid == groups[i])
	    return sbuf.st_mode & S_IRGRP;
    return sbuf.st_mode & S_IROTH;
}
//*****************************************************************************
//
// 		set and remove "lock" flag 
//
//*****************************************************************************

static int
setlock()
{
	if([oDelegate shouldSave] && ![oDelegate lockFlag])
		{
     	fseek(f,-4, SEEK_CUR);
		fputs("#@lock\n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setLockFlag];
 	hitArray[1] = 1;

    return 1;
}
static int
clearlock()
{
	if([oDelegate shouldSave] && [oDelegate lockFlag])
		{
     	fseek(f,-6, SEEK_CUR);
		fputs("lock  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
 	hitArray[1] = 1;

    return 1;
}
//*****************************************************************************
//
// 		set and remove "defaultRoute" flag 
//
//*****************************************************************************

static int
setdefaultroute()
{
	if([oDelegate shouldSave] && ![oDelegate defaultRoute])
		{
     	fseek(f,-12, SEEK_CUR);
		fputs("#@defaultroute\n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setDefaultRoute];
 	hitArray[0] = 1;

    return 1;
}
static int
cleardefaultroute()
{
	if([oDelegate shouldSave] && [oDelegate defaultRoute])
		{
     	fseek(f,-14, SEEK_CUR);
		fputs("defaultroute  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
 	hitArray[0] = 1;

    return 1;
}
//*****************************************************************************
//
// 		set and remove "debug" flag 
//
//*****************************************************************************

static int
setdebug()
{
	if([oDelegate shouldSave] && ![oDelegate debug])
		{
     	fseek(f,-5, SEEK_CUR);
		fputs("#@debug\n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setDebug];
 	hitArray[3] = 1;

    return 1;
}
static int
cleardebug()
{
	if([oDelegate shouldSave] && [oDelegate debug])
		{
     	fseek(f,-7, SEEK_CUR);
		fputs("debug  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
 	hitArray[3] = 1;

    return 1;
}
static int
setd()
{
	if([oDelegate shouldSave] && ![oDelegate debug])
		{
     	fseek(f,-2, SEEK_CUR);
		fputs("#@-d\n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setDebug];
 	hitArray[3] = 1;

    return 1;
}
static int
cleard()
{
	if([oDelegate shouldSave] && [oDelegate debug])
		{
     	fseek(f,-4, SEEK_CUR);
		fputs("-d  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
 	hitArray[3] = 1;

    return 1;
}
//*****************************************************************************
//
// 		set and remove "crtscts" flag 
//
//*****************************************************************************

static int
setcrtscts()
{
	if([oDelegate shouldSave] && ![oDelegate crtscts])
		{
     	fseek(f,-7, SEEK_CUR);
		fputs("-crtscts\n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setCrtscts];
 	hitArray[2] = 1;

    return 1;
}
static int
clearcrtscts()
{
	if([oDelegate shouldSave] && [oDelegate crtscts])
		{
     	fseek(f,-8, SEEK_CUR);
		fputs("crtscts \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
 	hitArray[2] = 1;

    return 1;
}

/*
 * setspeed - Set the speed.
 */
static int
setspeed(arg)
    char *arg;
{
    char *ptr;
    int spd;
	int lenOfarg = strlen(arg);

    spd = strtol(arg, &ptr, 0);
    if (ptr == arg || *ptr != 0 || spd == 0)
	return 0;

	if([oDelegate shouldSave] && (strcmp([oDelegate speed], arg) != 0))
		{									// user changed speed in GUI
     	fseek(f,-lenOfarg, SEEK_CUR);
		fputs([oDelegate speed], f);
		if((lenOfarg = strlen([oDelegate speed])) == 5)
			fputs("\n", f);
		if(lenOfarg == 4)
			fputs(" \n", f);
		if(lenOfarg == 3)
			fputs("  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
 		hitArray[5] = 1;
		}
	else									// else we just scanned an opt file
		{
		if([oDelegate setSpeed:arg])		// show results in GUI
 			hitArray[5] = 1;
		}

    inspeed = spd;
    return 1;
}


/*
 * setdevname - Set the device name.
 */
int
setdevname(cp)
    char *cp;
{
    struct stat statbuf;
    char *ttyname();
    char dev[MAXPATHLEN];
	int lenOfcp = strlen(cp);

    if (strncmp("/dev/", cp, 5) != 0) {
	strcpy(dev, "/dev/");
	strncat(dev, cp, MAXPATHLEN - 5);
	dev[MAXPATHLEN-1] = 0;
	cp = dev;
    }

    /*
     * Check if there is a device by this name.
     */
    if (stat(cp, &statbuf) < 0) {
	if (errno == ENOENT)
	    return 0;
	syslog(LOG_ERR, cp);
	return -1;
    }
  
	if([oDelegate shouldSave] && (strcmp([oDelegate devName], cp) != 0))
		{
     	fseek(f,-lenOfcp, SEEK_CUR);
		fputs([oDelegate devName], f);
		if((lenOfcp = strlen([oDelegate devName]))== 10)
			fputs("\n", f);
		if(lenOfcp == 9)
			fputs(" \n", f);
		if(lenOfcp == 8)
			fputs("  \n", f);
	    fseek(f, ftell(f), SEEK_SET);
		}
	else
		[oDelegate setDevName:cp];
 	hitArray[4] = 1;

    (void) strncpy(devnam, cp, MAXPATHLEN);
    devnam[MAXPATHLEN-1] = 0;
    default_device = FALSE;
  
    return 1;
}

int setDelegate(id del)
{
	oDelegate = del;

    return 1;
}
//*****************************************************************************
//
// 		the following do nothing  
//
//*****************************************************************************

/*
 * setkdebug - Set kernel debugging level.
 */
static int
setkdebug(argv)
    char **argv;
{
    return 1;
}

/*
 * noopt - Disable all options.
 */
static int
noopt()
{
    return 1;
}

/*
 * noaccomp - Disable Address/Control field compression negotiation.
 */
static int
noaccomp()
{
    return 1;
}


/*
 * noasyncmap - Disable async map negotiation.
 */
static int
noasyncmap()
{
    return 1;
}


/*
 * noip - Disable IP and IPCP.
 */
static int
noip()
{
    return 1;
}


/*
 * nomagicnumber - Disable magic number negotiation.
 */
static int
nomagicnumber()
{
    return 1;
}


/*
 * nomru - Disable mru negotiation.
 */
static int
nomru()
{
    return 1;
}


/*
 * setmru - Set MRU for negotiation.
 */
static int
setmru(argv)
    char **argv;
{
    return 1;
}


/*
 * setmru - Set the largest MTU we'll use.
 */
static int
setmtu(argv)
    char **argv;
{
    return 1;
}

static int
setcbcp(argv)
    char **argv;
{
    return 1;
}

/*
 * nopcomp - Disable Protocol field compression negotiation.
 */
static int
nopcomp()
{
    return 1;
}


/*
 * setpassive - Set passive mode (don't give up if we time out sending
 * LCP configure-requests).
 */
static int
setpassive()
{
    return 1;
}


/*
 * setsilent - Set silent mode (don't start sending LCP configure-requests
 * until we get one from the peer).
 */
static int
setsilent()
{
    return 1;
}


/*
 * nopap - Disable PAP authentication with peer.
 */
static int
nopap()
{
    return 1;
}


/*
 * reqpap - Require PAP authentication from peer.
 */
static int
reqpap()
{
    return 1;
}

/*
 * setupapfile - specifies UPAP info for authenticating with peer.
 */
static int
setupapfile(argv)
    char **argv;
{
    return 1;
}


/*
 * nochap - Disable CHAP authentication with peer.
 */
static int
nochap()
{
    return 1;
}


/*
 * reqchap - Require CHAP authentication from peer.
 */
static int
reqchap()
{
    return 1;
}


/*
 * setnovj - disable vj compression
 */
static int
setnovj()
{
    return 1;
}


/*
 * setnovjccomp - disable VJ connection-ID compression
 */
static int
setnovjccomp()
{
    return 1;
}


/*
 * setvjslots - set maximum number of connection slots for VJ compression
 */
static int
setvjslots(argv)
    char **argv;
{
    return 1;
}


/*
 * setconnector - Set a program to connect to a serial line
 */
static int
setconnector(argv)
    char **argv;
{
    return 1;
}

/*
 * setdisconnector - Set a program to disconnect from the serial line
 */
static int
setdisconnector(argv)
    char **argv;
{
    return 1;
}

/*
 * setwelcomer - Set a program to welcome a client after connection
 */
static int
setwelcomer(argv)
    char **argv;
{
    return 1;
}

/*
 * setmaxconnect - Set the maximum connect time
 */
static int
setmaxconnect(argv)
    char **argv;
{
    return 1;
}

/*
 * setdomain - Set domain name to append to hostname 
 */
static int
setdomain(argv)
    char **argv;
{
    return 1;
}


/*
 * setasyncmap - add bits to asyncmap (what we request peer to escape).
 */
static int
setasyncmap(argv)
    char **argv;
{
    return 1;
}


/*
 * setescape - add chars to the set we escape on transmission.
 */
static int
setescape(argv)
    char **argv;
{
    return 1;
}

/*
 * setnoipdflt - disable setipdefault()
 */
static int
setnoipdflt()
{
    return 1;
}


/*
 * setipcpaccl - accept peer's idea of our address
 */
static int
setipcpaccl()
{
    return 1;
}


/*
 * setipcpaccr - accept peer's idea of its address
 */
static int
setipcpaccr()
{
    return 1;
}


/*
 * setnetmask - set the netmask to be used on the interface.
 */
static int
setnetmask(argv)
    char **argv;
{
    return 1;
}

static int
setnocrtscts()
{
    return 1;
}

static int
setxonxoff()
{
    return 1;
}

static int
setnodetach()
{
    return 1;
}

static int
setdemand()
{
    return 1;
}

static int
setmodem()
{
    return 1;
}

static int
setlocal()
{
    return 1;
}

static int
setusehostname()
{
    return 1;
}

static int
setname(argv)
    char **argv;
{
        return 1;
}

static int
setuser(argv)
    char **argv;
{
        return 1;
}

static int
setremote(argv)
    char **argv;
{
        return 1;
}

static int
setauth()
{
        return 1;
}

static int
setnoauth()
{
        return 1;
}

static int
setnodefaultroute()
{
        return 1;
}

static int
setproxyarp()
{
        return 1;
}

static int
setnoproxyarp()
{
        return 1;
}

static int
setpersist()
{
        return 1;
}

static int
setnopersist()
{
        return 1;
}

static int
setdologin()
{
        return 1;
}

/*
 * Functions to set the echo interval for modem-less monitors
 */

static int
setlcpechointv(argv)
    char **argv;
{
        return 1;
}

static int
setlcpechofails(argv)
    char **argv;
{
        return 1;
}

/*
 * Functions to set timeouts, max transmits, etc.
 */
static int
setlcptimeout(argv)
    char **argv;
{
        return 1;
}

static int
setlcpterm(argv)
    char **argv;
{
        return 1;
}

static int
setlcpconf(argv)
    char **argv;
{
        return 1;
}

static int
setlcpfails(argv)
    char **argv;
{
        return 1;
}

static int
setipcptimeout(argv)
    char **argv;
{
        return 1;
}

static int
setipcpterm(argv)
    char **argv;
{
        return 1;
}

static int
setipcpconf(argv)
    char **argv;
{
        return 1;
}

static int
setipcpfails(argv)
    char **argv;
{
        return 1;
}

static int
setpaptimeout(argv)
    char **argv;
{
        return 1;
}

static int
setpapreqtime(argv)
    char **argv;
{
        return 1;
}

static int
setpapreqs(argv)
    char **argv;
{
        return 1;
}

static int
setchaptimeout(argv)
    char **argv;
{
        return 1;
}

static int
setchapchal(argv)
    char **argv;
{
        return 1;
}

static int
setchapintv(argv)
    char **argv;
{
        return 1;
}

static int
noccp()
{
        return 1;
}

static int
setbsdcomp(argv)
    char **argv;
{
        return 1;
}

static int
setnobsdcomp()
{
        return 1;
}

static int
setdeflate(argv)
    char **argv;
{
        return 1;
}

static int
setnodeflate()
{
        return 1;
}

static int
setpred1comp()
{
        return 1;
}

static int
setnopred1comp()
{
        return 1;
}

static int
setipparam(argv)
    char **argv;
{
        return 1;
}

static int
setpapcrypt()
{
        return 1;
}

static int
setidle(argv)
    char **argv;
{
        return 1;
}

static int
setholdoff(argv)
    char **argv;
{
        return 1;
}

/*
 * setdnsaddr - set the dns address(es)
 */
static int
setdnsaddr(argv)
    char **argv;
{
        return 1;
}

static int
setipxrouter (argv)
    char **argv;
{
        return 1;
}

static int
setipxname (argv)
    char **argv;
{
        return 1;
}

static int
setipxcptimeout (argv)
    char **argv;
{
        return 1;
}

static int
setipxcpterm (argv)
    char **argv;
{
        return 1;
}

static int
setipxcpconf (argv)
    char **argv;
{
        return 1;
}

static int
setipxcpfails (argv)
    char **argv;
{
        return 1;
}

static int
setipxnetwork(argv)
    char **argv;
{
        return 1;
}

static int
setipxanet()
{
        return 1;
}

static int
setipxalcl()
{
        return 1;
}

static int
setipxarmt()
{
        return 1;
}

static int
setipxnode(argv)
    char **argv;
{
        return 1;
}

static int
setipxproto()
{
    return 1;
}

static int
resetipxproto()
{
    return 1;
}

/*
 * readfile - take commands from a file.
 */
static int
readfile(argv)
    char **argv;
{
    return 1;
}
/*
 * callfile - take commands from /etc/ppp/peers/<name>.
 * Name may not contain /../, start with / or ../, or end in /..
 */
static int
callfile(argv)
    char **argv;
{
    return 1;
}
