/***************************************
  $Revision: 1.18 $

  UP module utilities

  Status: NOT REVIEWED, NOT TESTED

  Author(s):       Engin Gunduz

  ******************/ /******************
  Modification History:
        engin (17/01/2000) Created.
  ******************/ /******************
  Copyright (c) 2000                              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 "dbupdate.h" 

int error = 0; // a global variable to store the errors
char * error_msg = NULL; // a global variable to store the error messages
extern int tracing;

/* 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 */
    }
  }
}

/* concatanates the string at the end of error_msg */
void error_msg_cat(const char * string){

  if(string == NULL){
    return;
  }
  if(error_msg == NULL){
    error_msg = strdup(string);
  }else{
    error_msg = (char *)realloc(error_msg, strlen(error_msg) + strlen(string) + 2);
    error_msg = strcat(error_msg, "\n");
    error_msg = strcat(error_msg, string); 
  }
}


/* 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){
    error = UP_INT; /* internal error, RIPupd should return something */
    error_msg_cat("Internal error. RIPupd didn't return anything.");
    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);
      printf("TRACING: interpret_ripdb_result: error_no is [%s]\n", error_no);
    }else if(error_no != NULL && strcmp(error_no, "0") != 0){
      error_msg_cat(temp[i]);
    }
  }
  g_strfreev(temp);
  //if(error_no != NULL && error_msg != NULL){
  //  printf("TRACING: interpret_ripdb_result: Error: [%s][%s]\n", error_no, error_msg);  
  //}
  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;
   //char * to_be_returned = NULL;
     
  /* if the string is NULL or empty, then return error */
  if(string == NULL || strlen(string) == 0){
    error = UP_INT; /* internal error, RIPupd should return something */
    error_msg_cat("Internal error. RIPupd didn't return anything.");
    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);
      printf("TRACING: get_assigned_nic: error_no is [%s]\n", error_no);
    }else if(error_no != NULL && strcmp(error_no, "0") != 0){
      error_msg_cat(temp[i]);
    }else if(error_no != NULL && strcmp(error_no, "0") == 0 && i == 1){/* look for assigned NIC hdl */
      printf("error_no != NULL && strcmp(error_no, \"0\") == 0 && i == 1\n");
      /* in the second line RIPupdate returns for example "I[65][EK3-RIPE]" We
         need to extract EK3-RIPE part */
      //to_be_returned = (char *)malloc(128); /* 128 should be enough for a NIC hdl */
      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(nic_hdl != NULL){
        printf("DEBUG: get_assigned_nic will return [%s]\n", nic_hdl);
      }
      g_strfreev(temp);
      //return to_be_returned;
      return;
    }
  }
  g_strfreev(temp);
  if(error_no != NULL && error_msg != NULL){
    printf("TRACING: interpret_ripdb_result: Error: [%s][%s]\n", error_no, error_msg);  
  }
  return;
}



/* 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
   */
int send_object_db(char * arg, char * assigned_NIC, char * operation){

        int sockfd, numbytes;  
        char buf[MAXDATASIZE];
        struct hostent *he;
        struct sockaddr_in their_addr; /* connector's address information */
        char *result_string = NULL;
        char *to_be_returned = NULL;
        int err = 0;


        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, "\n\n" , strlen("\n\n"), 0) == -1)
            perror("send");
        if (send(sockfd, arg , strlen(arg), 0) == -1)
            perror("send");
        if (send(sockfd, "\n\n",2,0)  == -1)
            perror("send");


        while ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) != 0) {
            buf[numbytes] = '\0';
            printf("%s",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);
            }
        }

        err = interpret_ripdb_result(result_string);
        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);
        return err; /* 0 means no error in this context */ 
}






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






/* takes an object (pre-parsed) and returns its first attrib if it is not
   a person, and returns the nic-hdl if it is a person object */
char * get_search_key(Object *arg, char * type, const char * text){

    
    Attr *attr;    
    char *primary_key = NULL, *value = NULL;

    if(arg == NULL) return NULL;

    for(attr = arg->attrs.head(); attr; attr = arg->attrs.next(attr)){
       value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
       strncpy(value, (char *)(text+attr->offset) + strlen(attr->type->name())+1,
           attr->len - strlen(attr->type->name()) -2 );
           value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
       //cout << "value: #" << value << "#" << endl;
       if(strcmp(attr->type->name(),type) == 0 &&
              strcmp(type,"person") != 0){
         primary_key = strdup(value);
       }
       if(strcmp(attr->type->name(),"nic-hdl") == 0 &&
            strcmp(type,"person") == 0){
         primary_key = strdup(value);
       }
    }
    if(primary_key != NULL){ 
      return g_strstrip(primary_key);
    }else{
      return NULL;
    }
}




/* 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];
        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));
              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(arg[0])){
      count++;
    }else if(arg[0] == '\n' && isalpha(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(pos[2])){
        count++;
      }
    }
    if(tracing) {
      cout << "TRACING: count_objects returning " << count << endl;
    }
    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]) + 1);
          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 *  */

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

    arg = strip_lines(arg);

    objects =  g_strsplit(arg, "\n\n", 1000);
    temp = objects;
    for(i=0; temp[i] != NULL; i++){
      /* stripe off the trailing and leading white spaces-eols*/
      g_strstrip(temp[i]);
      if(strlen(temp[i]) > 0){/* if not an empty string */
        tobereturned = g_slist_append(tobereturned, temp[i]);
      }
    }
    return tobereturned;
}





/* takes the first object in the given char *, using empty lines as
   separator */
char * take_object(char * arg){
    char * object = NULL, * pos = NULL;
    char * temp = strdup(arg);
    
    if(isalpha(temp[0])){
      if(strstr(temp,"\n\n") == NULL){
        return temp;
      }else{
        pos = strstr(temp,"\n\n");
        pos[0] = '\0';
        return temp;
      }
    }else if(temp[0] == '\n' && isalpha(temp[1])){
      if(strstr(temp,"\n\n") == NULL){
        return (char *)temp[1];
      }else{
        pos = strstr(temp,"\n\n");
        pos[0] = '\0';
        return (char *)temp[1];
      }
    }else{
      temp = strstr(temp,"\n\n");
      temp = temp + 2;
      if(strstr(temp,"\n\n") == NULL){
        return temp;
      }else{
        pos = strstr(temp,"\n\n");
        pos[0] = '\0';
        return temp;
      }
    }
}





/* Takes an autnum_object, and returns the as-block containing this aut-num */
char * get_as_block(char *autnum_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(autnum_object, strlen(autnum_object));
  search_key = get_search_key(o,"aut-num",autnum_object);
  
  query_string = (char *)malloc(strlen("-Tas-block -r ")+strlen(search_key)+1);
  sprintf(query_string, "-Tas-block -r %s",search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such as-block" << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one as-block returned" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_object(result);
  }
  
}


/* Takes a route_object, and returns the aut-num mentioned in origin
   attribute of this route */
char * get_aut_num_object(char *route_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(route_object, strlen(route_object));
  search_key = get_search_key(o,"origin",route_object);
  
  query_string = (char *)malloc(strlen("-Tas-block -r ")+strlen(search_key)+1);
  sprintf(query_string, "-Taut-num -r %s",search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such aut-num" << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one aut-num returned" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_object(result);
  }
  
}




