/***************************************
  $Revision: 1.26 $

  UP module utilities

  Status: REVIEWED, NOT TESTED

  Author(s):       Engin Gunduz

  ******************/ /******************
  Modification History:
        engin (17/01/2000) Created.
		denis (31/08/2001) Modified for new API
  ******************/ /******************
  Copyright (c) 2000,2001,2002                    RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 ***************************************/

#include <time.h>
#include "dbupdate.h"
#include "UP_extrnl_syntax.h"
#include "ud.h"
#include "notification.h"

extern int tracing;
extern char * overridecryptedpw;
extern int test_mode;
extern char * updlog;
extern char * update_host;
extern int update_port;
extern char * query_host;
extern int query_port;
extern char * humailbox;
extern char * autobox;
extern char * netupdclientIP;

extern int reading_from_mail;
extern int networkupdate;
extern int webupdate; 
extern char *netupdclientIP;

extern char *update_mail_sender;
extern char *update_mail_subject;
extern char *update_mail_date;
extern char *update_mail_ID;
extern char *update_mail_cc;

extern char *header_type;
extern char *text_type;

extern char *current_source;
extern char *DBhost;
extern int  DBport;
extern char *DBuser;
extern char *DBname;
extern char *DBpasswd;

extern char * allocmnt;


/* authorise function takes the auth_vector, credentials struct, and 'overriden'
   variable. If overriden == 1, then it immediately returns UP_AUTH_OK 
   (because this means that the update contained a valid override attribute).
   Else, it goes through the auth_vector and when it finds a an "auth:"
   attribute which passes, then it returns UP_AUTH_OK. Otherwise, it returns
   UP_AUF (authorisation failed) */
   
int authorise(GSList * auth_vector, credentials_struct credentials, int overriden)
{
  int result = 0;

  if (tracing)
  {
    printf("TRACING: authorise started with override: %i\n", overriden);
  }
    
  /* If 'overriden' variable is 1, then return UP_AUTH_OK immediately */
  if (overriden == 1)
  {
    return UP_AUTH_OK;
  }
  else
  {
    result = AU_authorise(auth_vector, credentials);
    if (tracing)
	{
      printf("TRACING: authorise: AU_authorise returned %i\n", result);
    }
    
    if (result > 0)
	{
      return UP_AUTH_OK;
    }
    else
	{
      return UP_AUF; /* authorisation failed */
    }
  }
}



/* interprets the result string coming from RIPupd
   It is called by send_object_db.
   It returns the error no returned from RIPupd.  */
   
int interpret_ripdb_result(const char * string)
{
   char * error_no = NULL;
   char ** temp = NULL, ** temp2 = NULL;
   int i;
   int err = 0;
     
  /* if the string is NULL or empty, then return error */
  if (string == NULL || strlen(string) == 0)
  {
    return 0; 
  }

  /* split the string into lines */
  temp = g_strsplit(string , "\n", 0);
  for (i = 0; temp[i] != NULL; i++)
  {
    if (i == 0)
	{ /* this line must contain "%ERROR " string in the beginning */
      temp2 = g_strsplit(temp[0], " ", 0);
      error_no = strdup(temp2[1]);
      g_strfreev(temp2);
      err = atoi(error_no);
      if (tracing)
	  {
        printf("TRACING: interpret_ripdb_result: error_no is [%s]\n", error_no);
      }
    }
	else if (error_no != NULL && strcmp(error_no, "0") != 0)
	{
    }
  }
  g_strfreev(temp);
  if (error_no != NULL)
  {
    free(error_no);
  }
  return err; /* 0 means no error in this context */
}



/* Gets assigned NIC hdl from the string that is returned from 
   RIPupdate */
void get_assigned_nic(char * nic_hdl, const char * string)
{
   char * error_no = NULL;
   char ** temp = NULL, ** temp2 = NULL;
   int i;
     
  if (tracing)
  {                                
      printf("TRACING: get_assigned_nic is running\n");
  }

  /* if the string is NULL or empty, then return error */
  if (string == NULL || strlen(string) == 0)
  {
    return; 
  }

  /* split the string into lines */
  temp = g_strsplit(string , "\n", 0);
  for (i = 0; temp[i] != NULL; i++)
  {
    if (i == 0)
	{ /* this line must contain "%ERROR " string in the beginning */
      temp2 = g_strsplit(temp[0], " ", 0);
      error_no = strdup(temp2[1]);
      g_strfreev(temp2);
      if (tracing)
	  {
        printf("TRACING: get_assigned_nic: error_no is [%s]\n", error_no);
      }
    }
	else if (error_no != NULL && strcmp(error_no, "0") != 0)
	{
    }
	else if (error_no != NULL && strcmp(error_no, "0") == 0 && i == 1)
	{ /* look for assigned NIC hdl */
      /* in the second line RIPupdate returns for example "I[65][EK3-RIPE]" We
         need to extract EK3-RIPE part */
      nic_hdl = strncpy(nic_hdl, rindex(temp[i],'[') + 1 ,  
                                 rindex(temp[i],']') - rindex(temp[i],'[') - 1);
      nic_hdl[rindex(temp[i],']') - rindex(temp[i],'[') - 1] = '\0';
      if (tracing && nic_hdl != NULL)
	  {
        printf("TRACING: get_assigned_nic will return [%s]\n", nic_hdl);
      }
      g_strfreev(temp);
      return;
    }
  }
  g_strfreev(temp);
  return;
}



/* Obtains a transaction ID for an object. Will be called from send_object_db */
int up_get_transaction_id()
{
  SQ_connection_t * sql_connection;
  SQ_result_set_t *result;
  int error;
  long new_id;

  sql_connection = SQ_get_connection(DBhost, DBport, DBname, DBuser, DBpasswd); 
  if (!sql_connection)
  {
    fprintf(stderr, "No SQL connection\n");
    exit(1);
  }
  error = SQ_execute_query(sql_connection, "INSERT INTO tid VALUES(NULL)", &result);
  if (error)
  {
    fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
    exit(1);
  }

  new_id = mysql_insert_id(sql_connection);

  SQ_close_connection(sql_connection);  

  return new_id;
}



/* sends the object to the database. char * operation is either 'ADD' ,'DEL' or 'UPD'
   assigned_NIC is filled in if this is a person/role creation with AUTO nic hdl 
   assigned_NIC must be allocated enough memory before send_object_db is called 
   
   If the called do not expect a NIC hdl back, then assigned_NIC can be given NULL
   */
up_ripupd_result_struct * send_object_db(rpsl_object_t *object, char * assigned_NIC, char * operation)
{
  int sockfd, numbytes;  
  char buf[MAXDATASIZE + 1];
  struct hostent *he;
  struct sockaddr_in their_addr; /* connector's address information */
  char *result_string = NULL;
  int err = 0;
  char *to_be_sent = NULL;
  int tr_id;
  char * tr_id_str;
  char * tempstr;
  rpsl_object_t *sent_object;
  rpsl_attr_t *removed_attr;
  rpsl_error_t return_error;

  up_ripupd_result_struct * return_struct;

  if (tracing)
  { 
    printf("TRACING: send_object_db is running: assigned_NIC : [%s]; operation: [%s]\n", assigned_NIC ? assigned_NIC : "", operation);
  }
  return_struct = (up_ripupd_result_struct *)malloc(sizeof(up_ripupd_result_struct));
  return_struct->error_str = NULL;
  
  /* copy the object, remove the override password and create a text string */
  sent_object = rpsl_object_copy(object);
  removed_attr = rpsl_object_remove_attr_name(sent_object,"override",&return_error);
  to_be_sent = rpsl_object_get_text(sent_object,0);
  rpsl_object_delete(sent_object);

  if (tracing)
  { 
    printf("TRACING: send_object_db: to_be_sent : [\n%s]\n", to_be_sent);
  }

  /* get the transaction ID, to be sent to RIPupdate*/
  tr_id = up_get_transaction_id();

  /* convert it into a string */
  tr_id_str = (char *)malloc(64);
  sprintf(tr_id_str, "%d", tr_id);

  if (tracing)
  { 
    printf("TRACING: send_object_db: tr_id_str : [%s]\n", tr_id_str);
  }

  if ((he=gethostbyname(update_host)) == NULL)
  {  /* get the host info */
      perror("gethostbyname");
      exit(1);
  }

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
      perror("socket");
      exit(1);
  }

  their_addr.sin_family = AF_INET;  	/* host byte order */
  their_addr.sin_port = htons(update_port);    /* short, network byte order */
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero), 8); 	/* zero the rest of the struct */


  if (connect(sockfd, (struct sockaddr *)&their_addr, 
    									sizeof(struct sockaddr)) == -1)
  {
      perror("connect");
      exit(1);
  }

  if (send(sockfd, operation , strlen(operation), 0) == -1)
      perror("send");
  if (send(sockfd, " ", strlen(" "), 0) == -1)
      perror("send");	 
  if (send(sockfd, tr_id_str, strlen(tr_id_str), 0) == -1)
      perror("send");	 
  if (send(sockfd, "\n\n" , strlen("\n\n"), 0) == -1)
      perror("send");
  if (send(sockfd, to_be_sent, strlen(to_be_sent), 0) == -1)
      perror("send");
  if (send(sockfd, "\n\n", 2, 0)  == -1)
      perror("send");
  /* send the ACK now */
  if (send(sockfd, "ACK ",strlen("ACK "), 0)  == -1)
      perror("send");
  if (send(sockfd, tr_id_str, strlen(tr_id_str), 0) == -1)
      perror("send");	 
  if (send(sockfd, "\n\n",strlen("\n\n"), 0)  == -1)
      perror("send");

  if (tracing)
  { 
    printf("TRACING: send_object_db: send complete\n");
  }
      

  while ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) != 0)
  {
      buf[numbytes] = '\0';
      if (tracing)
      {
    	printf("received from socket [\n%s]\n",buf);
      }
      if (result_string == NULL)
      {
    	result_string = strdup(buf);
      }
      else
      {
    	result_string = (char *)realloc(result_string, 
    					   strlen(result_string) + strlen(buf) + 1);
    	result_string = strcat(result_string, buf);
      }
      if (strstr(result_string,"\n\n") != NULL)
      { /* if the result_string contains
    	 an empty line at the end, we will close */
    	break;
      };
  }

  free(tr_id_str);
  err = interpret_ripdb_result(result_string);

  if (tracing)
  { 
    printf("TRACING: send_object_db: interpret_ripdb_result returned : [%i]\n", err);
  }

  if (assigned_NIC != NULL)
  { /* if the caller of the function expected to get a NIC handle */
    get_assigned_nic(assigned_NIC, result_string);
  }
  close(sockfd);
  free(to_be_sent);
  return_struct->result = err;
  
  /*return_struct->error_str = strdup(result_string); */
  /* According to the error no got from RIPupdate, construct an error string  */
  switch (return_struct->result)
  {
    case 0: break; 
    case ERROR_U_MEM: 
    case ERROR_U_DBS:
    case ERROR_U_BADOP:
    case ERROR_U_COP:
    case ERROR_U_NSUP:
    case ERROR_U_BUG:
      tempstr = (char *)malloc(1024);
      snprintf(tempstr, 1024, "***Error: Please contact database admin: Error no %i",
    	  return_struct->result);
      return_struct->error_str = tempstr;
      break; 
    case ERROR_U_OBJ:
      if (tracing)
      {
         printf("\nresult_string [%s]\n\n", result_string);
      }
      tempstr = (char *)malloc(1024);
      /* if the object contains refs to unknown objects */
      if (strstr(result_string, "dummy") != NULL || 
            strstr(result_string, "reference cannot be resolved") != NULL )
      {
    	/* if the response from RIPupd contains "dummy not allowed" string 
           or a reference that cannot be resolved */
    	snprintf(tempstr, 1024, "***Error: Unknown object referenced");
      }
	  else if (strstr(result_string, "key-cert") != NULL)
	  {
      /* if the response from RIPupd contains "no key-cert object" string */
      snprintf(tempstr, 1024, "***Error: Unknown key-cert object referenced"); 
      }
      else
      {
      /* then, the object is referenced from other objects */
    	snprintf(tempstr, 1024, "***Error: Object is referenced from other objects");
      }
      return_struct->error_str = tempstr;
      break; 
    case ERROR_U_AUT:
      tempstr = (char *)malloc(1024);
      snprintf(tempstr, 1024, "***Error: Membership authorisation failure");
      return_struct->error_str = tempstr;
      break; 
    default: 
      tempstr = (char *)malloc(1024);
      snprintf(tempstr, 1024, "***Error: Please contact database admin: Error no %i",
    	  return_struct->result);
      return_struct->error_str = tempstr;
      break; 
  }
  return return_struct; 
}



/* takes an object (pre-parsed) and returns its first attrib if it is not
   a person/role, and returns the nic-hdl if it is a person/role object */
char * get_search_key(rpsl_object_t *object, const char * type)
{
    char *primary_key = NULL;
	char *lctype;
	GList *attr_list;

    if(object == NULL) return NULL;
	
	lctype = strdup(type);
	g_strdown(lctype);
	if ( strcmp(lctype, "person") == 0 || strcmp(lctype, "role") == 0 )
	{
		/* this is a person or role object */
		/* get the nic-hdl attribute */
		attr_list = rpsl_object_get_attr(object, "nic-hdl");
	}
	else
	{
		/* this is NOT a person or role object */
		/* get the class attribute */
		attr_list = rpsl_object_get_attr(object, type);
	}

	if ( attr_list )
	{
		primary_key = rpsl_attr_get_clean_value((rpsl_attr_t *)(attr_list->data));
	}
	free(lctype);
	return primary_key ;
}



/* sends char * arg to the specified host's specified port, and
   returns the reply as a string. This is used to query the
   whois host. Probably we must use WC (whois client) module here,
   but it must be extented */
char * send_and_get(char * host, int port, char * arg)
{
        int sockfd, numbytes; 
        char * result = NULL; 
        char buf[MAXDATASIZE + 1];
        struct hostent *he;
        struct sockaddr_in their_addr; /* connector's address information */
  
        if(tracing)
		{ 
          printf("TRACING: send_and_get: arg : [%s]; port: [%i]; host: [%s]\n", arg, port, host);
        }

        if ((he=gethostbyname(host)) == NULL)
		{  /* get the host info */
            perror("gethostbyname");
            exit(1);
        }

        if(tracing) 
		{ 
          printf("TRACING: send_and_get: called gethostbyname\n");
        }

        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		{
            perror("socket");
            exit(1);
        }

        if(tracing)
		{ 
          printf("TRACING: send_and_get: called socket\n");
        }

        their_addr.sin_family = AF_INET;      /* host byte order */
        their_addr.sin_port = htons(port);    /* short, network byte order */
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        bzero(&(their_addr.sin_zero), 8);     /* zero the rest of the struct */

        if (connect(sockfd, (struct sockaddr *)&their_addr, 
                                              sizeof(struct sockaddr)) == -1)
        {
            perror("connect");
            exit(1);
        }
        if (send(sockfd, arg , strlen(arg), 0) == -1)
               perror("send");
        if (send(sockfd, "\n",1,0)  == -1)
               perror("send");

        while ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) != 0)
		{
            buf[numbytes] = '\0';
            if (result == NULL)
			{
              result = strdup(buf);
            }
			else
			{
              result = (char *)realloc(result, strlen(result) + strlen(buf) + 1);
              result = strcat(result, buf);
            }
        }

        close(sockfd);
        return result;
}



/* counts the number of objects in a string */
int count_objects(char * arg)
{
    int count = 0;
    char *pos = NULL;
    char *temp = NULL;

    if(tracing) 
	{
      printf("TRACING: count_objects running\n");
    }
    
    if(arg != NULL)
	{
      temp = strdup(arg);
    }
	else
	{
      return 0;
    }
    
    if ( isalpha( (int)(arg[0]) ) )
	{
      count++;
    }
	else if (arg[0] == '\n' && isalpha( (int)(arg[1]) ) )
	{
      count++;
    }
    while ( (pos = strstr(temp,"\n\n")) )
	{
      pos[0] = 'a'; /* something non-EOL so that it won't be caught in the next loop */
      if ( isalpha( (int)(pos[2]) ) )
	  {
        count++;
      }
    }
    if(tracing) 
	{
      printf("TRACING: count_objects returning %d\n", count);
    }
    free(temp);
    return count;
}



/* strips lines beginning with '%' off  */
char * strip_lines(char * arg)
{
    char ** temp = NULL;
    char * string = NULL;
    int i;

    if (arg == NULL)
	{
       return NULL;
    }

    /* split the string into lines */
    temp = g_strsplit (arg, "\n", 0);

    for (i=0; temp[i] != NULL; i++)
	{
      if (temp[i][0] != '%')
	  {
        if (string == NULL)
		{
          string = strdup(temp[i]);
        }
		else
		{
          string = (char *)realloc(string, strlen(string) + strlen(temp[i]) + 2);
          string = strcat(string, "\n");
          string = strcat(string, temp[i]);
        }
      }
    }
    return string;
}


/* Separates the objects in the given char * arg using "\n\n" as
   separator. Returns a linked list whose data consist of separated
   objects as  char *  */

GList * take_objects(char * arg)
{
    char ** objects=NULL;
    char ** temp = NULL;
    char * temp_object;
    GList * tobereturned = NULL;
    int i;

    arg = strip_lines(arg);

    objects =  g_strsplit(arg, "\n\n", 1000);
    temp = objects;
    for (i=0; temp[i] != NULL; i++)
	{
      /* strip off the trailing and leading white spaces-eols*/
      g_strstrip(temp[i]);
      if (strlen(temp[i]) > 0)
	  { /* if not an empty string */
        /* here we must add a "\n" at the end of the object, since RAToolSet parser can't
          find the last attrib otherwise */
        temp_object = (char *)malloc(strlen(temp[i]) + 2);
        snprintf(temp_object, strlen(temp[i]) + 2, "%s\n", temp[i]);  
        tobereturned = g_list_append(tobereturned, temp_object);
      }
    }
    return tobereturned;
}



/* takes the first object in the given char *, using empty lines as
   separator */
char * take_object(char * arg)
{
    GList * objects;
    char * object;

    objects = take_objects(arg);
    if (g_list_length(objects) > 0)
	{
      object = strdup((char *)(g_list_nth_data(objects, 0)));
    }
	else
	{
      return NULL;
    }
    g_list_free(objects);

    return object;
}



