/***************************************
  $Revision: 1.16 $

  UP external syntax checks

  Status: REVIEWED, NOT TESTED

  Author(s):       Engin Gunduz

  ******************/ /******************
  Modification History:
        engin (15/12/2000) Created.
        denis (31/08/2001) Modified for new API
  ******************/ /******************
  Copyright (c) 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 "rpsl/object.hh"*/
#include "UP_extrnl_syntax.h"
#include "dbupdate.h"

#define UP_DATE_OK      0
#define UP_DATE_SYNERR  1
#define UP_DATE_FUTURE  2
#define UP_DATE_TOOSMALL        3
#define UP_DATE_INVMONTH        4
#define UP_DATE_INVDAY  5
#define UP_DATE_WRONGFORMAT 6
#define UP_DATE_NOK    7

char * up_date_errmsgs[]=
{

  "OK",
  "Syntax error in date of 'changed' attribute",
  "Date in the future in 'changed' attribute",
  "Date is older than the database itself in 'changed' attribute",
  "Invalid month in date in 'changed' attribute",
  "Invalid day in date in 'changed' attribute",
  "Date must be in YYYYMMDD format in 'change' attribute",
  "Syntax error in date of 'changed' attribute"
};


extern int tracing;

extern char * fingerprint;
extern char * keyowner;

extern int      num_sources;
extern char    *countries[];
extern char    *nicsuffixes[];
extern ca_updDbSource_t **upd_source_hdl;


/* void up_check_source_attr 
   checks for a valid source in the 'source' attributes */
void up_check_source_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
{
  int valid,i ;
  char *source_name;
  char *temp;
  GList *source_list;

  if (tracing)
  {
    printf("TRACING: up_check_source_attr running\n");
  }
 
  source_list = rpsl_object_get_attr(external_syntax_obj, "source");

  valid = i = 0 ;
  if ( source_list )
  {
    source_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(source_list->data) );
    for ( i=0; i<num_sources; i++ )
    {
      if ( ! strcasecmp( source_name, upd_source_hdl[i]->name) )
      {
        valid = 1;
        break;
      }
    }

/*    while(sources[i])
    {
      if(strcasecmp(sources[i++],source_name) == 0)
      {
        valid = 1;
        break;
      }
    } */

    g_list_free(source_list);
  }

  if (!valid)
  {
    /* the source is not recognised */

    if (tracing)
    {
      printf("TRACING: invalid source [%s]\n", source_name );
    }

    if (result->error_str == NULL)
	{
      result->error_str = strdup("***Error: No such source");
    }
	else
	{
      temp = (char *)malloc(strlen(result->error_str) 
              + strlen("***Error: No such source") + 2);
      sprintf(temp, "%s\n%s", result->error_str, 
              "***Error: No such source");
      free(result->error_str);
      result->error_str = temp;
    }
    /* and here we have to change the result code of "result" here ... */
    switch (result->result)
	{
      case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
      case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
      default:                 result->result = UP_EXTSYN_ERR; break;
    }
  }
  
  free(source_name);
}


/* void up_check_country_attr 
   checks for a valid country in the 'country' attributes */
void up_check_country_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
{
  int valid,i, matched ;
  char *country_name;
  char *temp;
  GList *country_list = NULL;
  GList *country_item = NULL;
 
  country_list = rpsl_object_get_attr(external_syntax_obj, "country");
  rpsl_attr_split_multiple(&country_list);
  
  if ( country_list == NULL )
    return;		/* only check if there is one */

  valid = 1 ;
  for ( country_item = country_list; country_item != NULL ; country_item = g_list_next(country_item) )
  {
    country_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(country_item->data) );
    matched = 0 ;
    i = 0 ;
    while(countries[i])
    {
      if(strcasecmp(countries[i++],country_name) == 0)
      {
        matched = 1;
        break;
      }
    }

    if ( ! matched )
    {
      valid = 0 ;
      break;
    }
    free(country_name);
  }
  g_list_free(country_list);

  if (!valid)
  {
    /* the country is not recognised */
    if (result->error_str == NULL)
	{
      result->error_str = malloc(strlen("***Error: No such country []") + strlen(country_name) +2);
      sprintf(result->error_str, "***Error: No such country [%s]", country_name);
    }
	else
	{
      temp = (char *)malloc(strlen(result->error_str) 
              + strlen("***Error: No such country []") + strlen(country_name) + 2);
      sprintf(temp, "%s\n***Error: No such country [%s]", result->error_str, 
              country_name);
      free(result->error_str);
      result->error_str = temp;
    }

    free(country_name);

    /* and here we have to change the result code of "result" here ... */
    switch (result->result)
	{
      case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
      case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
      default: ;
    }
  }
}

