/* snmpTargetAddrEntry MIB
   
   This file was generated by mib2c and is intended for use as a mib module
   for the ucd-snmp snmpd agent. Edited by Michael Baer

   last changed 2/2/99.
*/

#include <config.h>
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif

#include "mibincl.h"
#include "snmpTargetAddrEntry.h"
#include "read_config.h"
#include "callback.h"
#include "snmp-tc.h"
#include "util_funcs.h"

#define snmpTargetAddrOIDLen 11 /*This is base+column, 
				  i.e. everything but index*/

oid snmpTargetAddrOID[snmpTargetAddrOIDLen] = {1,3,6,1,6,3,12,1,2,1,0};

static unsigned long snmpTargetSpinLock = 0;
static struct targetAddrTable_struct *aAddrTable=0;


/* Utility routines */
struct targetAddrTable_struct *
get_addrTable(void) {
    return aAddrTable;
}

struct targetAddrTable_struct *get_addrForName(char *name) {
  struct targetAddrTable_struct *ptr;
  for(ptr = aAddrTable; ptr != NULL; ptr = ptr->next) {
      if (ptr->name && strcmp(ptr->name, name) == 0)
          return ptr;
  }
  return NULL;
}


/* TargetAddrTable_create creates and returns a pointer
   to a targetAddrTable_struct with default values set */
struct targetAddrTable_struct 
*snmpTargetAddrTable_create(void)
{
  struct targetAddrTable_struct *newEntry;

  newEntry = (struct targetAddrTable_struct *)
    malloc(sizeof(struct targetAddrTable_struct));

  if (newEntry) {
  newEntry->name        = 0;

  newEntry->tDomainLen  = 0;
  newEntry->tAddress    = 0;
 
  newEntry->timeout     = 1500;
  newEntry->retryCount  = 3;

  newEntry->tagList     = strdup("");
  newEntry->params      = 0;

  newEntry->storageType = SNMP_STORAGE_NONVOLATILE;
  newEntry->rowStatus   = SNMP_ROW_NONEXISTENT;
  newEntry->sess	= (struct snmp_session *)NULL;
  newEntry->next        = 0;
  }

  return newEntry;
}  /* snmpTargetAddrTable_create */


/* TargetAddrTable_dispose frees the space allocated to a
   targetAddrTable_struct */
void snmpTargetAddrTable_dispose(struct targetAddrTable_struct *reaped)
{
  SNMP_FREE(reaped->name);
  SNMP_FREE(reaped->tAddress);
  SNMP_FREE(reaped->tagList);
  SNMP_FREE(reaped->params);
  
  SNMP_FREE(reaped);
}  /* snmpTargetAddrTable_dispose  */

/* snmpTargetAddrTable_addToList adds a targetAddrTable_struct 
   to a list passed in. The list is assumed to be in a sorted order,
   low to high and this procedure inserts a new struct in the proper 
   location. Sorting uses OID values based on name. A new equal value 
   overwrites a current one. */
void snmpTargetAddrTable_addToList(
     struct targetAddrTable_struct *newEntry,
     struct targetAddrTable_struct **listPtr)
{
  static struct targetAddrTable_struct *curr_struct, *prev_struct;
  int    i;
  size_t newOIDLen = 0, currOIDLen = 0;
  oid    newOID[128], currOID[128];
  
  /* if the list is empty, add the new entry to the top */
  if ( (prev_struct = curr_struct = *listPtr) == 0 ) {
    *listPtr = newEntry;
    return;
  }
  else {
    /* get the 'OID' value of the new entry */
    newOIDLen = strlen(newEntry->name);
    for(i=0; i < (int)newOIDLen ;i++) {
      newOID[i] = newEntry->name[i];
    }

    /* search through the list for an equal or greater OID value */
    while (curr_struct != 0) {
      currOIDLen = strlen(curr_struct->name);
      for(i=0; i < (int)currOIDLen ;i++) {
	currOID[i] = curr_struct->name[i];
      }

      i=snmp_oid_compare(newOID, newOIDLen, currOID, currOIDLen);
      if (i==0) {  /* Exact match, overwrite with new struct */
	newEntry->next = curr_struct->next;
	/* if curr_struct is the top of the list */
	if (*listPtr == curr_struct)  *listPtr = newEntry;
	else prev_struct->next = newEntry;
	snmpTargetAddrTable_dispose(curr_struct);
	return;
      }
      else if (i < 0) { /* Found a greater OID, insert struct in front of it.*/
	newEntry->next = curr_struct;
	/* if curr_struct is the top of the list */
	if (*listPtr == curr_struct) *listPtr = newEntry;
	else prev_struct->next = newEntry;
	return;
      }
      prev_struct = curr_struct;
      curr_struct = curr_struct->next;
    }
  }
  /* if we're here, no larger OID was ever found, insert on end of list */
  prev_struct->next = newEntry;
}  /* snmpTargeAddrTable_addToList  */


void snmpTargetAddrTable_add(struct targetAddrTable_struct *newEntry) {
    snmpTargetAddrTable_addToList(newEntry, &aAddrTable);
}


/* snmpTargetAddrTable_remFromList removes a targetAddrTable_struct 
   from the list passed in */
void snmpTargetAddrTable_remFromList(
     struct targetAddrTable_struct *oldEntry,
     struct targetAddrTable_struct **listPtr)
{
  struct targetAddrTable_struct *tptr;

  if ( (tptr = *listPtr) == 0 ) return;
  else if (tptr == oldEntry) {
    *listPtr = (*listPtr)->next;
    snmpTargetAddrTable_dispose(tptr);
    return;
  }
  else  {
    while (tptr->next != 0) {
      if (tptr->next == oldEntry) {
	tptr->next = tptr->next->next;
	snmpTargetAddrTable_dispose(oldEntry);
	return;
      }
      tptr = tptr->next;
    }
  }	
}  /* snmpTargetAddrTable_remFromList  */