/* Takes an autnum_object, and returns the as-block containing this aut-num */
char * get_as_block(rpsl_object_t *autnum_object)
{
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  char *return_value = NULL;
  
  search_key = get_search_key(autnum_object,"aut-num");
  
  query_string = (char *)malloc(strlen("-Tas-block -s  -r ")+strlen(current_source)+strlen(search_key)+1);
  sprintf(query_string, "-Tas-block -s %s -r %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
	{
      printf("No such as-block\n"); 
    }
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
	{
      printf("More than one as-block returned\n");
    }
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}


/* Takes a route_object, and returns the aut-num mentioned in origin
   attribute of this route */
char * get_aut_num_object(rpsl_object_t *route_object)
{
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  char *return_value = NULL;
  
  search_key = get_search_key(route_object,"origin");
  
  query_string = (char *)malloc(strlen("-Taut-num -s  -r ")+strlen(current_source)+strlen(search_key)+1);
  sprintf(query_string, "-Taut-num -s %s -r %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
	{
      printf("No such aut-num\n");
    }
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
	{
      printf("More than one aut-num returned\n");
    }
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}



/* Takes a parsed domain_object, and returns the less specific domain of it */
char * get_less_specific_domain(rpsl_object_t *domain_object)
{
  char *query_string = NULL;
  char *result = NULL, *domain = NULL;
  char *return_value = NULL;
  int i,j, length;
  char *temp = NULL;
  char **splitted;

  domain = get_search_key(domain_object,"domain");

  /* split the domain from its dots ('50' is the max # of pieces, this number is just arbitrary) */
  splitted =   g_strsplit((char *)strdup(domain), ".", 50);

  for (i=1; splitted[i] != NULL; i++)
  {
    /* in the following for loop, we will construct the 'less spec' domains
       to be looked up in the DB */ 
    for (j=i; splitted[j] !=NULL; j++)
	{
      if (j==i)
	  {
        temp = (char *)strdup(splitted[j]);
      }
	  else
	  {
        length = strlen(temp); 
    	temp = (char *)realloc(temp, length + strlen(splitted[j]) + 2); 
		strcat(temp, ".");
		strcat(temp, splitted[j]);
      }
    }

    query_string = (char *)malloc( strlen("-Tdomain -s  -r -R ")+strlen(current_source)+strlen(temp)+1 );
    sprintf(query_string, "-Tdomain -s %s -r -R %s", current_source,temp);
    result = send_and_get(query_host, query_port, query_string);
    free(query_string);
	free(temp);

    if (count_objects(result) == 0)
	{
	  /* do nothing */
	  free(result);
    }
	else if (count_objects(result) > 1)
	{
      if (tracing)
	  {
        printf("TRACING: get_less_specific_domain: More than one domains returned\n");
      }
	  free(result);
      return NULL; /* error condition */
    }
	else
	{ /* count_objects(result) == 1 */
      return_value = take_object(result);
	  free(result);
      return return_value;
    }
  }
  g_strfreev(splitted);

  /* so, we couldn't  find any 'less specific' domain */
  return NULL;
}



/* Takes a hierarchical set_object, and returns the less specific set or auth-num of it
   by striping down the object's name ( eg, for as35:rs-trial:rs-myset, 
   as35:rs-trial is tried ) */
char * get_less_specific_set(rpsl_object_t *set_object, const char *type)
{
  char *search_key = NULL, *query_string = NULL;
  char *result = NULL;
  char *return_value = NULL;
  int i;
  
  search_key = get_search_key(set_object, type);

  for (i = strlen(search_key) -1; i > -1; i--)
  {
    if (search_key[i] == ':')
	{
      search_key[i] = '\0'; /* truncate the string */
      break;
    }
    if (i == 0)
	{ /* if we've reached the beginning of the string 
      (this means there wasn't any ';' in the string) */
      free(search_key);
      search_key = NULL;
    }
  }
  if ( search_key == NULL || strlen(search_key) == 0)
  { /* this mustn't happen in fact, since 
    we make sure that the name of the 
    set_object contains a ':' in a proper place */
    return NULL;
  }
   
  query_string = (char *)malloc(strlen("-Taut-num,as-set,rtr-set,peering-set,filter-set,route-set -s  -r ") 
           + strlen(current_source) + strlen(search_key) + 1);
  sprintf(query_string, "-Taut-num,as-set,rtr-set,peering-set,filter-set,route-set -s %s -r %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
    {
      printf("get_less_specific_set: No such object\n");
	}
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
    {
      printf("get_less_specific_set: More than one objects returned\n");
	}
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}



/* Takes an inetnum or inet6num object and returns one more/less specific of it */
char * get_specific(rpsl_object_t *inetnum_object, const char *type, char *flag)
{
  char *search_key = NULL, *query_string = NULL;
  char *result = NULL;
  char *return_value = NULL;
  
  search_key = get_search_key(inetnum_object, type);
  
  query_string = (char *)malloc(strlen("-Tinet6num  -s  -r  ")+strlen(current_source) + strlen(flag) + strlen(search_key) + 1);
  sprintf(query_string, "-T%s -s %s -r %s %s",type, current_source, flag, search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
      printf("TRACING: get_specific: No %s %s returned\n", flag, type);
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
      printf("TRACING: get_specific: More than one %s %s returned\n", flag, type);
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}



/* Takes a parsed route object and returns one less specific inetnum */
char * get_less_spec_inetnum(rpsl_object_t *route_object)
{
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  char * return_value = NULL;
  
  search_key = get_search_key(route_object, "route");
  
  query_string = (char *)malloc(strlen("-Tinetnum -s  -r -l ")+strlen(current_source) + strlen(search_key) + 1);
  sprintf(query_string, "-Tinetnum -s %s -r -l %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
	{
      printf("get_less_spec_inetnum: No such inetnum\n");
	}
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
	{
      printf("get_less_spec_inetnum: More than one inetnums returned\n");
	}
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}


/* Takes a parsed route object and returns exact match inetnum */
char * get_exact_match_inetnum(rpsl_object_t *route_object)
{
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  char * return_value = NULL;
  
  search_key = get_search_key(route_object, "route");
  
  query_string = (char *)malloc(strlen("-Tinetnum -s  -r -x ")+strlen(current_source) + strlen(search_key) + 1);
  sprintf(query_string, "-Tinetnum -s %s -r -x %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
	{
      printf("get_exact_match_inetnum: No such inetnum\n");
	}
	free(result);
    return NULL;
  }
  else if (count_objects(result) > 1)
  {
    if (tracing)
	{
      printf("get_exact_match_inetnum: More than one inetnums returned\n");
	}
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) == 1 */
    return_value = take_object(result);
	free(result);
    return return_value;
  }
}



/* Takes a route object and returns exact matches of this route */
GList *get_exact_match_routes(rpsl_object_t *route_object)
{
  char *search_key = NULL, *query_string = NULL;
  char *result = NULL;
  GList * return_value = NULL;
  
  search_key = get_search_key(route_object, "route");
  
  query_string = (char *)malloc(strlen("-Troute -s  -r -x ")+strlen(current_source) + strlen(search_key) + 1);
  sprintf(query_string, "-Troute -s %s -r -x %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if (tracing)
	{
      printf("get_exact_match_routes: No such route\n");
	}
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) >= 1 */
    return_value = take_objects(result);
	free(result);
    return return_value;
  }
}



/* Takes a route object and returns (immediate) less specifics of this route */
GList *get_less_spec_routes(rpsl_object_t *route_object)
{
  char *search_key = NULL, *query_string = NULL;
  char *result = NULL;
  GList * return_value = NULL;
  
  search_key = get_search_key(route_object, "route");
  
  query_string = (char *)malloc(strlen("-Troute -s  -r -l ")+strlen(current_source) + strlen(search_key) + 1);
  sprintf(query_string, "-Troute -s %s -r -l %s", current_source,search_key);
  result = send_and_get(query_host, query_port, query_string);
  free(search_key);
  free(query_string);

  if (count_objects(result) == 0)
  {
    if(tracing)
	{
      printf("get_less_spec_routes: No such route\n");
	}
	free(result);
    return NULL;
  }
  else
  { /* count_objects(result) >= 1 */
    return_value = take_objects(result);
	free(result);
    return return_value;
  }
}



/* Gets an object as a parsed structure and returns its 'mnt-by' attributes as a 
   GList (linked list)   */

GList *get_mntners(rpsl_object_t *object)
{
  GList *list_of_mntners = NULL;

  if(tracing)
  {
    printf("TRACING: get_mntners is running\n");
  }

  list_of_mntners = rpsl_object_get_attr(object, "mnt-by");

  rpsl_attr_split_multiple(&list_of_mntners);

  return list_of_mntners; 
}



/* Gets an object as a parsed structure and returns its 'mnt-irt' attributes as a 
   GList (linked list)   */

GList *get_irts(rpsl_object_t *object)
{
  GList *list_of_irts = NULL;

  if(tracing)
  {
    printf("TRACING: get_irts is running\n");
  }

  list_of_irts = rpsl_object_get_attr(object, "mnt-irt");
  rpsl_attr_split_multiple(&list_of_irts);

  return list_of_irts; 
}



/* Gets a GList of strings and returns 1 if one of them starts with substr, 0 otherwise */
int strstr_in_list(GList *list, const char *substr)
{
 GList * item = NULL;
 char * word; 

  if (tracing)
  {
    printf("TRACING: strstr_in_list is running\n");
  }
 
 for ( item = list; item != NULL ; item = g_list_next(item) )
 {
   word = strdup((char *)(item->data));
   g_strup(word);
   if (strstr(word, substr) == word)
   {
     free(word);
     return 1;
   }
   free(word);
 }
 /* none of them matched, so return 0 */
 return 0; 
}

/* Gets a GList of attr structures and returns 1 if one of their (upper case)values 
   starts with substr, otherwise returns 0 */
int strstr_in_attr_list(GList * list, const char * substr)
{
 GList * item = NULL;
 char * word; 

  if (tracing)
  {
    printf("TRACING: strstr_in_attr_list is running\n");
  }
 
 for( item = list; item != NULL ; item = g_list_next(item) )
 {
   word = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
   g_strup(word);
   if (strstr(word, substr) == word)
   {
     free(word);
     return 1;
   }
   free(word);
 }
 /* none of them matched, so return 0 */
 return 0; 
}



/* Gets a (maintainer/irt) object as a string and returns its 'auth' attributes 
   as a GList (linked list) */

GList *get_auths(char * object_str)
{
  const char *name = NULL;
  char *value = NULL;
  GList *attr;
  rpsl_object_t *object;
  GList *list_of_auths = NULL;

  if(tracing)
  {
    printf("TRACING: get_auths is running\n");
  }
  object = rpsl_object_init(object_str);
  
  list_of_auths = rpsl_object_get_attr(object, "auth");
  rpsl_attr_split_multiple(&list_of_auths);
  
  if(tracing) 
  {
	if ( rpsl_object_has_error(object, RPSL_ERRLVL_ERROR) )
	{
	  /* thre was an error during the parsing */
	  name = rpsl_object_get_class(object);
	  if ( name )
	  {
		attr = rpsl_object_get_attr(object, name);
		if ( attr )
		{
		  value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
		  if ( value )
		  {
			printf("TRACING: get_auths: error parsing object %s\n", value );
			free(value);
		  }
		  else
			printf("TRACING: get_auths: error parsing object\n");

		  rpsl_attr_delete_list(attr);
		}
	  }
	}
    printf("TRACING: get_auths: returning (with %d nodes)\n", g_list_length(list_of_auths));
  }

  rpsl_object_delete(object);
  return list_of_auths; 
}



/* Gets a parsed object and returns its 'attr_type' attributes as a 
   GList (linked list) */

GList *get_attr_list(rpsl_object_t *object, const char *attr_type)
{
  GList *list_of_attrs = NULL;
  char *object_str = NULL;

  if (tracing)
  {
    object_str = rpsl_object_get_text(object,0);
    printf("TRACING: get_attr_list is running searching for %s, object is [\n%s]\n", attr_type ? attr_type : "NULL", object_str ? object_str : "NULL");
    free(object_str);
  }

  list_of_attrs = rpsl_object_get_attr(object, attr_type);
  rpsl_attr_split_multiple(&list_of_attrs);

  return list_of_attrs; 
}



/* Gets a parsed object and returns its mnt_lower attributes as a 
   GList (linked list) */

GList *get_mnt_lowers(rpsl_object_t *object)
{
  GList *list_of_mnt_lowers = NULL;

  if (tracing)
  {
    printf("TRACING: get_mnt_lowers is running\n");
  }

  list_of_mnt_lowers = rpsl_object_get_attr(object, "mnt-lower");
  rpsl_attr_split_multiple(&list_of_mnt_lowers);
  
  return list_of_mnt_lowers; 
}


/* Gets a parsed object and returns its mnt_routes attributes as a 
   GList (linked list) */

GList *get_mnt_routes(rpsl_object_t *object)
{
  GList *list_of_mnt_routes = NULL;

  if (tracing)
  {
    printf("TRACING: get_mnt_routes is running\n");
  }

  list_of_mnt_routes = rpsl_object_get_attr(object, "mnt-routes");
  rpsl_attr_split_multiple(&list_of_mnt_routes );

  return list_of_mnt_routes; 
}


/* Gets a linked list of object strings and returns the mnt_routes attribs of
   them in a linked list */
GList *get_mnt_routes_from_list(GList *objects_str)
{
  GList *objects_str_item = NULL;
  GList *list_of_mnt_routes = NULL;
  const char *name = NULL;
  char *value = NULL;
  GList *attr;
  rpsl_object_t *object;
  
  for ( objects_str_item = objects_str; objects_str_item != NULL ; objects_str_item = g_list_next(objects_str_item) )
  {
	object = rpsl_object_init((char *)(objects_str_item->data));

	if (tracing)
	{
      if ( rpsl_object_has_error(object, RPSL_ERRLVL_ERROR) )
	  {
		/* thre was an error during the parsing */
		name = rpsl_object_get_class(object);
		if ( name )
		{
		  attr = rpsl_object_get_attr(object, name);
		  if ( attr )
		  {
		    value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
			if ( value )
			{
		      printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
			  free(value);
			}
			else
		      printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

			rpsl_attr_delete_list(attr);
		  }
		}
	  }
	}

    list_of_mnt_routes = g_list_concat(list_of_mnt_routes, get_mnt_routes(object));
    rpsl_object_delete(object);
  }

  return list_of_mnt_routes;
}


/* Gets a linked list of object strings and returns the mnt_lowers attribs of
   them in a linked list */
GList *get_mnt_lowers_from_list(GList * objects_str)
{
  GList *objects_str_item = NULL;
  GList *list_of_mnt_lowers = NULL;
  const char *name = NULL;
  char *value = NULL;
  GList *attr;
  rpsl_object_t *object;
  
  for( objects_str_item = objects_str; objects_str_item != NULL ; objects_str_item = g_list_next(objects_str_item) )
  {
	object = rpsl_object_init((char *)(objects_str_item->data));

	if (tracing)
	{
      if ( rpsl_object_has_error(object, RPSL_ERRLVL_ERROR) )
	  {
		/* thre was an error during the parsing */
		name = rpsl_object_get_class(object);
		if ( name )
		{
		  attr = rpsl_object_get_attr(object, name);
		  if ( attr )
		  {
		    value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
			if ( value )
			{
		      printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
			  free(value);
			}
			else
		      printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

			rpsl_attr_delete_list(attr);
		  }
		}
	  }
	}

    list_of_mnt_lowers = g_list_concat(list_of_mnt_lowers, get_mnt_lowers(object));
    rpsl_object_delete(object);
  }

  return list_of_mnt_lowers;
}


/* Gets a linked list of object strings and returns the mnt-by attribs of
   them in a linked list */
GList *get_mntners_from_list(GList *objects_str)
{
  GList *objects_str_item = NULL;
  GList *list_of_mntners = NULL;
  const char *name = NULL;
  char *value = NULL;
  GList *attr;
  rpsl_object_t *object;
  
  for ( objects_str_item = objects_str; objects_str_item != NULL ; objects_str_item = g_list_next(objects_str_item) )
  {
	object = rpsl_object_init((char *)(objects_str_item->data));

	if (tracing)
	{
      if ( rpsl_object_has_error(object, RPSL_ERRLVL_ERROR) )
	  {
		/* thre was an error during the parsing */
		name = rpsl_object_get_class(object);
		if ( name )
		{
		  attr = rpsl_object_get_attr(object, name);
		  if ( attr )
		  {
		    value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
			if ( value )
			{
		      printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
			  free(value);
			}
			else
		      printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

			rpsl_attr_delete_list(attr);
		  }
		}
	  }
	}

    list_of_mntners = g_list_concat(list_of_mntners, get_mntners(object));
    rpsl_object_delete(object);
  }

  return list_of_mntners;
}



/* retrieves the override password from the 'override' attribute  
   of the object. If none, it returns NULL   */
char *get_override(rpsl_object_t * object)
{

  GList *attr_list;

  if(tracing)
  {
    printf("TRACING: get_override is running\n");
  }
  
  attr_list = rpsl_object_get_attr(object, "override");
  if ( ! attr_list )
  {
    /* there was no 'override' attrib, so return NULL */
    return NULL;
  }

  /* there should only be one item in this list, 
     return the clean value of that attribute */
  return strdup(rpsl_attr_get_value((rpsl_attr_t *)(attr_list->data)));
}



/* checks override string (password) 
   returns OVR_OK if it is correct password */
int check_override(char * string)
{
   char ** temp;
   int i;
   char * crypted_password = strdup(overridecryptedpw);

   if(string == NULL) 
   {
     if(tracing) 
	 {
       printf("TRACING: check_override is returning FAILED\n");
     }
	 free (crypted_password);
     return UP_OVF; /* override attempt failed */ 
   }
   else
   {
    /* split the string */
     temp = g_strsplit (string, " ", 0);

     for(i=0; temp[i] != NULL; i++)
	 {
       if(strlen(temp[i]) != 0)
	   {
         if(strcmp(AU_crypt(temp[i], crypted_password), crypted_password) == 0)
		 {
           if(tracing) 
		   {
             printf("TRACING: check_override is returning %s OK\n", string);
           }
           g_strfreev(temp);
		   free (crypted_password);
           return OVR_OK; 
         }
       }
     }

     /* we couldn't find a word matching the override password */ 
     g_strfreev(temp);         
	 free (crypted_password);
     return UP_OVF; /* override attempt failed */
   }
}




/* takes a GSList of struct auth_struct and a GList of auths, and a mntner/irt name,
   add new elements to GSList of struct auth_struct and  returns the new
   GSList of struct auth_struct  */

GSList * add_to_auth_vector(GSList * list_of_auth_struct, GList * auths, char * mntner_name)
{
   GList * auth_item;
   char * auth_attrib = NULL;
   char * auth_attrib_uppercase = NULL, * argument = NULL;
   auth_struct * temp = NULL;
   int index = 1;
   
   for (auth_item = auths; auth_item != NULL; auth_item = g_list_next(auth_item))
   {
     auth_attrib = rpsl_attr_get_clean_value((rpsl_attr_t *)(auth_item->data));
     if(tracing)
	 {
       printf("TRACING: add_to_auth_vector: %s\n", auth_attrib);
     }
     /* Take the auth attribute and convert it into uppercase for comparisons */
     auth_attrib_uppercase = strdup(auth_attrib);
     g_strup(auth_attrib_uppercase);
     
     if ( strstr(auth_attrib_uppercase,"CRYPT-PW") == auth_attrib_uppercase )
	 {
       /* take the argument of the auth attribute */
       argument = strdup(auth_attrib + strlen("CRYPT-PW"));
       g_strstrip(argument);
       if(tracing) 
	   {
         printf("TRACING: add_to_auth_vector: adding new CRYPT-PW argument: %s\n", argument);
       }
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_CRYPT_PW;
       temp->auth = argument;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       list_of_auth_struct = g_slist_append(list_of_auth_struct, temp);
     }
     else if ( strstr(auth_attrib_uppercase,"MD5-PW") == auth_attrib_uppercase )
	 {
       /* take the argument of the auth attribute */
       argument = strdup(auth_attrib + strlen("MD5-PW"));
       g_strstrip(argument);
       if(tracing) 
	   {
         printf("TRACING: add_to_auth_vector: adding new MD5-PW argument: %s\n", argument);
       }
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_MD5_PW;
       temp->auth = argument;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       list_of_auth_struct = g_slist_append(list_of_auth_struct, temp);
     }
	 else if (strstr(auth_attrib_uppercase,"MAIL-FROM") == auth_attrib_uppercase)
	 {
       /* take the argument of the auth attribute */
       argument = strdup(auth_attrib + strlen("MAIL-FROM"));
       g_strstrip(argument);
       if(tracing)
	   {
         printf("TRACING: add_to_auth_vector: adding new MAIL-FROM argument: %s\n", argument);
       }
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_MAIL_FROM;
       temp->auth = argument;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       list_of_auth_struct = g_slist_append(list_of_auth_struct, temp);
     }
	 else if (strstr(auth_attrib_uppercase,"NONE") == auth_attrib_uppercase)
	 {
       /* take the argument of the auth attribute */
       if(tracing)
	   {
         printf("TRACING: add_to_auth_vector: adding new NONE argument\n");
       }
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_NONE;
       temp->auth = NULL;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       list_of_auth_struct = g_slist_append(list_of_auth_struct, temp);
    }
	else if (strstr(auth_attrib_uppercase,"PGPKEY-") == auth_attrib_uppercase)
	{
       argument = strdup(auth_attrib + strlen("PGPKEY-"));
       g_strstrip(argument);
       if(tracing)
	   {
         printf("TRACING: add_to_auth_vector: adding new PGPKEY argument: %s\n", argument);
       }
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_PGP;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       temp->auth = argument;
       list_of_auth_struct = g_slist_append(list_of_auth_struct, temp);
     }
	 else
	 {
       if (tracing)
	   {
         printf("TRACING: Error: invalid auth attrib: %s\n", auth_attrib);
       }
       return NULL;
     }
 
     free(auth_attrib_uppercase);
     free(auth_attrib); 
   }

   return list_of_auth_struct;
}




/* Gets a list of mntner names, retrieves those mntners from
   the database and extracts the 'auth' attributes, and
   constructs the authorisation vector, which is a GSList of
   struct auth_struct */

GSList * get_auth_vector(GList * mntners)
{
  GList * list_of_auths = NULL;
  GList * mntner_item = NULL;
  GSList * to_be_returned = NULL;
  char * query_string = NULL, * result = NULL, * object_str = NULL;
  char *value;

  for( mntner_item = mntners; mntner_item != NULL ; mntner_item = g_list_next(mntner_item) )
  {
    value = rpsl_attr_get_clean_value((rpsl_attr_t *)(mntner_item->data));
    if(tracing) 
	{
      printf("=====\nget_auth_vector: Got a mntner\n%s\n", value  );
    }
    query_string = (char *)malloc(strlen("-Tmntner -s  -r ")+strlen(current_source)+strlen(value)+1);
    sprintf(query_string, "-Tmntner -s %s -r %s",current_source,value);
    result = send_and_get(query_host, query_port, query_string);
	free(query_string);
    if (count_objects(result) == 0)
	{
      /* no such maintainer */
      if(tracing)
	  {
        printf("get_auth_vector: No such maintainer %s\n", value);
      }
	  free(result);
	  free(value);
      return NULL;
    }
	else if (count_objects(result) > 1)
	{
      if(tracing)
	  {
        printf("get_auth_vector: More than one objects returned for %s\n", value);
      }
    }
	else
	{ /* count_objects(result) == 1 */
      object_str = take_object(result);
      if(tracing)
	  {
        printf("TRACING: get_auth_vector: Calling get_auths with object [\n%s]\n", object_str);
      }

      list_of_auths = get_auths(object_str);
      if(tracing)
	  {
        printf("TRACING: get_auth_vector: get_auths returned (with %d nodes)\n", g_list_length(list_of_auths)) ;
      }

      /* add this to the auth_vector. ( mntner_item->data->value is the name of the maintainer  ) */
      to_be_returned = add_to_auth_vector(to_be_returned, list_of_auths, (char *)value);
      if(tracing)
	  {
       printf("TRACING: get_auth_vector: to_be_returned has now %d nodes\n",  g_slist_length(to_be_returned));
      }
	  
	  rpsl_attr_delete_list(list_of_auths);
    }
	free(value);
	free(result);
  }
  
  if(tracing) 
  {  
    printf("TRACING: get_auth_vector: to_be_returned has %i nodes\n", g_slist_length(to_be_returned)); 
  }
  return to_be_returned; 
}



/* Gets a list of irt names, retrieves those irts from
   the database and extracts the 'auth' attributes, and
   constructs the authorisation vector, which is a GSList of
   struct auth_struct */

GSList * get_irt_auth_vector(GList * irts)
{
  GList * list_of_auths = NULL;
  GList * irt_item = NULL;
  GSList * to_be_returned = NULL;
  char * query_string = NULL, * result = NULL, * object_str = NULL;
  char *value;

  for( irt_item = irts; irt_item != NULL ; irt_item = g_list_next(irt_item) )
  {
    value = rpsl_attr_get_clean_value((rpsl_attr_t *)(irt_item->data));
    if(tracing) 
	{
      printf("=====\nget_irt_auth_vector: Got an irt\n%s\n", value  );
    }
    query_string = (char *)malloc(strlen("-Tirt -s  -r ")+strlen(current_source)+strlen(value)+1);
    sprintf(query_string, "-Tirt -s %s -r %s",current_source,value);
    result = send_and_get(query_host, query_port, query_string);
	free(query_string);
    if (count_objects(result) == 0)
	{
      /* no such irt */
      if(tracing)
	  {
        printf("get_irt_auth_vector: No such irt %s\n", value);
      }
	  free(result);
	  free(value);
      return NULL;
    }
	else if (count_objects(result) > 1)
	{
      if(tracing)
	  {
        printf("get_irt_auth_vector: More than one objects returned for %s\n", value);
      }
    }
	else
	{ /* count_objects(result) == 1 */
      object_str = take_object(result);
      if(tracing)
	  {
        printf("TRACING: get_irt_auth_vector: Calling get_auths with object [\n%s]\n", object_str);
      }

      list_of_auths = get_auths(object_str);
      if(tracing)
	  {
        printf("TRACING: get_irt_auth_vector: get_auths returned (with %d nodes)\n", g_list_length(list_of_auths)) ;
      }

      /* add this to the auth_vector. ( irt_item->data->value is the name of the irt  ) */
      to_be_returned = add_to_auth_vector(to_be_returned, list_of_auths, (char *)value);
      if(tracing)
	  {
       printf("TRACING: get_irt_auth_vector: to_be_returned has now %d nodes\n",  g_slist_length(to_be_returned));
      }
	  
	  rpsl_attr_delete_list(list_of_auths);
    }
	free(value);
	free(result);
  }
  
  if(tracing) 
  {  
    printf("TRACING: get_irt_auth_vector: to_be_returned has %i nodes\n", g_slist_length(to_be_returned)); 
  }
  return to_be_returned; 
}




/* Gets a list of mntner attributes, retrieves those mntners from
   the database and extracts the 'mnt-nfy' attributes, and
   returns them as a GList */

GList * get_mntnfy_vector(GList *mntners)
{
  GList * list_of_mntnfy = NULL;
  GList * mntner_item = NULL;
  GList * temp;
  const GList * error_list = NULL;
  char * query_string = NULL, * result = NULL, * object_str = NULL;
  char *value;
  rpsl_object_t *object;
  
  for ( mntner_item = mntners; mntner_item != NULL ; mntner_item = g_list_next(mntner_item) )
  {
	value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(mntner_item->data) );
    if (tracing)
	{
      printf( "=====\nGot a mntner\n%s\n", value );
    }
    query_string = (char *)malloc(strlen("-Tmntner -s  -r ")+strlen(current_source)+strlen(value)+1);
    sprintf(query_string, "-Tmntner -s %s -r %s", current_source,value);
    result = send_and_get(query_host, query_port, query_string);
	free(query_string);
    if (count_objects(result) == 0)
	{
      /* no such maintainer */
      if(tracing)
	  {
        printf("get_mntnfy_vector: No such maintainer %s\n", value);
      }
    }
	else if (count_objects(result) > 1)
	{
      if (tracing)
	  {
        printf("get_mntnfy_vector: More than one objects returned for maintainer %s\n", value);
      }
    }
	else
	{ /* count_objects(result) == 1 */
      object_str = take_object(result);
	  object = rpsl_object_init(object_str);
	  error_list = rpsl_object_errors(object);

      if (tracing)
	  {
        printf("TRACING: get_mntnfy_vector: Calling get_attr_list\n");
      }

      temp = get_attr_list(object, "mnt-nfy");

      if (tracing)
	  {
        printf("TRACING: get_mntnfy_vector: get_attr_list returned (with %i nodes)\n", g_list_length(temp));
      }

      list_of_mntnfy = g_list_concat(list_of_mntnfy, temp);

      if (tracing)
	  {
        printf("TRACING: get_mntnfy_vector: list_of_mntnfy has now %i nodes\n", g_list_length(list_of_mntnfy));
      }
      rpsl_object_delete(object);
    }
	free(value);
	free(result);
  }
  
  if (tracing)
  {  
    printf("TRACING: get_mntnfy_vector: list_of_mntnfy has %i nodes\n", g_list_length(list_of_mntnfy)); 
  }
  return list_of_mntnfy; 
}




/* Gets a list of irt attributes, retrieves those irts from
   the database and extracts the 'irt-nfy' attributes, and
   returns them as a GList */

GList * get_irtnfy_vector(GList *irts)
{
  GList * list_of_irtnfy = NULL;
  GList * irt_item = NULL;
  GList * temp;
  const GList * error_list = NULL;
  char * query_string = NULL, * result = NULL, * object_str = NULL;
  char *value;
  rpsl_object_t *object;
  
  for ( irt_item = irts; irt_item != NULL ; irt_item = g_list_next(irt_item) )
  {
	value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(irt_item->data) );
    if (tracing)
	{
      printf( "=====\nGot a irt\n%s\n", value );
    }
    query_string = (char *)malloc(strlen("-Tirt -s  -r ")+strlen(current_source)+strlen(value)+1);
    sprintf(query_string, "-Tirt -s %s -r %s", current_source,value);
    result = send_and_get(query_host, query_port, query_string);
	free(query_string);
    if (count_objects(result) == 0)
	{
      /* no such irt */
      if(tracing)
	  {
        printf("get_irtnfy_vector: No such irt %s\n", value);
      }
    }
	else if (count_objects(result) > 1)
	{
      if (tracing)
	  {
        printf("get_irtnfy_vector: More than one objects returned for irt %s\n", value);
      }
    }
	else
	{ /* count_objects(result) == 1 */
      object_str = take_object(result);
	  object = rpsl_object_init(object_str);
	  error_list = rpsl_object_errors(object);

      if (tracing)
	  {
        printf("TRACING: get_irtnfy_vector: Calling get_attr_list\n");
      }

      temp = get_attr_list(object, "irt-nfy");

      if (tracing)
	  {
        printf("TRACING: get_irtnfy_vector: get_attr_list returned (with %i nodes)\n", g_list_length(temp));
      }

      list_of_irtnfy = g_list_concat(list_of_irtnfy, temp);

      if (tracing)
	  {
        printf("TRACING: get_irtnfy_vector: list_of_irtnfy has now %i nodes\n", g_list_length(list_of_irtnfy));
      }
      rpsl_object_delete(object);
    }
	free(value);
	free(result);
  }
  
  if (tracing)
  {  
    printf("TRACING: get_irtnfy_vector: list_of_irtnfy has %i nodes\n", g_list_length(list_of_irtnfy)); 
  }
  return list_of_irtnfy; 
}



/* Gets a list of mntner names, retrieves those mntners from
   the database and extracts the 'upd-to' attributes, and
   returns them as a GList */

GList * get_updto_vector(GList * mntners)
{
  GList * list_of_updto = NULL;
  GList * mntner_item = NULL;
  char * query_string = NULL, * result = NULL, * object_str = NULL;
  GList * temp;
  const GList * error_list = NULL;
  char *value;
  rpsl_object_t *object;
  
  for ( mntner_item = mntners; mntner_item != NULL ; mntner_item = g_list_next(mntner_item) )
  {
	value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(mntner_item->data) );
    if (tracing)
	{
      printf( "=====\nGot a mntner\n%s\n", value );
    }
    query_string = (char *)malloc(strlen("-Tmntner -s  -r ")+strlen(current_source)+strlen(value)+1);
    sprintf(query_string, "-Tmntner -s %s -r %s", current_source,value);
    result = send_and_get(query_host, query_port, query_string);
    if (count_objects(result) == 0)
	{
      /* no such maintainer */
      if(tracing)
	  {
        printf("get_updto_vector: No such maintainer %s\n", value);
      }
    }
	else if(count_objects(result) > 1)
	{
      if (tracing)
	  {
        printf("get_updto_vector: More than one objects returned for maintainer %s\n", value);
      }
    }
	else
	{ /* count_objects(result) == 1 */
      object_str = take_object(result);
	  object = rpsl_object_init(object_str);
	  error_list = rpsl_object_errors(object);

      if (tracing)
	  {
        printf("TRACING: get_updto_vector: Calling get_attr_list\n");
      }

      temp = get_attr_list(object, "upd-to");

      if (tracing)
	  {
        printf("TRACING: get_updto_vector: get_attr_list returned (with %i nodes)\n", g_list_length(temp));
      }

      list_of_updto = g_list_concat(list_of_updto, temp);

      if (tracing)
	  {
        printf("TRACING: get_updto_vector: list_of_mntnfy has now %i nodes\n",  g_list_length(list_of_updto));
      }
      rpsl_object_delete(object);
    }
	free(value);
	free(result);
  }
  
  if (tracing)
  {  
    printf("TRACING: get_updto_vector: list_of_updto has %i nodes\n", g_list_length(list_of_updto)); 
  }
  return list_of_updto; 
}