/* Takes a domain_object, and returns the less specific domain of it */
char * get_less_specific_domain(char *domain_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL, * domain = NULL;
  Object * o = new Object();
  int i,j, length;
  char * temp = NULL;
  char ** splitted;

  code = o->scan(domain_object, strlen(domain_object));
  domain = get_search_key(o,"domain",domain_object);

  /* 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++){
      length = 0;
      if(temp!=NULL){
        length = strlen(temp); 
      }
      temp = (char *)realloc(temp, length + strlen(splitted[j]) + 2); 
      if(j==i){
        temp = (char *)strdup(splitted[j]);
      }else{
        sprintf(temp, "%s.%s", temp, splitted[j]);
      }
    }
    query_string = (char *)malloc(strlen("-Tdomain -r -R ")+strlen(temp)+1);
    sprintf(query_string, "-Tdomain -r -R %s", temp);
    result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
    if(count_objects(result) == 0){
    }else if(count_objects(result) > 1){
      if(tracing){
        cout << "TRACING: get_less_specific_domain: More than one domains returned" << endl;
      }
      return NULL; /* error condition */
    }else{ /* count_objects(result) == 1 */
      return take_object(result);
    }
    
  }
  /* release the memory allocated to **splitted */
  for(i=0; splitted[i] != NULL; i++){ 
    free(splitted[i]);
  }  
  /* 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(char *set_object, char *type){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  int i;
  
  code = o->scan(set_object, strlen(set_object));
  search_key = get_search_key(o, type, set_object);
  delete(o);

  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 -r ")+strlen(search_key)+1);
  sprintf(query_string, "-Taut-num,as-set,rtr-set,peering-set,filter-set -r  %s", search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such object"  << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one objects returned" << endl;
    return NULL;
  }else{ // count_objects(result) == 1
    return take_object(result);
  }
  
}







/* Takes an inetnum or inet6num object and returnes one less specific of it */
char * get_less_specific(char *inetnum_object, char *type){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(inetnum_object, strlen(inetnum_object));
  search_key = get_search_key(o, type, inetnum_object);
  
  query_string = (char *)malloc(strlen("-Tinet6num -r -l ") + strlen(search_key) + 1);
  sprintf(query_string, "-T%s -r -l %s",type, search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such " << type << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one " << type << " returned" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_object(result);
  }
  
}



/* Takes a route object and returnes one less specific inetnum */
char * get_less_spec_inetnum(char *route_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(route_object, strlen(route_object));
  search_key = get_search_key(o, "route", route_object);
  
  query_string = (char *)malloc(strlen("-Tinetnum -r -l ") + strlen(search_key) + 1);
  sprintf(query_string, "-Tinetnum -r -l %s", search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such inetnum" << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one inetnums returned" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_object(result);
  }
  
}


/* Takes a route object and returnes exact match inetnum */
char * get_exact_match_inetnum(char *route_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(route_object, strlen(route_object));
  search_key = get_search_key(o, "route", route_object);
  
  query_string = (char *)malloc(strlen("-Tinetnum -r -x ") + strlen(search_key) + 1);
  sprintf(query_string, "-Tinetnum -r -x %s", search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "No such inetnum" << endl;
    return NULL;
  }else if(count_objects(result) > 1){
    cout << "More than one inetnums returned" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_object(result);
  }
  
}



/* Takes a route object and returnes exact matches of this route */
GSList * get_exact_match_routes(char *route_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(route_object, strlen(route_object));
  search_key = get_search_key(o, "route", route_object);
  
  query_string = (char *)malloc(strlen("-Troute -r -x ") + strlen(search_key) + 1);
  sprintf(query_string, "-Troute -r -x %s", search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "get_exact_match_routes: No such route" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_objects(result);
  }
  
}



/* Takes a route object and returns (immediate) less specifics of this route */
GSList * get_less_spec_routes(char *route_object){
  bool code;
  char * search_key = NULL, * query_string = NULL;
  char * result = NULL;
  Object * o = new Object();
  
  code = o->scan(route_object, strlen(route_object));
  search_key = get_search_key(o, "route", route_object);
  
  query_string = (char *)malloc(strlen("-Troute -r -l ") + strlen(search_key) + 1);
  sprintf(query_string, "-Troute -r -l %s", search_key);
  result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
  if(count_objects(result) == 0){
    cout << "get_less_spec_routes: No such route" << endl;
    return NULL;
  }else{ /* count_objects(result) == 1 */
    return take_objects(result);
  }
  
}



/* Gets an object as a string and returns its 'mnt-by' attributes as a 
   GSList (linked list)   */

GSList *get_mntners(char * object){
  bool code;
  Object * o;
  Attr *attr;
  char *value  = NULL;
  GSList *list_of_mntners = NULL;

  if(tracing) {
    printf("TRACING: get_mntners is running\n");
  }
  o = new Object;
  code = o->scan(object,strlen(object));
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(object+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    //cout << "value: #" << value << "#" << endl;
    if(strcmp(attr->type->name(),"mnt-by") == 0){
      if(tracing) {
        cout << "TRACING: get_mntners: adding " << g_strstrip(value) << endl;
      }
      list_of_mntners = g_slist_append(list_of_mntners, strdup(g_strstrip(value)));
    }
    free(value);
  }


  return list_of_mntners; 
}


/* Gets a preparsed object, its text and an attribute name. Returns a list of
   attribute values */
GSList *get_attributes(Object * o, const char * attrib, const char * text){

  char * value = NULL;
  Attr *attr;
  GSList *list_of_attributes = NULL;

  //if(tracing) {
  //  printf("TRACING: get_attributes is running\n");
  //}
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(text+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    if(strcmp(attr->type->name(), attrib) == 0){
      if(tracing) {
        cout << "TRACING: get_attributes: adding " << g_strstrip(value) << endl;
      }
      list_of_attributes = g_slist_append(list_of_attributes, strdup(g_strstrip(value)));
    }
    //free(value);
  }

  //if(tracing) {
  //  printf("TRACING: get_attributes is returning\n");
  //}
  
  return list_of_attributes; 
}


/* Gets a preparsed object, an attribute name. Returns the value of first occurence
   of this attribute */
char *get_attribute(Object * o, const char * attrib, char * text){

  char * value = NULL;
  Attr *attr;

  if(tracing) {
    printf("TRACING: get_attributes is running\n");
  }
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(text+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    if(strcmp(attr->type->name(), attrib) == 0){
      if(tracing) {
        cout << "TRACING: get_attribute: will return " << value << endl;
      }
      return value;
    }else{
      free(value);
    }
  }

  if(tracing) {
    printf("TRACING: get_attribute is returning\n");
  }
  
  return NULL; 
}