/* lookup OID in the link list of Addr Table Entries */
struct targetAddrTable_struct *
search_snmpTargetAddrTable(
     oid    *baseName,
     size_t  baseNameLen,
     oid    *name,
     size_t *length,
     int    exact)
{
   static struct targetAddrTable_struct *temp_struct;
   int    i;
   size_t myOIDLen = 0;
   oid    newNum[128];

   /* lookup entry in addrTable linked list, Get Current MIB ID */
   memcpy(newNum, baseName, baseNameLen*sizeof(oid));
  
   for( temp_struct = aAddrTable; temp_struct != 0; temp_struct = temp_struct->next) {
     for(i=0; i < (int)strlen(temp_struct->name) ;i++) {
       newNum[baseNameLen+i] = temp_struct->name[i];
     }
     myOIDLen = baseNameLen+strlen(temp_struct->name);
     i=snmp_oid_compare(name, *length, newNum, myOIDLen);
     /* Assumes that the linked list sorted by OID, low to high */
     if ( (i==0 && exact!=0) || (i<0 && exact==0) ) {
       if (exact == 0) {
	 memcpy(name, newNum, myOIDLen*sizeof(oid));
	 *length = myOIDLen;
       }
       return temp_struct;
     }
   }
   return(0);
}  /* search_snmpTargetAddrTable  */


/* snmpTargetAddr_rowStatusCheck is boolean funciton that  checks 
   the status of a row's values in order to determine whether
   the row should be notReady or notInService  */
int snmpTargetAddr_rowStatusCheck(struct targetAddrTable_struct *entry)
{
  if ( (entry->tDomainLen == 0) || (entry->tAddress == 0) ||
       (entry->params == 0)  )
    return 0;
  else
    return 1;
}  /* snmtpTargetAddrTable_rowStatusCheck */


/* Init routines */

/* this variable defines function callbacks and type return information 
   for the snmpTargetAddrEntry mib */

struct variable2 snmpTargetAddrEntry_variables[] = {
  { SNMPTARGETADDRTDOMAIN,     ASN_OBJECT_ID , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRTDOMAINCOLUMN } },
  { SNMPTARGETADDRTADDRESS,    ASN_OCTET_STR , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRTADDRESSCOLUMN } },
  { SNMPTARGETADDRTIMEOUT,     ASN_INTEGER   , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRTIMEOUTCOLUMN } },
  { SNMPTARGETADDRRETRYCOUNT,  ASN_INTEGER   , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRRETRYCOUNTCOLUMN } },
  { SNMPTARGETADDRTAGLIST,     ASN_OCTET_STR , RWRITE, 
    var_snmpTargetAddrEntry, 1, {SNMPTARGETADDRTAGLISTCOLUMN } },
  { SNMPTARGETADDRPARAMS,      ASN_OCTET_STR , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRPARAMSCOLUMN } },
  { SNMPTARGETADDRSTORAGETYPE, ASN_INTEGER   , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRSTORAGETYPECOLUMN } },
  { SNMPTARGETADDRROWSTATUS,   ASN_INTEGER   , RWRITE, 
    var_snmpTargetAddrEntry, 1, { SNMPTARGETADDRROWSTATUSCOLUMN } },

};

struct variable2 snmpTargetSpinLock_var[] = {
  { SNMPTARGETSPINLOCK, ASN_INTEGER, RWRITE, var_targetSpinLock, 1, { 1 } }
};

static oid snmpTargetSpinLock_oid[] = { 1, 3, 6, 1, 6, 3, 12, 1 };

/* now load this mib into the agents mib table */
oid snmpTargetAddrEntry_variables_oid[] = { 1,3,6,1,6,3,12,1,2,1 };


void init_snmpTargetAddrEntry(void) {
  aAddrTable = 0;
  DEBUGMSGTL(("snmpTargetAddrEntry","init\n"));
  REGISTER_MIB("target/snmpTargetAddrEntry", snmpTargetAddrEntry_variables,
			variable2, snmpTargetAddrEntry_variables_oid);
  REGISTER_MIB("target/snmpTargetSpinLock", snmpTargetSpinLock_var,
			variable2, snmpTargetSpinLock_oid);

  snmpd_register_config_handler("targetAddr", snmpd_parse_config_targetAddr,
				0, NULL);

  /* we need to be called back later */
  snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
                         store_snmpTargetAddrEntry, NULL);

}  /* init_snmpTargetAddrEntry */


int snmpTargetAddr_addName(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  size_t len;
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no name in config string\n"));
    return(0);
  }
  else {
    len = strlen(cptr);    
    /* spec check for string 1-32 */
    if (len < 1 || len > 32)  {
      DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: name out of range in config string\n"));
      return(0);
    }
    entry->name = (char *)malloc(len + 1);
    strncpy(entry->name, cptr, len);
    entry->name[len] = '\0';
  }
  return(1);
} /* addName */
  

int snmpTargetAddr_addTDomain(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  size_t len=128;
  
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no tDomain in config string\n"));
    return(0);
  }

  if ( !read_objid(cptr, entry->tDomain, &len) ) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: tDomain unreadable in config string\n"));
    return(0);
  }

  /* spec check for oid 1-128 */
  if (len < 1 || len > 128)  {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: tDomain out of range in config string\n"));
    return(0);
  }
  
  entry->tDomainLen = len;
  return(1);
} /* snmpTargetAddr_addTDomain */