/* void up_check_nicsuffixes 
   checks for a valid suffix at the end of a 'nic-hdl' attributes */
void up_check_nicsuffixes(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
{
  int valid,i ;
  char *name;
  char *temp;
  GList *list;

  if (tracing)
  {
    printf("TRACING: up_check_nicsuffixes running\n");
  }
 
  list = rpsl_object_get_attr(external_syntax_obj, "nic-hdl");

  valid = i = 0 ;
  if ( list )
  {
    name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(list->data) );
    if ( !strchr(name,'-') || strncasecmp(name,"AUTO-",strlen("AUTO-")) == 0 )
    {
      valid = 1;
    }
    else
    {
      while (nicsuffixes[i])
      {
        if ( strcasecmp(nicsuffixes[i++],strchr(name,'-')+1) == 0 )
        {
          valid = 1;
          break;
        }
      }
      if ( ! valid )
      {
        i = 0;
        for ( i=0; i<num_sources; i++ )
        {
          if ( ! strcasecmp( upd_source_hdl[i]->name, strchr(name,'-')+1) )
          {
            valid = 1;
            break;
          }
        }

/*        while (sources[i])
        {
          if (strcasecmp(sources[i++],strchr(name,'-')+1) == 0 )
          {
            valid = 1;
            break;
          }
        } */

        if ( ! valid )
        {
          i = 0;
          while (countries[i])
          {
            if ( strcasecmp(countries[i++],strchr(name,'-')+1) == 0 )
            {
              valid = 1;
              break;
            }
          }
        }
      }
    }
    free(name);
    g_list_free(list);

    if (!valid)
    {
      /* the nicsuffix is not recognised */
      if (result->error_str == NULL)
	  {
        result->error_str = strdup("***Error: Invalid nic-hdl suffix");
      }
	  else
	  {
        temp = (char *)malloc(strlen(result->error_str) 
                + strlen("***Error: Invalid nic-hdl suffix") + 2);
        sprintf(temp, "%s\n%s", result->error_str, 
                "***Error: Invalid nic-hdl suffix");
        free(result->error_str);
        result->error_str = temp;
      }
      /* and here we have to change the result code of "result" here ... */
      switch (result->result)
	  {
        case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
        case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
        case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
        case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
        default: ;
      }
    }
  }
}


/* obtains a list of dates in the given 
   list of attributes  */
GList * up_get_dates(GList * attribute_list)
{
  GList * item;
  char * str, *temp; 
  GList * list = NULL;

  for ( item = attribute_list; item != NULL ; item = g_list_next(item) )
  {
    /* is this a 'changed' attribute? */
    if ( strcmp(rpsl_attr_get_name((rpsl_attr_t *)(item->data)), "changed") == 0 )
	{
      str = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));


      /* now, we have the 'changed' attribute's content in "normalized" form 
         We are sure it contains a date. So, it must be the second (and last)
         word in the attrib. */
      assert(index(str,' ') != NULL);
      temp = (char *)malloc(strlen(str) - (index(str,' ') - str ));
      temp = strncpy(temp, index(str,' ') + 1, strlen(str) - (index(str,' ') - str ) - 1);
      temp[strlen(str) - (index(str,' ') - str ) - 1] = '\0'; /* NULL terminate it */
      list = g_list_append (list, temp);   
    }
  }
  
  return list;
}




/* Does the 'changed' attribute we got have a date already?
   Returns 1 if it does, 0 if not. */
int up_changed_has_date(char * value)
{
  /* now, if there is still a white space, then we have a date in the string
     (it has to be something like "ripe-dbm@ripe.net 20001210") */
  if (index(value, ' ') != NULL)
  {
    return 1; 
  }
  else
  {
    return 0;
  }
}