/* Gets a GSList of strings and returns 1 if one of them starts with substr, 0 otherwise */
int strstr_in_list(GSList * list, const char * substr){

 GSList * next = NULL;
 char * word; 

  if(tracing) {
    printf("TRACING: strstr_in_list is running\n");
  }
 
 for( next = list; next != NULL ; next = g_slist_next(next) ){
   word = strdup((char *)next->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) object as a string and returns its 'auth' attributes 
   as a GSList (linked list) */

GSList *get_auths(char * object){
  bool code;
  Object * o;
  Attr *attr;
  char *value  = NULL;
  GSList *list_of_auths = NULL;

  if(tracing){
    printf("TRACING: get_auths is running\n");
  }
  o = new Object;
  code = o->scan(object,strlen(object));
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(object+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    //cout << "value: #" << value << "#" << endl;
    if(strcmp(attr->type->name(),"auth") == 0){
      if(tracing) {
        cout << "TRACING: get_auths: adding " << g_strstrip(value) << endl;
      }
      list_of_auths = g_slist_append(list_of_auths, strdup(g_strstrip(value)));
      if(tracing) {
        cout << "TRACING: get_auths: # of nodes in list_of_auths is now " << g_slist_length(list_of_auths) << endl;
      }
    }
  }

  if(tracing) {
    cout << "TRACING: get_auths: returning (with " << g_slist_length(list_of_auths) << " nodes)" << endl;
  }
  return list_of_auths; 
}





/* Gets an object as a string an returns its mnt_lower attributes as a 
   GSList (linked list) */

GSList *get_mnt_lowers(char * object){
  bool code;
  Object * o;
  Attr *attr;
  char *value  = NULL;
  GSList *list_of_mnt_lowers = NULL;


  if(tracing) {
    printf("TRACING: get_mnt_lowers is running\n");
  }
  o = new Object;
  code = o->scan(object,strlen(object));
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(object+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    //cout << "value: #" << value << "#" << endl;
    if(strcmp(attr->type->name(),"mnt-lower") == 0){
      if(tracing) {
        cout << "TRACING: get_mnt_lowers: adding " << g_strstrip(value) << endl;
      }
      list_of_mnt_lowers = g_slist_append(list_of_mnt_lowers, strdup(g_strstrip(value)));
    }
  }


  return list_of_mnt_lowers; 
}


/* Gets an object as a string an returns its mnt_routes attributes as a 
   GSList (linked list) */

GSList *get_mnt_routes(char * object){
  bool code;
  Object * o;
  Attr *attr;
  char *value  = NULL;
  GSList *list_of_mnt_routes = NULL;

  if(tracing) {
  cout << "TRACING: get_mnt_routes is running" << endl;
  }
  o = new Object;
  code = o->scan(object,strlen(object));
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(object+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    //cout << "value: #" << value << "#" << endl;
    if(strcmp(attr->type->name(),"mnt-routes") == 0){
      if(tracing) {
        cout << "TRACING: get_mnt_routes: adding " << g_strstrip(value) << endl;
      }
      list_of_mnt_routes = g_slist_append(list_of_mnt_routes, strdup(g_strstrip(value)));
    }
  }

  return list_of_mnt_routes; 
}


/* Gets a linked list of objects and returns the mnt_routes attribs of
   them in a linked list */
GSList *get_mnt_routes_from_list(GSList * objects){
  GSList *next = NULL;
  GSList *list_of_mnt_routes = NULL;
  
  for( next = objects; next != NULL ; next = g_slist_next(next) ){
    list_of_mnt_routes = g_slist_concat(list_of_mnt_routes, get_mnt_routes((char *)next->data));
  }

  return list_of_mnt_routes;
}



/* Gets a linked list of objects and returns the mnt_routes attribs of
   them in a linked list */
GSList *get_mnt_lowers_from_list(GSList * objects){
  GSList *next = NULL;
  GSList *list_of_mnt_lowers = NULL;
  
  for( next = objects; next != NULL ; next = g_slist_next(next) ){
    list_of_mnt_lowers = g_slist_concat(list_of_mnt_lowers, get_mnt_lowers((char *)next->data));
  }

  return list_of_mnt_lowers;
}



/* retrieves the override password from the 'override' attribute  
   of the object. If none, it returns NULL   */
char *get_override(char * object){
  bool code;
  Object * o;
  Attr *attr;
  char *value  = NULL;

  if(tracing){
    printf("TRACING: get_override is running\n");
  }
  o = new Object;
  code = o->scan(object,strlen(object));
  
  for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
    value = (char*)malloc((*attr).len - strlen(attr->type->name()) - 1);
    strncpy(value, (char *)(object+attr->offset) + strlen(attr->type->name())+1,
        attr->len - strlen(attr->type->name()) -2 );
    value[attr->len - strlen(attr->type->name()) - 2 ] = '\0';
    //cout << "value: #" << value << "#" << endl;
    if(strcmp(attr->type->name(),"override") == 0){
      if(tracing) {
        cout << "TRACING: get_override: returning " << g_strstrip(value) << endl;
      }
      return  strdup(g_strstrip(value));
    }
  }
  /* there was no 'override' attrib, so return NULL */
  return NULL; 
}






/* 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(CRYPTEDPASSWD);
   if(string == NULL) {
     if(tracing) {
       printf("TRACING: check_override is returning FAILED\n");
     }
     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){
         printf("%s\n", temp[i]);
         if(strcmp(AU_crypt(temp[i], crypted_password), crypted_password) == 0){
           g_strfreev(temp);
           if(tracing) {
             printf("TRACING: check_override is returning OK\n", string);
           }
           return OVR_OK; 
         }
       }
     }

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







/* takes a GSList of struct auth_struct and a GSList of auths, and a mntner 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, GSList * auths, char * mntner_name){
   //GSList * to_be_returned = NULL;
   GSList * next;
   char * auth_attrib = NULL;
   char * auth_attrib_uppercase = NULL, * argument = NULL;
   //struct auth_struct * temp = NULL;
   auth_struct * temp = NULL;
   int index = 1;
      
   for(next = auths; next != NULL; next = g_slist_next(next)){
     auth_attrib = strdup((char *)next->data);
     auth_attrib = g_strstrip(auth_attrib);
     if(tracing) {
       cout << "TRACING: add_to_auth_vector: " << auth_attrib << endl;
     }
     /* 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) {
         cout << "TRACING: add_to_auth_vector: adding new argument: " << argument << endl;
       }
       //temp = (struct auth_struct *)malloc(sizeof(auth_struct));
       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,"MAIL-FROM") == auth_attrib_uppercase){
       /* take the argument of the auth attribute */
       argument = strdup(auth_attrib + strlen("MAIL-FROM"));
       g_strstrip(argument);
       if(tracing) {
         cout << "TRACING: add_to_auth_vector: adding new argument: " << argument << endl;
       }
       //temp = (struct auth_struct *)malloc(sizeof(auth_struct));
       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 */
       //argument = strdup(auth_attrib + strlen("NONE"));
       //g_strstrip(argument);
       //cout << "DEBUG: add_to_auth_vector: adding new argument: " << argument << endl;
       //temp = (struct auth_struct *)malloc(sizeof(auth_struct));
       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,"PGP-") == auth_attrib_uppercase){
       //temp = (struct auth_struct *)malloc(sizeof(auth_struct));
       temp = (auth_struct *)malloc(sizeof(auth_struct));
       temp->type = AU_PGP;
       temp->mntner_name = mntner_name;
       temp->index = index++;
       /* temp->pgp_struct must be assigned, not yet implemented */
       cout << "Not implemented totally (PGP)" << endl;
     }else{
       cout << "DEBUG: Error: invalid auth attrib: " << auth_attrib << endl;
       return NULL;
     }
   }
   free(auth_attrib_uppercase);
   free(auth_attrib); 
   return list_of_auth_struct;

}










/* constructs the authorisation vector, which is a GSList of
   struct auth_struct */