int snmpTargetAddr_addTAddress(
     struct targetAddrTable_struct *entry,
     char   *cptr,
     size_t len)
{
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no tAddress in config string\n"));
    return(0);
  }
  else {
    /* spec check for string 1-32 */
    /*    if (len < 1 || len > 32)  {
	  DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: name out of range in config string\n"));
	  return(0);
      } */
    SNMP_FREE(entry->tAddress);
    entry->tAddress = (u_char *)malloc(len);
    entry->tAddressLen = len;
    memcpy(entry->tAddress, cptr, len);
  }
  return(1);
} /* snmpTargetAddr_addTAddress */
  
  
int snmpTargetAddr_addTimeout(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetParamsEntry: no Timeout in config string\n"));
    return(0);
  }
  else if (!(isdigit(*cptr))) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargeParamsEntry: Timeout is not a digit in config string\n"));
    return(0);
  }
  /* check Timeout >= 0 */
  else if ( (entry->timeout = (int)strtol(cptr, (char **)NULL, 0)) < 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargeParamsEntry: Timeout out of range in config string\n"));
    return(0);
  }
  return(1);
}  /* snmpTargetAddr_addTimeout  */
  
  
int snmpTargetAddr_addRetryCount(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetParamsEntry: no Retry Count in config string\n"));
    return(0);
  }
  else if (!(isdigit(*cptr))) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargeParamsEntry: Retry Count is not a digit in config string\n"));
    return(0);
  }
  /* spec check 0..255 */
  else {
    entry->retryCount = (int)strtol(cptr, (char **)NULL, 0);
    if ( (entry->retryCount < 0) ||
	 (entry->retryCount > 255) )  {
      DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargeParamsEntry: Retry Count is out of range in config string\n"));
      return(0);
    }
  }
  return(1);
}  /* snmpTargetAddr_addRetryCount  */

 
int snmpTargetAddr_addTagList(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  size_t len;
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no tag list in config string\n"));
    return(0);
  }
  else {
    len = strlen(cptr);    
    /* spec check for string 0-255 */
    if (len < 0 || len > 255)  {
      DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: tag list out of range in config string\n"));
      return(0);
    } 
    SNMP_FREE(entry->tagList);
    entry->tagList = (char *)malloc(len + 1);
    strncpy(entry->tagList, cptr, len);
    entry->tagList[len] = '\0';
  }
  return(1);
} /* snmpTargetAddr_addTagList */
  
 
int snmpTargetAddr_addParams(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  size_t len;
  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no params in config string\n"));
    return(0);
  }
  else {
    len = strlen(cptr);    
    /* spec check for string 1-32 */
    if (len < 1 || len > 32)  {
      DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: params out of range in config string\n"));
      return(0);
    } 
    entry->params = (char *)malloc(len + 1);
    strncpy(entry->params, cptr, len);
    entry->params[len] = '\0';
  }
  return(1);
} /* snmpTargetAddr_addParams */

  
int snmpTargetAddr_addStorageType(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  char   buff[1024];

  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no storage type in config string\n"));
    return(0);
  }
  else if (!(isdigit(*cptr))) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: storage type is not a digit in config string\n"));
    return(0);
  }
  /* check that storage type is a possible value */
  else if ( ((entry->storageType = (int)strtol(cptr, (char **)NULL, 0)) 
	     != SNMP_STORAGE_OTHER) &&
	    (entry->storageType != SNMP_STORAGE_VOLATILE) && 
	    (entry->storageType != SNMP_STORAGE_NONVOLATILE)  &&
	    (entry->storageType != SNMP_STORAGE_PERMANENT) && 
	    (entry->storageType != SNMP_STORAGE_READONLY) )  {
    sprintf(buff,"ERROR snmpTargetAddrEntry: storage type not a valid value of other(%d), volatile(%d), nonvolatile(%d), permanent(%d), or readonly(%d) in config string.\n", SNMP_STORAGE_OTHER, SNMP_STORAGE_VOLATILE, SNMP_STORAGE_NONVOLATILE, SNMP_STORAGE_PERMANENT, SNMP_STORAGE_READONLY);
    DEBUGMSGTL(("snmpTargetAddrEntry", buff));

    return(0);
  }
  return(1);
}  /* snmpTargetAddr_addStorageType */
  
  
int snmpTargetAddr_addRowStatus(
     struct targetAddrTable_struct *entry,
     char   *cptr)
{
  char buff[1024];

  if (cptr == 0) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no Row Status in config string\n"));
    return(0);
  }
  else if (!(isdigit(*cptr))) {
    DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: Row Status is not a digit in config string\n"));
    return(0);
  }
  /* check that row status is a valid value */
  else if ( ((entry->rowStatus = (int)strtol(cptr, (char **)NULL, 0)) 
	     != SNMP_ROW_ACTIVE) &&
	    (entry->rowStatus != SNMP_ROW_NOTINSERVICE) &&
	    (entry->rowStatus != SNMP_ROW_NOTREADY) ) {
    sprintf(buff, "ERROR snmpTargetAddrEntry: Row Status is not a valid value of active(%d), notinservice(%d), or notready(%d) in config string.\n", SNMP_ROW_ACTIVE, SNMP_ROW_NOTINSERVICE, SNMP_ROW_NOTREADY);
    DEBUGMSGTL(("snmpTargetAddrEntry", buff));
    
    return(0);
  }
  return(1);
}  /* snmpTargetAddr_addRowStatus  */