/* gets one or more route objects filters out the ones which don't have the same
   origin as 'char * origin' argument */
char * up_filter_out_diff_origins(char * objects_str, char * origin)
{
  GList * object_str_list = NULL, * object_str_item =NULL;
  const GList *error_list = NULL; 
  char * objects_to_be_returned = NULL;
  char * key = NULL;
  rpsl_object_t *object;
  
  if (tracing) 
  {
    printf("TRACING: up_filter_out_diff_origins\n");
  }

  /* strip the lines beginning with '%' off */
  objects_str = strip_lines(objects_str);
  
  /* separate the objects, store them in a linked list */
  object_str_list = take_objects(objects_str);

  for (object_str_item = object_str_list; object_str_item != NULL; object_str_item = g_list_next(object_str_item))
  {
    object = rpsl_object_init((char *)(object_str_item->data));
	error_list = rpsl_object_errors(object);
    key = get_search_key(object, "origin");
    if (key != NULL && strcasecmp(g_strstrip(origin), key) == 0)
	{
      if (objects_to_be_returned == NULL)
	  {
        objects_to_be_returned = strdup((char *)(object_str_item->data));
      }
	  else
	  {
        objects_to_be_returned = (char *)realloc(objects_to_be_returned, 
                      strlen(objects_to_be_returned) + strlen((char *)(object_str_item->data)) + 2);
        objects_to_be_returned = strcat(objects_to_be_returned, "\n");
        objects_to_be_returned = strcat(objects_to_be_returned, (char *)(object_str_item->data));
      }
    }
    rpsl_object_delete(object);
	free(key);
  }

  if(tracing) 
  {
      printf("TRACING: up_filter_out_diff_origins: returning:\n%s\n", objects_to_be_returned ? objects_to_be_returned : "(NULL)");
  }
  
  return objects_to_be_returned; 
}



/* gets one or more person/role objects filters out the ones which don't have the same
   nic_hdl as 'char * nic_hdl' argument */
char * up_filter_out_diff_nichdls(char * objects_str, char * nic_hdl)
{
  GList * object_str_list = NULL, * object_str_item =NULL;
  char * objects_to_be_returned = NULL;
  char * key = NULL;
  rpsl_object_t *object;
  
  if (tracing)
  {
    printf("TRACING: up_filter_out_diff_nichdls\n");
  }

  /* strip the lines beginning with '%' off */
  objects_str = strip_lines(objects_str);
  
  /* separate the objects strings, store them in a linked list */
  object_str_list = take_objects(objects_str);

  for (object_str_item = object_str_list; object_str_item != NULL; object_str_item = g_list_next(object_str_item))
  {
    object = rpsl_object_init((char *)(object_str_item->data));
    key = get_search_key(object, "nic-hdl");
    if (key != NULL && strcasecmp(g_strstrip(nic_hdl), key) == 0)
	{
      if (objects_to_be_returned == NULL)
	  {
        objects_to_be_returned = strdup((char *)(object_str_item->data));
      }
	  else
	  {
        objects_to_be_returned = (char *)realloc(objects_to_be_returned, 
                      strlen(objects_to_be_returned) + strlen((char *)(object_str_item->data)) + 2);
        objects_to_be_returned = strcat(objects_to_be_returned, "\n");
        objects_to_be_returned = strcat(objects_to_be_returned, (char *)(object_str_item->data));
      }
    }
    rpsl_object_delete(object);
  }

  if(tracing)
  {
      printf("TRACING: up_filter_out_diff_nichdls: returning:\n%s\n", objects_to_be_returned ? objects_to_be_returned :"(NULL)");
  }

  return objects_to_be_returned; 
}