GSList * get_auth_vector(GSList * mntners){
  GSList * list_of_auths = NULL;
  GSList * next = NULL;
  GSList * to_be_returned = NULL;
  char * query_string = NULL, * result = NULL, * object = NULL;
  GSList * temp;

  for( next = mntners; next != NULL ; next = g_slist_next(next) ){
    if(tracing) {
      cout << "=====" << endl << "Got a mntner" << endl;
      cout << (char *)next->data << endl;
    }
    query_string = (char *)malloc(strlen("-Tmntner -r ")+strlen((char *)next->data)+1);
    sprintf(query_string, "-Tmntner -r %s",(char *)next->data);
    result = send_and_get(QUERY_HOST, QUERY_PORT, query_string);
    if(count_objects(result) == 0){
      //if(tracing) {
      //  cout << "No such maintainer, exiting" << endl;
      //}
      //exit(1);
      /* no such maintainer */
      return NULL;
    }else if(count_objects(result) > 1){
      if(tracing) {
        cout << "More than one objects returned" << endl;
      }
    }else{ /* count_objects(result) == 1 */
      object = take_object(result);
      if(tracing) {
        printf("TRACING: get_auth_vector: Calling get_auths(char *)\n");
      }
      temp = get_auths(object);
      if(tracing) {
        cout << "TRACING: get_auth_vector: get_auths(char *) returned (with " << g_slist_length(temp) << " nodes)" << endl;
      }
      list_of_auths = g_slist_concat(list_of_auths, temp);
      if(tracing) {
        cout << "TRACING: get_auth_vector: list_of_auths has now " <<  g_slist_length(list_of_auths) << " nodes" << endl;
      }
      /* add this to the auth_vector. ( next->data is the name of the maintainer  ) */
      if(tracing) {
       cout << "TRACING: get_auth_vector: to_be_returned has now " <<  g_slist_length(to_be_returned) << " nodes" << endl;
      }
      to_be_returned = add_to_auth_vector(to_be_returned, list_of_auths, (char *)next->data);
    }
  }
  
  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 one or more route objects filters out the ones which don't have the same
   origin as 'char * origin' argument */
char * filter_out_diff_origins(char * objects, char * origin){
  GSList * object_list = NULL, * next =NULL;
  char * objects_to_be_returned = NULL;
  bool code;
  char * key = NULL;
  Object * o = new Object();
  
  
  if(tracing) {
    printf("TRACING: filter_out_diff_origins\n");
  }

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

  for(next = object_list; next != NULL; next = g_slist_next(next)){
    code = o->scan((char *)next->data, strlen((char *)next->data));
    key = get_search_key(o, "origin", (char *)next->data);
    if(key != NULL && strcasecmp(g_strstrip(origin), key) == 0){
      if(objects_to_be_returned == NULL){
        objects_to_be_returned = strdup((char *)next->data);
      }else{
        objects_to_be_returned = (char *)realloc(objects_to_be_returned, 
                      strlen(objects_to_be_returned) + strlen((char *)next->data) + 2);
        objects_to_be_returned = strcat(objects_to_be_returned, "\n");
        objects_to_be_returned = strcat(objects_to_be_returned, (char *)next->data);
      }
    }
  }

  delete(o);
  if(tracing) {
    if(objects_to_be_returned != NULL){
      printf("TRACING: filter_out_diff_origins: returning:\n%s\n", objects_to_be_returned? "(NULL)":objects_to_be_returned);
    }else {
      printf("TRACING: filter_out_diff_origins: returning NULL\n");
      
    }
  }
  return objects_to_be_returned; 
  
}




/* 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(char *new_object, char *old_object, char *type, credentials_struct credentials){
   
   GSList *old_mntners = NULL, *new_mntners = NULL;
   GSList *old_auths = NULL, *new_auths = NULL;
   GSList *as_block_mnt_lowers = NULL;
   GSList *old_auth_vector = NULL, *new_auth_vector = NULL, *as_block_auth_vector = NULL;
   GSList *less_specific_auth_vector = NULL, *less_specific_mnt_lowers = NULL;
   GSList *less_specific_mntners = NULL;
   GSList *aut_num_maintainers = NULL;
   GSList *aut_num_auth_vector = NULL;
   GSList *exact_match_routes = NULL;  
   GSList *exact_match_routes_maintainers = NULL;
   GSList *exact_match_routes_auth_vector = NULL;
   GSList *less_spec_routes = NULL;
   GSList *less_spec_routes_mntners = NULL;
   GSList *less_spec_routes_auth_vector = NULL;
   GSList *exact_match_inetnum_mnt_routes = NULL;
   GSList *exact_match_inetnum_auth_vector = NULL;
   GSList *less_spec_inetnum_mntners = NULL;
   GSList *less_spec_inetnum_auth_vector = NULL;
   GSList *exact_match_intenum_auth_vector = NULL;
   GSList *exact_match_auth_vector = NULL;
    
   char *as_block_object = NULL, *less_specific_object = NULL;
   char *less_specific_domain = NULL;
   char *less_spec_inetnum = NULL;
   char *exact_match_inetnum = NULL;
   char *less_specific_object_type = NULL;
   char *override_string = NULL;
   char *set_name = NULL;
   char * aut_num_object = NULL;
   Object *set_object = new Object();
   Object *temp_obj;
   bool code;
   bool aut_num_auth_OK = false;

   int overriden = 0;
   
   /* 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){ 
     overriden = 0;
   }else if(check_override(override_string) == OVR_OK){
     overriden = 1; /* authorisation is overriden */
   }else if(check_override(override_string) == UP_OVS){
     return UP_OVS; /* override syntax error --it must have at least two words */
   }else{
     return UP_OVF; /* override failed! */
   }


   /*  
    *  Handle the "person", "role", "limerick", "inet-rtr" types 
    */
   if(strcmp(type,"person")   == 0 || strcmp(type,"role")     == 0 ||
      strcmp(type,"limerick") == 0 || strcmp(type,"inet-rtr") == 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);
       return authorise(old_auth_vector, credentials, overriden);
     }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. */
         return UP_AUF; /* auth failed */
       }
       /*printf("DEBUG: check_auth: new_auth_vector has %i, new_mntners has %i nodes\n",
              g_slist_length(new_auth_vector) ,g_slist_length(new_mntners));*/
       return authorise(new_auth_vector, credentials, overriden);
     }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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ // both are NULL, mustn't happen
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         return UP_INT; /* internal error */
     }
   }

   /*  
    *  Handle the "auth-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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }else if( new_object != NULL && old_object == NULL ){ /* the object is to be created */
       as_block_object = get_as_block(new_object);
       if(as_block_object == NULL ){
         return UP_ABN; /* As-block does not exist */
         }else{
           as_block_mnt_lowers = get_mnt_lowers(as_block_object);
           as_block_auth_vector = get_auth_vector(as_block_mnt_lowers);
           if(as_block_mnt_lowers != NULL && as_block_auth_vector == NULL){
             /* then, the mntners in 'as_block_mnt_lowers' do not exist. Problem. */
             return UP_AUF; /* auth failed */
           }
         if(authorise(as_block_auth_vector, credentials, overriden) == UP_AUTH_OK ){
           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. */
             return UP_AUF; /* auth failed */
           }
           return authorise(new_auth_vector, credentials, overriden);
         }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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ /* both are NULL, mustn't happen */
         if(tracing) {
           cout << "TRACING: check_auth: internal error: Both pointers are NULL" << endl;
         } 
         return UP_INT; /* internal error */
     }
   } 

   /*  
    *  Handle the "mntner/as-block" types 
    */
   else if(strcmp(type,"mntner")  == 0 || strcmp(type,"as-block")  == 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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }else if( new_object != NULL && old_object == NULL ){ /* the object is to be created */
       if(overriden){
         return UP_AUTH_OK; 
       }else{/* If not overriden, and if not coming from ripe-dbm, must be forwarded to ripe-dbm */
         if(tracing) {
           cout << "DEBUG: check_auth: '" << type << "' creation requested" << endl;
         }
         return UP_AUF; /* 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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ // both are NULL, mustn't happen
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         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 */
       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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }else if( new_object != NULL && old_object == NULL ){ /* the object is to be created */
       less_specific_object = get_less_specific(new_object, type);
       if(less_specific_object == NULL){
         if(overriden){
           return UP_AUTH_OK; 
         }else{
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }else{ /* if we got an inet(6)num object */
         less_specific_mnt_lowers = get_mnt_lowers(less_specific_object);
         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_mnt_lowers' do not exist. Problem. */
           return UP_AUF; /* auth failed */
         }
         if(authorise(less_specific_auth_vector, credentials, overriden) == UP_AUTH_OK){
           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. */
             return UP_AUF; /* auth failed */
           }
           return authorise(new_auth_vector, credentials, overriden);
         }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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ /* both are NULL, mustn't happen */
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }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 = get_less_specific_domain(new_object);
      if(less_specific_domain == 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_mnt_lowers = get_mnt_lowers(less_specific_domain);
         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_mnt_lowers' do not exist. Problem. */
           return UP_AUF; /* auth failed */
         }
         if(authorise(less_specific_auth_vector, credentials, overriden) == UP_AUTH_OK){
           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. */
             return UP_AUF; /* auth failed */
           }
           return authorise(new_auth_vector, credentials, overriden);
         }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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ /* both are NULL, mustn't happen */
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }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 = get_aut_num_object(new_object); 
       if(aut_num_object == NULL){
         if(overriden){
           return UP_AUTH_OK; 
         }else{
           return UP_HOF; /* hierarchical authorisation failed */
         }
       }else{/* there is a corresponding aut-num in the db */
         printf("DEBUG: check_auth: will try to authorise the route using aut-num\n");
         aut_num_maintainers = get_mnt_routes(aut_num_object);
         if(aut_num_maintainers != NULL){
           aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
           if(authorise(aut_num_auth_vector, credentials, overriden) == UP_AUTH_OK){
             aut_num_auth_OK = true;
           }else{/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
             return UP_HOF;
           }
         }else{/* aut_num_maintainers is NULL */
            aut_num_maintainers = get_mnt_lowers(aut_num_object);
            if(aut_num_maintainers != NULL){
              aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
              if(authorise(aut_num_auth_vector, credentials, overriden) == UP_AUTH_OK){
                aut_num_auth_OK = TRUE;
              }else{/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
                return UP_HOF; /* hierarchical authorisation failed */
              }
            }else{/* aut_num_maintainers is NULL */
              aut_num_maintainers = get_mntners(aut_num_object);
              if(aut_num_maintainers != NULL){
                aut_num_auth_vector = get_auth_vector(aut_num_maintainers);
                if(authorise(aut_num_auth_vector, credentials, overriden) == UP_AUTH_OK){
                  aut_num_auth_OK = TRUE;
                }else{/* authorise(aut_num_auth_vector, credentials, overriden) != UP_AUTH_OK */
                  return UP_HOF; /* hierarchical authorisation failed */
                }
              }else{/* aut_num_maintainers is NULL */
                aut_num_auth_OK = TRUE;
              }
              
            }
         }
         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 = get_exact_match_routes(new_object);
           if(exact_match_routes != NULL){
             exact_match_routes_maintainers = get_mnt_routes_from_list(exact_match_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. */
               return UP_AUF; /* auth failed */
              }
             if(authorise(exact_match_routes_auth_vector, credentials, overriden) == UP_AUTH_OK){
               /* 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. */
                 return UP_AUF; /* auth failed */
               }
               return authorise(new_auth_vector, credentials, overriden);
             }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 = get_less_spec_routes(new_object);
             if(less_spec_routes != NULL){
               less_spec_routes_mntners = get_mnt_routes_from_list(less_spec_routes);
               less_spec_routes_mntners = g_slist_concat(less_spec_routes_mntners, 
                                             get_mnt_lowers_from_list(less_spec_routes));
               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. */
                 return UP_AUF; /* auth failed */
               }
               if(authorise(less_spec_routes_auth_vector, credentials, overriden) == UP_AUTH_OK){
                 /* 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. */
                   return UP_AUF; /* auth failed */
                 }
                 return authorise(new_auth_vector, credentials, overriden);
               }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 = get_exact_match_inetnum(new_object);
               if(exact_match_inetnum != NULL){
                 exact_match_inetnum_mnt_routes = get_mnt_routes(exact_match_inetnum);
                 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. */
                   return UP_AUF; /* auth failed */
                 }
                 if(authorise(exact_match_intenum_auth_vector, credentials, overriden) == UP_AUTH_OK){
                   /* 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. */
                     return UP_AUF; /* auth failed */
                   }
                   return authorise(new_auth_vector, credentials, overriden);
                 }else{
                   return UP_HOF; /* hierarchical authorisation failed */
                 }
               }else{/* exact_match_inetnum == NULL */
                 /* then, we will try to find less spec inetnums */
                 less_spec_inetnum = get_less_spec_inetnum(new_object);
                 if(less_spec_inetnum != NULL){
                   less_spec_inetnum_mntners = get_mnt_routes(less_spec_inetnum);
                   less_spec_inetnum_mntners = g_slist_concat(less_spec_inetnum_mntners, 
                                  get_mnt_lowers(less_spec_inetnum));
                   less_spec_inetnum_auth_vector = get_auth_vector(less_spec_inetnum_mntners);
                   if(less_spec_inetnum_mntners != NULL && less_spec_inetnum_auth_vector == NULL){
                     /* then, the mntners in 'less_spec_inetnum_mntners' do not exist. Problem. */
                     return UP_AUF; /* auth failed */
                   }
                   if(authorise(exact_match_auth_vector, credentials, overriden) == UP_AUTH_OK){
                     /* 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. */
                       return UP_AUF; /* auth failed */
                     }
                     return authorise(new_auth_vector, credentials, overriden);
                   }else{/* authorise(exact_match_auth_vector, credentials, overriden) != UP_AUTH_OK */
                     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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ /* both are NULL, mustn't happen */
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         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. */
         return UP_AUF; /* auth failed */
       }
       return authorise(old_auth_vector, credentials, overriden);
     }else if( new_object != NULL && old_object == NULL ){ /* the object is to be created */
        code = set_object->scan(new_object, strlen(new_object));
        set_name = get_search_key(set_object, type, new_object);
       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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }else{/* the name is hierarchical */
         less_specific_object = get_less_specific_set(new_object, type);
         if(less_specific_object != NULL){/* such an object exists */
           temp_obj = new Object();
           code = temp_obj->scan(less_specific_object, strlen(less_specific_object));
           less_specific_object_type = get_type(temp_obj);
           delete(temp_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_object);
             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. */
              return UP_AUF; /* auth failed */
             }
             if(less_specific_auth_vector != NULL){
               return authorise(less_specific_auth_vector, credentials, overriden);
             }else{/* the less specific object doesn't contain any mnt-lower */
               less_specific_mntners = get_mntners(less_specific_object);
               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. */
                 return UP_AUF; /* auth failed */
               }
               if(less_specific_auth_vector != NULL){/* less spec object has some mnt-by attribs, 
                                                        use them  */
                   return authorise(less_specific_auth_vector, credentials, overriden);
               }else{/* the less specific object doesn't contain any mnt-by either */
                 if(overriden){
                   return UP_AUTH_OK; 
                 }else{
                   return UP_HOF; /* hierarchical authorisation failed */
                 }
               }
             }
           }else{ /* this is _not_ an aut-num object*/
             less_specific_mntners = get_mntners(less_specific_object);
             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. */
               return UP_AUF; /* auth failed */
             }
             if(less_specific_auth_vector != NULL ){/* the set obj has some mnt-by attribs */
               return authorise(less_specific_auth_vector, credentials, overriden);
             }else{
               if(overriden){
                 return UP_AUTH_OK; 
               }else{
                 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. */
         return UP_AUF; /* auth failed */
       }
       if(old_auth_vector){ /* if we have mntners in the old object, use them */
         return authorise(old_auth_vector, credentials, overriden);
       }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. */
           return UP_AUF; /* auth failed */
         }
         return authorise(new_auth_vector, credentials, overriden);
       }
     }else{ /* both are NULL, mustn't happen */
         cout << "DEBUG: check_auth: internal error: Both pointers are NULL" << endl;
         return UP_INT; /* internal error */
     }
   




   }else{ /* We exhausted all object classes. If we are here, then there is a problem */
     cout << "check_auth: This type '" << type << "' is unknown" << endl;
     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(char * arg){

    bool code = true;
    char *type=NULL, *primary_search_key = NULL, *search_string = NULL;
    Object *o;
    o = new Object;
    char *result = NULL, *origin = NULL;
    
    error = 0; 
    code = o->scan(arg,strlen(arg));
    type = get_type(o);
    primary_search_key = get_search_key(o, type, arg);
    if(tracing) {
      cout << "type=" << type << endl;
      cout << "primary_search_key=" << primary_search_key << endl;
    }
    /* prepare the search string */
    //search_string = (char *)malloc(strlen(primary_search_key) + strlen("-x -R -r -T")
    //                                      + strlen(type) + 1);
    /* if the object is a pn ro a ro object, then get all pn/ro's with the
       same NIC hdl */
    if(strcmp(type,"person") == 0 || strcmp(type,"role") == 0){
      /* prepare the search string */
      search_string = (char *)malloc(strlen(primary_search_key) + strlen("-x -R -r -T")
                                          + strlen("person,role") + 1);
      sprintf(search_string, "-x -R -r -Tperson,role %s", primary_search_key);
    }else{
      /* prepare the search string */
      search_string = (char *)malloc(strlen(primary_search_key) + strlen("-x -R -r -T")
                                          + strlen(type) + 1);
      sprintf(search_string, "-x -R -r -T%s %s",type, primary_search_key);
    }
    result = send_and_get(QUERY_HOST, QUERY_PORT, search_string);
    if(tracing) {
      cout << "TRACING: send_and_get has returned" << endl;
      cout << "TRACING: send_and_get returned (with search '"<< search_string <<"'): " << endl 
           << result << endl;
    }
    /* Attention: here we must also check these:
         for ro/pn objects: The name must also the same. When the NIC hdl is the
               same but names are different, we must somehow return an error.
               Also, when we search for a person, we must also look for role objects
               (and vice versa) since the RIPupdate does not distinguish between
               role & person objects. We have to check it here.
         for rt objects: We also have to check the identicalness of origin
               attributes.                
               
          These are not yet implemented.     
               */

    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(o, "origin", arg);
      if(tracing) {
        printf("TRACING: Got origin of route: %s\n", origin);
      }
      result = filter_out_diff_origins(result, origin);  
      if(tracing) {
        printf("TRACING: Filtered routes\n");
      }
    }
    // 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) {
      cout << "TRACING: Take_object returned ***\n" << result << "***" << endl;
      }
    }else{ /* we have more than one objects, error! */
      error = UP_MOR;
      return 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 stringPack(char *dest, const char *source)
{

  if(tracing) {
    printf("TRACING: stringPack 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;
                        }
                }
}

/* 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(strstr(temp[i], "delete:") != temp[0]){
        //printf("DEBUG: temp[i] = %s\n", temp[i]);
        if(string == NULL){
          string = strdup(temp[i]);
        }else{
          string = (char *)realloc(string, strlen(string) + strlen(temp[i]) + 1);
          string = strcat(string, "\n");
          string = strcat(string, temp[i]);
        }
      }
    }
    g_strfreev(temp);
    return string;
}



int identical(const char * old_version, const char * new_version){
  char * arg1 = strdup(old_version);
  char * arg2 = strdup(new_version);
  int result = 0;
  char *temp1, *temp2; 

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

  /* delete the 'delete:' attrib */
  arg1 = delete_delete_attrib(arg2);
  /* convert tabs to white spaces */
  arg1 = g_strdelimit(arg1, "\t", ' ');
  arg2 = g_strdelimit(arg2, "\t", ' ');
  
  temp1 = (char *)malloc(strlen(arg1)); 
  temp2 = (char *)malloc(strlen(arg2));
  stringPack(temp1, arg1);
  stringPack(temp2, arg2);

  result = strcmp(temp1, temp2);
  //printf("TRACING: identical: the objects are:\n[%s]\n[%s]\n", temp1, 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 * arg){

   char * temp, * temp2;
   char * initials = NULL;
   int len, i;
   char ** vector;

   temp = strdup(arg);
   g_strstrip(temp);
   temp2 = (char *)malloc(strlen(temp) + 1);
   stringPack(temp2, temp);
   vector = g_strsplit(temp2, " ", 0);
   for(i = 0; vector[i] != NULL && i < 4; i++){
     //printf("%i\n",i);
     if(strlen(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);free(temp2);g_strfreev(vector);
   return initials;
}







/* Gets an object whose NIC hdl is AUTO and to be modified (to be sent to RIPupdate)
   and  modifies the nic-hdl: attribute, returns the new object.
   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 */

char * replace_AUTO_NIC_hdl(char * arg, char * auto_nic_hdl){

  GString* temp_string; 
  char * to_be_returned = NULL;
  char * person_role_name= NULL;
  char * initials = NULL;
  char ** temp = NULL;
  int i, pos;
  Object * o = new Object;

  temp = g_strsplit(arg, "\n", 0);

  for(i = 0; temp[i] != NULL; i++){
    //printf("Line: %s\n", temp[i]);
    if(strstr(temp[i], "nic-hdl:") == temp[i]){/* if it starts with nic-hdl */
      temp_string = g_string_new(temp[i]);
      if(strstr(temp_string->str, "AUTO-") != NULL){
        auto_nic_hdl = strncpy(auto_nic_hdl, strstr(temp_string->str, "AUTO-"), 
            temp_string->len + temp_string->str - strstr(temp_string->str, "AUTO-") );
        auto_nic_hdl[temp_string->len + temp_string->str - strstr(temp_string->str, "AUTO-")] = '\0';
        g_strstrip(auto_nic_hdl);
        printf("DEBUG: auto_nic is [%s]\n", auto_nic_hdl);
        pos = strstr(temp_string->str, "AUTO-") - temp_string->str;
        temp_string = g_string_erase(temp_string,
            strstr(temp_string->str, "AUTO-") - temp_string->str, strlen(auto_nic_hdl)/*strlen("AUTO-")*/);
        
        temp_string = g_string_insert(temp_string, pos, UPDATE_SOURCE);
        temp_string = g_string_insert(temp_string, pos, "*-");
        o->scan(arg, strlen(arg));
        person_role_name = get_attribute(o, get_type(o), arg);
        delete(o);
        initials = find_initials(person_role_name);
        free(person_role_name);
        temp_string = g_string_insert(temp_string, pos, initials);
        free(initials);
        
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp_string->str);
          g_string_free(temp_string, TRUE);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + temp_string->len + 2);
          to_be_returned = strcat(to_be_returned, "\n");
          to_be_returned = strcat(to_be_returned, temp_string->str);
          g_string_free(temp_string, TRUE);
        }
      }else{
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp[i]);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + strlen(temp[i]) + 2);
          to_be_returned = strcat(to_be_returned, "\n");
          to_be_returned = strcat(to_be_returned, temp[i]);
        }
      }
    }else{/* if it doesn't begin with nic-hdl */
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp[i]);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + strlen(temp[i]) + 2);
          strcat(to_be_returned, "\n");
          strcat(to_be_returned, temp[i]);
        }

    }

  }
  g_strfreev (temp);
  return to_be_returned;
}



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

