#include "../defs.h"
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>

#include "../defaults.h"
#include "asn1.h"
#include "snmp.h"
#include "snmp_impl.h"
#include "snmp_vars.h"
#include "system.h"

#include "context.h"
#include "acl.h"
#include "view.h"

static oid currentTime[] = {1, 3, 6, 1, 6, 3, 3, 1, 2, 1};
static oid restartTime[] = {1, 3, 6, 1, 6, 3, 3, 1, 2, 2};
static oid cacheTime[] = {1, 3, 6, 1, 6, 3, 3, 1, 2, 3};

#define OIDCMP(l1, l2, o1, o2) (((l1) == (l2)) \
				&& !bcmp((char *)(o1), (char *)(o2), \
					 (l1)*sizeof(oid)))

#define CONTEXTIDENTITY_MASK		0x0001
#define CONTEXTINDEX_MASK		0x0002
#define CONTEXTVIEWINDEX_MASK		0x0004
#define CONTEXTLOCALENTITY_MASK		0x0008
#define CONTEXTLOCALTIME_MASK		0x0010
#define CONTEXTDSTPARTYINDEX_MASK	0x0020
#define CONTEXTSRCPARTYINDEX_MASK	0x0040
#define CONTEXTPROXYCONTEXT_MASK	0x0080
#define CONTEXTSTORAGETYPE_MASK		0x0100
#define CONTEXTSTATUS_MASK		0x0200

#define CONTEXTCOMPLETE_MASK		0x03FF	/* all collumns */

struct contextEntry *
context_rowCreate(contextID, contextIDLen)
    oid *contextID;
    int contextIDLen;
{
    struct contextEntry *cp;

    if (contextIDLen > 32)
	return NULL;
    cp = context_createEntry(contextID, contextIDLen);
    cp->contextBitMask = 0;
    cp->contextStatus = cp->reserved->contextStatus = CONTEXTNONEXISTENT;

    cp->contextBitMask = cp->reserved->contextBitMask =
	CONTEXTINDEX_MASK | CONTEXTSTATUS_MASK;
    /* Watch out for this becoming permanent by accident:
     * If during FREE stage below we discover row didn't exist before,
     * free row.
     */
    return cp;
}

context_rowDelete(contextID, contextIDLen)
    oid *contextID;
    int contextIDLen;
{
    context_destroyEntry(contextID, contextIDLen);
}

/*
 * If statP is non-NULL, the referenced object is at that location.
 * If statP is NULL and cp is non-NULL, the instance exists, but not this
 * variable.
 * If statP is NULL and cp is NULL, then neither this instance nor the
 * variable exists.
 */