/* gets one or more route objects, filters out the ones which have the same
   origin as 'char * origin' argument */
char * UP_filter_out_same_origins(char * objects_str, rpsl_object_t * object)
{
  GList * object_list = NULL, * object_item =NULL;
  const GList *error_list = NULL; 
  char * objects_to_be_returned = NULL;
  char * key = NULL;
  rpsl_object_t  *obj;
  char * origin;
    
  if (tracing)
  {
    printf("TRACING: UP_filter_out_same_origins\n");
  }

  origin = get_search_key(object, "origin");

  /* strip the lines beginning with '%' off */
  objects_str = strip_lines(objects_str);
  
  /* separate the objects, store them in a linked list */
  object_list = take_objects(objects_str);

  for (object_item = object_list; object_item != NULL; object_item = g_list_next(object_item))
  {
    obj = rpsl_object_init((char *)(object_item->data));
	error_list = rpsl_object_errors(obj);

    key = get_search_key(obj, "origin");
    if (key != NULL && strcasecmp(g_strstrip(origin), key) != 0)
	{
      if (objects_to_be_returned == NULL)
	  {
        objects_to_be_returned = strdup((char *)(object_item->data));
      }
	  else
	  {
        objects_to_be_returned = (char *)realloc(objects_to_be_returned, 
                      strlen(objects_to_be_returned) + strlen((char *)(object_item->data)) + 2);
        objects_to_be_returned = strcat(objects_to_be_returned, "\n");
        objects_to_be_returned = strcat(objects_to_be_returned, (char *)(object_item->data));
      }
    }
	rpsl_object_delete(obj);
  }

  if (tracing)
  {
      printf("TRACING: up_filter_out_same_origins: returning:\n%s\n", objects_to_be_returned ? objects_to_be_returned : "(NULL)");
  }

  return objects_to_be_returned; 
}



/* If the status is ALLOCATED PI or ALLOCATED PA (inetnum) 
   or ALLOCATED-BY-RIR (inet6num)
   only valid if the maintainers in the mnt-by attributes contain 
   at least one of the names mentioned in ALLOCMNT config variable. 
   Receives an object as a parsed object
            the type (inetnum or inet6num)
            the new status value
   Returns UP_AUTH_OK if the status/mnt-by combination is valid
           UP_AUF     if the status/mnt-by combination is not valid
*/
int up_check_reserved_status(rpsl_object_t *object, const char *type, char *new_status)
{
  GList * mnt_by_list = NULL;
  GList *item;

  char *status;
  char *mnt_by;
  char **allocmnt_list;
  int i;

  /* Gather a list of mnt-by attributes */
  mnt_by_list = rpsl_object_get_attr(object, "mnt-by");
  rpsl_attr_split_multiple(&mnt_by_list);

  status = strdup(new_status);
  g_strdown(status);
 
  /* construct a list of mntners that are in allocmnt */
  allocmnt_list = g_strsplit(allocmnt, " ", 0); /* delimited by " " */
   
  if ( (! strcmp(type, "inetnum") && strstr(status, "allocated") != NULL)
      || (! strcmp(type, "inet6num") && strstr(status, "allocated-by-rir") != NULL) )
  { 
    free(status);
    
    for ( item = mnt_by_list; item != NULL ; item = g_list_next(item) )
	{
      mnt_by = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
      for (i=0; allocmnt_list[i] != NULL; i++)
	  { 
        /* loop thru the list of allocmnt maintainers */
        if ((strlen(allocmnt_list[i]) != 0) && strcasecmp(mnt_by, allocmnt_list[i]) == 0)
		{
          /* this mnt-by is in the allocmnt list */
          free(mnt_by);
          g_strfreev(allocmnt_list);
          rpsl_attr_delete_list(mnt_by_list);
          return UP_AUTH_OK; 
        }
      }  
      free(mnt_by);
    }
    
    g_strfreev(allocmnt_list);
    rpsl_attr_delete_list(mnt_by_list);
    
    /* none of the mnt-by are in the allocmnt list */
    return UP_AUF;
  }
  else
  {  /* the status attribute is not a reserved category */
    free(status);
    g_strfreev(allocmnt_list);
    rpsl_attr_delete_list(mnt_by_list);

    return UP_AUTH_OK;
  }
}




/*  Get the value of the status of an inet(6)num object 
    Receives an object as a parsed object
    Returns the status value or NULL if none found
*/

char * up_get_status(rpsl_object_t *object)
{
   GList *status_attrs;
   char *status;

   status_attrs = rpsl_object_get_attr(object, "status");
   if ( status_attrs != NULL )
   {
     status = rpsl_attr_get_clean_value((rpsl_attr_t *)(status_attrs->data));
     rpsl_attr_delete_list(status_attrs);
     return status;
   }
   else
     return NULL;
}



/*  Get the value of the status of the more/less specific object for an inet(6)num object 
    Receives an object as a parsed object
             the type (inetnum or inet6num)
             address of the status value pointer
             flag (-m or -l)
    Returns NULL   if there is no more/less specific inet(6)num object
            1 if there is a more/less specific inet(6)num object
            status value (or NULL if none found) set in the address
*/

int up_get_specific_status(rpsl_object_t *object, const char *type, char **status, char *flag)
{
   const GList *error_list = NULL;
   char *specific_object_str = NULL;

   rpsl_object_t *specific_obj = NULL;

   /* get the one more/less specific inet(6)num object */
   specific_object_str = get_specific(object, type, flag);
   if (specific_object_str == NULL)
   {
     /* there is no more/less specific inet(6)num object */
     if (tracing)
     {
       printf("TRACING: up_get_specific_status: no %s inet(6)num object found\n", flag);
     }
   
     *status = NULL;
     return NULL;
   }
   specific_obj = rpsl_object_init(specific_object_str);
   error_list = rpsl_object_errors(specific_obj);
   free (specific_object_str);

   /* get the status of the more/less specific object */
   *status = up_get_status(specific_obj);
   rpsl_object_delete(specific_obj);

   if (tracing)
   {
     printf("TRACING: up_get_specific_status: %s specific_status [%s] \n",
                  flag, *status ? *status : "NONE");
   }
   
   return 1;
}

/*  Find if the inet(6)num object has any more specific objects 
    Receives an object as a parsed object
             the type (inetnum or inet6num)
    Returns NULL   if there is no more specific inet(6)num object
            1 if there is a more specific inet(6)num object
*/

int up_find_more_specific(rpsl_object_t *object, const char *type)
{
   char *more_specific_object_str = NULL;

   /* get the one more specific inet(6)num object */
   more_specific_object_str = get_specific(object, type, "-m");
   if (more_specific_object_str == NULL)
     return NULL;
   else
   {
     /* there is a more specific inet(6)num object */
     if (tracing)
     {
       printf("TRACING: up_get_more_specific_status: more specific inet(6)num object found\n");
     }
   
     return 1;
   }
}


/* check the new status and less specific status according to the defined rules for inetnum
   Receives an object as a parsed object
            the new status
            the less specific status
            flag for existance of less specific object 
                (NULL - does not exist, not NULL - does exist)
            the override value
   Returns standard auth return codes:
           UP_AUTH_OK         if all the status checks are OK
           UP_HOF or UP_AUF   if any of the status checks fail
*/

int up_check_inetnum_status_rules(rpsl_object_t *object, char *new_status, char *less_specific_status, int ls_obj_exists, int overriden)
{
  int result;

  if ( ! ls_obj_exists )
  {
     /* there is no less specific inetnum object */
     if (overriden)
     {
       /* override the status check when no less specific object found */
       return UP_AUTH_OK; 
     }
     else
     {
       return UP_HOF; /* hierarchical authorisation failed */
     }
  }

  if ( ! less_specific_status )
  {
    /* the less specific object exists but has no status value */
    return UP_HOF; /* hierarchical authorisation failed */
  }
  
  /* check if the status/mnt-by combination is valid */
  result = up_check_reserved_status(object, "inetnum", new_status);
  if ( result != UP_AUTH_OK)
    return result;

  /* now check the relative status values */
  if ( ! strcmp(new_status, "LIR-PARTITIONED PA") || ! strcmp(new_status, "LIR-PARTITIONED PI") )
  {
    if ( 
	     ( (! strcmp(new_status, "LIR-PARTITIONED PA")) && strcmp(less_specific_status, "ALLOCATED PA") && strcmp(less_specific_status, "LIR-PARTITIONED PA") && strcmp(less_specific_status, "ALLOCATED UNSPECIFIED") )
	   || 
	     ( (! strcmp(new_status, "LIR-PARTITIONED PI")) && strcmp(less_specific_status, "ALLOCATED PI") && strcmp(less_specific_status, "LIR-PARTITIONED PI") && strcmp(less_specific_status, "ALLOCATED UNSPECIFIED") ) 
	   )
    {
	  return UP_HOF; /* hierarchical authorisation failed */
    }
  }
  
  /* all check passed */
  return UP_AUTH_OK;
}


/* check the new status and less specific status according to the defined rules for inet6num
   Receives an object as a parsed object
            the new status
            the less specific status
            the more specific status
            flag for existance of less specific object 
                (NULL - does not exist, not NULL - does exist)
            flag for existance of more specific object 
            the override value
   Returns standard auth return codes:
           UP_AUTH_OK         if all the status checks are OK
           UP_HOF or UP_AUF   if the any of status checks fail
*/

int up_check_inet6num_status_rules(rpsl_object_t *object, char *new_status, char *less_specific_status, char *more_specific_status, int ls_obj_exists, int ms_obj_exists, int overriden)
{
  int result;

  if (tracing)
  {
    printf("TRACING: up_check_inet6num_status_rules:\n");
    printf("    new_status [%s] less_specific_status [%s] more_specific_status [%s]\n", 
                   new_status, less_specific_status ? less_specific_status : "NONE", 
                   more_specific_status ? more_specific_status : "NONE");
    printf("    ls_obj_exists [%d] ms_obj_exists [%d] overriden [%d]\n", 
                   ls_obj_exists, ms_obj_exists, overriden);
  }

  if ( ! ls_obj_exists )
  {
     /* there is no less specific inet6num object */
     if (overriden)
     {
       /* override the status check when no less specific object found */
       return UP_AUTH_OK; 
     }
     else
     {
       return UP_HOF; /* hierarchical authorisation failed */
     }
  }

  if ( ! less_specific_status )
  {
    /* the less specific object has no status value */
    return UP_HOF; /* hierarchical authorisation failed */
  }

  if ( strcasecmp(less_specific_status, "ALLOCATED-BY-RIR") 
    && strcasecmp(less_specific_status, "ALLOCATED-BY-LIR") 
    && strcasecmp(less_specific_status, "ASSIGNED") )
  {
    /* the less specific inet6num status is not recognised */
	return UP_HOF; /* hierarchical authorisation failed */
  }
  
  /* check if the status/mnt-by combination is valid */
  result = up_check_reserved_status(object, "inet6num", new_status);
  if ( result != UP_AUTH_OK)
    return result;

  /* check the relative status rules */
  if ( ! strcasecmp(new_status, "ASSIGNED") || ! strcasecmp(new_status, "ALLOCATED-BY-LIR") )
  {
    /* less specific status must be ALLOCATED-BY-LIR or ALLOCATED-BY-RIR */
    if ( strcasecmp(less_specific_status, "ALLOCATED-BY-RIR")
      && strcasecmp(less_specific_status, "ALLOCATED-BY-LIR") )
    {
      /* invalid status */
	  return UP_HOF; /* hierarchical authorisation failed */
    }
  }

  if ( ! strcasecmp(new_status, "ASSIGNED") && ms_obj_exists )
  {
    /* invalid status */
	return UP_HOF; /* hierarchical authorisation failed */
  }
  
  return UP_AUTH_OK;
}


/*  Check the status value of an inet(6)num object against the hierarchical rules.
    Receives the new object and old (or NULL if creation) object as parsed objects.
             the type (inetnum or inet6num)
             the override value
    Returns standard auth return codes:
            UP_AUTH_OK if the status checks are OK
            UP_HOF     if the status checks fail
*/

int up_check_status(rpsl_object_t *new_object, rpsl_object_t *old_object, const char *type, int overriden)
{
  rpsl_object_t *object;
  const GList *error_list = NULL;
  char *old_status = NULL;
  char *new_status = NULL;
  char *less_specific_status = NULL;
  char *more_specific_status = NULL;
  int result = NULL;
  int ls_obj_exists = NULL;
  int ms_obj_exists = NULL;
  int update = NULL;

  if (tracing)
  {
    printf("TRACING: up_check_status running\n");
  }

  if ( new_object != NULL && old_object == NULL )
  {
    /* this is a creation */
    update = NULL;
    object = new_object;
  }
  else if ( new_object != NULL && old_object != NULL )
  {
    /* this is an update */
    update = 1;
    object = old_object;
  }
  else
  {
    /* this is a deletion, no status checks required */
    return UP_AUTH_OK;
  }

  /* get the status of the new inetnum object */
  new_status = up_get_status(new_object);
  if ( ! new_status )
  {
    die;  /* should not happen, syntax error should already have been trapped */
  }

  if ( update )
  {
    /* get the status of the old inetnum object */
    old_status = up_get_status(old_object);
    if ( ! old_status )
    {
	  old_status = strdup("");  /* to allow for legacy objects with no status */
    }
  }

  if (tracing)
  {
    printf("TRACING: check_status: old_status [%s] new status [%s]\n",
                  update ? old_status : "N/A", new_status );
  }

  if ( ! update || strcmp(new_status, old_status) )
  {
    /* this is a creation or
       it is an update and the status has changed, 
       make sure the new value is allowed */

    /* get the status of the less specific and more specific objects */
    ls_obj_exists = up_get_specific_status(object, type, &less_specific_status, "-l");
    ms_obj_exists = up_get_specific_status(object, type, &more_specific_status, "-m");

    if ( ! strcmp(type, "inetnum") )
      result = up_check_inetnum_status_rules(object, new_status, less_specific_status, ls_obj_exists, overriden);
    else
      result = up_check_inet6num_status_rules(object, new_status, less_specific_status, more_specific_status, ls_obj_exists, ms_obj_exists, overriden);

    if ( less_specific_status )
      free(less_specific_status);
    if ( old_status )
	  free (old_status);
    free (new_status);

    return result;
  }
  else
  {
    /* update with no change in status, so no checks required */
    return UP_AUTH_OK;
  }
}


/* Check authorisation
   Applies authorisation rules according to the object type 
   
   Arguments:
      char *new_object: the new object,
      char *old_object: the old object, as found in the database,
      char *type: type of the object
      credentials_struct credentials: a struct which
        contains credentials of the update, such as 'From:' field of
        the e-mail header and passwords in the update   */