char * replace_refs_to_AUTO_NIC_hdl(char * changed_obj, char * arg, GHashTable * auto_nic_hash){

  char * auto_nic = NULL;
  GString* temp_string; 
  char * to_be_returned = NULL;
  char ** temp = NULL;
  int i, pos;

  //printf("DEBUG: replace_first_ref_to_AUTO_NIC_hdl is running\n");

  temp = g_strsplit(arg, "\n", 0);

  for(i = 0; temp[i] != NULL; i++){
    //printf("Line: %s\n", temp[i]);
    if(   strstr(temp[i], "admin-c:") == temp[i]    /*    if it starts with admin-c */
       || strstr(temp[i], "tech-c:" ) == temp[i]    /* or if it starts with tech-c */
       || strstr(temp[i], "zone-c:" ) == temp[i]    /* or if it starts with zone-c */
       || strstr(temp[i], "author:" ) == temp[i]){  /* or if it starts with author */
      temp_string = g_string_new(temp[i]);
      if(strstr(temp_string->str, "AUTO-") != NULL){
        auto_nic = (char *)malloc(temp_string->len + temp_string->str - strstr(temp_string->str, "AUTO-")  + 1);
        auto_nic = strncpy(auto_nic, strstr(temp_string->str, "AUTO-"), 
            temp_string->len + temp_string->str - strstr(temp_string->str, "AUTO-") );
        auto_nic[temp_string->str + temp_string->len - strstr(temp_string->str, "AUTO-")] = '\0'; 
        g_strstrip(auto_nic);
        printf("DEBUG: auto_nic is [%s]\n", auto_nic);
        pos = strstr(temp_string->str, "AUTO-") - temp_string->str;
        temp_string = g_string_erase(temp_string,
            strstr(temp_string->str, "AUTO-") - temp_string->str, strlen(auto_nic)/*strlen("AUTO-")*/);
        
        //temp_string = g_string_insert(temp_string, pos, UPDATE_SOURCE);
        //temp_string = g_string_insert(temp_string, pos, "*-");
        /* if we have this AUTO NIC hdl in the hash, put it. */
        if(g_hash_table_lookup(auto_nic_hash, auto_nic)){
          temp_string = g_string_insert(temp_string, pos, (char *)g_hash_table_lookup(auto_nic_hash, auto_nic));
        }else{/* else, return 0 immediately */
          g_strfreev (temp);
          return NULL;
        }
        
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp_string->str);
          g_string_free(temp_string, TRUE);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + temp_string->len + 2);
          to_be_returned = strcat(to_be_returned, "\n");
          to_be_returned = strcat(to_be_returned, temp_string->str);
          g_string_free(temp_string, TRUE);
        }
      }else{
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp[i]);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + strlen(temp[i]) + 2);
          to_be_returned = strcat(to_be_returned, "\n");
          to_be_returned = strcat(to_be_returned, temp[i]);
        }
      }
    }else{/* if it doesn't begin with ac,tc,ac or author */
        if(to_be_returned == NULL){
          to_be_returned = strdup(temp[i]);
        }else{
          to_be_returned = (char *)realloc(to_be_returned, strlen(to_be_returned) + strlen(temp[i]) + 2);
          strcat(to_be_returned, "\n");
          strcat(to_be_returned, temp[i]);
        }

    }

  }
  g_strfreev (temp);
  //free(arg);
  //changed_obj = strdup(to_be_returned);
  //free(to_be_returned);
  printf("DEBUG: replace_first_ref_to_AUTO_NIC_hdl is returning,\nto_be_returned=[%s]\n", to_be_returned);
  return to_be_returned;
}