int
write_context(action, var_val, var_val_type, var_val_len, statP, name, length)
   int      action;
   u_char   *var_val;
   u_char   var_val_type;
   int      var_val_len;
   u_char   *statP;
   oid      *name;
   int      length;
{
    struct contextEntry *cp, *rp;
    int var, indexlen, len;
    oid *index;
    int32 val;
    oid buf[32];
    int bigsize = 1000, size;
    struct aclEntry *ap;
    struct viewEntry *vp;
    u_int32 get_myaddr(), myaddr;
    
#if 0
    if (length < 13)  /* maybe this should be 15 to guarantee oidlength >= 2 */
	return SNMP_ERR_NOCREATION;  
    var = name[11];
    indexlen = name[12];
    index = name + 13;
    if (length != 13 + indexlen)
	return SNMP_ERR_NOCREATION;

    cp = context_getEntry(index, indexlen);
    if (cp)
	rp = cp->reserved;
    if (action == RESERVE1 && !cp){
	if ((cp = context_rowCreate(index, indexlen)) == NULL)
	    return SNMP_ERR_RESOURCEUNAVAILABLE;
	rp = cp->reserved;
	/* create default vals here in reserve area
	 * contextIndex is automatically defval'd by context_createEntry().
         */
	rp->contextTDomain = DOMAINSNMPUDP;
	bzero((char *)rp->contextTAddress, 6);
	rp->contextTAddressLen = 6;
	rp->contextMaxMessageSize = 484;
	rp->contextLocal = 2; /* FALSE */
	rp->contextAuthProtocol = NOAUTH;
	rp->contextAuthClock = 0;
	rp->contextAuthPrivateLen = 0;
	rp->contextAuthPublicLen = 0;
	rp->contextAuthLifetime = 300;
	rp->contextPrivProtocol = NOPRIV;
	rp->contextPrivPrivateLen = 0;
	rp->contextPrivPublicLen = 0;
	rp->contextStorageType = 2; /* Volatile */
	rp->contextStatus = CONTEXTACTIVE;
	rp->contextBitMask = CONTEXTCOMPLETE_MASK ^ CONTEXTLOCAL_MASK; /* XXX */
    } else if (action == COMMIT){
	if (cp->contextStatus == CONTEXTNONEXISTENT){
	    /* commit the default vals */
	    /* This hacpens at most once per entry because the status is set to
	       valid after the first pass.  After that, this commit code
	       does not get executed.  It is also important to note that this
	       gets executed before any of the commits below (and never after
	       them), so they overlay their data on top of these defaults.
	       This commit code should allow for the object specific code
	       to have overlayed data after the code above has executed.
	      */
	    cp->contextTDomain = rp->contextTDomain;
	    bcopy(rp->contextTAddress, cp->contextTAddress, rp->contextTAddressLen);
	    cp->contextTAddressLen = rp->contextTAddressLen;
	    cp->contextMaxMessageSize = rp->contextMaxMessageSize;
	    cp->contextLocal = rp->contextLocal;
	    cp->contextAuthProtocol = rp->contextAuthProtocol;
	    cp->contextAuthClock = rp->contextAuthClock;
	    gettimeofday(&cp->tv, (struct timezone *)0);
	    cp->tv.tv_sec -= cp->contextAuthClock;
	    cp->contextAuthPrivateLen = rp->contextAuthPrivateLen;
	    cp->contextAuthPublicLen = rp->contextAuthPublicLen;
	    cp->contextAuthLifetime = rp->contextAuthLifetime;
	    cp->contextPrivProtocol = rp->contextPrivProtocol;
	    cp->contextPrivPrivateLen = rp->contextPrivPrivateLen;
	    cp->contextPrivPublicLen = rp->contextPrivPublicLen;
	    cp->contextStorageType = rp->contextStorageType;
	    cp->contextStatus = rp->contextStatus;
	    cp->contextBitMask = rp->contextBitMask;
	    
	}
    } else if (action == FREE){
	if (cp && cp->contextStatus == CONTEXTNONEXISTENT){
	    context_rowDelete(index, indexlen);
	    cp = rp = NULL;
	}
	if (cp)	/* satisfy postcondition for bitMask */
	    rp->contextBitMask = cp->contextBitMask;
    }

/* XXX !!! check return values from the asn_parse_* routines */
    switch(var){
      case CONTEXTTDOMAIN:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OBJECT_ID)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(buf)/sizeof(oid);
	    asn_parse_objid(var_val, &bigsize, &var_val_type, buf, &size);
	    if (OIDCMP(size, sizeof(snmpUdpDomain)/sizeof(oid), buf,
		       snmpUdpDomain)){
		rp->contextTDomain = DOMAINSNMPUDP;
		rp->contextBitMask |= CONTEXTTDOMAIN_MASK;
	    } else {
		return SNMP_ERR_WRONGVALUE;
	    }
	} else if (action == COMMIT){
	    cp->contextTDomain = rp->contextTDomain;
	}
	break;
      case CONTEXTTADDRESS:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OCTET_STR)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(rp->contextTAddress);
	    asn_parse_string(var_val, &bigsize, &var_val_type,
			     rp->contextTAddress, &size);
	    rp->contextTAddressLen = size;
	    /* if other TDomains were possible, it would be necessary to
	       check the size in the reserve2 phase to see if it was
	       consistent with the TDomain.
	       Also: what if TAddr is changed to a local context: consider
	       implications for MaxMessageSize.
	     */
	    if (size != 6)
		return SNMP_ERR_WRONGLENGTH;
	    rp->contextBitMask |= CONTEXTTADDRESS_MASK;
	} else if (action == COMMIT){
	    cp->contextTAddressLen = rp->contextTAddressLen;
	    bcopy(rp->contextTAddress, cp->contextTAddress, cp->contextTAddressLen);
	}
	break;
      case CONTEXTMAXMESSAGESIZE:
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    if (val < 484 || val > 65507)
		return SNMP_ERR_WRONGVALUE;
	    rp->contextMaxMessageSize = val;
	    rp->contextBitMask |= CONTEXTMAXMESSAGESIZE_MASK;
	} else if (action == RESERVE2){
	    myaddr = get_myaddr();
	    if ((rp->contextTDomain == DOMAINSNMPUDP)
		&& !bcmp((char *)&myaddr, rp->contextTAddress, 4)){
		/* context is local */
		/* 1500 should be constant in snmp_impl.h */
		if (rp->contextMaxMessageSize > 1500)
		    return SNMP_ERR_INCONSISTENTVALUE;
	    }
	} else if (action == COMMIT){
	    cp->contextMaxMessageSize = rp->contextMaxMessageSize;
	}
	break;
      case CONTEXTLOCAL:
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    if (val < 1 || val > 2)
		return SNMP_ERR_WRONGVALUE;
	    rp->contextLocal = val;
	    rp->contextBitMask |= CONTEXTLOCAL_MASK;
	} else if (action == RESERVE2){
	    myaddr = get_myaddr();
	    if (val == 1 && (rp->contextTDomain == DOMAINSNMPUDP)
		&& bcmp((char *)&myaddr, rp->contextTAddress, 4)){
		/* this is an attempt to set this context local with a
		   remote IP address */
		    return SNMP_ERR_INCONSISTENTVALUE;
	    }
	} else if (action == COMMIT){
	    cp->contextLocal = rp->contextLocal;
	}
	break;
      case CONTEXTAUTHPROTOCOL:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OBJECT_ID)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(buf)/sizeof(oid);
	    asn_parse_objid(var_val, &bigsize, &var_val_type, buf, &size);
	    if (OIDCMP(size, sizeof(noAuth)/sizeof(oid), buf, noAuth)){
		rp->contextAuthProtocol = NOAUTH;
	    } else if (OIDCMP(size, sizeof(snmpv2MD5AuthProt)/sizeof(oid), buf,
			      snmpv2MD5AuthProt)){
		rp->contextAuthProtocol = SNMPV2MD5AUTHPROT;
	    } else {
		/* no other currently defined */
		return SNMP_ERR_WRONGVALUE ;
	    }
	    rp->contextBitMask |= CONTEXTAUTHPROTOCOL_MASK;
	} else if (action == COMMIT){
	    cp->contextAuthProtocol = rp->contextAuthProtocol;
	}
	break;
      case CONTEXTAUTHCLOCK:
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    rp->contextAuthClock = val;
	    rp->contextBitMask |= CONTEXTAUTHCLOCK_MASK;
	} else if (action == COMMIT){
	    cp->contextAuthClock = rp->contextAuthClock;
	    gettimeofday(&cp->tv, (struct timezone *)0);
	    cp->tv.tv_sec -= cp->contextAuthClock;
	}
	break;
      case CONTEXTAUTHPRIVATE:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OCTET_STR)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(rp->contextAuthPrivate);
	    asn_parse_string(var_val, &bigsize, &var_val_type,
			     rp->contextAuthPrivate, &size);
	    rp->contextAuthPrivateLen = size;
	    if (size > 16)
		return SNMP_ERR_WRONGLENGTH;
	    rp->contextBitMask |= CONTEXTAUTHPRIVATE_MASK;
	} else if (action == COMMIT){
	    if (!(cp->contextBitMask & CONTEXTAUTHPRIVATE_MASK))
		cp->contextAuthPrivateLen = 0;
	    for(len = 0; (len < cp->contextAuthPrivateLen)
		&& (len < rp->contextAuthPrivateLen); len++){
		cp->contextAuthPrivate[len] ^=
		    rp->contextAuthPrivate[len];
	    }
	    while(len < rp->contextAuthPrivateLen)
		cp->contextAuthPrivate[len] =
		    rp->contextAuthPrivate[len];
	    cp->contextAuthPrivateLen = rp->contextAuthPrivateLen;
	}
	break;
      case CONTEXTAUTHPUBLIC:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OCTET_STR)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(rp->contextAuthPublic);
	    asn_parse_string(var_val, &bigsize, &var_val_type,
			     rp->contextAuthPublic, &size);
	    rp->contextAuthPublicLen = size;
	    if (size > 32)
		return SNMP_ERR_WRONGLENGTH;
	    rp->contextBitMask |= CONTEXTAUTHPUBLIC_MASK;
	} else if (action == COMMIT){
	    cp->contextAuthPublicLen = rp->contextAuthPublicLen;
	    bcopy((char *)rp->contextAuthPublic,
		  (char *)cp->contextAuthPublic, cp->contextAuthPublicLen);
	}
	break;
      case CONTEXTAUTHLIFETIME:
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    /* what range should I check for ???
	    if (val < 1 || val > 3600)
		return SNMP_ERR_WRONGVALUE;
	    */
	    rp->contextAuthLifetime = val;
	    rp->contextBitMask |= CONTEXTAUTHLIFETIME_MASK;
	} else if (action == COMMIT){
	    cp->contextAuthLifetime = rp->contextAuthLifetime;
	}
	break;
      case CONTEXTPRIVPROTOCOL:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OBJECT_ID)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(buf)/sizeof(oid);
	    asn_parse_objid(var_val, &bigsize, &var_val_type, buf, &size);
	    if (OIDCMP(size, sizeof(noPriv)/sizeof(oid), buf, noPriv)){
		rp->contextPrivProtocol = NOPRIV;
	    } else if (OIDCMP(size, sizeof(dESPrivProt)/sizeof(oid), buf,
			      dESPrivProt)){
		rp->contextPrivProtocol = DESPRIVPROT;
	    } else {
		/* no other currently defined */
		return SNMP_ERR_WRONGVALUE;
	    }
	    rp->contextBitMask |= CONTEXTPRIVPROTOCOL_MASK;
	} else if (action == COMMIT){
	    cp->contextPrivProtocol = rp->contextPrivProtocol;
	}
	break;
      case CONTEXTPRIVPRIVATE:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OCTET_STR)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(rp->contextPrivPrivate);
	    asn_parse_string(var_val, &bigsize, &var_val_type,
			     rp->contextPrivPrivate, &size);
	    rp->contextPrivPrivateLen = size;
	    if (size > 16)
		return SNMP_ERR_WRONGLENGTH;
	    rp->contextBitMask |= CONTEXTPRIVPRIVATE_MASK;
	} else if (action == COMMIT){
	    if (!(cp->contextBitMask & CONTEXTPRIVPRIVATE_MASK))
		cp->contextPrivPrivateLen = 0;
	    for(len = 0; (len < cp->contextPrivPrivateLen)
		&& (len < rp->contextPrivPrivateLen); len++){
		cp->contextPrivPrivate[len] ^=
		    rp->contextPrivPrivate[len];
	    }
	    while(len < rp->contextPrivPrivateLen)
		cp->contextPrivPrivate[len] =
		    rp->contextPrivPrivate[len];
	    cp->contextPrivPrivateLen = rp->contextPrivPrivateLen;
	}
	break;
      case CONTEXTPRIVPUBLIC:
	if (action == RESERVE1){
	    if (var_val_type != ASN_OCTET_STR)
		return SNMP_ERR_WRONGTYPE;
	    size = sizeof(rp->contextPrivPublic);
	    asn_parse_string(var_val, &bigsize, &var_val_type,
			     rp->contextPrivPublic, &size);
	    rp->contextPrivPublicLen = size;
	    if (size > 32)
		return SNMP_ERR_WRONGLENGTH;
	    rp->contextBitMask |= CONTEXTPRIVPUBLIC_MASK;
	} else if (action == COMMIT){
	    bcopy((char *)rp->contextPrivPublic, (char *)cp->contextPrivPublic,
		  rp->contextPrivPublicLen);
	    cp->contextPrivPublicLen = rp->contextPrivPublicLen;
	}
	break;
      case CONTEXTSTORAGETYPE:
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    if (val < 1 || val > 4)
		return SNMP_ERR_WRONGVALUE;
	    if (val != 2) /* above is as per MIB,
			     this is implementation specific */
		return SNMP_ERR_WRONGVALUE;
	    rp->contextStorageType = val;
	    rp->contextBitMask |= CONTEXTSTORAGETYPE_MASK;
	} else if (action == COMMIT){
	    cp->contextStorageType = rp->contextStorageType;
	}
	break;
      case CONTEXTSTATUS: /* read-write access */
	if (action == RESERVE1){
	    if (var_val_type != ASN_INTEGER)
		return SNMP_ERR_WRONGTYPE;
	    asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
	    if (val < 1 || val > 6 || val == 3)
		return SNMP_ERR_WRONGVALUE;
	    rp->contextStatus = val;
	    rp->contextBitMask |= CONTEXTSTATUS_MASK;
	} else if (action == RESERVE2){
	    if (((rp->contextStatus == CONTEXTCREATEANDGO)
		|| (rp->contextStatus == CONTEXTCREATEANDWAIT))
		&& (cp->contextStatus != CONTEXTNONEXISTENT))
		return SNMP_ERR_INCONSISTENTVALUE;
	    if (((rp->contextStatus == CONTEXTACTIVE)
		|| (rp->contextStatus == CONTEXTNOTINSERVICE))
		&& (cp->contextStatus == CONTEXTNONEXISTENT))
		return SNMP_ERR_INCONSISTENTVALUE;
	    if (((rp->contextStatus == CONTEXTACTIVE)
		 || (rp->contextStatus == CONTEXTNOTINSERVICE))
		&& (rp->contextBitMask != CONTEXTCOMPLETE_MASK))
		return SNMP_ERR_INCONSISTENTVALUE;
	    /* tried to set incomplete row valid */
	} else if (action == COMMIT){
	    if (rp->contextStatus == CONTEXTCREATEANDGO)
		rp->contextStatus = CONTEXTACTIVE;
	    if (rp->contextStatus == CONTEXTCREATEANDWAIT)
		rp->contextStatus = CONTEXTNOTINSERVICE;
	    cp->contextStatus = rp->contextStatus;
	} else if (action == ACTION && cp->contextStatus == CONTEXTDESTROY){
	    /* delete all related acl entries */
	    acl_scanInit();
	    ap = acl_scanNext();
	    do {
		for(; ap; ap = acl_scanNext()){
		    if ((ap->aclTargetLen == cp->contextIdentityLen
			 && !bcmp(ap->aclTarget, cp->contextIdentity,
				  ap->aclTargetLen * sizeof(oid)))
			|| (ap->aclSubjectLen == cp->contextIdentityLen
			    && !bcmp(ap->aclSubject, cp->contextIdentity,
				     ap->aclSubjectLen * sizeof(oid)))){
			acl_destroyEntry(ap->aclTarget, ap->aclTargetLen,
					 ap->aclSubject, ap->aclSubjectLen);
			acl_scanInit();
			ap = acl_scanNext();
			break;
			/* ap is still set, so we'll start over again */
		    }
		}
	    } while (ap);
		
	    /* delete all related view entries */
	    view_scanInit();
	    vp = view_scanNext();
	    do {
		for(; vp; vp = view_scanNext()){
		    if (vp->viewContextLen == cp->contextIdentityLen
			&& !bcmp(vp->viewContext, cp->contextIdentity,
				 vp->viewContextLen * sizeof(oid))){
			view_destroyEntry(vp->viewContext, vp->viewContextLen,
					  vp->viewSubtree, vp->viewSubtreeLen);
			view_scanInit();
			vp = view_scanNext();
			break;
			/* vp is still set, so we'll start over again */
		    }
		}
	    } while (vp);
		
	    /* then delete the context itself */
	    context_rowDelete(cp->contextIdentity, cp->contextIdentityLen);
	}
	/* if action and context created and it is local, open up new
	 * listening port, if acpropriate.
	 */
	break;
      case CONTEXTIDENTITY:
      default:
	    return SNMP_ERR_NOCREATION;
    }
    if (action == COMMIT)	/* make any new collumns acpear */
	cp->contextBitMask = rp->contextBitMask;