/* supplies the current date in YYYYMMDD format (for example 20011010) */
char * UP_get_current_date()
{
  /* We will use Glib's functions here */

  char * date;
  struct tm * time_struct;
  
  time_t * time_loc;

  time_loc = (time_t *)malloc(sizeof(time_t));
  time(time_loc);
  
  time_struct = localtime(time_loc);


  date = (char *)malloc(9);
  sprintf(date, "%04i%02i%02i", 
          time_struct->tm_year + 1900, 
          time_struct->tm_mon + 1,
          time_struct->tm_mday);
  return date;
}




/* int up_add_dates: adds dates to 'changed' attributes which 
     are missing one.
     Returns 1 if no problems encountered
     Returns 0 if a problem encountered, and the error string is set */
int up_add_dates(rpsl_object_t *external_syntax_obj, GList *attribute_list, char ** warning_str, char ** error_str)
{
  GList * item;
  char * current_date;
  int count_no_date = 0; 
  char * temp;
  rpsl_attr_t *changed;
  char *value;
  int pos;
  
  *warning_str = NULL;
  *error_str   = NULL;

  /* get the current date in YYYYMMDD format (for example 20011010) */
  current_date = UP_get_current_date();
  
  for ( item = attribute_list; item != NULL ; item = g_list_next(item) )
  {
    /* is this a 'changed' attribute? */
    if (strcmp(rpsl_attr_get_name((rpsl_attr_t *)(item->data)), "changed") == 0)
	{
      /* if this attribute does not have a date in it, add it. Also add 
          a warning message about this */
	  value = rpsl_attr_get_clean_value((rpsl_attr_t *)(item->data));
      if ( !up_changed_has_date(value) )
	  {
        count_no_date++;
		/* create a copy of this changed attribute and add the date to the value */
		changed = rpsl_attr_copy((rpsl_attr_t *)(item->data));
        temp = (char *)malloc(strlen(value) + strlen(current_date) + 2 );
        sprintf(temp, "%s %s", value, current_date);
        rpsl_attr_replace_value(changed, temp);
        free(temp);
		/* delete the original attribute from the object */
		pos = rpsl_attr_get_ofs(changed);
		rpsl_object_remove_attr(external_syntax_obj, pos, NULL);
		/* add the new changed attribute in the same position */
		rpsl_object_add_attr(external_syntax_obj, changed, pos, NULL);
        /* add a warning message */
        if ( *warning_str == NULL)
		{
          *warning_str = (char *)malloc(strlen("WARNING  date '' added to 'changed' attribute") + 9 );
          sprintf(*warning_str, "WARNING  date '%s' added to 'changed' attribute", current_date);
        }
		else
		{
          temp = (char *)malloc(strlen(*warning_str) + 1 
                                       + strlen("WARNING  date '' added to 'changed' attribute") + 9 );
          sprintf(temp, "%s\nWARNING  date '%s' added to 'changed' attribute", 
                              *warning_str, current_date);
          free(*warning_str);
          *warning_str = temp; 
        }
      }
	  free(value);
    }
  }
  
  if (count_no_date > 1)
  { 
    *error_str = strdup("***Error: More than one 'changed' attributes without dates");
    return 0;
  }
  else
  {
    return 1;
  }
}




/* Checks the order of dates in the given list. 
   If they are in order, returns 1, 
   if not, returns 0 */
int up_check_date_order(GList * list)
{
  GList * item;
  char * previous;
  char *value;

  /* if list is empty, return 1 immediately */
  if (list == NULL)
  {
    return 1;
  }

  /* initialize the 'previous' date */
  previous = strdup("00000000");
   
  for ( item = list; item != NULL ; item = g_list_next(item))
  {
    assert((item->data) != NULL);
    /* if the new date is smaller than the previous */
	value = (char *)(item->data);
    if ( strcmp(value, previous) < 0 )
	{
      free(previous);
      return 0;
    }
    free(previous);
    previous = strdup(value);
  }
   
  free(previous);
  /* Reached the end, without finding out-of-order date. Return 1, then */
  return 1; 
}





/* up_check_date: checks the syntax of the date, given as the only
   argument (char *). The argument is checked if it is in YYYYMMDD
   format, and returns an error code accordingly */