/* Takes an object in a char * , and returns 1 if this object has 
   an AUTO NIC handle. Otherwise, returns 0 */
int has_AUTO_NIC_hdl(const char * object){

  Object * o = new Object();
  GSList * attributes = NULL;
  bool code;

  code = o->scan(object, strlen(object));

  if(code && !(o->isDeleted)){
    attributes = get_attributes(o, "nic-hdl", object);
    if(attributes != NULL){
      if(strstr_in_list(attributes, "AUTO-") == 1){/* if it contains a ref to AUTO nic */
        g_slist_free(attributes);
        delete(o);
        return 1;
      }
    }
    /* if control reaches here, then we will return 0 */
    g_slist_free(attributes);
    delete(o);
    return 0; 
  }else{/* it doesn't pass syntax check. So, it doesn't matter if 
           it contains refs to AUTO NIC hdls. */
    delete(o); 
    return 0;        
  }
    
}


/* Takes an object in a char * , and returns 1 if this object contains
   a reference to an AUTO NIC handle. Otherwise, returns 0 */
int has_ref_to_AUTO_nic_hdl(const char * object){

  Object * o = new Object();
  GSList * attributes = NULL;
  bool code;

  code = o->scan(object, strlen(object));

  if(code && !(o->isDeleted)){
    attributes = get_attributes(o, "admin-c", object);
    if(attributes != NULL){
      if(strstr_in_list(attributes, "AUTO-") == 1){/* if it contains a ref to AUTO nic */
        g_slist_free(attributes);
        delete(o);
        return 1;
      }
    }
    g_slist_free(attributes);
    attributes = get_attributes(o, "tech-c", object);
    if(attributes != NULL){
      if(strstr_in_list(attributes, "AUTO-") == 1){/* if it contains a ref to AUTO nic */
        g_slist_free(attributes);
        delete(o);
        return 1;
      }
    }

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


/*  */
void add_to_ack(const char * msg, const char * file_name){

   FILE * ack_file;

   if((ack_file = fopen(file_name, "a")) == NULL){
     perror("Couldn't open ack file");
     return;
   }
   fprintf(ack_file, "%s\n", msg);
   fclose(ack_file);
}

/*  */
void add_to_ack_string(const string msg, const char * file_name){

   ofstream ack_file(file_name, ios::app);

   if(!ack_file){
     cerr << "Couldn't open ack file" << endl;
     return;
   }
   ack_file << msg << endl;
   ack_file.close();
}


/* Checks the object's syntax, retrives the old version of it from the db, 
   and checks auth2. If everything is OK, then sends it to RIPdb, where referential
   integrity is checked, and the object is really committed to the db.
   
     Arguments:
        char * arg: The object,
        credentials_struct credentials: The struct containing the credentials, such as 
          'From:' field of the e-mail update,
        GHashTable * NIC_hdl_hash: A hash containing 
        char * ack_file_name:  The file name, to be used to store ACK message 
*/

int process_object(char * arg, credentials_struct credentials, GHashTable * NIC_hdl_hash, char * ack_file_name){
    bool code = true;
    Object *o;
    char * old_version = NULL;
    o = new Object;
    int result = 0;
    int result_from_RIPupd = 0;
    char * auto_nic = NULL;
    char * changed_obj = NULL;
    char * obj_with_AUTO_NIC_hdl;
    char * assigned_NIC;

    char * value = NULL;/* these two are for */
    Attr * attr;        /* ack messages only */ 
    
    if(has_ref_to_AUTO_nic_hdl(arg)){/* if this object has refs to AUTO NIC hdls*/
       /* then first replace AUTO NIC hdls with assigned NIC hdls (in NIC_hdl_hash) */
       if((arg = replace_refs_to_AUTO_NIC_hdl(changed_obj, arg, NIC_hdl_hash)) == NULL){
         return UP_ANE; /* AUTO NIC hdl error */
       };
    }
    
    code = o->scan(arg,strlen(arg));
    if(code){
      /* is the object to be deleted? */
      if(o->isDeleted){
        printf("This object is to be deleted\n"); 
        old_version = get_old_version(arg);
        if(old_version == NULL){ // the object doesn't exist in the db!
          add_to_ack("\nDeletion Failed: Object doesn't exist", ack_file_name);
          add_to_ack(o->type->getName(), ack_file_name);
          add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
          return UP_NSO; /* no such object */
        }else {/* the object is in the db */
          if(identical(old_version, arg)){/* if the old & new versions are identical */
            result = check_auth(NULL, old_version, o->type->getName(), credentials);
            if(result == UP_AUTH_OK){ 
              if(tracing) {
                printf("TRACING: Will send the obj to be deleted\n");
              }
              result_from_RIPupd = send_object_db(arg, NULL, "DEL");
              if(result_from_RIPupd == 0){
                add_to_ack("\nDeletion succeeded", ack_file_name);
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }else{
                add_to_ack("\nDeletion failed: Referential intergrity failure", ack_file_name);
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }
              result_from_RIPupd = 0;
            }else{ /* auth failed */
              if(tracing) {
                printf("TRACING: Auth failed\n");
              }
              if(error_msg != NULL){
                  cout << error_msg << endl;
              }
              add_to_ack("\nDeletion failed: Auth failed", ack_file_name);
              add_to_ack(o->type->getName(), ack_file_name);
              add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              return UP_AUF; /* Auth failed */
            } 
          }else{/* the new & old versions do not match */
            add_to_ack("Deletion failed: new & old versions do not match", ack_file_name);
            return UP_NOM; /* new & old versions do not match */
          }
        }
      }else {/* the object is _not_ to be deleted */
        if(has_AUTO_NIC_hdl(arg)){/* it the object has an AUTO NIC hdl */
          /* then its nic-hdl attribute must be modified so that RIPupdate
             would understand that it must assign a NIC handle to it */
          /* but first check the auth */
          result = check_auth(arg, NULL, o->type->getName(), credentials);
          if(result == UP_AUTH_OK){
            if(tracing) {                                
                printf("TRACING: Will send the obj to be created with AUTO NIC hdl\n");
            }
            auto_nic = (char *)malloc(1024); /* should be enough for a NIC hdl */
            obj_with_AUTO_NIC_hdl = replace_AUTO_NIC_hdl(arg, auto_nic);
            if(tracing) {  
              printf("TRACING:  Called replace_AUTO_NIC_hdl, get [%s]\n", obj_with_AUTO_NIC_hdl);
              printf("TRACING: Will send the obj to be added\n");
            }
            assigned_NIC = (char *)malloc(128); /* this should be enough for a NIC hdl */
            result_from_RIPupd = send_object_db(obj_with_AUTO_NIC_hdl, assigned_NIC, "ADD");
            if(result_from_RIPupd == 0){
              add_to_ack("\nCreation succeeded", ack_file_name);
              add_to_ack(o->type->getName(), ack_file_name);
              add_to_ack(assigned_NIC, ack_file_name);
            }else{
              add_to_ack("\nCreation failed: Referential integrity failure", ack_file_name);
              add_to_ack(o->type->getName(), ack_file_name);
              add_to_ack(arg, ack_file_name);
            }
            result_from_RIPupd = 0;
            if(tracing && assigned_NIC != NULL) {  
              printf("TRACING: send_object_db returned [%s] as assigned NIC hdl\n", assigned_NIC);
            }
            if(assigned_NIC != NULL){
              printf("DEBUG: auto_nic=[%s], assigned_NIC=[%s]\n", auto_nic, assigned_NIC);
              g_hash_table_insert(NIC_hdl_hash, auto_nic, assigned_NIC);
              printf("DEBUG: NIC_hdl_hash has %i pairs\n",g_hash_table_size(NIC_hdl_hash));
            }
            
          }else{
            // auth failed !
            if(tracing) {
              printf("TRACING: Auth failed\n");
            }
            if(error_msg != NULL){
              cout << error_msg << endl;
            }
            ER_perror(0, result, "");
            add_to_ack("\nCreation failed: Auth failed", ack_file_name);
            add_to_ack(o->type->getName(), ack_file_name);
            add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
            return UP_AUF; /* Auth failed */
          }
        }
        else{ 
          old_version = get_old_version(arg);
          if(old_version != NULL){/* so, this is an update operation */
            result = check_auth(arg, old_version, o->type->getName(), credentials);    
            if(result == UP_AUTH_OK){
              if(tracing) {                                
                printf("TRACING: Will send the obj to be updated\n");
              }
              result_from_RIPupd = send_object_db(arg, NULL, "UPD");
              if(result_from_RIPupd == 0){
                add_to_ack("\nUpdate succeeded", ack_file_name);
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }else{
                add_to_ack("\nUpdate failed: Referential integrity failure", ack_file_name);
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }
              result_from_RIPupd = 0;
            }else{
              // auth failed !
              if(tracing) {
                printf("TRACING: Auth failed\n");
              }
              if(error_msg != NULL){
                cout << error_msg << endl;
              }
              add_to_ack("\nUpdate failed: Auth failed", ack_file_name);
              add_to_ack(o->type->getName(), ack_file_name);
              add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              return UP_AUF; /* Auth failed */
            }
          }else { /* old_version  == NULL, so, creation */
            result = check_auth(arg, NULL, o->type->getName(), credentials);
            if(result == UP_AUTH_OK){ 
              if(tracing) {                                
                printf("TRACING: Will send the obj to be added\n");
              }
              result_from_RIPupd = send_object_db(arg, NULL, "ADD");
              if(result_from_RIPupd == 0){
                add_to_ack("\nCreation succeeded", ack_file_name); 
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }else{
                add_to_ack("\nCreation failed: Referential integrity failure", ack_file_name); 
                add_to_ack(o->type->getName(), ack_file_name);
                add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              }
              result_from_RIPupd = 0;
            }else{
              // auth failed !
              if(tracing) {
                printf("TRACING: Auth failed\n");
              }
              if(error_msg != NULL){
                cout << error_msg << endl;
              }
              ER_perror(0, result, "");
              add_to_ack("\nCreation failed: Auth failed", ack_file_name);
              add_to_ack(o->type->getName(), ack_file_name);
              add_to_ack(get_search_key(o, o->type->getName(), arg), ack_file_name);
              return UP_AUF; /* Auth failed */
            }
          } 
        }
      }
    }else{// even if obj doesn't parse properly, it may be a legacy object
          // which the user wants to delete...
       printf("DEBUG: Object didn't parse\n");   
       add_to_ack("\nFailed: Syntax error in object", ack_file_name);
       add_to_ack(arg, ack_file_name);   
       //for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
       //  value = (char*)malloc((*attr).len );
       //  strncpy(value, (char *)(arg+attr->offset) ,
       //    attr->len - 1);
       //  value[attr->len - 1] = '\0';
       //  add_to_ack(value, ack_file_name);
       //  if(!attr->errors.empty()){
       //    add_to_ack_string(attr->errors, ack_file_name);
       //  }
       //  free(value);
       // }
       // if(o->has_error){
       //   add_to_ack_string(o->errors, ack_file_name);
       // }
 
       return UP_NIY; /* Not implemented yet */
    }
}




/* Gets the "From" line of the incoming mail message and finds out an 
   address to send the acknowledgement */
char * find_to_address(const char * from_line){
  char * pos1 = NULL, * pos2 = NULL;
  char * temp = NULL;
  
  if(from_line == NULL){
    return NULL;
  }
  if(strstr(from_line, "From:") != from_line){/* there is a problem, the line must start with 
                                                 "From:" */
    fprintf(stderr, "The line doesn't start with 'From:'\n");
    return NULL;
  }
  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';
    printf("DEBUG: find_to_address\n");
    printf("DEBUG: find_to_address temp=[%s]\n", temp);
    return temp;
  }else{/* the line contains only the address, then */
   return temp; 
  }
}  