#endif
    return SNMP_ERR_NOERROR;
}

u_char *
var_context(vp, name, length, exact, var_len, write_method)
    register struct variable *vp;   /* IN - pointer to variable entry that points here */
    register oid *name;      /* IN/OUT - input name requested, output name found */
    register int *length;    /* IN/OUT - length of input and output oid's */
    int          exact;      /* IN - TRUE if an exact match was requested. */
    int          *var_len;   /* OUT - length of variable or 0 if function returned. */
    int          (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
    oid newname[MAX_NAME_LEN], lowname[MAX_NAME_LEN];
    int newnamelen, lownamelen;
    struct contextEntry *cp, *lowcp = NULL;
    u_int32 mask;
    struct timeval now;
extern int write_context();
/*
 * This routine handles requests for variables of the form:

 * .iso.org.dod.internet.snmpV2.snmpModules.partyMIB.partyMIBObjects
 * .snmpContexts.contextTable.contextEntry.X.oid
 * or .1.3.6.1.6.3.3.2.2.1.1.X.oid, where the oid suffix is
 * variable length
 * Therefore, the index starts at name[12].
 */

    mask = 1 << (vp->magic - 1);
    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
    if (exact){
        if (*length < 13 ||
	    bcmp((char *)name, (char *)vp->name, 11 * sizeof(oid)))
	    return NULL;
    	*write_method = write_context;
        cp = context_getEntry(name + 12, *length - 12);
	if (cp == NULL)
	    return NULL;
	if (!(cp->contextBitMask & mask))
	    return NULL;
    } else {
      /* find "next" control entry */
      context_scanInit();
      for(cp = context_scanNext(); cp; cp = context_scanNext()){
	if (!(cp->contextBitMask & mask))
	    continue;
	bcopy((char *)cp->contextIdentity, (char *)(newname + 12),
	      cp->contextIdentityLen * sizeof(oid));
	newnamelen = 12 + cp->contextIdentityLen;
	if ((compare(newname, newnamelen, name, *length) > 0) &&
	    (!lowcp || compare(newname, newnamelen,
			       lowname, lownamelen) < 0)){
	    /*
	     * if new one is greater than input and closer to input than
	     * previous lowest, save this one as the "next" one.
	     */
	    bcopy((char *)newname, (char *)lowname, newnamelen * sizeof(oid));
	    lownamelen = newnamelen;
	    lowcp = cp;
	}
      }
      if (lowcp == NULL)
	  return NULL;
      cp = lowcp;
      bcopy((char *)lowname, (char *)name, lownamelen * sizeof(oid));
      *length = lownamelen;
    }

    *var_len = sizeof(int32);
    long_return = 0;

    switch (vp->magic){
      case CONTEXTINDEX:
	return (u_char *)&cp->contextIndex;
      case CONTEXTLOCAL:
	return (u_char *)&cp->contextLocal;
      case CONTEXTVIEWINDEX:
	return (u_char *)&cp->contextViewIndex;
      case CONTEXTLOCALENTITY:
	*var_len = cp->contextLocalEntityLen;
	return (u_char *)cp->contextLocalEntity;
      case CONTEXTLOCALTIME:
	if (cp->contextLocalTime == CURRENTTIME){
	    *var_len = sizeof(currentTime);
	    return (u_char *)currentTime;
	} else if (cp->contextLocalTime == RESTARTTIME){
	    *var_len = sizeof(restartTime);
	    return (u_char *)restartTime;
	} else {
	    ERROR("");
	    return NULL;
	}
      case CONTEXTDSTPARTYINDEX:
	*var_len = 8;
	bzero(return_buf, 8);
	return (u_char *)return_buf;
      case CONTEXTSRCPARTYINDEX:
	*var_len = 8;
	bzero(return_buf, 8);
	return (u_char *)return_buf;
      case CONTEXTPROXYCONTEXT:
        *var_len = cp->contextProxyContextLen * sizeof(oid);
        return (u_char *)cp->contextProxyContext;
      case CONTEXTSTORAGETYPE:
	return (u_char *)&cp->contextStorageType;
      case CONTEXTSTATUS:
	if (cp->contextStatus == CONTEXTNOTINSERVICE
	    && cp->contextBitMask != CONTEXTCOMPLETE_MASK){
	    long_return = CONTEXTNOTREADY;
	    return (u_char *)&long_return;
	}
	return (u_char *)&cp->contextStatus;
      default:
            ERROR("");
    }
    return NULL;
}