int up_check_date(const char * arg)
{
  int date_int; /* integer representation of the date (arg) */
  char * current_date;
  int year, month, day; /* integers for the components of the date */

  errno = 0;
  date_int = atoi(arg);
      
  if (errno != 0)
  { /* there was an error in the conversion, syntax error */
    return UP_DATE_SYNERR;
  }
    
  /* wrong format */
  if (date_int <= 10000000 )
  { /* the date is not in YYYYMMDD format */
    return UP_DATE_WRONGFORMAT;
  }

  /* check if it is too small */  
  if (date_int <= 19840000 )
  { /* the date is older than the DB itself! */
    return UP_DATE_TOOSMALL;
  }

  /* check if it is too big */
  if (date_int >= 100000000 )
  {/* too big: syntax error */
    return UP_DATE_SYNERR;
  }

  /* and now check year, month and day components */
  year = date_int / 10000;
  month = (date_int - (year * 10000) ) / 100;
  day = (date_int % 100);
  
  /* check year */
  if (year < 1984 )
  {
    return UP_DATE_TOOSMALL;
  }

  /* check month */
  if (month < 1 || month > 12)
  {
    return UP_DATE_INVMONTH;
  }

  /* check day */
  if (day < 1 || day > 31)
  {
    return UP_DATE_INVDAY;
  }

  switch ( month )
  {
    case 1: case 3: case 5: case 7:
    case 8: case 10: case 12:
         if (day > 31)
		 {
           return UP_DATE_INVDAY;
         };
         break;
    case 2: 
         if ( (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) && (day > 29 ))
		 { /* leap year */
           return UP_DATE_INVDAY;
         }
		 else if( (!(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) && (day > 28) )
		 { /* non-leap year */
           return UP_DATE_INVDAY;
         };
         break;
    case 4: case 6: case 9: case 11:
         if (day > 30)
		 {
           return UP_DATE_INVDAY;
         };
         break;
    default: return UP_DATE_INVMONTH;
  }

  /* check if the arg is in the future or not */
  current_date = UP_get_current_date();
  if (strcmp(current_date, arg) < 0 )
  { /* arg is in the future */
    free(current_date);
    return UP_DATE_FUTURE;
  }
  free(current_date);
    
  return UP_DATE_OK;
}



/* Checks the syntax of the dates in the list */
date_syntax_struct * up_check_dates_syntax(GList * list)
{
  GList * item;
  date_syntax_struct * result;
  int res;

  /* initialize the result struct */
  result = (date_syntax_struct *)malloc(sizeof(date_syntax_struct));
  result->result = UP_DATE_OK;
  result->error_str = NULL;

  /* if list is empty, return immediately */
  if (list == NULL)
  {
    return result;
  }

  /* loop through the members of the list, check each of them */
  for ( item = list; item != NULL ; item = g_list_next(item))
  {
    assert((item->data) != NULL);
    
    /* check the date */
    res = up_check_date((char *)(item->data));
    switch (res)
	{
      case UP_DATE_OK: break;
      
      case UP_DATE_FUTURE:
      case UP_DATE_TOOSMALL:
      case UP_DATE_INVDAY:
      case UP_DATE_INVMONTH:
      case UP_DATE_WRONGFORMAT:

             if (result->error_str == NULL)
			 {
               result->error_str = (char *)malloc(strlen("***Error: ") + strlen(up_date_errmsgs[res]) 
                                                  + strlen(": ") + strlen((char *)(item->data)) + 1);
               sprintf(result->error_str, "***Error: %s: %s", up_date_errmsgs[res],
                       (char *)(item->data));
             }
			 else
			 {
               result->error_str = (char *)realloc(result->error_str, strlen(result->error_str) + 1 
                                                   + strlen("***Error: ") + strlen(up_date_errmsgs[res]) 
                                                   + strlen(": ") + strlen((char *)(item->data)) + 1);
               sprintf(result->error_str, "%s\n***Error: %s: %s",
                       result->error_str, up_date_errmsgs[res], (char *)(item->data));
             }
             result->result = UP_DATE_NOK; /* Not OK */

             break;
             
             
      case UP_DATE_SYNERR: /* syntax error in the date */

      default:
             if (result->error_str == NULL)
			 {
               result->error_str = (char *)malloc(strlen("***Error: ") + strlen(up_date_errmsgs[UP_DATE_SYNERR]) 
                                                  + strlen(": ") + strlen((char *)(item->data)) + 1);
               sprintf(result->error_str, "***Error: %s: %s", up_date_errmsgs[UP_DATE_SYNERR],
                       (char *)(item->data));
             }
			 else
			 {
               result->error_str = (char *)realloc(result->error_str, strlen(result->error_str) + 1 
                                                   + strlen("***Error: ") + strlen(up_date_errmsgs[UP_DATE_SYNERR]) 
                                                   + strlen(": ") + strlen((char *)(item->data)) + 1);
               sprintf(result->error_str, "%s\n***Error: %s: %s",
                       result->error_str, up_date_errmsgs[UP_DATE_SYNERR], (char *)(item->data));
             }
             result->result = UP_DATE_NOK; /* Not OK */
             break;
    }
  }
  
  return result;
}



/* void up_check_changed_attr 
   checks the order of dates in the 'changed' attributes */
void up_check_changed_attr(rpsl_object_t *external_syntax_obj, external_syntax_struct * result)
{
  GList * date_list;
  int res;
  char ** warning, **error;
  char * temp;
  date_syntax_struct * date_check_res;
  GList *changed_list;

  warning = (char **)malloc(sizeof(char **));
  error   = (char **)malloc(sizeof(char **));
  changed_list = rpsl_object_get_attr(external_syntax_obj, "changed");

  /* Now, add dates to the "changed" attributes */
  res = up_add_dates(external_syntax_obj, changed_list, warning, error);
  if (!res)
  {
    /* so, add the error string to result's error string */
    if (result->error_str == NULL)
	{
      result->error_str = strdup(*error);
    }
	else
	{
      temp = (char *)malloc(strlen(result->error_str) + strlen(*error) + 2);
      sprintf(temp, "%s\n%s", result->error_str, *error);
      free(result->error_str);
      result->error_str = temp;
    }
  }

  /* and get the list of dates, we must check their order */
  /* we may have added a date to one of the changed attrs so get the list again */
  rpsl_attr_delete_list(changed_list);
  changed_list = rpsl_object_get_attr(external_syntax_obj, "changed");
  date_list = up_get_dates(changed_list);
  /* and check the order */ 
  res = up_check_date_order(date_list);
  if (!res)
  {
    /* so, add the error string to result's error string */
    if (result->error_str == NULL)
	{
      result->error_str = strdup("***Error: The dates in the 'changed' attributes should be in order");
    }
	else
	{
      temp = (char *)malloc(strlen(result->error_str) 
              + strlen("***Error: The dates in the 'changed' attributes should be in order") + 2);
      sprintf(temp, "%s\n%s", result->error_str, 
              "***Error: The dates in the 'changed' attributes should be in order");
      free(result->error_str);
      result->error_str = temp;
    }
    /* and here we have to change the result code of "result" here ... */
    switch (result->result)
	{
      case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
      case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
      default: ;
    }
  }

  /* check the syntax of dates */
  date_check_res = up_check_dates_syntax(date_list);
  if (date_check_res->result != UP_DATE_OK)
  {
    /* so, add the error string to result's error string */
    if (result->error_str == NULL)
	{
      result->error_str = strdup(date_check_res->error_str);
    }
	else
	{
      temp = (char *)malloc(strlen(result->error_str) 
              + strlen(date_check_res->error_str) + 2);
      sprintf(temp, "%s\n%s", result->error_str, 
              date_check_res->error_str);
      free(result->error_str);
      result->error_str = temp;
    }
    /* and here we have to change the result code of "result" here ... */
    switch (result->result)
	{
      case UP_EXTSYN_OK:       result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_ERR:      result->result = UP_EXTSYN_ERR; break;
      case UP_EXTSYN_WARN:     result->result = UP_EXTSYN_ERR_WARN; break;
      case UP_EXTSYN_ERR_WARN: result->result = UP_EXTSYN_ERR_WARN; break;
      default: ;
    }
  }
}


/* performs a simple check on a inetnum attribute. Assumes that
   the RPSL parser has already checked it. Tries to see if the attr
   is a range or not  */
int up_check_an_inetnum_attr(const char * arg){
  

  char * str;
  char * pos;

  str = strdup(arg);

  while((pos = index(str, '\n')) != NULL){
    *pos = ' ';
  }

  /* strip off the comment */
  if((pos = index(str, '#')) != NULL){
    *pos = '\0';
  }
   
   
  /* Most of the syntax check is done by RPSL parser. We only need to check
     that the argument is a _range_ of IPv4 addresses. So it suffices to
     check the existence of '-' in the arg */
  if(index(str, '-') != NULL){
    
    free(str);
    return 1;
    
  }else{

    free(str);
    return 0;

  }
}


/* void up_add_keycert_attrs
   adds the generated attrs of key-cert objects */
void up_add_keycert_attrs(rpsl_object_t *generated_obj)
{
  const char *type;
  char *attr_str;
  rpsl_attr_t *method_attr;
  rpsl_attr_t *owner_attr;
  rpsl_attr_t *fingerpr_attr;

  if (tracing)
  {
    printf("TRACING: UP_add_keycert_attrs: is running\n");
  }
  
  /* if this is a key-cert object */
  type = rpsl_object_get_class(generated_obj);
  if ( strcmp(type, "key-cert") == 0 )
  {
      method_attr = rpsl_attr_init("method: PGP", type);
	  if ( method_attr )
      {
    	rpsl_object_add_attr(generated_obj, method_attr, 1, NULL);
	  }

      attr_str = (char *)malloc( sizeof("owner: ") + strlen(keyowner) +1 );
	  strcpy(attr_str, "owner: ");
	  strcat(attr_str, keyowner);
      if (tracing)
      {
        printf("TRACING: UP_add_keycert_attrs: owner attr_str [%s]\n", attr_str);
      }
      owner_attr = rpsl_attr_init(attr_str, "key-cert");
	  if ( owner_attr )
      {
    	rpsl_object_add_attr(generated_obj, owner_attr, 2, NULL);
	  }
      free(attr_str);

      attr_str = (char *)malloc( sizeof("fingerpr: ") + strlen(fingerprint) +1 );
	  strcpy(attr_str, "fingerpr: ");
	  strcat(attr_str, fingerprint);
      if (tracing)
      {
        printf("TRACING: UP_add_keycert_attrs: fingerprint attr_str [%s]\n", attr_str);
      }
      fingerpr_attr = rpsl_attr_init(attr_str, "key-cert");
	  if ( fingerpr_attr )
      {
    	rpsl_object_add_attr(generated_obj, fingerpr_attr, 3, NULL);
	  }
      free(attr_str);
  }
}


/* up_reconstruct_object: Reconstructs the object's text representation
     using the parsed object */
void up_reconstruct_object(rpsl_object_t *external_syntax_obj, external_syntax_struct *result)
{
  char * recons_obj = NULL;
  
  recons_obj = rpsl_object_get_text(external_syntax_obj,RPSL_STD_COLUMN);

  result->new_obj = recons_obj;
}



/*  UP_check_external_syntax: Checks the syntax of attributes which are not checked
       by the api parser module. */
external_syntax_struct * UP_check_external_syntax(rpsl_object_t *external_syntax_obj)
{
  external_syntax_struct *result;
  
  if (tracing)
  {                                
	printf("TRACING: UP_check_external_syntax running\n");
  }

  result = (external_syntax_struct *)malloc(sizeof(external_syntax_struct));

  /* initialize the struct */
  result->result = 0;
  result->error_str = strdup(""); 
  result->warning_str = strdup("");

  up_check_source_attr(external_syntax_obj, result);

  up_check_country_attr(external_syntax_obj, result);

  up_check_nicsuffixes(external_syntax_obj, result);

  up_check_changed_attr(external_syntax_obj, result);
    
  up_reconstruct_object(external_syntax_obj, result);

  if (tracing)
  {
    printf("TRACING: UP_check_external_syntax: the reconstructed object is=[%s]\n", result->new_obj);
    printf("TRACING: UP_check_external_syntax: ... and the result code is=[%i]\n", result->result);
  }

  return result;  
}



/* generates the "generated" attributes of a key-cert object. Returns the 
   new object string*/
char *UP_generate_kc_attrs(rpsl_object_t *generated_obj)
{
  external_syntax_struct *result;
  char *obj_str;

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

  result = (external_syntax_struct *)malloc(sizeof(external_syntax_struct));

  /* initialize the struct */
  result->result = 0;
  result->error_str = strdup(""); 
  result->warning_str = strdup("");

  up_check_changed_attr(generated_obj, result);
  up_add_keycert_attrs(generated_obj); 
  
  up_reconstruct_object(generated_obj, result);

  if (tracing)
  {
    printf("TRACING: UP_generate_kc_attrs: the reconstructed object is=[%s]\n", result->new_obj);
    printf("TRACING: UP_generate_kc_attrs: ... and the result code is=[%i]\n", result->result);
  }

  obj_str = strdup(result->new_obj);
  free(result);
  return obj_str;  
}



/* char * up_assign_i6_status: Determines the status attribute of
    an inet6num object. It takes the inet6num attribute of the
    object as its only argument. If prefix length is less than
    4, then returns NULL */
char * up_assign_i6_status(const char * inet6num_attr)
{

  char ** split_str;
  int prefix_length;
  int result;

  /* we need the prefix length here.*/
  split_str = g_strsplit(inet6num_attr, "/", 0);
  if(split_str[1] != NULL){

    result = sscanf(split_str[1], "%i", &prefix_length);
    if(result != 0 && result != EOF){

      if(prefix_length >= 0 && prefix_length <= 3){

        g_strfreev(split_str); 
        return NULL;
        
      }else if(prefix_length >= 4 && prefix_length <= 15){

        g_strfreev(split_str); 
        return strdup("TLA");
        
      }else if(prefix_length >= 16 && prefix_length <= 35){

        g_strfreev(split_str); 
        return strdup("SUBTLA");
        
      }else if(prefix_length >= 36 && prefix_length <= 48){

        g_strfreev(split_str); 
        return strdup("NLA");
   
      }else if(prefix_length >= 48 && prefix_length <= 64){

        g_strfreev(split_str); 
        return strdup("SLA");
        
      }else{

        /* "default" status */
        g_strfreev(split_str); 
        return strdup("SLA");
        
      }
      
    }else{
      
      /* return "default" status */
      g_strfreev(split_str);
      return strdup("SLA");
      
    }
  }else{
    
    /* return "default" status */
    g_strfreev(split_str);
    return strdup("SLA");

  }
  
}



/* GSList * up_add_inet6num_attrs
   adds the generated attrs of inet6num objects */
/*GSList * up_add_inet6num_attrs(Object * obj, char * obj_text, GSList * attribute_list, 
                               external_syntax_struct * result)*/
void up_add_inet6num_attrs(rpsl_object_t *generated_obj)                               
{

  int attribute_no;
  char *status_value;
  rpsl_attr_t * status_attr;
  char *inet6num_attr_str, *status_attr_str;
  const char *type;
  GList *attributes_changed;
  


  /* if this is an inet6num  object */
  type = rpsl_object_get_class(generated_obj);
  if( ! strcmp(type, "inet6num") )
  {
      inet6num_attr_str = get_search_key(generated_obj, "inet6num");
      status_value = up_assign_i6_status(inet6num_attr_str);
      status_attr_str = (char *)UT_malloc(strlen("status: ") + strlen(status_value) + 1);
      strcpy(status_attr_str, "status: ");
      strcat(status_attr_str, status_value);
      status_attr = rpsl_attr_init(status_attr_str, type);
	  free(status_attr_str);
	  if ( status_attr )
      {
    	/* we will put the status attribute before the first 'changed' attribute */
    	attribute_no = 1; /* a default position (the second attribute) in case we cannot find
                        	 a 'changed' attribute */    
    	attributes_changed = rpsl_object_get_attr(generated_obj, "changed");    
    	if ( attributes_changed != NULL )
		{
          attribute_no = ((rpsl_attr_t *)(attributes_changed->data))->num;
    	}
    	rpsl_object_add_attr(generated_obj, status_attr, attribute_no, NULL);
      }
  }
}