void snmpd_parse_config_targetAddr(const char *token, char *char_ptr)
{
  char  *cptr = char_ptr, buff[1024];
  struct targetAddrTable_struct *newEntry;
  int                            i;

  newEntry = snmpTargetAddrTable_create();
  
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addName(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addTDomain(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = read_config_read_octet_string(cptr, (u_char **)&newEntry->tAddress,
                                       &newEntry->tAddressLen);
  if (!cptr || !(newEntry->tAddress)) {
      DEBUGMSGTL(("snmpTargetAddrEntry","ERROR snmpTargetAddrEntry: no TAddress in config string\n"));
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addTimeout(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addRetryCount(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addTagList(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addParams(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addStorageType(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  cptr = copy_word(cptr, buff);
  if (snmpTargetAddr_addRowStatus(newEntry, buff) == 0) {
    snmpTargetAddrTable_dispose(newEntry);
    return;
  }
  sprintf(buff, "snmp_parse_config_targetAddr, read: %s\n",
		   newEntry->name);
  for(i=0;i<newEntry->tDomainLen;i++) {
    sprintf(&buff[strlen(buff)], ".%d", (int)newEntry->tDomain[i]);
  }
  sprintf(&buff[strlen(buff)], " %s %d %d %s %s %d %d\n",
	  newEntry->tAddress, newEntry->timeout, newEntry->retryCount,
	  newEntry->tagList,  newEntry->params,  newEntry->storageType, 
	  newEntry->rowStatus);
  DEBUGMSGTL(("snmpTargetAddrEntry", buff));

  snmpTargetAddrTable_addToList(newEntry, &aAddrTable);
} /* snmpd_parse_config_target */


/* Shutdown routines */


/* store_snmpTargetAddrEntry handles the persistent storage proccess 
   for this MIB table. It writes out all the non-volatile rows 
   to permanent storage on a shutdown  */
int 
store_snmpTargetAddrEntry(int majorID, int minorID, void *serverarg,
                          void *clientarg)
{
  struct targetAddrTable_struct *curr_struct;
  char line[1024];
  int  i;

  if ( (curr_struct = aAddrTable) != 0) {
    while (curr_struct != 0) {
      if ( (curr_struct->storageType == SNMP_STORAGE_NONVOLATILE || 
	    curr_struct->storageType == SNMP_STORAGE_PERMANENT) 
	   &&
	   (curr_struct->rowStatus == SNMP_ROW_ACTIVE ||
	    curr_struct->rowStatus == SNMP_ROW_NOTINSERVICE) ) {
	sprintf(line, "targetAddr %s ", curr_struct->name);
	for(i=0; i < curr_struct->tDomainLen; i++) {
	  sprintf(&line[strlen(line)], ".%i", (int)curr_struct->tDomain[i]);
	}
        sprintf(&line[strlen(line)], " ");
        read_config_save_octet_string(&line[strlen(line)],
                                      curr_struct->tAddress,
                                      curr_struct->tAddressLen);

	sprintf(&line[strlen(line)], " %i %i \"%s\" %s %i %i", 
			 curr_struct->timeout, 
			 curr_struct->retryCount,  curr_struct->tagList,
			 curr_struct->params,      curr_struct->storageType, 
			 curr_struct->rowStatus);
	
	/* store to file */
	snmpd_store_config(line);
      }
      curr_struct = curr_struct->next;
    }
  }
  return SNMPERR_SUCCESS;

}  /*  store_snmpTargetAddrEntry  */


/*MIB table access routines */


u_char *
var_snmpTargetAddrEntry(
    struct variable *vp,
    oid     *name,
    size_t  *length,
    int     exact,
    size_t  *var_len,
    WriteMethod **write_method)
{

  /* variables we may use later */
  static long                    long_ret;
  static char                    string[1500];
  static oid                     objid[128];
  struct targetAddrTable_struct *temp_struct;
  int                            i=0;

  /*  Set up write_method first, in case we return NULL before getting to the
      switch (vp->magic) below.  In some of these cases, we still want to call
      the appropriate write_method, if only to have it return the appropriate
      error.  */

  switch (vp->magic) {
  case SNMPTARGETADDRTDOMAIN:
    *write_method = write_snmpTargetAddrTDomain;
    break;
  case SNMPTARGETADDRTADDRESS:
    *write_method = write_snmpTargetAddrTAddress;
    break;
  case SNMPTARGETADDRRETRYCOUNT:
    *write_method = write_snmpTargetAddrRetryCount;
    break;
  case SNMPTARGETADDRTAGLIST:
    *write_method = write_snmpTargetAddrTagList;
    break;
  case SNMPTARGETADDRPARAMS:
    *write_method = write_snmpTargetAddrParams;
    break;
  case SNMPTARGETADDRSTORAGETYPE:
    *write_method = write_snmpTargetAddrStorageType;
    break;
  case SNMPTARGETADDRROWSTATUS:
    *write_method = write_snmpTargetAddrRowStatus;
    break;
  default:
    *write_method = NULL;
  }  

  *var_len = sizeof(long_ret); /* assume an integer and change later if not */

  /* look for OID in current table */
  if ( (temp_struct = search_snmpTargetAddrTable(vp->name, vp->namelen, 
				      name, length, exact)) == 0 ) {
    return(0);
  }
  
  /* We found what we were looking for, either the next OID or the exact OID */
  /* this is where we do the value assignments for the mib results. */
  switch(vp->magic) {
  case SNMPTARGETADDRTDOMAIN:
    if (temp_struct->tDomainLen <= 0) {
      return(0);
    }
    else {
      for (i=0;i<temp_struct->tDomainLen;i++) {
	objid[i] = temp_struct->tDomain[i];
      }
      *var_len = temp_struct->tDomainLen * sizeof(oid);
    }
    return (unsigned char *) objid;
    
  case SNMPTARGETADDRTADDRESS:
    if (temp_struct->tAddress == 0)  return(0);
    *var_len = temp_struct->tAddressLen;
    return (unsigned char *) temp_struct->tAddress;
    
  case SNMPTARGETADDRTIMEOUT:
    long_ret = temp_struct->timeout;
    return (unsigned char *) &long_ret;

  case SNMPTARGETADDRRETRYCOUNT:
    long_ret = temp_struct->retryCount;
    return (unsigned char *) &long_ret;

  case SNMPTARGETADDRTAGLIST:
    if (temp_struct->tagList != NULL) {
	strcpy(string, temp_struct->tagList);
	*var_len = strlen(string);
	return (unsigned char *) string;
    } else {
	return NULL;
    }

  case SNMPTARGETADDRPARAMS:
    if (temp_struct->params == 0) return(0);
    strcpy(string, temp_struct->params);
    *var_len = strlen(string);
    return (unsigned char *) string;
    
  case SNMPTARGETADDRSTORAGETYPE:
    long_ret = temp_struct->storageType;
    return (unsigned char *) &long_ret;

  case SNMPTARGETADDRROWSTATUS:
    long_ret = temp_struct->rowStatus;
    return (unsigned char *) &long_ret;
    
  default:
    DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_snmpTargetAddrEntry\n", vp->magic));
  }
  return 0;
}  /* var_snmpTargetAddrEntry */


int
write_snmpTargetAddrTDomain(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  struct targetAddrTable_struct *target = NULL;
  static oid old_oid[MAX_OID_LEN];
  static size_t old_oid_len;
  
  if (action == RESERVE1) {
      if (var_val_type != ASN_OBJECT_ID) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTDomain not ASN_OBJECT_ID\n"));
	  return SNMP_ERR_WRONGTYPE;
      }
      if ((var_val_len > (MAX_OID_LEN * sizeof(oid))) ||
	  (var_val_len % sizeof(oid) != 0)) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTDomain: bad length\n"));
	  return SNMP_ERR_WRONGLENGTH;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTDOMAINCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) == 0) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTDomain: BAD OID!\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else {
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",	
		      "write to snmpTargetAddrTDomain: row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
	  if (target->rowStatus == SNMP_ROW_ACTIVE) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
	      "write to snmpTargetAddrTDomain: not allowed in active row.\n"));
	      return SNMP_ERR_INCONSISTENTVALUE;
	  }

	  /*  Finally, we're golden, save current value.  */

	  memcpy(old_oid, target->tDomain, target->tDomainLen * sizeof(oid));
	  old_oid_len = target->tDomainLen;

	  memcpy((u_char *)target->tDomain, var_val, var_val_len);
	  target->tDomainLen = var_val_len / sizeof(oid);

	  /*  If row is new, check if its status can be updated.  */
	  if ((target->rowStatus == SNMP_ROW_NOTREADY) &&
	      (snmpTargetAddr_rowStatusCheck(target) != 0)) {
	      target->rowStatus = SNMP_ROW_NOTINSERVICE;
	  }
      }
  } else if (action == FREE || action == UNDO) {
      /*  Try to undo the SET here (abnormal usage of FREE clause)  */
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTDOMAINCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) != NULL) {
	  if (target->storageType != SNMP_STORAGE_READONLY &&
	      target->rowStatus   != SNMP_ROW_ACTIVE) {
	      memcpy((u_char *)target->tDomain, (u_char *)old_oid,
		                                  (old_oid_len * sizeof(oid)));
	      target->tDomainLen = old_oid_len;
	      if (target->rowStatus == SNMP_ROW_NOTINSERVICE &&
		  snmpTargetAddr_rowStatusCheck(target) == 0) {
		  target->rowStatus = SNMP_ROW_NOTREADY;
	      }
	  }
      }
  }
  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrTDomain */


int
write_snmpTargetAddrTAddress(
   int action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  struct targetAddrTable_struct *target = NULL;
  static char *old_addr = NULL;
  static size_t old_len = 0;

  if (action == RESERVE1) {
      if (var_val_type != ASN_OCTET_STR) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTAddress not ASN_OCTET_STR\n"));
	  return SNMP_ERR_WRONGTYPE;
      } else if (var_val_len < 1 || var_val_len > 255) {
	  return SNMP_ERR_WRONGLENGTH;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTADDRESSCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) == 0) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTAddress: BAD OID!\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else {
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",	
		      "write to snmpTargetAddrTAddress: row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
	  if (target->rowStatus == SNMP_ROW_ACTIVE) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
	     "write to snmpTargetAddrTAddress: not allowed in active row.\n"));
	      return SNMP_ERR_INCONSISTENTVALUE;
	  }

	  old_addr = target->tAddress;
	  old_len  = target->tAddressLen;
	  target->tAddress = (u_char *)malloc(var_val_len);
	  if (target->tAddress == NULL) {
	      return SNMP_ERR_RESOURCEUNAVAILABLE;
	  }
	  memcpy(target->tAddress, var_val, var_val_len);
	  target->tAddressLen = var_val_len;

	  /*  If row is new, check if its status can be updated.  */
	  if ((target->rowStatus == SNMP_ROW_NOTREADY) &&
	      (snmpTargetAddr_rowStatusCheck(target) != 0)) {
	      target->rowStatus = SNMP_ROW_NOTINSERVICE;
	  }
      }
  } else if (action == COMMIT) {
      SNMP_FREE(old_addr);
      old_addr = NULL;
  } else if (action == FREE || action == UNDO) {
      /*  Try to undo the SET here (abnormal usage of FREE clause)  */
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTADDRESSCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) != NULL) {
	  if (target->storageType != SNMP_STORAGE_READONLY && 
	      target->rowStatus   != SNMP_ROW_ACTIVE) {
	      SNMP_FREE(target->tAddress);
	      target->tAddress    = old_addr;
	      target->tAddressLen = old_len;
	      if (target->rowStatus == SNMP_ROW_NOTINSERVICE &&
		  snmpTargetAddr_rowStatusCheck(target) == 0) {
		  target->rowStatus = SNMP_ROW_NOTREADY;
	      }
	  }
      }
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrTAddress */


int
write_snmpTargetAddrTimeout(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  /* variables we may use later */
  static long                    long_ret;
  size_t                         size;
  struct targetAddrTable_struct *temp_struct;

  if (var_val_type != ASN_INTEGER) {
      DEBUGMSGTL(("snmpTargetAddrEntry","write to snmpTargetAddrTimeout not ASN_INTEGER\n"));
      return SNMP_ERR_WRONGTYPE;
  }
  if (var_val_len > (size = sizeof(long_ret))) {
      DEBUGMSGTL(("snmpTargetAddrEntry","write to snmpTargetAddrTimeout: bad length\n"));
      return SNMP_ERR_WRONGLENGTH;
  }
  long_ret = *((long *) var_val);
  
  /* spec check range, no spec check */
  
  /* Find row in linked list and check pertinent status... */
  snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTIMEOUTCOLUMN;
  if ((temp_struct = search_snmpTargetAddrTable
       (snmpTargetAddrOID, snmpTargetAddrOIDLen, 
	name, &name_len, 1)) == 0 ) {
    DEBUGMSGTL(("snmpTargetAddrEntry","write to snmpTargetAddrTimeout : BAD OID\n"));
    return SNMP_ERR_NOSUCHNAME;
  }
  /* row exists, check if it is changeable */
  if (temp_struct->storageType == SNMP_STORAGE_READONLY) {
    DEBUGMSGTL(("snmpTargetAddrEntry","write to snmpTargetAddrTimeout : row is read only\n"));
    return SNMP_ERR_NOTWRITABLE;
  }

  /* Finally, we're golden, should we save value? */
  if (action == COMMIT)  {
    temp_struct->timeout = long_ret;
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrTimeout */


int
write_snmpTargetAddrRetryCount(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  static long long_ret;
  struct targetAddrTable_struct *target;

  if (action == RESERVE1) {
      if (var_val_type != ASN_INTEGER) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrRetryCount not ASN_INTEGER\n"));
	  return SNMP_ERR_WRONGTYPE;
      }
      if (var_val_len != sizeof(long)) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrRetryCount: bad length\n"));
	  return SNMP_ERR_WRONGLENGTH;
      }
      long_ret = *((long *) var_val);
      if (long_ret < 0 || long_ret > 255) {
	  return SNMP_ERR_WRONGVALUE;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = 
	                                        SNMPTARGETADDRRETRYCOUNTCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen, 
					       name, &name_len, 1)) == NULL) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTimeout: BAD OID\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else {
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
		     "write to snmpTargetAddrRetryCount: row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
      }
  } else if (action == COMMIT) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = 
	                                        SNMPTARGETADDRRETRYCOUNTCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen, 
					       name, &name_len, 1)) != NULL) {
	  target->retryCount = long_ret;
      }
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrRetryCount */

static int is_delim(const char c) {
    return (c == 0x020 || c == 0x09 || c == 0x0d || c == 0x0b);
}

int
snmpTagListValid(const char *tagList, const size_t tagListLen)
{
    size_t i = 0;
    int inTag = 0;

    for (i = 0; i < tagListLen; i++) {
	if (is_delim(tagList[i]) && !inTag) {
	    /*  Either a leading delimiter or two consecutive delimiters.  */
	    return 0;
	} else if (is_delim(tagList[i]) && inTag) {
	    inTag = 0;
	} else if (!is_delim(tagList[i]) && !inTag) {
	    inTag = 1;
	}
    }
    if (!inTag) {
	/*  Trailing delimiter.  */
	return 0;
    }
    return 1;
}

int
write_snmpTargetAddrTagList(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  struct targetAddrTable_struct *target = NULL;
  static char *old_tlist;

  if (action == RESERVE1) {
      if (var_val_type != ASN_OCTET_STR) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTagList not ASN_OCTET_STR\n"));
	  return SNMP_ERR_WRONGTYPE;
      }
      if (var_val_len > 255) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTagList: bad length\n"));
	  return SNMP_ERR_WRONGLENGTH;
      }
      if (!snmpTagListValid(var_val, var_val_len)) {
	  return SNMP_ERR_WRONGVALUE;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTAGLISTCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) == NULL) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrTagList: BAD OID!\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else {
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
			"write to snmpTargetAddrTagList: row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
	  old_tlist = target->tagList;
	  target->tagList = (char *)malloc(var_val_len + 1);
	  if (target->tagList == NULL) {
	      return SNMP_ERR_RESOURCEUNAVAILABLE;
	  }
	  memcpy(target->tagList, var_val, var_val_len);
	  target->tagList[var_val_len] = '\0';
      }
  } else if (action == COMMIT) {
      SNMP_FREE(old_tlist);
      old_tlist = NULL;
  } else if (action == FREE || action == UNDO) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRTAGLISTCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) != NULL) {
	  if (target->storageType != SNMP_STORAGE_READONLY) {
	      SNMP_FREE(target->tagList);
	      target->tagList = old_tlist;
	  }
      }
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrTagList */


int
write_snmpTargetAddrParams(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  struct targetAddrTable_struct *target = NULL;
  static char *old_params = NULL;

  if (action == RESERVE1) {
      if (var_val_type != ASN_OCTET_STR) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrParams not ASN_OCTET_STR\n"));
	  return SNMP_ERR_WRONGTYPE;
      } else if (var_val_len < 1 || var_val_len > 32) {
	  return SNMP_ERR_WRONGLENGTH;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRPARAMSCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) == 0) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrParams: BAD OID!\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else {
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",	
		      "write to snmpTargetAddrParams: row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
	  if (target->rowStatus == SNMP_ROW_ACTIVE) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
	     "write to snmpTargetAddrParams: not allowed in active row.\n"));
	      return SNMP_ERR_INCONSISTENTVALUE;
	  }

	  old_params = target->params;
	  target->params = (u_char *)malloc(var_val_len + 1);
	  if (target->params == NULL) {
	      return SNMP_ERR_RESOURCEUNAVAILABLE;
	  }
	  memcpy(target->params, var_val, var_val_len);
	  target->params[var_val_len] = '\0';

	  /*  If row is new, check if its status can be updated.  */
	  if ((target->rowStatus == SNMP_ROW_NOTREADY) &&
	      (snmpTargetAddr_rowStatusCheck(target) != 0)) {
	      target->rowStatus = SNMP_ROW_NOTINSERVICE;
	  }
      }
  } else if (action == COMMIT) {
      SNMP_FREE(old_params);
      old_params = NULL;
  } else if (action == FREE || action == UNDO) {
      /*  Try to undo the SET here (abnormal usage of FREE clause)  */
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = SNMPTARGETADDRPARAMSCOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen,
					       name, &name_len, 1)) != NULL) {
	  if (target->storageType != SNMP_STORAGE_READONLY && 
	      target->rowStatus   != SNMP_ROW_ACTIVE) {
	      SNMP_FREE(target->params);
	      target->params = old_params;
	      if (target->rowStatus == SNMP_ROW_NOTINSERVICE &&
		  snmpTargetAddr_rowStatusCheck(target) == 0) {
		  target->rowStatus = SNMP_ROW_NOTREADY;
	      }
	  }
      }
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrParams */

int
write_snmpTargetAddrStorageType(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  long long_ret = *((long *)var_val);
  struct targetAddrTable_struct *target;

  if (action == RESERVE1) {
      if (var_val_type != ASN_INTEGER) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrStorageType not ASN_INTEGER\n"));
	  return SNMP_ERR_WRONGTYPE;
      }
      if (var_val_len != sizeof(long)) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrStorageType: bad length\n"));
	  return SNMP_ERR_WRONGLENGTH;
      }
      if (long_ret != SNMP_STORAGE_OTHER && 
	  long_ret != SNMP_STORAGE_VOLATILE &&
	  long_ret != SNMP_STORAGE_NONVOLATILE) {
	  DEBUGMSGTL(("snmpTargetAddrEntry", "write to snmpTargetAddrStorageType: attempted storage type not a valid"));
	  DEBUGMSG(("snmpTargetAddrEntry", " value of other(%d), volatile(%d), or nonvolatile(%d)\n", 
		    SNMP_STORAGE_OTHER, SNMP_STORAGE_VOLATILE, 
		    SNMP_STORAGE_NONVOLATILE));
	  return SNMP_ERR_WRONGVALUE;
      }
  } else if (action == RESERVE2) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = 
	                                       SNMPTARGETADDRSTORAGETYPECOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen, 
					       name, &name_len, 1)) == NULL) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrStorageType: BAD OID\n"));
	  return SNMP_ERR_INCONSISTENTNAME;
      } else { 
	  if (target->storageType == SNMP_STORAGE_PERMANENT || 
	      target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry",
			  "write to snmpTargetAddrStorageType: row has unchangeable storage status: %d\n",
			  target->storageType));
	      return SNMP_ERR_WRONGVALUE;
	  }
      }
  } else if (action == COMMIT) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] = 
	                                       SNMPTARGETADDRSTORAGETYPECOLUMN;
      if ((target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen, 
					       name, &name_len, 1)) != NULL) {
	  target->storageType = long_ret;
      }
  }

  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrStorageType */


/* snmpTargeAddr_createNewRow is called from write_snmpTargetAddrRowStatus
   when a new row is required. It creates a new row with 
   the index of the passed in 'name' (i.e. full index OID) and
   adds it to the linked list. 'name' should be the full OID of the new index. 
   It passes back 0 if unsuccessfull.*/
int snmpTargetAddr_createNewRow(
     oid   *name,
     size_t name_len)
{
  size_t newNameLen;
  int i;
  struct targetAddrTable_struct *temp_struct;

  /* setup a new snmpTargetAddrTable structure and add it to the list */
  newNameLen = name_len - snmpTargetAddrOIDLen;
  if (newNameLen > 0) {
    temp_struct       = snmpTargetAddrTable_create();
    temp_struct->name = (char *)malloc(newNameLen + 1);
    if (temp_struct->name == NULL) {
      return 0;
    }

    for (i = 0; i < (int)newNameLen; i++) {
      temp_struct->name[i] = (char)name[i+snmpTargetAddrOIDLen];
    }

    temp_struct->name[newNameLen]  = '\0';
    temp_struct->rowStatus         = SNMP_ROW_NOTREADY;
    
    snmpTargetAddrTable_addToList(temp_struct, &aAddrTable);

    return 1;
  }

  return 0;
}  /* snmpTargetAddr_createNewRow */
	