int check_auth(rpsl_object_t *new_object, rpsl_object_t *old_object, const char *type, credentials_struct credentials)
{
   GList *old_mntners = NULL, *new_mntners = NULL;
   GList *old_irts = NULL, *new_irts = NULL;
   GList *changed_irts = NULL; 
   GList *as_block_mnt_lowers = NULL;
   GSList *old_auth_vector = NULL, *new_auth_vector = NULL;
   GSList *changed_auth_vector = NULL;
   GSList *as_block_auth_vector = NULL;
   GSList *less_specific_auth_vector = NULL;
   GList *less_specific_mnt_lowers = NULL;
   GList *less_specific_mntners = NULL;
   GList *aut_num_maintainers = NULL;
   GSList *aut_num_auth_vector = NULL;
   GList *exact_match_routes_str = NULL;  
   GList *exact_match_routes_maintainers = NULL;
   GSList *exact_match_routes_auth_vector = NULL;
   GList *exact_match_maintainers = NULL;
   GSList *exact_match_auth_vector = NULL;
   GList *less_spec_routes_str = NULL;
   GList *less_spec_routes_mntners = NULL;
   GSList *less_spec_routes_auth_vector = NULL;
   GList *exact_match_inetnum_mnt_routes = NULL;
   GSList *exact_match_inetnum_auth_vector = NULL;
   GList *less_spec_inetnum_mntners = NULL;
   GSList *less_spec_inetnum_auth_vector = NULL;
   GList *less_spec_inetnum_mnt_bys = NULL;
   GList *exact_match_inetnum_mnt_bys;

   GList *old_name = NULL;
   GList *new_name = NULL;
   GList *attr;
   const GList *error_list = NULL;
   GList *status_attrs;

   char *less_specific_status;
   char *old_status;
   char *new_status;
   int status_result;
   char *as_block_object_str = NULL;
   char *less_specific_object_str = NULL;
   char *less_specific_domain_str = NULL;
   char *less_spec_inetnum_str = NULL;
   char *exact_match_inetnum_str = NULL;
   const char *less_specific_object_type = NULL;
   char *override_string = NULL;
   char *set_name = NULL;
   char * aut_num_object_str = NULL;
   char * name_old = NULL;
   char * name_new = NULL;
   const char *name;
   int aut_num_auth_OK = FALSE;

   int auth_return, saved_auth_return;
   char *value;

   rpsl_object_t *as_block_obj = NULL;
   rpsl_object_t *less_specific_obj = NULL;
   rpsl_object_t *less_specific_domain_obj = NULL;
   rpsl_object_t *aut_num_obj = NULL;
   rpsl_object_t *exact_match_inetnum_obj = NULL;
   rpsl_object_t *less_spec_inetnum_obj = NULL;

   int overriden = 0;
   
   if (tracing)
   {                                
	 printf("TRACING: check_auth is running with object type [%s]\n", type);
   }

   /* first check if it is overriden or not. if overriden, check the override
      password. If it is correct, continue, setting "overriden" to 1. If not,   
      immediately exit returning ERR_UP_OVF                                   */
   override_string = get_override((new_object == NULL) ? old_object : new_object );
   if(override_string == NULL)
   { 
	 if (tracing)
	 {                                
	   printf("TRACING: overriden not set\n");
	 }
     overriden = 0;
   }
   else if ( check_override(override_string) == OVR_OK )
   {
	 if (tracing)
	 {                                
	   printf("TRACING: overriden set\n");
	 }
     overriden = 1; /* authorisation is overriden */
     free(override_string);
	 override_string = NULL;
   }
   else
   {
	 if (tracing)
	 {                                
	   printf("TRACING: override failed\n");
	 }
     free(override_string);
	 override_string = NULL;
     return UP_OVF; /* override failed! */
   }


   /*  
    *  Handle the "person", "role", "limerick", "inet-rtr", "key-cert" types 
    */
   if(strcmp(type,"person")   == 0 || strcmp(type,"role")     == 0 ||
      strcmp(type,"limerick") == 0 || strcmp(type,"inet-rtr") == 0 ||
      strcmp(type,"key-cert") == 0 )
   {
     if( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
       if (old_auth_vector)
	     g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
       new_mntners = get_mntners(new_object);
       new_auth_vector = get_auth_vector(new_mntners);
       if(new_mntners != NULL && new_auth_vector == NULL)
	   {
         /* then, the mntners in 'new_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(new_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(new_auth_vector, credentials, overriden);
	   if (new_auth_vector)
	     g_slist_free(new_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       /* check name change of person/role */
       if ( strcmp(type,"person") == 0 || strcmp(type,"role") == 0 )
	   {
         old_name = get_attr_list(old_object, type);
         new_name = get_attr_list(new_object, type);

         if(old_name != NULL && new_name != NULL
             && g_list_nth(old_name, 0) != NULL && g_list_nth(new_name, 0) != NULL
             && (g_list_nth(old_name, 0)->data) != NULL
             && (g_list_nth(new_name, 0)->data) != NULL)
         {

           name_old = rpsl_attr_get_clean_value((rpsl_attr_t *)(g_list_nth(old_name, 0)->data));
           name_new = rpsl_attr_get_clean_value((rpsl_attr_t *)(g_list_nth(new_name, 0)->data));
		   rpsl_attr_delete_list(old_name);
		   rpsl_attr_delete_list(new_name);

           if ( strcmp(name_old, name_new) )
		   {
             free(name_old); free(name_new);
             return UP_NAM; /* name of a person/role object can't be changed */
           }
           free(name_old);free(name_new);
         }
		 else
		 {
		   rpsl_attr_delete_list(old_name);
		   rpsl_attr_delete_list(new_name);
           return UP_INT; /* there was a problem with obtaining the name of person obj */
         }
       }
      
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }
   }

   /*  
    *  Handle the "aut-num" type 
    */
   else if (strcmp(type,"aut-num")  == 0 )
   {
     if ( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
       as_block_object_str = get_as_block(new_object);
       if (as_block_object_str == NULL )
	   {
         return UP_ABN; /* As-block does not exist */
       } 
	   else
	   {
	     as_block_obj = rpsl_object_init(as_block_object_str);
		 if (tracing)
		 {
    	   if ( rpsl_object_has_error(as_block_obj, RPSL_ERRLVL_ERROR) )
		   {
			 /* thre was an error during the parsing */
			 name = rpsl_object_get_class(as_block_obj);
			 if ( name )
			 {
			   attr = rpsl_object_get_attr(as_block_obj, name);
			   if ( attr )
			   {
		    	 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
				 if ( value )
				 {
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing as_block object %s\n", value );
				   free(value);
				 }
				 else
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing as_block object\n");

				 rpsl_attr_delete_list(attr);
			   }
			 }
		   }
		 }

         as_block_mnt_lowers = get_mnt_lowers(as_block_obj);
         as_block_auth_vector = get_auth_vector(as_block_mnt_lowers);
		 rpsl_object_delete(as_block_obj);
         if (as_block_mnt_lowers != NULL && as_block_auth_vector == NULL)
		 {
           /* then, the mntners in 'as_block_mnt_lowers' do not exist. Problem. */
		   rpsl_attr_delete_list(as_block_mnt_lowers);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(as_block_auth_vector, credentials, overriden);
         if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
		 {
           saved_auth_return = auth_return;
           new_mntners = get_mntners(new_object);
           new_auth_vector = get_auth_vector(new_mntners);
           if(new_mntners != NULL && new_auth_vector == NULL)
		   {
             /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		     rpsl_attr_delete_list(new_mntners);
             return UP_AUF; /* auth failed */
           }
           auth_return = authorise(new_auth_vector, credentials, overriden);
		   if (new_auth_vector)
	         g_slist_free(new_auth_vector);
           if ( auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
             return UP_OKM;
           else
             return auth_return;
         }
		 else
		 {
           return UP_HOF; /* hierarchical auth failed */
         }
       }
     }
	 else if( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
           g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if(tracing) 
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         } 
         return UP_INT; /* internal error */
     }
   } 

   /*  
    *  Handle the "mntner/as-block/irt" types 
    */
   else if (strcmp(type,"mntner")  == 0 || strcmp(type,"as-block")  == 0 || strcmp(type,"irt")  == 0 )
   {
     if ( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
       if (overriden || test_mode)
	   {
         return UP_AUTH_OK; 
       }
	   else
	   { /* If not overriden, must be forwarded to <HUMAILBOX> */
         if (tracing) 
		 {
           printf("TRACING: check_auth: '%s' creation requested\n", type);
         }
         return UP_FWD; /* must be forwarded to <HUMAILBOX> */
       }
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }
   }

   /*  
    *  Handle the "inetnum/inet6num" types 
    */
   else if (strcmp(type,"inetnum")  == 0 || strcmp(type,"inet6num")  == 0 )
   {
     if ( new_object == NULL && old_object != NULL )
	 { 
       /* the object is to be deleted */
       /* dont check for mnt-irt on deletion */

       /******* status check **********/
       status_result = up_check_status(new_object, old_object, type, overriden);
       if ( status_result != UP_AUTH_OK )
         return status_result;
       
       /******* mntner check **********/
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { 
       /* the object is to be created */
       /******* irt check **********/
	   /* if an object is created with an mnt-irt attribute, then it must 
          pass the authorisation for the mnt-irt */
       new_irts = get_irts(new_object);
       new_auth_vector = get_irt_auth_vector(new_irts);
       if (new_irts != NULL && new_auth_vector == NULL)
	   {
         /* then, the irts in 'new_irts' do not exist. Problem. */
		 rpsl_attr_delete_list(new_irts);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(new_auth_vector, credentials, overriden);
	   if (new_auth_vector)
  	     g_slist_free(new_auth_vector);
       rpsl_attr_delete_list(new_irts);
	   if ( auth_return == UP_AUF || auth_return == UP_MFF || auth_return == UP_MIX )
	   {
	     return UP_HOF; /* hierarchical authorisation failed */
	   }

       /* get the one less specific inet(6)num object */
       less_specific_object_str = get_specific(new_object, type, "-l");
       if (less_specific_object_str == NULL)
	   {
         /* there is no less specific object, fail if not overriden */
         if ( ! overriden )
		 {
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }
	   else
	   { /* we got a less specific inet(6)num object */
	     less_specific_obj = rpsl_object_init(less_specific_object_str);
	     error_list = rpsl_object_errors(less_specific_obj);
		 if (tracing)
		 {
    	   if ( rpsl_object_has_error(less_specific_obj, RPSL_ERRLVL_ERROR) )
		   {
			 /* thre was an error during the parsing */
			 name = rpsl_object_get_class(less_specific_obj);
			 if ( name )
			 {
			   attr = rpsl_object_get_attr(less_specific_obj, name);
			   if ( attr )
			   {
		    	 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
				 if ( value )
				 {
		    	   printf("TRACING: check_auth: error parsing object %s\n", value );
				   free(value);
				 }
				 else
		    	   printf("TRACING: check_auth: error parsing object\n");

				 rpsl_attr_delete_list(attr);
			   }
			 }
		   }
		 }

         /******* status check **********/
         status_result = up_check_status(new_object, old_object, type, overriden);
         if ( status_result != UP_AUTH_OK )
         {
		   rpsl_object_delete(less_specific_obj);
           return status_result;
         }

         /******* less_specific check **********/
         less_specific_mnt_lowers = get_mnt_lowers(less_specific_obj);
         less_specific_auth_vector = get_auth_vector(less_specific_mnt_lowers);
		 rpsl_object_delete(less_specific_obj);

         if (less_specific_mnt_lowers != NULL && less_specific_auth_vector == NULL)
		 {
           /* then, the mntners in 'less_specific_mnt_lowers' do not exist. Problem. */
		   rpsl_attr_delete_list(less_specific_mnt_lowers);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(less_specific_auth_vector, credentials, overriden);
         if (less_specific_auth_vector != NULL)
         {
		   g_slist_free(less_specific_auth_vector);
         }
         if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
		 {
           /******* mntner check **********/
           new_mntners = get_mntners(new_object);
           new_auth_vector = get_auth_vector(new_mntners);
           if (new_mntners != NULL && new_auth_vector == NULL)
		   {
             /* then, the mntners in 'new_mntners' do not exist. Problem. */
		     rpsl_attr_delete_list(new_mntners);
             return UP_AUF; /* auth failed */
           }
           auth_return = authorise(new_auth_vector, credentials, overriden);
		   if (new_auth_vector)
  	         g_slist_free(new_auth_vector);
	       return auth_return;
         }
		 else
		 {
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { 
       /* this is an update */
       /******* status check **********/
       status_result = up_check_status(new_object, old_object, type, overriden);
       if ( status_result != UP_AUTH_OK )
         return status_result;

       /******* irt check **********/
	   /* check for mnt-irt in both old and new object */
       /* it only needs to pass the authorisation of an mnt-irt when the
          mnt-irt is first added to the object */
       old_irts = get_irts(old_object);
       new_irts = get_irts(new_object);
       /* find irts that have just been added to this object */
       changed_irts = NT_compare_lists(old_irts, new_irts, 2);  /* 2 means 'just added' */
       
       changed_auth_vector = get_irt_auth_vector(changed_irts);
       if (changed_irts != NULL && changed_auth_vector == NULL)
	   {
         /* then, the irts in 'changed_irts' do not exist. Problem. */
         rpsl_attr_delete_list(old_irts);
         rpsl_attr_delete_list(new_irts);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(changed_auth_vector, credentials, overriden);
	   g_slist_free(changed_auth_vector);
       rpsl_attr_delete_list(old_irts);
       rpsl_attr_delete_list(new_irts);
	   if ( auth_return == UP_AUF || auth_return == UP_MFF || auth_return == UP_MIX)
	   {
	     return UP_HOF; /* hierarchical authorisation failed */
	   }

       /******* mntner check **********/
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }
   }
   
   /*  
    *  Handle the "domain" type 
    */
   else if (strcmp(type,"domain")  == 0)
   {
     if ( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
       /* now, we have to find a 'less specific domain object' for this. 
          If there is no less specific object, then creation is possible
          only with overriding. */
      less_specific_domain_str = get_less_specific_domain(new_object);
      if (less_specific_domain_str == NULL)
	  {
        if (overriden)
		{/* we didn't get a 'less specific' domain object */
           return UP_AUTH_OK; 
         }
		 else
		 {
           return UP_HOF; /* hierarchical authorisation failed */
         }
      }
	  else
	  { /* we get a 'less specific' domain object */
	     less_specific_domain_obj = rpsl_object_init(less_specific_domain_str);
		 if (tracing)
		 {
    	   if ( rpsl_object_has_error(less_specific_domain_obj, RPSL_ERRLVL_ERROR) )
		   {
			 /* thre was an error during the parsing */
			 name = rpsl_object_get_class(less_specific_domain_obj);
			 if ( name )
			 {
			   attr = rpsl_object_get_attr(less_specific_domain_obj, name);
			   if ( attr )
			   {
		    	 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
				 if ( value )
				 {
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
				   free(value);
				 }
				 else
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

				 rpsl_attr_delete_list(attr);
			   }
			 }
		   }
		 }

         less_specific_mnt_lowers = get_mnt_lowers(less_specific_domain_obj);
         less_specific_auth_vector = get_auth_vector(less_specific_mnt_lowers);
         rpsl_object_delete(less_specific_domain_obj);

         if (less_specific_mnt_lowers != NULL && less_specific_auth_vector == NULL)
		 {
           /* then, the mntners in 'less_specific_mnt_lowers' do not exist. Problem. */
		   rpsl_attr_delete_list(less_specific_mnt_lowers);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(less_specific_auth_vector, credentials, overriden);
         if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
		 {
           saved_auth_return = auth_return;
           new_mntners = get_mntners(new_object);
           new_auth_vector = get_auth_vector(new_mntners);
           if (new_mntners != NULL && new_auth_vector == NULL)
		   {
             /* then, the mntners in 'new_mntners' do not exist. Problem. */
		     rpsl_attr_delete_list(new_mntners);
             return UP_AUF; /* auth failed */
           }
           auth_return = authorise(new_auth_vector, credentials, overriden);
		   if (new_auth_vector)
  	         g_slist_free(new_auth_vector);
           if ( auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM )
             return UP_OKM;
           else
	         return auth_return;
         }
		 else
		 {
           return UP_HOF; /* hierarchical authorisation failed */
         }
      }
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }
   }
   

   /*  
    *  Handle the "route" type 
    */
   else if (strcmp(type,"route")  == 0)
   {
     if ( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_mntners' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     } 
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
       /* first we have to find the aut-num object mentioned in the 
          origin attribute */

       aut_num_object_str = get_aut_num_object(new_object); 
       if (aut_num_object_str == NULL)
	   {
         if (overriden)
		 {
           return UP_AUTH_OK; 
         }
		 else
		 {
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }
	   else
	   { /* there is a corresponding aut-num in the db */
         if (tracing)
		 {
           printf("TRACING: check_auth: will try to authorise the route using aut-num\n");
         }
	     aut_num_obj = rpsl_object_init(aut_num_object_str);
		 if (tracing)
		 {
    	   if ( rpsl_object_has_error(aut_num_obj, RPSL_ERRLVL_ERROR) )
		   {
			 /* thre was an error during the parsing */
			 name = rpsl_object_get_class(aut_num_obj);
			 if ( name )
			 {
			   attr = rpsl_object_get_attr(aut_num_obj, name);
			   if ( attr )
			   {
		    	 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
				 if ( value )
				 {
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
				   free(value);
				 }
				 else
		    	   printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

				 rpsl_attr_delete_list(attr);
			   }
			 }
		   }
		 }

         aut_num_maintainers = get_mnt_routes(aut_num_obj);
         if (aut_num_maintainers != NULL)
		 {
           aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
           auth_return = authorise(aut_num_auth_vector, credentials, overriden);
           if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
		   {
             aut_num_auth_OK = TRUE;
           }
		   else
		   {/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
		     rpsl_attr_delete_list(aut_num_maintainers);
             return UP_HOF;
           }
         }
		 else
		 {/* aut_num_maintainers is NULL */
            aut_num_maintainers = get_mnt_lowers(aut_num_obj);
            if (aut_num_maintainers != NULL)
			{
              aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
              auth_return = authorise(aut_num_auth_vector, credentials, overriden);
              if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
			  {
                aut_num_auth_OK = TRUE;
              }
			  else
			  {/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
		        rpsl_attr_delete_list(aut_num_maintainers);
                return UP_HOF; /* hierarchical authorisation failed */
              }
            }
			else
			{/* aut_num_maintainers is NULL */
              aut_num_maintainers = get_mntners(aut_num_obj);
              if (aut_num_maintainers != NULL)
			  {
                aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
                auth_return = authorise(aut_num_auth_vector, credentials, overriden);
                if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
				{
                  aut_num_auth_OK = TRUE;
                }
				else
				{/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
		          rpsl_attr_delete_list(aut_num_maintainers);
                  return UP_HOF; /* hierarchical authorisation failed */
                }
              }
			  else
			  {/* aut_num_maintainers is NULL */
                aut_num_auth_OK = TRUE;
              }
              
            }
         }
         rpsl_object_delete(aut_num_obj);

         if (aut_num_auth_OK)
		 {
           /* now, we have to find an exact match for this route object. 
              If there is no exact match object, then we will go on to find
              less specific. */
           exact_match_routes_str = get_exact_match_routes(new_object);
           if (exact_match_routes_str != NULL)
		   {
             /* there are one or more exact match routes */
             exact_match_routes_maintainers = get_mnt_routes_from_list(exact_match_routes_str);
             if ( exact_match_routes_maintainers )
             {
               /* the exact match(s) has some mnt-routes */
               exact_match_routes_auth_vector = get_auth_vector(exact_match_routes_maintainers);
               if (exact_match_routes_maintainers != NULL && exact_match_routes_auth_vector == NULL)
			   {
                 /* then, the mntners in 'exact_match_routes_maintainers' do not exist. Problem. */
		         rpsl_attr_delete_list(exact_match_routes_maintainers);
                 return UP_AUF; /* auth failed */
               }
               auth_return = authorise(exact_match_routes_auth_vector, credentials, overriden);
             }
             else
             {
               /* no mnt-routes so check the mnt-by of the exact match */
               exact_match_maintainers = get_mntners_from_list(exact_match_routes_str);
               exact_match_auth_vector = get_auth_vector(exact_match_maintainers);
               if (exact_match_maintainers != NULL && exact_match_auth_vector == NULL)
			   {
                 /* then, the mntners in 'exact_match_maintainers' do not exist. Problem. */
		         rpsl_attr_delete_list(exact_match_maintainers);
                 return UP_AUF; /* auth failed */
               }
               auth_return = authorise(exact_match_auth_vector, credentials, overriden);
             }
             if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
			 {
               saved_auth_return = auth_return;
               /* then, check mnt_bys of the route itself */
               new_mntners = get_mntners(new_object);
               new_auth_vector = get_auth_vector(new_mntners);
               if (new_mntners != NULL && new_auth_vector == NULL)
			   {
                 /* then, the mntners in 'new_mntners' do not exist. Problem. */
		         rpsl_attr_delete_list(new_mntners);
                 return UP_AUF; /* auth failed */
               }
               auth_return = authorise(new_auth_vector, credentials, overriden);
		       if (new_auth_vector)
  	             g_slist_free(new_auth_vector);
               if ( auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
                 return UP_OKM;
               else
	             return auth_return;
             }
			 else
			 { /*authorise(exact_match_routes_auth_vector, credentials, overriden) != UP_AUTH_OK*/
               return UP_HOF; /* hierarchical authorisation failed */
             }
           }
		   else
		   { /* exact_match_routes == NULL */
             /* then we have to look for less specific route objs */
             less_spec_routes_str = get_less_spec_routes(new_object);
             if (less_spec_routes_str != NULL)
			 {
               less_spec_routes_mntners = get_mnt_routes_from_list(less_spec_routes_str);
               less_spec_routes_mntners = g_list_concat(less_spec_routes_mntners, 
                                             get_mnt_lowers_from_list(less_spec_routes_str));
               less_spec_routes_auth_vector = get_auth_vector(less_spec_routes_mntners);
               if (less_spec_routes_mntners != NULL && less_spec_routes_auth_vector == NULL)
			   {
                 /* then, the mntners in 'less_spec_routes_mntners' do not exist. Problem. */
		         rpsl_attr_delete_list(less_spec_routes_mntners);
                 return UP_AUF; /* auth failed */
               }
               if ( less_spec_routes_mntners != NULL )
               {
                 auth_return = authorise(less_spec_routes_auth_vector, credentials, overriden);
                 if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
			     {
                   saved_auth_return = auth_return;
                   /* then, check mnt_bys of the route itself */
                   new_mntners = get_mntners(new_object);
                   new_auth_vector = get_auth_vector(new_mntners);
                   if (new_mntners != NULL && new_auth_vector == NULL)
				   {
                     /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		             rpsl_attr_delete_list(new_mntners);
                     return UP_AUF; /* auth failed */
                   }
                   auth_return = authorise(new_auth_vector, credentials, overriden);
		           if (new_auth_vector)
  	                 g_slist_free(new_auth_vector);
                   if ( auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM )
                     return UP_OKM;
                   else
	                 return auth_return;
                 }
			     else
			     { /*authorise(less_spec_routes_auth_vector, credentials, overriden) != UP_AUTH_OK*/
                   return UP_HOF; /* hierarchical authorisation failed */
                 }
               }
               else
               {
                 /* there are no mnt-routes or mnt-lower in less specific route objs */
                 /* check mnt-by of less specific route objs */
                 less_spec_routes_mntners = get_mntners_from_list(less_spec_routes_str);
                 less_spec_routes_auth_vector = get_auth_vector(less_spec_routes_mntners);
                 if (less_spec_routes_mntners != NULL && less_spec_routes_auth_vector == NULL)
			     {
                   /* then, the mntners in 'less_spec_routes_mntners' do not exist. Problem. */
		           rpsl_attr_delete_list(less_spec_routes_mntners);
                   return UP_AUF; /* auth failed */
                 }
                 auth_return = authorise(less_spec_routes_auth_vector, credentials, overriden);
                 if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
			     {
                   saved_auth_return = auth_return;
                   /* then, check mnt_bys of the route itself */
                   new_mntners = get_mntners(new_object);
                   new_auth_vector = get_auth_vector(new_mntners);
                   if (new_mntners != NULL && new_auth_vector == NULL)
				   {
                     /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		             rpsl_attr_delete_list(new_mntners);
                     return UP_AUF; /* auth failed */
                   }
                   auth_return = authorise(new_auth_vector, credentials, overriden);
		           if (new_auth_vector)
  	                 g_slist_free(new_auth_vector);
                   if (auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
                     return UP_OKM;
                   else
	                 return auth_return;
                 }
			     else
			     { /*authorise(less_spec_routes_auth_vector, credentials, overriden) != UP_AUTH_OK*/
                   return UP_HOF; /* hierarchical authorisation failed */
                 }
               }
             }
			 else
			 {  /* less_spec_routes == NULL */
               /* so, we have to get the exact match inetnum */
               exact_match_inetnum_str = get_exact_match_inetnum(new_object);
               if (exact_match_inetnum_str != NULL)
			   {
				 exact_match_inetnum_obj = rpsl_object_init(exact_match_inetnum_str);
				 if (tracing)
				 {
    			   if ( rpsl_object_has_error(exact_match_inetnum_obj, RPSL_ERRLVL_ERROR) )
				   {
					 /* thre was an error during the parsing */
					 name = rpsl_object_get_class(exact_match_inetnum_obj);
					 if ( name )
					 {
					   attr = rpsl_object_get_attr(exact_match_inetnum_obj, name);
					   if ( attr )
					   {
		    			 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
						 if ( value )
						 {
		    			   printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
						   free(value);
						 }
						 else
		    			   printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

						 rpsl_attr_delete_list(attr);
					   }
					 }
				   }
				 }

                 exact_match_inetnum_mnt_routes = get_mnt_routes(exact_match_inetnum_obj);
				 exact_match_inetnum_mnt_bys = get_mntners(exact_match_inetnum_obj);
				 rpsl_object_delete(exact_match_inetnum_obj);

                 exact_match_inetnum_auth_vector = get_auth_vector(exact_match_inetnum_mnt_routes);
                 if (exact_match_inetnum_mnt_routes != NULL && exact_match_inetnum_auth_vector == NULL)
				 {
                   /* then, the mntners in 'exact_match_inetnum_mnt_routes' do not exist. Problem. */
		           rpsl_attr_delete_list(exact_match_inetnum_mnt_routes);
                   return UP_AUF; /* auth failed */
                 }

				 /* if there are mnt_routes in the exact match inetnum */
				 if (exact_match_inetnum_mnt_routes != NULL)
				 {
				   auth_return = authorise(exact_match_inetnum_auth_vector, credentials, overriden);
				   if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
				   {
                     saved_auth_return = auth_return;
					 /* then, check mnt_bys of the route itself */
					 new_mntners = get_mntners(new_object);
					 new_auth_vector = get_auth_vector(new_mntners);
					 if (new_mntners != NULL && new_auth_vector == NULL)
					 {
					   /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		               rpsl_attr_delete_list(new_mntners);
					   return UP_AUF; /* auth failed */
					 }
                     auth_return = authorise(new_auth_vector, credentials, overriden);
		             if (new_auth_vector)
  	                   g_slist_free(new_auth_vector);
                     if (auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
                       return UP_OKM;
                     else
	                   return auth_return;
				   }
				   else
				   {
					 return UP_HOF; /* hierarchical authorisation failed */
				   }
				 }
				 else
				 { /* if there was no mnt_routes in the exact match inetnum, then use mnt-by of it */
				   exact_match_inetnum_auth_vector = get_auth_vector(exact_match_inetnum_mnt_bys);
				   if (exact_match_inetnum_mnt_bys != NULL && exact_match_inetnum_auth_vector == NULL)
				   {
					 /* then, the mntners in 'exact_match_inetnum_mnt_bys' do not exist. Problem. */
		             rpsl_attr_delete_list(exact_match_inetnum_mnt_bys);
                     return UP_AUF; /* auth failed */
                   }
                   
                   /* check mnt-by of exact match inetnum */
                   auth_return = authorise(exact_match_inetnum_auth_vector, credentials, overriden);
                   if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
				   {
                     saved_auth_return = auth_return;
                     /* then, check mnt_bys of the route itself */
                     new_mntners = get_mntners(new_object);
                     new_auth_vector = get_auth_vector(new_mntners);
                     if (new_mntners != NULL && new_auth_vector == NULL)
				     {
                       /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		               rpsl_attr_delete_list(new_mntners);
                       return UP_AUF; /* auth failed */
                     }
                     auth_return = authorise(new_auth_vector, credentials, overriden);
		             if (new_auth_vector)
  	                   g_slist_free(new_auth_vector);
                     if (auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
                       return UP_OKM;
                     else
	                   return auth_return;
                   }
				   else
				   {
                     return UP_HOF; /* hierarchical authorisation failed */
                   }
                 }
               }
			   else
			   {/* exact_match_inetnum == NULL */
                 /* then, we will try to find less spec inetnums */
                 less_spec_inetnum_str = get_less_spec_inetnum(new_object);
                 if (less_spec_inetnum_str != NULL)
				 {
				   less_spec_inetnum_obj = rpsl_object_init(less_spec_inetnum_str);
				   if (tracing)
				   {
    				 if ( rpsl_object_has_error(less_spec_inetnum_obj, RPSL_ERRLVL_ERROR) )
					 {
					   /* thre was an error during the parsing */
					   name = rpsl_object_get_class(less_spec_inetnum_obj);
					   if ( name )
					   {
						 attr = rpsl_object_get_attr(less_spec_inetnum_obj, name);
						 if ( attr )
						 {
		    			   value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
						   if ( value )
						   {
		    				 printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
							 free(value);
						   }
						   else
		    				 printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

						   rpsl_attr_delete_list(attr);
						 }
					   }
					 }
				   }

                   less_spec_inetnum_mntners = get_mnt_routes(less_spec_inetnum_obj);
                   less_spec_inetnum_mntners = g_list_concat(less_spec_inetnum_mntners, 
                                  get_mnt_lowers(less_spec_inetnum_obj));
                   less_spec_inetnum_auth_vector = get_auth_vector(less_spec_inetnum_mntners);

				   less_spec_inetnum_mnt_bys = get_mntners(less_spec_inetnum_obj);

				   rpsl_object_delete(less_spec_inetnum_obj);

                   if (less_spec_inetnum_mntners != NULL && less_spec_inetnum_auth_vector == NULL)
				   {
                     /* then, the mntners in 'less_spec_inetnum_mntners' do not exist. Problem. */
		             rpsl_attr_delete_list(less_spec_inetnum_mntners);
                     return UP_AUF; /* auth failed */
                   }
				   if (less_spec_inetnum_mntners != NULL)
				   { /* if there are mntners in mnt-lower and/or mnt-routes */
					 auth_return = authorise(less_spec_inetnum_auth_vector, credentials, overriden);
					 if (auth_return == UP_AUTH_OK || auth_return == UP_OKM)
					 {
                       saved_auth_return = auth_return;
					   /* then, check mnt_bys of the route itself */
					   new_mntners = get_mntners(new_object);
					   new_auth_vector = get_auth_vector(new_mntners);
					   if (new_mntners != NULL && new_auth_vector == NULL)
					   {
						 /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		                 rpsl_attr_delete_list(new_mntners);
						 return UP_AUF; /* auth failed */
					   }
                       auth_return = authorise(new_auth_vector, credentials, overriden);
		               if (new_auth_vector)
  	                     g_slist_free(new_auth_vector);
                       if (auth_return == UP_AUTH_OK && saved_auth_return == UP_OKM)
                         return UP_OKM;
                       else
	                     return auth_return;
					 }
					 else
					 { /* authorise(exact_match_auth_vector, credentials, overriden) != UP_AUTH_OK */
					   return UP_HOF; /* hierarchical authorisation failed */
					 }
				   }
				   else
				   { /* there isn't any mnt-lower or mnt-routes in the less spec inetnum */
						 /* so we must use mnt-by of less spec inetum */
					 less_spec_inetnum_auth_vector = get_auth_vector(less_spec_inetnum_mnt_bys);
					 if (less_spec_inetnum_mnt_bys != NULL && less_spec_inetnum_auth_vector == NULL)
					 {
					   /* then, the mntners in 'less_spec_inetnum_mnt_bys' do not exist. Problem. */

		               rpsl_attr_delete_list(less_spec_inetnum_mnt_bys);
                       return UP_AUF; /* auth failed */
                     }
					 auth_return = authorise(less_spec_inetnum_auth_vector, credentials, overriden);
					 if (auth_return == UP_AUTH_OK  ||  auth_return == UP_OKM)
					 {
                       saved_auth_return = auth_return;
					   /* then, check mnt_bys of the route itself */
					   new_mntners = get_mntners(new_object);
					   new_auth_vector = get_auth_vector(new_mntners);
					   if (new_mntners != NULL && new_auth_vector == NULL)
					   {
						 /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		                 rpsl_attr_delete_list(new_mntners);
						 return UP_AUF; /* auth failed */
					   }
                       auth_return = authorise(new_auth_vector, credentials, overriden);
		               if (new_auth_vector)
  	                     g_slist_free(new_auth_vector);
                       if (auth_return == UP_AUTH_OK  && saved_auth_return == UP_OKM)
                         return UP_OKM;
                       else
	                     return auth_return;
					 }
					 else
					 {
					   return UP_HOF; /* hierarchical authorisation failed */
					 }
                   }
                 }
				 else
				 {/* less_spec_inetnum == NULL */
                   /* now that we couldn't find any route or inetnum object
                      to be used in authentication. So, only if the auth is
                      overriden the object will be created. */
                   if (overriden)
				   {
                     return UP_AUTH_OK; 
                   }
				   else
				   {
                     return UP_HOF; /* hierarchical authorisation failed */
                   }
                 }
               }
             }
           }
         }
		 else
		 {/* ! aut_num_auth_OK */
           return UP_HOF; /* hierarchical auth failed */
         }
       }
          
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_auth_vector' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }
   }


   /*  
    *  Handle the set objects ("as-set","rtr-set", "peering-set", "route-set" and "filter-set" types 
    */
   else if (strcmp(type,"as-set")       == 0 || strcmp(type,"rtr-set")     == 0 ||
           strcmp(type,"peering-set")  == 0 || strcmp(type,"filter-set")  == 0 ||
           strcmp(type,"route-set")    == 0 )
   {
     if ( new_object == NULL && old_object != NULL )
	 { /* the object is to be deleted */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_auth_vector' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       auth_return = authorise(old_auth_vector, credentials, overriden);
	   g_slist_free(old_auth_vector);
	   return auth_return;
     }
	 else if ( new_object != NULL && old_object == NULL )
	 { /* the object is to be created */
        set_name = get_search_key(new_object, type);
       if (strstr(set_name,":") == NULL )
	   { /* if the name is _not_ hierarchical */
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_auth_vector' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
	   else
	   { /* the name is hierarchical */
         less_specific_object_str = get_less_specific_set(new_object, type);
         if (less_specific_object_str != NULL)
		 { /* such an object exists */
		   less_specific_obj = rpsl_object_init(less_specific_object_str);
		   if (tracing)
		   {
    		 if ( rpsl_object_has_error(less_specific_obj, RPSL_ERRLVL_ERROR) )
			 {
			   /* thre was an error during the parsing */
			   name = rpsl_object_get_class(less_specific_obj);
			   if ( name )
			   {
				 attr = rpsl_object_get_attr(less_specific_obj, name);
				 if ( attr )
				 {
		    	   value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(attr->data) );
				   if ( value )
				   {
		    		 printf("TRACING: get_mnt_routes_from_list: error parsing object %s\n", value );
					 free(value);
				   }
				   else
		    		 printf("TRACING: get_mnt_routes_from_list: error parsing object\n");

				   rpsl_attr_delete_list(attr);
				 }
			   }
			 }
		   }

           less_specific_object_type = rpsl_object_get_class(less_specific_obj);

           if (strcmp(less_specific_object_type, "aut-num") == 0)
		   { /* if this is an aut-num object */
             less_specific_mnt_lowers = get_mnt_lowers(less_specific_obj);
             less_specific_auth_vector = get_auth_vector(less_specific_mnt_lowers);
             if (less_specific_mnt_lowers != NULL && less_specific_auth_vector == NULL)
			 {
               /* then, the mntners in 'less_specific_auth_vector' do not exist. Problem. */
		      rpsl_attr_delete_list(less_specific_mnt_lowers);
              rpsl_object_delete(less_specific_obj);
              return UP_AUF; /* auth failed */
             }
             if (less_specific_auth_vector != NULL)
			 {
               auth_return = authorise(less_specific_auth_vector, credentials, overriden);
	           g_slist_free(less_specific_auth_vector);
               rpsl_object_delete(less_specific_obj);
	           return auth_return;
             }
			 else
			 { /* the less specific object doesn't contain any mnt-lower */
               less_specific_mntners = get_mntners(less_specific_obj);
               less_specific_auth_vector = get_auth_vector(less_specific_mntners);
               if (less_specific_mntners != NULL && less_specific_auth_vector == NULL)
			   {
                 /* then, the mntners in 'less_specific_mntners' do not exist. Problem. */
		         rpsl_attr_delete_list(less_specific_mntners);
                 rpsl_object_delete(less_specific_obj);
                 return UP_AUF; /* auth failed */
               }
               if (less_specific_auth_vector != NULL)
			   {  /* less spec object has some mnt-by attribs, 
                                                        use them  */
                   auth_return = authorise(less_specific_auth_vector, credentials, overriden);
	               g_slist_free(less_specific_auth_vector);
                   rpsl_object_delete(less_specific_obj);
	               return auth_return;
               }
			   else
			   { /* the less specific object doesn't contain any mnt-by either */
                 if (overriden)
				 {
                   rpsl_object_delete(less_specific_obj);
                   return UP_AUTH_OK; 
                 }
				 else
				 {
                   rpsl_object_delete(less_specific_obj);
                   return UP_HOF; /* hierarchical authorisation failed */
                 }
               }
             }
           }
		   else
		   { /* this is _not_ an aut-num object*/
             less_specific_mntners = get_mntners(less_specific_obj);
             less_specific_auth_vector = get_auth_vector(less_specific_mntners);
             if (less_specific_mntners != NULL && less_specific_auth_vector == NULL)
			 {
               /* then, the mntners in 'less_specific_mntners' do not exist. Problem. */
		       rpsl_attr_delete_list(less_specific_mntners);
               rpsl_object_delete(less_specific_obj);
               return UP_AUF; /* auth failed */
             }
             if (less_specific_auth_vector != NULL )
			 { /* the set obj has some mnt-by attribs */
               auth_return = authorise(less_specific_auth_vector, credentials, overriden);
	           g_slist_free(less_specific_auth_vector);
               rpsl_object_delete(less_specific_obj);
	           return auth_return;
             }
			 else
			 {
               if (overriden)
			   {
                 rpsl_object_delete(less_specific_obj);
                 return UP_AUTH_OK; 
               }
			   else
			   {
                 rpsl_object_delete(less_specific_obj);
                 return UP_HOF; /* hierarchical authorisation failed */
               }
             }
           }
         }
		 else
		 { /* we don't have a less specific of this set object in the DB  */
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }
     }
	 else if ( new_object != NULL && old_object != NULL )
	 { /* this is an update */
       old_mntners = get_mntners(old_object);
       old_auth_vector = get_auth_vector(old_mntners);
       if (old_mntners != NULL && old_auth_vector == NULL)
	   {
         /* then, the mntners in 'old_auth_vector' do not exist. Problem. */
		 rpsl_attr_delete_list(old_mntners);
         return UP_AUF; /* auth failed */
       }
       if (old_auth_vector)
	   { /* if we have mntners in the old object, use them */
         auth_return = authorise(old_auth_vector, credentials, overriden);
	     g_slist_free(old_auth_vector);
	     return auth_return;
       }
	   else
	   {
         new_mntners = get_mntners(new_object);
         new_auth_vector = get_auth_vector(new_mntners);
         if (new_mntners != NULL && new_auth_vector == NULL)
		 {
           /* then, the mntners in 'new_mntners' do not exist. Problem. */
		   rpsl_attr_delete_list(new_mntners);
           return UP_AUF; /* auth failed */
         }
         auth_return = authorise(new_auth_vector, credentials, overriden);
		 if (new_auth_vector)
  	       g_slist_free(new_auth_vector);
	     return auth_return;
       }
     }
	 else
	 { /* both are NULL, mustn't happen */
         if (tracing)
		 {
           printf("TRACING: check_auth: internal error: Both pointers are NULL\n");
         }
         return UP_INT; /* internal error */
     }

   }
   else
   { /* We exhausted all object classes. If we are here, then there is a problem */
     printf("check_auth: This type '%s' is unknown\n", type);
     return UP_NIY; /* not implemented yet */
   }
   return UP_AUF; /* if we come to this point, then auth failed */ 
}



/* Gets the old version of the given "arg" object, which is in char * format
   and returns the old version again in char * format */

char * get_old_version(rpsl_object_t *object, char * arg)
{
    const char *type=NULL;
	char *lctype = NULL;
	char *primary_search_key = NULL, *search_string = NULL;
    char *result = NULL, *origin = NULL, *nic_hdl = NULL;
    
    type = rpsl_object_get_class(object);
	lctype = strdup(type);
	g_strdown(lctype);

    primary_search_key = get_search_key(object, lctype);
    if ( primary_search_key == NULL )
    {
      if(tracing)
      {
        printf("type=%s\n", type);
        printf("primary_search_key is NULL\n");
      }
	  return NULL;
	}

    if(tracing) 
	{
      printf("TRACING: type= %s\n", type);
      printf("TRACING: primary_search_key= %s\n", primary_search_key);
    }

    /* if the object is a pn or a ro object, then get all pn/ro's with the same NIC hdl */
    if ( strcmp(lctype,"person") == 0 || strcmp(lctype,"role") == 0 )
	{
      /* prepare the search string */
      search_string = (char *)malloc(strlen(primary_search_key) + strlen("-x -R -r -T -s ")
                                          +strlen(current_source)+ strlen("person,role") + 2);
      sprintf(search_string, "-x -R -r -Tperson,role -s %s %s", current_source, primary_search_key);
    }
	else
	{
      /* prepare the search string */
      search_string = (char *)malloc(strlen(primary_search_key) + strlen("-x -R -r -T -s ")
                                          +strlen(current_source)+ strlen(lctype) + 2);
      sprintf(search_string, "-x -R -r -T%s -s %s %s",lctype, current_source, primary_search_key);
    }
	
    result = send_and_get(query_host, query_port, search_string);
    if(tracing) 
	{
      printf("TRACING: send_and_get returned with search %s result %s\n", search_string, result);
    }
	free(search_string);
	free(primary_search_key);
	if ( result == NULL )
	  return NULL;

    /* and here, we must filter the 'result' with NIC handle */
    if ( strcmp(lctype,"person") == 0 )
	{
      if(tracing) 
	  {
        printf("TRACING: This is a person\n");
      }
      /* if this is a person, then we must filter out the persons with different
         nic-hdl attributes (since it is possible to have this NIC hdl in the name
         of a person object, and whois will return that object too) */
      nic_hdl = get_search_key(object, "nic-hdl");
      if(tracing) 
	  {
        printf("TRACING: Got nic-hdl of person: %s\n", nic_hdl);
      }
      result = up_filter_out_diff_nichdls(result, nic_hdl);  
      if(tracing) 
	  {
        printf("TRACING: Filtered person\n");
      }
	  free(nic_hdl);
    }

    /* also, we must filter the 'result' with NIC handle for roles */
    if(strcmp(type,"role") == 0)
	{
      if(tracing) 
	  {
        printf("TRACING: This is a role\n");
      }
      /* if this is a role, then we must filter out the roles with different
         nic-hdl attributes (since it is possible to have this NIC hdl in the name
         of a role object, and whois will return that object too) */
      nic_hdl = get_search_key(object, "nic-hdl");
      if(tracing) 
	  {
        printf("TRACING: Got nic-hdl of role: %s\n", nic_hdl);
      }
      result = up_filter_out_diff_nichdls(result, nic_hdl);  
      if(tracing) 
	  {
        printf("TRACING: Filtered role\n");
      }
	  free(nic_hdl);
    }

    if(strcmp(type,"route") == 0)
	{
      if(tracing) 
	  {
        printf("TRACING: This is a route\n");
      }
      /* if this is a route, then we must filter out the routes with different
         origin attributes */
      origin = get_search_key(object, "origin");
      if(tracing) 
	  {
        printf("TRACING: Got origin of route: %s\n", origin);
      }
      result = up_filter_out_diff_origins(result, origin);  
      if(tracing) 
	  {
        printf("TRACING: Filtered routes\n");
      }
	  free(origin);
    }
    
    /* count the objects */
    if(count_objects(result) == 0)
	{
      result = NULL; /* we don't have such an object */
    }
	else if(count_objects(result) == 1)
	{
      result = take_object(result);
      if(tracing) 
	  {
      printf("TRACING: Take_object returned ***%s\n", result);
      }
    }
	else
	{ /* we have more than one objects, error! */
      result = NULL;
    }
	
    return result;
}




/* Gets a credentials_struct whose 'from' field will be filled in and
   the mail header. Finds the 'From:' line in the header and sets
   the 'from' field to this line (all line, including the 'From:' string,
   since some users have put regexps which match the whole line in their
   'auth' attributes.) */
void process_mail_header(credentials_struct * credentials_ptr, char * arg)
{
  char * header = strdup(arg);
  char * temp = (char *)malloc(strlen(header));

  while (index(header, '\n') != NULL)
  {
    temp = strdup(header);
    temp[index(temp, '\n') - temp] = '\0';
    if (strstr(temp, "From:") == temp)
	{
      if (tracing)
	  {
        printf("TRACING: process_mail_header: Assigning %s\n", temp);
      }
      credentials_ptr->from = strdup(temp);
      free(temp);
      return;
    }
    header = header + (index(header, '\n') - header + 1);
  }
  free(temp);
}



void up_string_pack(char *dest, const char *source)
{
  if(tracing) 
  {
    printf("TRACING: up_string_pack running\n");
  }

/*----------------------------------------------------------------------*\

*  Function to rewrite a line of text with only one blankspace between  *
*  each word.
*
\*----------------------------------------------------------------------*/
/*
 * This while loop continues until the NULL character is copied into
 * the destination string.  If a tab character is copied into the
 * destination string, it is replaced with a blank-space character.
 *
 * Multiple blank-space and/or tab characters are skipped in the source
 * string until any other character is found.
 */

  while (1)
  {
    *dest = *source;

    if (*dest == '\t')
            (*dest = ' ');

    /* Exit if have copied the end of the string. */
    if (*dest == '\0')
            return;

/*
* If the source character was a blank-space or a tab, move to the next
* source character.  While the source character is a blank-space or a
* tab, move to the next character (i.e. ignore these characters).  When
* any other character is found in the source string, move to the next
* element of the destination string.
*
* Otherwise, simultaneously, move to the next elements of the destination
* and the source strings.
*/

    if ( (*source == ' ') || (*source == '\t') )
    {
        ++source;
        while ( (*source == ' ') || (*source == '\t') )
                {
                ++source;
                }

        ++dest;
    }
    else
    {
        ++dest;
        ++source;
    }
  }
}


/* replaces the erase_str occurences with insert_str in str (which is a ptr to GString) */
char * UP_replace_strings(char * str, const char * erase_str, const char * insert_str)
{
  GString * g_str;  
  int pos;
  char * result_str;
  
  /* erase_str mustn't be NULL */
  assert(erase_str != NULL);
  
  /* if insert str is NULL, make it empty string */
  if(insert_str == NULL)
  {
    insert_str = strdup(""); 
  }
  
  g_str = g_string_new(str);
  
  /* replace erase_str with insert_str */
  while(strstr(g_str->str, erase_str) != NULL)
  {
    pos = strstr(g_str->str, erase_str) - g_str->str;
    g_str = g_string_erase(g_str, pos, strlen(erase_str));
    if(insert_str != NULL)
	{
      g_str = g_string_insert(g_str, pos, insert_str);
    }
  }

  /* save the result string */
  result_str = strdup(g_str->str);

  /* free the GString structure (TRUE means 'also free the char string') */
  g_string_free(g_str, TRUE);

  return result_str;
}



/* replaces the erase_str occurences with insert_str in g_str (which is a ptr to GString) */
GString * UP_replace_GStrings(GString * g_str, const char * erase_str, const char * insert_str)
{
  int pos;
  
  if (insert_str == NULL)
  { /* then don't do anything */
    return g_str;
  }
   
  /* replace erase_str with insert_str */
  while (strstr(g_str->str, erase_str) != NULL)
  {
    pos = strstr(g_str->str, erase_str) - g_str->str;
    g_str = g_string_erase(g_str, pos, strlen(erase_str));
    g_str = g_string_insert(g_str, pos, insert_str);
  }
  return g_str;
}



/* looks if two objects are identical or not.
    Takes two objects, one as char *, the other as
	a parsed object, and returns 1 if
    they are identical, returns 0 if not.

    Algorithm is very simple: All strings of tabs and 
    white spaces are collapsed into a single white space,
    and then the strings are compared (strcmp) */
int identical(const char * old_version, rpsl_object_t *object)
{
  char * arg1 = strdup(old_version);
  char * arg2 = NULL;
  rpsl_object_t *object2;
  rpsl_error_t error;
  int result = 0;
  char *temp1, *temp2; 
  char *temp;
  
  object2 = rpsl_object_copy(object);
  rpsl_object_remove_attr_name(object2, "delete", &error);
  rpsl_object_remove_attr_name(object2, "override", &error);
  arg2 = rpsl_object_get_text(object2,RPSL_STD_COLUMN);

  arg1 = g_strstrip(arg1);
  arg2 = g_strstrip(arg2);

  /* convert tabs to white spaces */
  arg1 = g_strdelimit(arg1, "\t", ' ');
  arg2 = g_strdelimit(arg2, "\t", ' ');
  
  temp1 = (char *)malloc(strlen(arg1) + 1); 
  temp2 = (char *)malloc(strlen(arg2) + 1);
  up_string_pack(temp1, arg1);
  up_string_pack(temp2, arg2);

  /* if there are still \r's at the end of strings, remove them */
  if((temp1[strlen(temp1) - 1]) == '\r')
  {
    temp1[strlen(temp1) - 1] = '\0';
  }
  if((temp2[strlen(temp2) - 1]) == '\r')
  {
    temp2[strlen(temp2) - 1] = '\0';
  }

  /* there may be white spaces at the end of the strings now, remove them */
  if((temp1[strlen(temp1) - 1]) == ' ')
  {
    temp1[strlen(temp1) - 1] = '\0';
  }
  if((temp2[strlen(temp2) - 1]) == ' ')
  {
    temp2[strlen(temp2) - 1] = '\0';
  }

  /* remove the white spaces just before the EOLs (since this is not taken care of by
     the up_string_pack func) */
  temp = UP_replace_strings(temp1, " \n", "\n");
  free(temp1);
  temp1 = temp;

  temp = UP_replace_strings(temp2, " \n", "\n");
  free(temp2);
  temp2 = temp;

  result = strcmp(temp1, temp2);
  if(tracing){
    printf("TRACING: identical: the objects are:\n[%s]\n[%s]\n", temp1, temp2);
    printf("TRACING: identical: the lengths are:\n[%i]\n[%i]\n", strlen(temp1), strlen(temp2));
  }
  free(arg1);
  free(arg2);
  free(temp1);
  free(temp2);
  if(result  == 0)
  {
    if(tracing) 
	{
      printf("TRACING: identical returning 1\n");
    }
    return 1;
  }
  else
  {
    if(tracing) 
	{
      printf("TRACING: identical returning 0\n");
    }
    return 0;
  }
}


/* constructs an initials string from a given name (for NIC hdl generation) */
char * find_initials(const char * person_role_name)
{
   char * temp, *pos;
   char * initials = NULL;
   int len, i;
   char ** vector;

   temp = strdup(person_role_name);
   if ((pos = index(temp, '#')) != NULL)
   { /* delete the EOL comment */
     pos[0] = '\0';
   }

   vector = g_strsplit(temp, " ", 0);
   for (i = 0; vector[i] != NULL && i < 4; i++)
   {
     if ( (strlen(vector[i]) > 0 ) && isalpha( (int)(vector[i][0]) ) )
	 {
       if (initials == NULL)
	   {
         initials = (char *)malloc(2);
         initials[0] = vector[i][0]; 
		 initials[1] = '\0';
       }
	   else
	   {
         len = strlen(initials);
         initials = (char *)realloc(initials, len + 2 );
         initials[len] = vector[i][0];
         initials[len + 1] = '\0';
       }
     }
   }
   free(temp);
   g_strfreev(vector);
   return initials;
}




/*  Gets the letter combination to be used in the automatically
    generated NIc handle. It the letter combination is specified
    in the AUTO NIC handle, return that. If not, return NULL
    (in which case the initials of the name must be used) */
char * get_combination_from_autonic(const char * autonic)
{
  GString * temp;
  char * str = NULL;
  char * pos;

  temp = g_string_new(autonic);
  temp = g_string_up(temp);
  if ((pos = index(temp->str, '#')) != NULL)
  { 
    /* delete the EOL comment */
    pos[0] = '\0';
  }
  g_strstrip(temp->str);
  temp->len = strlen(temp->str);/* we directly played with temp->str, so adjust temp->len accordingly */
 
  temp = g_string_erase(temp, 0, strlen("AUTO-"));
  /* delete all digits from the beginning of the string */
  while (temp->len > 0 && ((temp->str)[0] >= '0' && (temp->str)[0] <= '9'))
  {
    temp = g_string_erase(temp, 0, 1);
  }

  if (temp->len < 2 )
  {
    g_string_free(temp, TRUE);
    return NULL;
  }
  else
  {
    str = temp->str;
    g_string_free(temp, FALSE);
    g_strup(str);
    if(strlen(str) > 4)
	{
      str[4] = '\0'; 
    }
    return str;
  }
}




/* Gets an object whose NIC hdl is an auto NIC handle and to be modified (to be sent to RIPupdate)
   and  modifies the nic-hdl: attribute.
   For example, "nic-hdl: AUTO-1" becomes "nic-hdl: HG*-RIPE . Also,
   auto_nic is set to "AUTO-1"
   auto_nic must be allocated enough memory before replace_AUTO_NIC_hdl called */
rpsl_object_t * replace_AUTO_NIC_hdl(rpsl_object_t *object, char * auto_nic_hdl)
{
  GList *nichdl_item;
  rpsl_object_t *object2 = NULL;
  rpsl_attr_t *attr;
  GList *class_attr;
  char * person_role_name = NULL;
  char * initials = NULL;
  char *value, *new_value = NULL;
  const char *type;
  int pos;

  if (tracing)
  {                                
      printf("TRACING: replace_AUTO_NIC_hdl running\n");
  }

  nichdl_item = rpsl_object_get_attr(object, "nic-hdl"); /* list with one item only */

  value = rpsl_attr_get_clean_value((rpsl_attr_t *)(nichdl_item->data));
  g_strdown(value);
  if (tracing)
  {                                
      printf("TRACING: auto nic-hdl value is [%s]\n", value);
  }

  if (strstr(value, "auto-") != NULL)
  {
    /* this attribute must be replaced with a new attribute containing a nic-hdl */
    strcpy(auto_nic_hdl, value);
    pos = rpsl_attr_get_ofs((rpsl_attr_t *)(nichdl_item->data));

	if (tracing)
	{                                
    	printf("TRACING: pos [%d]\n", pos);
	}

     /* if the letter combination is already specified, get it */
    initials = get_combination_from_autonic(auto_nic_hdl);
    /* if the letter combination is not in the AUTO nichdl, obtain it from the name */
    if(initials == NULL)
	{
	  type = rpsl_object_get_class(object);
	  class_attr = rpsl_object_get_attr(object, type);
	  person_role_name = rpsl_attr_get_clean_value((rpsl_attr_t *)(class_attr->data));
	  rpsl_attr_delete_list(class_attr);
      initials = find_initials(person_role_name);
	  free(person_role_name);
    }
	if (tracing)
	{                                
    	printf("TRACING: initials [%s]\n", initials ? initials : "NULL");
	}

	object2 = rpsl_object_copy(object);
    new_value = (char *)malloc(strlen(initials) + strlen(current_source) + 3);
	strcpy(new_value, initials);
	strcat(new_value, "*-");
	strcat(new_value, current_source);
	if (tracing)
	{                                
    	printf("TRACING: new_value [%s]\n", new_value);
	}

	/* now copy original attribute, replace value, remove old attr and add replacement */
	attr = rpsl_attr_copy((rpsl_attr_t *)(nichdl_item->data));
	rpsl_attr_replace_value(attr, new_value);
	free(initials);
	free(new_value);
	free(value);

	/* remove the attribute with the auto- */
	rpsl_object_remove_attr(object2, pos, NULL);
		
	/* insert new attribute with nic-hdl */
	rpsl_object_add_attr(object2, attr, pos, NULL);
  }
  rpsl_attr_delete_list(nichdl_item);
  
  return(object2);
}




/* replaces the refs to AUTO NIC hdls with the assigned one */

char * replace_refs_to_AUTO_NIC_hdl(rpsl_object_t *object, GHashTable * auto_nic_hash, char *arg)
{
  char * nic_hdl = NULL;
  char *name;
  char *value;
  char *return_str;
  char *tempstr;
  rpsl_attr_t *attr;
  const GList * attr_list = NULL;
  const GList * list_item = NULL;
  int pos;

  if(tracing)
  {
    printf("TRACING: replace_refs_to_AUTO_NIC_hdl is running: arg:[%s]\n", arg ? arg : "NULL");
  }

  attr_list = rpsl_object_get_all_attr(object);
  
//  for (list_item = attr_list; list_item != NULL; list_item = g_list_next(list_item ))
//  {
  list_item = attr_list;
  while (list_item != NULL)
  {
	name = strdup(rpsl_attr_get_name((rpsl_attr_t *)(list_item->data)));
	g_strdown(name);
	value = rpsl_attr_get_clean_value((rpsl_attr_t *)(list_item->data));
	g_strdown(value);
	pos = rpsl_attr_get_ofs((rpsl_attr_t *)(list_item->data));
  	if (    strstr(name, "admin-c") == name
	     || strstr(name, "tech-c")  == name
	     || strstr(name, "zone-c")  == name
	     || strstr(name, "author")  == name )
	{
	  /* attr starts with admin-c, tech-c, zone-c or author */
	  if ( strstr(value, "auto-") != NULL)
	  {
        if(tracing)
		{
			printf("TRACING: replace_refs_to_AUTO_NIC_hdl: auto_nic is [%s]\n", value);
        }
        
        /* if we have this AUTO NIC hdl in the hash, put it in. */
        if( (nic_hdl = (char *)g_hash_table_lookup(auto_nic_hash, value)) )
		{
        	if(tracing)
			{
				printf("TRACING: replace_refs_to_AUTO_NIC_hdl: nic_hdl is [%s]\n", nic_hdl);
        	}
			/* create a new attribute with the auto nic handle */
			attr = rpsl_attr_copy((rpsl_attr_t *)(list_item->data));
            rpsl_attr_replace_value(attr, nic_hdl);

			/* remove the attribute with the auto- */
			rpsl_object_remove_attr(object, pos, NULL);
			
			/* insert new attribute with nic-hdl */
			rpsl_object_add_attr(object, attr, pos, NULL);

            /* replacing the attr destroys the list, so start the list again */
            attr_list = rpsl_object_get_all_attr(object);
            list_item = attr_list; 
        }
		else
		{ /* else, return 0 immediately */
			free(name);
			free (value);
			return NULL;
        }
	  }
	}

	free(name);
	free (value);
	
	list_item = g_list_next(list_item);
  }
	
  return_str =  rpsl_object_get_text(object,RPSL_STD_COLUMN);

  /* now, if we don't have a '\n' at the end of the return_str  string, we will
     add one, since RAToolSet parser cannot deal with objects without a '\n' at the end */
  if(return_str[strlen(return_str) - 1] != '\n')
  {
    /* so, add a '\n' */
    tempstr = (char *)malloc(strlen(return_str) + 2);
    sprintf(tempstr, "%s\n", return_str);
    free(return_str);
    return_str = tempstr;
  }
   
  if (tracing)
  {
    printf("TRACING: replace_refs_to_AUTO_NIC_hdl is returning,\nreturn_str=[%s]\n", return_str);
  }

  return return_str;
}




/* UP_put_assigned_NIC will replace the auto NIC handle of the object with its
   assigned NIC handle and return an amended copy of the object */
rpsl_object_t * UP_put_assigned_NIC(rpsl_object_t *object, char * assigned_NIC)
{
  rpsl_object_t *object2;
  rpsl_attr_t *attr;
  GList * nichdl_item;
  char *value;
  int pos;

  nichdl_item = rpsl_object_get_attr(object, "nic-hdl");  /* a list with only one item */

  value = rpsl_attr_get_clean_value((rpsl_attr_t *)(nichdl_item->data));
  g_strdown(value);
  if (strstr(value, "auto-") != NULL)
  {
    /* replace the AUTO-NIC hdl with the assigned one  */

    if (tracing)
    {
      printf("TRACING: UP_put_assigned_NIC: auto_nic is [%s]\n", value);
    }

	object2 = rpsl_object_copy(object);
	/* now copy original attribute, replace value, remove old attr and add replacement */
	attr = rpsl_attr_copy((rpsl_attr_t *)(nichdl_item->data));
	rpsl_attr_replace_value(attr, assigned_NIC);
    pos = rpsl_attr_get_ofs((rpsl_attr_t *)(nichdl_item->data));

	/* remove the attribute with the auto- */
	rpsl_object_remove_attr(object2, pos, NULL);
		
	/* insert new attribute with nic-hdl */
	rpsl_object_add_attr(object2, attr, pos, NULL);
  }
  rpsl_attr_delete_list(nichdl_item);

  return object2;
}




/* Takes a parsed object, and returns 1 if this object has 
   an AUTO NIC handle. Otherwise, returns 0 */
int has_AUTO_NIC_hdl(const rpsl_object_t * object)
{
  GList *attributes = NULL;

  if ( !rpsl_object_is_deleted(object) )
  {
    attributes = rpsl_object_get_attr(object, "nic-hdl");
    if (attributes != NULL)
	{
      if (strstr_in_attr_list(attributes, "AUTO-") == 1)
	  { /* if it contains a ref to AUTO nic */
        rpsl_attr_delete_list(attributes);
        return 1;
      }
    }
    /* if control reaches here, then we will return 0 */
    rpsl_attr_delete_list(attributes);
    return 0; 
  }
  else
  { /* it doesn't pass syntax check. So, it doesn't matter if 
           it contains refs to AUTO NIC hdls. */
    return 0;        
  }
}


/* Takes an rpsl_object_t structure , and returns 1 if this object contains
   a reference to an AUTO NIC handle. Otherwise, returns 0 */
int has_ref_to_AUTO_nic_hdl(rpsl_object_t *object)
{
  GList * attributes = NULL;

  if (! rpsl_object_is_deleted(object) )
  {
    attributes = rpsl_object_get_attr(object, "admin-c");
    rpsl_attr_split_multiple(&attributes);
    if (attributes != NULL)
	{
      if (strstr_in_attr_list(attributes, "AUTO-") == 1)
	  { /* if it contains a ref to AUTO nic */
        rpsl_attr_delete_list(attributes);
        return 1;
      }
    }
    rpsl_attr_delete_list(attributes);
    attributes = rpsl_object_get_attr(object, "tech-c");
    rpsl_attr_split_multiple(&attributes);
    if (attributes != NULL)
	{
      if (strstr_in_attr_list(attributes, "AUTO-") == 1)
	  { /* if it contains a ref to AUTO nic */
        rpsl_attr_delete_list(attributes);
        return 1;
      }
    }

    rpsl_attr_delete_list(attributes);
    attributes = rpsl_object_get_attr(object, "zone-c");
    rpsl_attr_split_multiple(&attributes);
    if (attributes != NULL)
	{
      if(strstr_in_attr_list(attributes, "AUTO-") == 1)
	  { /* if it contains a ref to AUTO nic */
        rpsl_attr_delete_list(attributes);
        return 1;
      }
    }
    rpsl_attr_delete_list(attributes);
    attributes = rpsl_object_get_attr(object, "author");
    rpsl_attr_split_multiple(&attributes);
    if (attributes != NULL)
	{
      if (strstr_in_attr_list(attributes, "AUTO-") == 1)
	  { /* if it contains a ref to AUTO nic */
        rpsl_attr_delete_list(attributes);
        return 1;
      }
    }
    rpsl_attr_delete_list(attributes);
    /* if control reaches here, then we will return 0 */
    return 0; 
  }
  else
  {  /* it doesn't pass syntax check. So, it doesn't matter if 
           it contains refs to AUTO NIC hdls. */
    return 0;        
  }
}



/* Gets the "From" line of the incoming mail message and finds out an 
   address to send the acknowledgement */
char * find_email_address(const char * from_line)
{
  char * pos1 = NULL, * pos2 = NULL, * pos = NULL;
  char * temp = NULL;
  char * part1 = NULL, * part2 = NULL;
  
  if (from_line == NULL)
  {
    return NULL;
  }
  if (strstr(from_line, "From:") != from_line)
  {
    temp = strdup(from_line);
  }
  else
  {
    temp = strdup(from_line + strlen("From:"));
  }
  g_strstrip(temp);
  if (index(temp, '<'))
  { /* then the line is something like '"John White" <john@inter.net>' */
    pos1 = index(temp, '<');
    pos2 = index(temp, '>');
    temp = strncpy(temp, pos1 + 1, pos2 - pos1 -1);
    temp[pos2 - pos1 - 1] = '\0';
    if (tracing)
	{
     printf("TRACING: find_email_address temp=[%s]\n", temp);
    }
  }

  /* and now, we have to remove the parts in parantheses */ 
  while (   index(temp, '(') != NULL && index(temp, ')') != NULL
          && index(temp, '(') < index(temp, ')') )
  {
    part1 = strdup(temp);
    /* terminate the string */
    pos = index(part1, '(');
    *pos = '\0';

    part2 = strdup(index(temp, ')') + 1);
    strcat(part1, part2);
    free(temp);
    temp = strdup(part1);
    free(part1);
    free(part2);
  }
  
  g_strstrip(temp); 
  return temp;
}  



/* removes the '\n's and '\r's at the end of the arg, and returns it  */
char * UP_remove_EOLs(char * arg)
{
  while ( strlen(arg) > 0 &&
          (arg[strlen(arg) - 1] == '\n' || 
           arg[strlen(arg) - 1] == '\r') )
  {
    arg[strlen(arg) - 1] = '\0';
  }
 
  return arg;
}



/* Duplicates the given arg, and replaces 
    $FROM,
    $SUBJECT,
    $MDATE,
    $MSGID,
    $CC,
    $HUMAILBOX
    $AUTOBOX
    $FROMHOST

    and $TIME & $DATE
    
    strings with the corresponding variables.
    
*/
char * UP_replace_globals(const char * arg)
{
  GString * g_str;
  char * to_be_returned;
  time_t cur_time;
  char * temp, * time_str, * date_str;

  /* get time */
  cur_time = time(NULL);
  temp = strdup(ctime(&cur_time));
  /* temp is now something like "Fri Sep 13 00:00:00 1986\n\0", fields are const width */ 
  
  time_str = (char *)malloc(9);  
  time_str = strncpy(time_str, temp + 11, 8);
  time_str[8] = '\0';  
            
  date_str = (char *)malloc(16);
  date_str = strncpy(date_str, temp, 11);
  date_str[11] = '\0';
  date_str = strncat(date_str, temp + 20, 4);
  
   
  free(temp);
                                         
  g_str = g_string_new(arg);

  g_str = UP_replace_GStrings(g_str, "$FROMHOST", netupdclientIP); 

  g_str = UP_replace_GStrings(g_str, "$TIME", time_str);

  g_str = UP_replace_GStrings(g_str, "$DATE", date_str);

  g_str = UP_replace_GStrings(g_str, "$SUBJECT", update_mail_subject);

  g_str = UP_replace_GStrings(g_str, "$FROM", update_mail_sender);

  g_str = UP_replace_GStrings(g_str, "$MDATE", update_mail_date); 

  g_str = UP_replace_GStrings(g_str, "$MSGID", update_mail_ID);

  if (update_mail_cc == NULL)
    g_str = UP_replace_GStrings(g_str, "$CC", ""); 
  else
    g_str = UP_replace_GStrings(g_str, "$CC", update_mail_cc);
  
  g_str = UP_replace_GStrings(g_str, "$HUMAILBOX", humailbox);

  g_str = UP_replace_GStrings(g_str, "$AUTOBOX", autobox);

  g_str = UP_replace_GStrings(g_str, "$HEADERTYPE", header_type); 

  g_str = UP_replace_GStrings(g_str, "$TEXTTYPE", text_type); 

  free(time_str);
  free(date_str);

  to_be_returned = strdup(g_str->str); 
  g_string_free(g_str, 1); 
  return to_be_returned;
}




/* Adds the given file to the update log */
void UP_add_to_upd_log(const char * filename)
{
  time_t now;
  struct tm * tmstr;
  time_t cur_time;
  char * time_str;
  char datestr[10]; 
  char * updlogfile;
  FILE * infile, * log_file;
  char   buf[1024];


  if (( infile = fopen(filename, "r")) == NULL)
  {
    fprintf(stderr, "UP_add_to_upd_log: Can't open upd file, %s\n", filename);
    return;
  }
  
  /* We need to get the a date string to construct the updlog file name */
  time(&now);
  tmstr = localtime(&now);
  strftime(datestr, 10, "%Y%m%d", tmstr);

  /* now that we have the date string, we can construct updlog file name */
  updlogfile = (char *)malloc(strlen(updlog) + strlen(datestr) + 2);
  snprintf(updlogfile, strlen(updlog) + strlen(datestr) + 2,
           "%s.%s", updlog, datestr);
  
 
  if (( log_file = fopen(updlogfile, "a")) == NULL)
  {
    fprintf(stderr, "UP_add_to_upd_log: Can't open upd log file, %s\n", updlogfile);
	free(updlogfile);
    return;
  }
   
  /* get time */
  cur_time = time(NULL);
  time_str = strdup(ctime(&cur_time));
  /* cut the '\n' at the end */
  time_str[strlen(time_str) - 1] = '\0';

  if (reading_from_mail)
  {
    fprintf(log_file, ">>> time: %s MAIL UPDATE <<<\n\n", time_str);
  }
  else if (networkupdate)
  {
    fprintf(log_file, ">>> time: %s NETWORKUPDATE UPDATE (%s) <<<\n\n", 
                      time_str, netupdclientIP ? netupdclientIP : "NULL");
  }
  else if (webupdate)
  {
    fprintf(log_file, ">>> time: %s WEB UPDATE (%s) <<<\n\n", 
                       time_str, netupdclientIP ? netupdclientIP : "NULL");
  }
  else
  {
    fprintf(log_file, ">>> time: %s UPDATE <<<\n\n", time_str);
  }

  free(time_str);
  while ( fgets(buf, 1023, infile) != NULL ) 
  {
    fprintf(log_file, "%s", buf);
  }
  free(updlogfile);

  fclose(infile);
  fclose(log_file);
}



/* Logs the object to the update log */
void UP_log_networkupdate(const char * object_str, const char * host)
{
  time_t now;
  struct tm * tmstr;
  time_t cur_time;
  char * time_str;
  char datestr[10]; 
  char * updlogfile;
  FILE * log_file;

  /* We need to get the a date string to construct the updlog file name */
  time(&now);
  tmstr = localtime(&now);
  strftime(datestr, 10, "%Y%m%d", tmstr);

  /* now that we have the date string, we can construct updlog file name */
  updlogfile = (char *)malloc(strlen(updlog) + strlen(datestr) + 2);
  snprintf(updlogfile, strlen(updlog) + strlen(datestr) + 2,
           "%s.%s", updlog, datestr);
  
  if (( log_file = fopen(updlogfile, "a")) == NULL)
  {
    fprintf(stderr, "UP_add_to_upd_log: Can't open upd log file, %s\n", updlogfile);
	free(updlogfile);
    return;
  }
  free(updlogfile);
   
  /* get time */
  cur_time = time(NULL);
  time_str = strdup(ctime(&cur_time));
  /* cut the '\n' at the end */
  time_str[strlen(time_str) - 1] = '\0';

  fprintf(log_file, ">>> time: %s NETWORKUPDATE UPDATE (%s) <<<\n\n", time_str, host);

  free(time_str);

  fprintf(log_file, "%s\n", object_str);

  fclose(log_file);
}




/* Performs a preliminary check on a string: Tries to guess if the arg is an object or not.
   The criteria is: If we have a colon (":") in the first line of the string, then it is
   probably an object */
int UP_is_object(const char * arg)
{
   if (arg == NULL)
   {
     return 0; /* not an object */
   }

   if (index(arg ,'\n'))
   { /* does it consist of multiple lines? */
     if (index(arg ,':') != NULL  && (index(arg ,':') < index(arg ,'\n')))
	 {
       return 1;
     }
	 else
	 { /* it doesn't have any ":" or, first ":" is not in the first line */
       return 0;
     }
   }
   else
   { /* it has a single line, possibly not an object */
     return 0;
   }
}


int UP_remove_override_attr( rpsl_object_t *object )
{
  rpsl_error_t return_error;
  rpsl_attr_t *removed_attr;

  return_error.code = (gint)NULL;
  removed_attr = rpsl_object_remove_attr_name(object,"override",&return_error);
  if ( (removed_attr == NULL) && return_error.level >= RPSL_ERRLVL_ERROR )
  {
	 /* error returned */
	 /* could be that there was no override attribute in this object */
     if ( return_error.code == RPSL_ERR_NOSUCHATTR )
	   return 1;  /* This is OK, object has no override attribute */
	 else
	   /* there was an override attr in this object and it has not been removed */
	   return 0;
  }
  else
    /* no errors, override attribute has been removed */
	 return 1; 
}


/****************************************************************************************************/

/*******************  Redundant Functions ***********************************************************/



/* strips lines beginning with "override:" off  */
char * delete_override(char * arg){

    char ** temp = NULL;
    char * string = NULL;
    int i;

    if(arg == NULL){
       return NULL;
    }

    /* split the string into lines */
    temp = g_strsplit (arg, "\n", 0);

    for(i=0; temp[i] != NULL; i++){
      /* if the line begins with "override:", then do not copy it */
      if(strstr(temp[i], "override:") != temp[i]){
        if(string == NULL){
          string = strdup(temp[i]);
        }else{
          string = (char *)realloc(string, strlen(string) + strlen(temp[i]) + 2);
          string = strcat(string, "\n");
          string = strcat(string, temp[i]);
        }
      }
    }
    g_strfreev(temp);
    return string;
}


/* takes a pre-parsed object, and returns its type */
/* char * get_class_type(Object *arg){
    
    char * be_returned = NULL;
    if(arg == NULL) return NULL;
    be_returned = strdup(arg->type->getName());  
    return g_strstrip(be_returned);
}
*/







/*************** still used in nt module **************/
/* strips lines beginning with "delete:" off  */
char * delete_delete_attrib(char * arg){

    char ** temp = NULL;
    char * string = NULL;
    int i;

    if(arg == NULL){
       return NULL;
    }

    /* split the string into lines */
    temp = g_strsplit (arg, "\n", 0);

    for(i=0; temp[i] != NULL; i++){
      /* if the line begins with "delete:", then do not copy it */
      if(strstr(temp[i], "delete:") != temp[i]){
        if(string == NULL){
          string = strdup(temp[i]);
        }else{
          string = (char *)realloc(string, strlen(string) + strlen(temp[i]) + 2);
          string = strcat(string, "\n");
          string = strcat(string, temp[i]);
        }
      }
    }
    g_strfreev(temp);
    return string;
}