/* Assign a value to the Row Status variable */
int
write_snmpTargetAddrRowStatus(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
  static long value;
  struct targetAddrTable_struct *target = NULL;

  if (action == RESERVE1) {
      value = *((long *)var_val);
      if (var_val_type != ASN_INTEGER) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrRowStatus not ASN_INTEGER\n"));
	  return SNMP_ERR_WRONGTYPE;
      }
      if (var_val_len != sizeof(int)) {
	  DEBUGMSGTL(("snmpTargetAddrEntry",
		      "write to snmpTargetAddrRowStatus: bad length\n"));
	  return SNMP_ERR_WRONGLENGTH;
      }
      if (value == RS_NOTREADY || value < 1 || value > 6) {
	  return SNMP_ERR_WRONGVALUE;
      }

      /*  Check index value is reasonable.  */

      if (name_len < snmpTargetAddrOIDLen + 1 ||
	  name_len > snmpTargetAddrOIDLen + 32) {
	  DEBUGMSGTL(("snmpTargetAddrEntry", "bad index length %d\n",
		      name_len - snmpTargetAddrOIDLen));
	  return SNMP_ERR_NOCREATION;
      }

      /*  Search for struct in linked list.  */

      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] =SNMPTARGETADDRROWSTATUSCOLUMN;
      target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					       snmpTargetAddrOIDLen, 
					       name, &name_len, 1);

      if (target != NULL) {
	  if (value == RS_CREATEANDGO || value == RS_CREATEANDWAIT) {
	      value = RS_NOTREADY;
	      return SNMP_ERR_INCONSISTENTVALUE;
	  }
	  if (target->storageType == SNMP_STORAGE_READONLY) {
	      DEBUGMSGTL(("snmpTargetAddrEntry", "row is read only\n"));
	      return SNMP_ERR_NOTWRITABLE;
	  }
	  if (target->storageType == SNMP_STORAGE_PERMANENT) {
	      if (value == RS_DESTROY) {
		  DEBUGMSGTL(("snmpTargetAddrEntry",
			      "unable to destroy permanent row\n"));
		  return SNMP_ERR_INCONSISTENTVALUE;
	      }
	  }
      } else {
	  if (value == RS_ACTIVE || value == RS_NOTINSERVICE) {
	      return SNMP_ERR_INCONSISTENTVALUE;
	  }
	  if (value == RS_CREATEANDGO || value == RS_CREATEANDWAIT) {
	      if (snmpTargetAddr_createNewRow(name, name_len) == 0) {
		  DEBUGMSGTL(("snmpTargetAddrEntry",
			      "couldn't malloc() new row\n"));
		  return SNMP_ERR_RESOURCEUNAVAILABLE;
	      }
	  }
      }
  } else if (action == ACTION) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] =SNMPTARGETADDRROWSTATUSCOLUMN;
      target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					  snmpTargetAddrOIDLen, 
					  name, &name_len, 1);

      if (target != NULL) {
	  if (value == RS_CREATEANDGO) {
	      /*  Check whether all the required objects have been set.  */
	      if (snmpTargetAddr_rowStatusCheck(target)) {
		  target->rowStatus = RS_ACTIVE;
	      } else {
		  target->rowStatus = RS_NOTREADY;
	      }
	  } else if (value == RS_CREATEANDWAIT) {
	      /*  Check whether all the required objects have been set.  */
	      if (snmpTargetAddr_rowStatusCheck(target)) {
		  target->rowStatus = RS_NOTINSERVICE;
	      } else {
		  target->rowStatus = RS_NOTREADY;
	      }
	  } else if (value == RS_ACTIVE) {
	      if (target->rowStatus == RS_NOTINSERVICE) {
		  target->rowStatus = RS_ACTIVE;
	      } else if (target->rowStatus == RS_NOTREADY) {
		  return SNMP_ERR_INCONSISTENTVALUE;
	      }
	  } else if (value == RS_NOTINSERVICE) {
	      if (target->rowStatus == RS_ACTIVE) {
		  target->rowStatus = RS_NOTINSERVICE;
	      } else if (target->rowStatus == RS_NOTREADY) {
		  return SNMP_ERR_INCONSISTENTVALUE;
	      }
	  }
      }
  } else if (action == COMMIT) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] =SNMPTARGETADDRROWSTATUSCOLUMN;
      target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					  snmpTargetAddrOIDLen, 
					  name, &name_len, 1);
      if (target != NULL) {
	  if (value == RS_DESTROY) {
	      snmpTargetAddrTable_remFromList(target, &aAddrTable);
	  }
	  if (value == RS_NOTINSERVICE) {
	      if (target->sess != NULL) {
		  snmp_close(target->sess);
		  target->sess = NULL;
	      }
	  }
      }
  } else if (action == UNDO || action == FREE) {
      snmpTargetAddrOID[snmpTargetAddrOIDLen-1] =SNMPTARGETADDRROWSTATUSCOLUMN;
      target = search_snmpTargetAddrTable(snmpTargetAddrOID, 
					  snmpTargetAddrOIDLen, 
					  name, &name_len, 1);
      if (value == RS_CREATEANDGO || value == RS_CREATEANDWAIT) {
	  if (target != NULL) {
	      snmpTargetAddrTable_remFromList(target, &aAddrTable);
	  }
      }
  }
  return SNMP_ERR_NOERROR;
}  /* write_snmpTargetAddrRowStatus */



int
write_targetSpinLock(
   int      action,
   u_char   *var_val,
   u_char   var_val_type,
   size_t   var_val_len,
   u_char   *statP,
   oid      *name,
   size_t   name_len)
{
    if (action == RESERVE1) {
	if (var_val_type != ASN_INTEGER) {
	    return SNMP_ERR_WRONGTYPE;
	}
	if (var_val_len != sizeof(unsigned long)) {
	    return SNMP_ERR_WRONGLENGTH;
	}
	if (*((unsigned long *)var_val) != snmpTargetSpinLock) {
	    return SNMP_ERR_INCONSISTENTVALUE;
	}
    } else if (action == COMMIT) {
	if (snmpTargetSpinLock == 2147483647) {
	    snmpTargetSpinLock = 0;
	} else {
	    snmpTargetSpinLock++;
	}
    }
    return SNMP_ERR_NOERROR;
}



u_char *
var_targetSpinLock(struct variable *vp,
		   oid *name,
		   size_t *length,
		   int exact,
		   size_t *var_len,
		   WriteMethod **write_method)
{
    if (header_generic(vp, name, length, exact, var_len, write_method) == 
	MATCH_FAILED) {
	*write_method = write_targetSpinLock;
	return NULL;
    }
    if (vp->magic == SNMPTARGETSPINLOCK) {
	*write_method = write_targetSpinLock;
	*var_len = sizeof(unsigned long);
	return (u_char *)&(snmpTargetSpinLock);
    }
    return NULL;
}
