/* risxhandler.c: functions to write risx datasets to a database */
/* markus@mhoenicka.de 2003-05-13 */

/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* ToDo:
   - test sending incomplete or invalid XML data
*/

/* Overview */
/* This set of functions parses a XML file containing risx.dtd
   datasets. We use expat as a non-validating XML parser. We register
   three handlers for start tags, character data, and end tags. The
   elements are pushed on a stack in the start tags handler. Each
   structure defining an element contains a start element of another
   stack for the attributes of this element. These stacks are used in
   the character data handler and the end tag handler to retrieve
   parent and ancestor elements and attributes of the current element
   where necessary. The attribute stack of the current element is
   freed in the end tag handler and the current element is popped off
   the stack as well. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <expat.h> /* header of the XML parser */
#include <syslog.h> /* priority levels of log messages */
#include <iconv.h>
#include <sys/types.h> /* for getpid() */
#include <unistd.h>    /* for getpid() */
#include <dbi/dbi.h>

#include "backend.h"
#include "linklist.h"
#include "refdb.h"
#include "refdbd.h" /* depends on backend.h */
#include "risdb.h"
#include "xmlhandler.h"
#include "risxhandler.h"
#include "strfncs.h"
#include "connect.h"
#include "dbfncs.h"
#include "authorinfo.h"
#include "risdata.h"
#include "connect.h"

extern int n_log_level;
extern int nongeek_offset;



/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  risx_start_handler(): handler for start tags
  
  void risx_start_handler has no return value

  void* ptr_data this is a ptr to "non-global" global data that all
             handlers share - will be cast to type struct addrisx_data*

  const char *el ptr to a string containing the element name

  const char** ptr_attr ptr to an array of attributes (name-value pairs)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void risx_start_handler(void *ptr_data, const char *el, const char **ptr_attr) {
  const char* type = NULL;
  const char* id = NULL;
  const char* citekey = NULL;
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  char* new_msgpool;
  char sql_command[1024] = "";
  int i;
  int result;
  unsigned long long n_periodical_id;
  struct elstack* ptr_el_new;
  struct attrlist* ptr_attr_new;
  struct addrisx_data* ptr_ardata;
  dbi_result dbires;

  ptr_ardata = (struct addrisx_data*)ptr_data;

  if (ptr_ardata->replace_ref != ADDREF_CHECK) {
    *prefix = '\0';
  }

/*   fprintf(stderr, "start_handler found el:%s<< attname:%s<< attvalue:%s<<ndb_error:%d<< nmem_error:%d<< n_skip:%d<<\n", el, ptr_attr[0], ptr_attr[1], ptr_ardata->ndb_error, ptr_ardata->nmem_error, ptr_ardata->n_skip); */
/*   LOG_PRINT(LOG_DEBUG, sql_command); */

  if (!ptr_ardata->ndb_error && !ptr_ardata->nmem_error && !ptr_ardata->n_skip) {
    if (!strcmp(el, "ris")) {
      (ptr_ardata->depth_adjust)++;
    }
    else if (!strcmp(el, "entry")) {
      /* If the db server supports it, start a transaction. We want one
	 transaction per reference */
      if (my_dbi_conn_begin(ptr_ardata->conn)) {
	(ptr_ardata->ndb_error)++;
	LOG_PRINT(LOG_WARNING, "begin transaction failed");
	return;
      }
  
      /* lock the tables we'll write to to prevent concurrent writes
	 from different clients */
      if (my_dbi_conn_lock(ptr_ardata->conn, ptr_ardata->replace_ref)) {
	(ptr_ardata->ndb_error)++;
	LOG_PRINT(LOG_WARNING, "Cannot lock tables");
	return;
      }

      /* reset a few variables relevant to entries */
      *(ptr_ardata->first_author) = '\0';
      *(ptr_ardata->real_citekey) = '\0';
      *(ptr_ardata->ck_year) = '\0';
      ptr_ardata->create_new = 1;

      /* isolate attributes */
      for (i = 0; ptr_attr[i]; i += 2) {
	if (!strcmp(ptr_attr[i], "type")) {
	  type = ptr_attr[i+1];
	}
	else if (!strcmp(ptr_attr[i], "id")) {
	  id = ptr_attr[i+1];
	}
	else if (!strcmp(ptr_attr[i], "citekey")) {
	  citekey = ptr_attr[i+1];
	}
      }

      /* we're out of luck if the type attribute is missing or too long */
      if (!type) {
	(ptr_ardata->ndb_error)++;
	LOG_PRINT(LOG_WARNING, "type attribute missing");
	return;
      }
      else if (strlen(type) > 6
	       || !strstr(REFTYPES,type)) {
	sprintf(sql_command, "426:%s->GEN\n", type);
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	strcpy(ptr_ardata->type, "GEN");
      }
      else {
	strcpy(ptr_ardata->type, type);
      }

      /* see whether id or citekey already exist in the database */
      if (citekey && *citekey) {
	char *new_key;

	/* truncate */
	if ((new_key = preprocess_citekey_copy(citekey, 255)) == NULL) {
	  return;
	}
	else {
	  strcpy(ptr_ardata->real_citekey, new_key);
	  free(new_key);
	}

	sprintf(sql_command, "SELECT refdb_id FROM t_%srefdb WHERE refdb_citekey=\'%s\'", prefix, ptr_ardata->real_citekey);
      }
      else if (id && *id) {
	if (strlen(id) > 20) { /* largest 8-byte integer */
	  (ptr_ardata->ndb_error)++;
	  LOG_PRINT(LOG_WARNING, "ID value too long");
	  return ;
	}
	sprintf(sql_command, "SELECT refdb_id FROM t_%srefdb WHERE refdb_id=%s", prefix, id);
      }

      if (*sql_command) {
	/* search for existing entry */
	LOG_PRINT(LOG_DEBUG, sql_command);
      
	dbires = dbi_conn_query(ptr_ardata->conn, sql_command);
	if (!dbires) {
	  (ptr_ardata->ndb_error)++;
	  LOG_PRINT(LOG_WARNING, "Search ID failed");
	  return;
	}

	/* we have to consider these cases:
	   - addref: entry with same ID or citekey doesn't exist-> add
	   - addref: entry with same ID/citekey exists-> error
	   - updateref: entry with same ID/citekey doesn't exist-> add
	   - updateref: entry with same ID/citekey exists-> update */
    
	if (dbi_result_next_row(dbires)) { /* requested ID exists */
	  if (ptr_ardata->replace_ref != ADDREF_ADD
	      && ptr_ardata->replace_ref != ADDREF_CHECK) {
	    ptr_ardata->create_new = 0;
	    ptr_ardata->n_refdb_id = my_dbi_result_get_idval(dbires, "refdb_id");
	  }
	  else { /* we're supposed to add */
	    if (*(ptr_ardata->real_citekey)) {/* we can't add lest we overwrite existing data */
	      sprintf(sql_command, "refused to overwrite existing dataset %s", ptr_ardata->real_citekey);
	      LOG_PRINT(LOG_INFO, sql_command);
	      (ptr_ardata->n_skip)++;
/* 	      sprintf(sql_command, "refused to overwrite existing dataset %s\n", ptr_ardata->real_citekey); */
	      sprintf(sql_command, "407:"ULLSPEC":%s\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), ptr_ardata->real_citekey);
	      if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
		(ptr_ardata->nmem_error)++;
		return;
	      }
	      else {
		ptr_ardata->msgpool = new_msgpool;
	      }
	      return;
	    }
	    else { /* ignore numerical ID and assign a new one */
	      LOG_PRINT(LOG_INFO, "numerical ID ignored");
	      sprintf(sql_command, "409:"ULLSPEC":%s\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), id);
/* 	      if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "numerical ID ignored\n", &(ptr_ardata->msgpool_len), 0)) == NULL) { */
 	      if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) { 
		(ptr_ardata->nmem_error)++;
		return;
	      }
	      else {
		ptr_ardata->msgpool = new_msgpool;
	      }
	    }
	  }
	}
	else { /* requested ID could not be found */
	  if (ptr_ardata->replace_ref == ADDREF_UPDATE) {
	    ptr_ardata->create_new = 1;
	  }
	  else if (ptr_ardata->replace_ref == ADDREF_UPDATE_PERSONAL) {
	    dbi_result_free(dbires);
	    (ptr_ardata->ndb_error)++;
	    LOG_PRINT(LOG_WARNING, "ID not found");
	    if (citekey && *citekey) {
	      sprintf(sql_command, "411:"ULLSPEC":%s\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), ptr_ardata->real_citekey);
	    }
	    else {
	      sprintf(sql_command, "410:%s\n", id);
	    }
/* 	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "ID not found\n", &(ptr_ardata->msgpool_len), 0)) == NULL) { */
	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	      (ptr_ardata->nmem_error)++;
	      return;
	    }
	    else {
	      ptr_ardata->msgpool = new_msgpool;
	    }
	    return;
	  }
	  else if (!*(ptr_ardata->real_citekey)) { /* if add, ignore numerical ID and assign a new one */
	    LOG_PRINT(LOG_INFO, "numerical ID ignored");
	      sprintf(sql_command, "409:"ULLSPEC":%s\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), id);
/* 	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "numerical ID ignored\n", &(ptr_ardata->msgpool_len), 0)) == NULL) { */
	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	      (ptr_ardata->nmem_error)++;
	      return;
	    }
	    else {
	      ptr_ardata->msgpool = new_msgpool;
	    }
	  }
	}
	dbi_result_free(dbires);
      }
      else { /* no ID string */
	if (ptr_ardata->replace_ref == ADDREF_UPDATE) {
	  ptr_ardata->create_new = 1; /* if no ID string, simply add the dataset */
	}
	else if (ptr_ardata->replace_ref == ADDREF_UPDATE_PERSONAL){
	  LOG_PRINT(LOG_WARNING, "ID missing");
	  (ptr_ardata->ndb_error)++;
/* 	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "ID not found\n", &(ptr_ardata->msgpool_len), 0)) == NULL) { */
	  sprintf(sql_command, "412:"ULLSPEC"\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset));
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  return;
	}
	/* else: add will assign new ID anyway */
      }

      /* if we're replacing, first remove the existing entry as far as necessary */
      if (!ptr_ardata->create_new
	  && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
/* 	sprintf(sql_command, "try to replace reference "ULLSPEC"\n", (unsigned long long)(ptr_ardata->n_refdb_id)); */
/* 	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) { */
/* 	  (ptr_ardata->nmem_error)++; */
/* 	  return; */
/* 	} */
/* 	else { */
/* 	  ptr_ardata->msgpool = new_msgpool; */
/* 	} */

	/* search orphans in t_keyword */
	/* printf("orphans in t_keyword\n"); */
	result = remove_keyword_entries(ptr_ardata->n_refdb_id, ptr_ardata->conn, 0);
	if (result) {
	  if (result == 1) {

	    /* Todo: convert to LOG_WARNING, return user-digestible string instead */
	    strcpy(sql_command, "select from t_xkeyword failed\n");
	  }
	  else if (result == 2) {
	    strcpy(sql_command, "delete from t_keyword failed\n");
	  }
	  else if (result == 3) {
	    strcpy(sql_command, "delete from t_xkeyword failed\n");
	  }

	  (ptr_ardata->ndb_error)++;

	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  return;
	}
	/* else: all fine */

	/* search orphans in t_author */
	result = remove_author_entries(ptr_ardata->n_refdb_id, ptr_ardata->conn);
	if (result) {
	  if (result == 1) {
	    strcpy(sql_command, "select from t_xauthor failed\n");
	  }
	  else if (result == 2) {
	    strcpy(sql_command, "delete from t_author failed\n");
	  }
	  else if (result == 3) {
	    strcpy(sql_command, "delete from t_xauthor failed\n");
	  }

	  (ptr_ardata->ndb_error)++;

	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  return;
	}
	/* else: all fine */

	/* search orphans in t_xuser */
	result = remove_xuser_entries(ptr_ardata->n_refdb_id, ptr_ardata->username, ptr_ardata->conn);
	if (result != 0 && result != 4) {
	  if (result == 1) {
	    strcpy(sql_command, "select from t_xuser failed\n");
	  }
	  else if (result == 3) {
	    strcpy(sql_command, "delete from t_xuser failed\n");
	  }

	  (ptr_ardata->ndb_error)++;

	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  return;
	}
	/* else: all fine */

	/* search orphans in t_ulink */
	result = remove_ulink_entries(ptr_ardata->n_refdb_id, /*ptr_ardata->username*/ NULL, ptr_ardata->conn, 0 /* reference */);
	if (result != 0 && result != 4) {
	  if (result == 1) {
	    strcpy(sql_command, "select from t_xuser failed\n");
	  }
	  else if (result == 3) {
	    strcpy(sql_command, "delete from t_xuser failed\n");
	  }

	  (ptr_ardata->ndb_error)++;

	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  return;
	}
	/* else: all fine */

	/* search orphans in t_periodical */
	sprintf(sql_command, "SELECT refdb_periodical_id FROM t_refdb WHERE refdb_id="ULLSPEC, (unsigned long long)(ptr_ardata->n_refdb_id));

	LOG_PRINT(LOG_DEBUG, sql_command);

	dbires = dbi_conn_query(ptr_ardata->conn, sql_command);
	if (!dbires) {
	  LOG_PRINT(LOG_WARNING, "deleteref failed");
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "deleteref failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}

	while (dbi_result_next_row(dbires)) {
	  n_periodical_id = my_dbi_result_get_idval(dbires, "refdb_periodical_id");
	  if (n_periodical_id != 0 && dbi_conn_error(ptr_ardata->conn, NULL) == 0) {
	    if (remove_periodical_entries(n_periodical_id, ptr_ardata->conn)) {
	      if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "remove periodical failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
		(ptr_ardata->nmem_error)++;
		return;
	      }
	      else {
		ptr_ardata->msgpool = new_msgpool;
	      }
	      (ptr_ardata->ndb_error)++;
	      return;
	    }
	  }
	} /* end while */
	dbi_result_free(dbires);

	/* reset all values in t_refdb, keep citekey, use new type */
    sprintf(sql_command, "UPDATE t_refdb SET refdb_type=\'%s\', refdb_pubyear=NULL, refdb_secyear=NULL, refdb_startpage=NULL, refdb_endpage=NULL, refdb_abstract=NULL, refdb_title=NULL, refdb_volume=NULL, refdb_issue=NULL, refdb_booktitle=NULL, refdb_city=NULL, refdb_publisher=NULL, refdb_title_series=NULL, refdb_address=NULL, refdb_issn=NULL, refdb_pyother_info=NULL, refdb_secother_info=NULL, refdb_periodical_id=NULL, refdb_user1=NULL, refdb_user2=NULL, refdb_user3=NULL, refdb_user4=NULL, refdb_user5=NULL, refdb_typeofwork=NULL, refdb_area=NULL, refdb_ostype=NULL, refdb_degree=NULL, refdb_runningtime=NULL, refdb_classcodeintl=NULL, refdb_classcodeus=NULL, refdb_senderemail=NULL, refdb_recipientemail=NULL, refdb_mediatype=NULL, refdb_numvolumes=NULL, refdb_edition=NULL, refdb_computer=NULL, refdb_conferencelocation=NULL, refdb_registrynum=NULL, refdb_classification=NULL, refdb_section=NULL, refdb_pamphletnum=NULL, refdb_chapternum=NULL WHERE refdb_id="ULLSPEC, ptr_ardata->type, (unsigned long long)(ptr_ardata->n_refdb_id));

	LOG_PRINT(LOG_DEBUG, sql_command);

	dbires = dbi_conn_query(ptr_ardata->conn, sql_command);
	if (!dbires) {
	  LOG_PRINT(LOG_WARNING, "deleteref failed");
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "deleteref failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	dbi_result_free(dbires);
      }


      if (ptr_ardata->create_new) {
	/* generate temporary citekey if necessary */
	if (!*(ptr_ardata->real_citekey)) {
	  snprintf(ptr_ardata->real_citekey, 256, "DUMMY%s%d", ptr_ardata->ptr_clrequest->my_hostname, getpid());
	}

	/* insert a new empty dataset into the main table to start with */
	sprintf(sql_command, "INSERT INTO t_%srefdb (refdb_type,refdb_citekey) VALUES (\'%s\',\'%s\')", prefix, ptr_ardata->type, ptr_ardata->real_citekey);
	dbires = dbi_conn_query(ptr_ardata->conn, sql_command);
	LOG_PRINT(LOG_DEBUG, sql_command);
	if (!dbires) {
	  (ptr_ardata->ndb_error)++;
	  LOG_PRINT(LOG_WARNING, "insert into t_refdb failed");
	  return;
	}

	dbi_result_free(dbires);

	/* retrieve refdb_id of newly created dataset */
	if (!strcmp(my_dbi_conn_get_cap(ptr_ardata->conn, "named_seq"), "f")) {
	  ptr_ardata->n_refdb_id = dbi_conn_sequence_last(ptr_ardata->conn, NULL);
	}
	else {
	  sprintf(sql_command, "t_%srefdb_refdb_id_seq", prefix);
	  ptr_ardata->n_refdb_id = dbi_conn_sequence_last(ptr_ardata->conn, sql_command);
	}

/* 	sprintf(sql_command, "try to add set as reference "ULLSPEC"\n", (unsigned long long)(ptr_ardata->n_refdb_id)); */
/* 	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) { */
/* 	  LOG_PRINT(LOG_WARNING, get_status_msg(801)); */
/* 	  (ptr_ardata->nmem_error)++; */
/* 	  return; */
/* 	} */
/* 	else { */
/* 	  ptr_ardata->msgpool = new_msgpool; */
/* 	} */
      } /* end if create_new */

      /* get a risdata object to pool the t_refdb info */
      ptr_ardata->ptr_risdata = new_risdata();
      if (!ptr_ardata->ptr_risdata) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	(ptr_ardata->nmem_error)++;
	return;
      }

      ptr_ardata->ptr_risdata->n_id = ptr_ardata->n_refdb_id;

      if (ptr_ardata->real_citekey && *ptr_ardata->real_citekey) {
	result = set_risdata_field(ptr_ardata->ptr_risdata, "citekey", ptr_ardata->real_citekey, ptr_ardata->conn);
	if (result == 1) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	}
      }
      if (ptr_ardata->type && *(ptr_ardata->type)) {
	result = set_risdata_field(ptr_ardata->ptr_risdata, "type", ptr_ardata->type, ptr_ardata->conn);
	if (result == 1) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	}
      }
    } /* end if "entry" */

    else if (!strcmp(el, "date") || !strcmp(el, "reprint")) {
      *(ptr_ardata->year) = '\0';
      *(ptr_ardata->month) = '\0';
      *(ptr_ardata->day) = '\0';
      *(ptr_ardata->date_buffer) = '\0';
    }
    else if (!strcmp(el, "pubdate")) {
      *(ptr_ardata->otherinfo) = '\0';
    }
    else if (!strcmp(el, "author")) {
      reset_authorinfo(ptr_ardata->ptr_ainfo);
    }
    else if (!strcmp(el, "part") || !strcmp(el, "set")) {
      ptr_ardata->authorpos = 0;
    }
    else if (!strcmp(el, "publication")) {
      ptr_ardata->authorpos = 0;
      (ptr_ardata->perinfo).full = NULL;
      (ptr_ardata->perinfo).abbrev = NULL;
      (ptr_ardata->perinfo).custabbrev1 = NULL;
      (ptr_ardata->perinfo).custabbrev2 = NULL;
    }
    else if (!strcmp(el, "libinfo")) {
      const char* user = NULL;
      
      /* isolate attributes */
      for (i = 0; ptr_attr[i]; i += 2) {
	if (!strcmp(ptr_attr[i], "user")) {
	  user = ptr_attr[i+1];
	}
      }
      
      /* create user and xuser entries */
      result = insert_user(user, ptr_ardata->n_refdb_id, &(ptr_ardata->n_user_id), ptr_ardata->conn, ptr_ardata->drivername, ptr_ardata->replace_ref, 0);
      
      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "search user failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 2) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert t_user failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 3) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert t_xuser failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 4) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "username too long\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 5) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert user failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 6) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "query t_xuser failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 7) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "failed to add reference to personal reference list\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 8) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "out of memory\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }

    /* add current element to element stack */
    ptr_el_new = malloc(sizeof(struct elstack));
    if (ptr_el_new == NULL) {
      (ptr_ardata->nmem_error)++;
    }
    else {
      /*    printf("have memory\n"); */
      strncpy(ptr_el_new->elname, el, 63);
      ptr_el_new->elname[63] = '\0'; /* terminate just in case */
      ptr_el_new->n_elvalue_len = ELVALUE_LENGTH;
      ptr_el_new->ptr_elvalue = malloc(ELVALUE_LENGTH);
      if (ptr_el_new->ptr_elvalue == NULL) {
	(ptr_ardata->nmem_error)++;
      }
      else {
	*(ptr_el_new->ptr_elvalue) = '\0';
      }
      ptr_el_new->ptr_next = ptr_ardata->ptr_first;
      ptr_el_new->ptr_attr_first = NULL;
      ptr_ardata->ptr_first = ptr_el_new;
/*       printf("%s", ptr_el_new->elname); */
      
      /* add current attributes to the element */
      /*    printf("add attributes\n"); */
      for (i = 0; ptr_attr[i]; i += 2) {
	ptr_attr_new = malloc(sizeof(struct attrlist));
	if (ptr_attr_new == NULL) {
	  (ptr_ardata->nmem_error)++;
	  break;
	}
	strncpy(ptr_attr_new->attribute_name, ptr_attr[i], 63);
	ptr_attr_new->attribute_name[63] = '\0';
	strncpy(ptr_attr_new->attribute_value, ptr_attr[i+1], 63);
	ptr_attr_new->attribute_value[63] = '\0';
	ptr_attr_new->ptr_next = (ptr_ardata->ptr_first)->ptr_attr_first;
	(ptr_ardata->ptr_first)->ptr_attr_first = ptr_attr_new;
/*         printf(" %s='%s'", ptr_attr[i], ptr_attr[i + 1]); */
      }
    /*    printf("done adding attributes\n"); */
      (ptr_ardata->depth)++;
    }
  }

  return;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  risx_end_handler(): handler for end tags

  void risx_end_handler has no return value

  void* ptr_data this is a ptr to "non-global" global data that all
             handlers share - will be cast to type struct addrisx_data*

  const char *el ptr to a string containing the element name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void risx_end_handler(void *ptr_data, const char *el) {
  char sql_command[256];
  char* new_msgpool = NULL;
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  int result;
  struct elstack* ptr_el_remove;
  struct attrlist* ptr_attr_remove;
  struct addrisx_data* ptr_ardata;
  dbi_result dbires;

  ptr_ardata = (struct addrisx_data*)ptr_data;

  if (ptr_ardata->replace_ref != ADDREF_CHECK) {
    *prefix = '\0';
  }

/*   printf("end handler found el:%s<<ndb_error:%d<< nmem_error:%d<<\n", el, ptr_ardata->ndb_error, ptr_ardata->nmem_error); */

  if (ptr_ardata->n_skip) {
    if (!strcmp(el, "entry")) {
      (ptr_ardata->n_skip)--;
      (ptr_ardata->skipped_count)++;
      (ptr_ardata->set_count)++;

      /* close transaction of skipped dataset, if any, and unlock the tables */
      my_dbi_conn_rollback(ptr_ardata->conn);
      my_dbi_conn_unlock(ptr_ardata->conn);
    }
    return;
  }

  if (ptr_ardata->depth) {
    (ptr_ardata->depth)--;
  }

  if (!ptr_ardata->ndb_error && !ptr_ardata->nmem_error) {
    /* do a character conversion if required. expat dumps all
       character data as UTF-8 regardless of the input encoding */
    size_t inlength;
    size_t outlength;
    char* my_elvalue = NULL; /* this ptr will be modified by iconv() */
    char* my_elvalue_start = NULL; /* records initial state of my_elvalue */
    const char* my_instring = NULL; /* this ptr will be modified by iconv() */

    if (ptr_ardata->conv_descriptor && *((ptr_ardata->ptr_first)->ptr_elvalue)) {
      inlength = strlen((ptr_ardata->ptr_first)->ptr_elvalue)/*  + 1 */;
      /* with the encodings supported by our database engines, the converted
	 string can't be longer than the input string */
      outlength = inlength + 1;

      if ((my_elvalue = malloc(outlength)) == NULL) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->nmem_error)++;
	return;
      }

      /* keep start of the converted string */
      my_elvalue_start = my_elvalue;

      /* variable will be modified by iconv, so don't use original */
      my_instring = (const char*)((ptr_ardata->ptr_first)->ptr_elvalue);

      /* now actually do the conversion */
      if (iconv(ptr_ardata->conv_descriptor, &my_instring, &inlength, &my_elvalue, &outlength) == (size_t)(-1)) {
	if (errno == EILSEQ) {
	  new_msgpool = mstrcat(ptr_ardata->msgpool, "iconv: invalid input character sequence\n", &(ptr_ardata->msgpool_len), 0);
	  LOG_PRINT(LOG_WARNING, "iconv: invalid input character sequence");
	}
	else if (errno == E2BIG) {
	  new_msgpool = mstrcat(ptr_ardata->msgpool, "iconv: output buffer too small\n", &(ptr_ardata->msgpool_len), 0);
	  LOG_PRINT(LOG_WARNING, "iconv: output buffer too small");
	}
	else if (errno == EINVAL) {
	  new_msgpool = mstrcat(ptr_ardata->msgpool, "iconv: incomplete input character\n", &(ptr_ardata->msgpool_len), 0);
	  LOG_PRINT(LOG_WARNING, "iconv: incomplete input character");
	}

	if (new_msgpool == NULL) {
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: conversion went ok. We free the original string and replace
	 it with the converted copy */
      if ((ptr_ardata->ptr_first)->ptr_elvalue) {
	free((ptr_ardata->ptr_first)->ptr_elvalue);
      }
      *my_elvalue = '\0'; /* terminate converted string */
      (ptr_ardata->ptr_first)->ptr_elvalue = my_elvalue_start;
      (ptr_ardata->ptr_first)->n_elvalue_len = strlen((ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* else: no conversion required */

    /* ------------------------------------------------------------ */
    if (!strcmp(el, "title") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      char* title_type;

      result = 0;

      if (is_descendant_of(ptr_ardata->ptr_first, "part")) {
	/* e.g. article, chapter titles */
	result = set_risdata_field(ptr_ardata->ptr_risdata, "title", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      }
      else if (is_descendant_of(ptr_ardata->ptr_first, "publication")) {
	/* most important: journal titles and such */
	/* also here: things like book titles */
	title_type = get_attr(ptr_ardata->ptr_first, "type");

	/* full is the default used by the dtd */
	if (!title_type || (title_type && !strcmp(title_type, "full"))) {
	  if (has_periodical_data(ptr_ardata->type)) {
	    if (((ptr_ardata->perinfo).full = strdup((ptr_ardata->ptr_first)->ptr_elvalue)) == NULL || dbi_conn_quote_string(ptr_ardata->conn, &((ptr_ardata->perinfo).full)) == 0) {
	      if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
		(ptr_ardata->nmem_error)++;
		return;
	      }
	      else {
		ptr_ardata->msgpool = new_msgpool;
	      }
	      (ptr_ardata->ndb_error)++;
	      return;
	    }
	  }
	  else {
	    result = set_risdata_field(ptr_ardata->ptr_risdata, "booktitle", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
	  }
	}
	else if (title_type && !strcmp(title_type, "abbrev")) {
	  /* abbreviated journal title */
	  if (((ptr_ardata->perinfo).abbrev = strdup((ptr_ardata->ptr_first)->ptr_elvalue)) == NULL || dbi_conn_quote_string(ptr_ardata->conn, &((ptr_ardata->perinfo).abbrev)) == 0) {
	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	      (ptr_ardata->nmem_error)++;
	      return;
	    }
	    else {
	      ptr_ardata->msgpool = new_msgpool;
	    }
	    (ptr_ardata->ndb_error)++;
	    return;
	  }
	}
	else if (title_type && !strcmp(title_type, "user1")) {
	  /* user abbrev1 of a journal title */
	  if (((ptr_ardata->perinfo).custabbrev1 = strdup((ptr_ardata->ptr_first)->ptr_elvalue)) == NULL || dbi_conn_quote_string(ptr_ardata->conn, &((ptr_ardata->perinfo).custabbrev1)) == 0) {
	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	      (ptr_ardata->nmem_error)++;
	      return;
	    }
	    else {
	      ptr_ardata->msgpool = new_msgpool;
	    }
	    (ptr_ardata->ndb_error)++;
	    return;
	  }
	}
	else if (title_type && !strcmp(title_type, "user2")) {
	  /* user abbrev1 of a journal title */
	  if (((ptr_ardata->perinfo).custabbrev2 = strdup((ptr_ardata->ptr_first)->ptr_elvalue)) == NULL || dbi_conn_quote_string(ptr_ardata->conn, &((ptr_ardata->perinfo).custabbrev2)) == 0) {
	    if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	      (ptr_ardata->nmem_error)++;
	      return;
	    }
	    else {
	      ptr_ardata->msgpool = new_msgpool;
	    }
	    (ptr_ardata->ndb_error)++;
	    return;
	  }
	}
	else {
	  /* this means we've received invalid risx data */
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "invalid title attribute", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->ndb_error)++;
	    return;
	  }
	}
      }
      else { /* set */
	result = set_risdata_field(ptr_ardata->ptr_risdata, "title_series", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      }

      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "author") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      char* temp_author;
      
      if (!*(ptr_ardata->ptr_ainfo->name)) {
	temp_author = assemble_full_author(ptr_ardata->ptr_ainfo, &(ptr_ardata->nmem_error));

	if (temp_author) {
	  set_authorinfo_name(ptr_ardata->ptr_ainfo, temp_author);
	  free(temp_author);
	}
	else {
	  set_authorinfo_name(ptr_ardata->ptr_ainfo, "");
	}	  
      }
      /* else: corporate name is in ptr_ainfo->name anyway */

      /* role attribute, function checks for NULL value */
      set_authorinfo_role(ptr_ardata->ptr_ainfo, get_attr(ptr_ardata->ptr_first, "role"));

      /* guess contributor type by occurrence, with the help of the role attribute */
      if (is_descendant_of(ptr_ardata->ptr_first, "part")) {
	strcpy(ptr_ardata->ptr_ainfo->role, "author");
	result = insert_author(ptr_ardata->ptr_ainfo, 1 /*part author*/, ptr_ardata->authorpos, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, ptr_ardata->replace_ref);
	if (!ptr_ardata->authorpos) {
	  strncpy(ptr_ardata->first_author, ptr_ardata->ptr_ainfo->lastname, 255);
	  (ptr_ardata->first_author)[255] = '\0';
	}
      }
      else if (is_descendant_of(ptr_ardata->ptr_first, "publication")) {
	/* publication contributors are considered authors unless the monograph is a collection of parts, in which case they are editors */
	if (!strcmp(ptr_ardata->type, "CHAP")
	    || !strcmp(ptr_ardata->type, "CONF")
	    ) {
	  if (!*(ptr_ardata->ptr_ainfo->role)) {
	    strcpy(ptr_ardata->ptr_ainfo->role, "editor");
	  }
	}
	else {
	  if (!*(ptr_ardata->ptr_ainfo->role)) {
	    strcpy(ptr_ardata->ptr_ainfo->role, "author");
	  }
	}
	result = insert_author(ptr_ardata->ptr_ainfo, 2 /*publication author*/, ptr_ardata->authorpos, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, ptr_ardata->replace_ref);
      }
      else { /* set */
	if (!*(ptr_ardata->ptr_ainfo->role)) {
	  strcpy(ptr_ardata->ptr_ainfo->role, "editor");
	}
	result = insert_author(ptr_ardata->ptr_ainfo, 3 /*set author*/, ptr_ardata->authorpos, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, ptr_ardata->replace_ref);
      }

      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 2) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "query AU failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 3) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert AU failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 4) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "driver not supported\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 5) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert AU x failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }

      (ptr_ardata->authorpos)++;
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "name")) {
      set_authorinfo_name(ptr_ardata->ptr_ainfo, (ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "lastname")) {
      set_authorinfo_lastname(ptr_ardata->ptr_ainfo, (ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "firstname")) {
      set_authorinfo_firstname(ptr_ardata->ptr_ainfo, (ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "middlename")) {
      add_authorinfo_middlename(ptr_ardata->ptr_ainfo, (ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "suffix")) {
      set_authorinfo_suffix(ptr_ardata->ptr_ainfo, (ptr_ardata->ptr_first)->ptr_elvalue);
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "pubdate") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      char* pubtype;
      char otherinfo_buffer[512];
      int ndate_type = 0;

      if (*(ptr_ardata->year) || *(ptr_ardata->month)
	  || *(ptr_ardata->day) || *(ptr_ardata->otherinfo)) {
	pubtype = get_attr(ptr_ardata->ptr_first, "type");
	if (pubtype && !strcmp(pubtype, "secondary")) {
	  ndate_type = 1;
	}
	else { /* primary date, save for citation key */
	  strncpy(ptr_ardata->ck_year, ptr_ardata->year, 4);
	  (ptr_ardata->ck_year)[4] = '\0';
	}

      
	/* ToDo: check for buffer overflow and NULL strings */
	sprintf(otherinfo_buffer, "/%s/%s/%s", (ptr_ardata->month) ? ptr_ardata->month : "", (ptr_ardata->day) ? ptr_ardata->day : "", (ptr_ardata->otherinfo) ? ptr_ardata->otherinfo : "");
	
	result = set_risdata_dateinfo(ptr_ardata->ptr_risdata, ndate_type, atoi(ptr_ardata->year), otherinfo_buffer, ptr_ardata->conn);
	
	if (result == 1) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	/* else: all fine */
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "date")) {
      if (is_descendant_of(ptr_ardata->ptr_first, "reprint")) {
	sprintf(ptr_ardata->date_buffer, "%s-%s-%s", ptr_ardata->year, ptr_ardata->month, ptr_ardata->day);
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "year")) {
	strncpy(ptr_ardata->year, (ptr_ardata->ptr_first)->ptr_elvalue, 4);
	(ptr_ardata->year)[4] = '\0';
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "month")) {
      size_t len;

      len = strlen((ptr_ardata->ptr_first)->ptr_elvalue);

      if (len > 1) {
	strncpy(ptr_ardata->month, (ptr_ardata->ptr_first)->ptr_elvalue, 2);
	(ptr_ardata->month)[2] = '\0';
      }
      else if (len == 1) {
	(ptr_ardata->month)[0] = '0';
	(ptr_ardata->month)[1] = (ptr_ardata->ptr_first)->ptr_elvalue[0];
	(ptr_ardata->month)[2] = '\0';
      }
      else {
	strcpy(ptr_ardata->month, "00");
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "day")) {
      size_t len;

      len = strlen((ptr_ardata->ptr_first)->ptr_elvalue);

      if (len > 1) {
	strncpy(ptr_ardata->day, (ptr_ardata->ptr_first)->ptr_elvalue, 2);
	(ptr_ardata->day)[2] = '\0';
      }
      else if (len == 1) {
	(ptr_ardata->day)[0] = '0';
	(ptr_ardata->day)[1] = (ptr_ardata->ptr_first)->ptr_elvalue[0];
	(ptr_ardata->day)[2] = '\0';
      }
      else {
	strcpy(ptr_ardata->day, "00");
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "otherinfo")) {
      strncpy(ptr_ardata->otherinfo, (ptr_ardata->ptr_first)->ptr_elvalue, 255);
      (ptr_ardata->otherinfo)[255] = '\0';
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "volume") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "volume", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "issue") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "issue", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "conftitle") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "booktitle", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "startpage") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "startpage", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "endpage") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "endpage", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "city") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "city", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "publisher") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "publisher", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "serial") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "issn", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "address") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "address", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
/*     else if (!strcmp(el, "url") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) { */
/*       result = insert_ulink((ptr_ardata->ptr_first)->ptr_elvalue, 0 /\* URL *\/, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, ptr_ardata->n_user_id, 0 /\* reference *\/, ptr_ardata->replace_ref); */
/* /\*       result = set_risdata_field(ptr_ardata->ptr_risdata, "url", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn); *\/ */
/*       if (result == 1) { */
/* 	LOG_PRINT(LOG_WARNING, get_status_msg(801)); */
/* 	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) { */
/* 	  (ptr_ardata->nmem_error)++; */
/* 	  return; */
/* 	} */
/* 	else { */
/* 	  ptr_ardata->msgpool = new_msgpool; */
/* 	} */
/* 	(ptr_ardata->ndb_error)++; */
/* 	return; */
/*       } */
/*       /\* else: all fine *\/ */
/*     } */
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "userdef") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      char* type;
      char tofield[6] = "user1";

      type = get_attr(ptr_ardata->ptr_first, "type");

      if (type) {
	if (!strcmp(type, "1")) {
	  strcpy(tofield, "user1");
	}
	else if (!strcmp(type, "2")) {
	  strcpy(tofield, "user2");
	}
	else if (!strcmp(type, "3")) {
	  strcpy(tofield, "user3");
	}
	else if (!strcmp(type, "4")) {
	  strcpy(tofield, "user4");
	}
	else if (!strcmp(type, "5")) {
	  strcpy(tofield, "user5");
	}
      
	result = set_risdata_field(ptr_ardata->ptr_risdata, tofield, (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
	if (result == 1) {
	  LOG_PRINT(LOG_WARNING, get_status_msg(801));
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	/* else: all fine */
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "misc") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      char* type;
      char tofield[11] = "misc1";

      type = get_attr(ptr_ardata->ptr_first, "type");

      if (type) {
	if (!strcmp(type, "1")) {
	  strcpy(tofield, "misc1");
	}
	else if (!strcmp(type, "2")) {
	  if (!strcmp(ptr_ardata->type, "ADVS")) {
	    strcpy(tofield, "doi");
	  }
	  else {
	    strcpy(tofield, "misc2");
	  }
	}
	else if (!strcmp(type, "3")) {
	  if (strcmp(ptr_ardata->type, "ADVS")
	      && strcmp(ptr_ardata->type, "COMP")
	      && strcmp(ptr_ardata->type, "MPCT")
	      && strcmp(ptr_ardata->type, "PAT")
	      && strcmp(ptr_ardata->type, "SOUND")
	      && strcmp(ptr_ardata->type, "VIDEO")) {
	    strcpy(tofield, "doi");
	  }
	  else if (!strcmp(ptr_ardata->type, "ADVS")
		   || !strcmp(ptr_ardata->type, "COMP")
		   || !strcmp(ptr_ardata->type, "MPCT")
		   || !strcmp(ptr_ardata->type, "SOUND")
		   || !strcmp(ptr_ardata->type, "VIDEO")) {
	    strcpy(tofield, "mediatype");
	  }
	  else if (!strcmp(ptr_ardata->type, "PAT")) {
	    strcpy(tofield, "typeofwork");
	  }
	}
      
	if (!strcmp(tofield, "doi")) {
	  result = insert_ulink((ptr_ardata->ptr_first)->ptr_elvalue, 5 /* doi */, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, ptr_ardata->n_user_id, 0 /* reference */, ptr_ardata->replace_ref);
	}
	else {
	  result = set_risdata_field(ptr_ardata->ptr_risdata, tofield, (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);
	}

	if (result == 1) {
	  LOG_PRINT(LOG_WARNING, get_status_msg(801));
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	/* else: all fine */
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "link")) {
      char* type;
      int n_type;
      unsigned long long n_user_id;

      type = get_attr(ptr_ardata->ptr_first, "type");

      if (type) {
	if (!strcmp(type, "pdf")) {
	  n_type = 1;
	}
	else if (!strcmp(type, "fulltext")) {
	  n_type = 2;
	}
	else if (!strcmp(type, "related")) {
	  n_type = 3;
	}
	else if (!strcmp(type, "image")) {
	  n_type = 4;
	}
	else if (!strcmp(type, "doi")) {
	  n_type = 5;
	}
	else { /* url or attribute missing */
	  n_type = 0;
	}

	/* if descendant of libinfo, use username, else don't */
	if (is_descendant_of(ptr_ardata->ptr_first, "libinfo")) {
	  n_user_id = ptr_ardata->n_user_id;
	}
	else {
	  n_user_id = 0;
	}

	result = insert_ulink((ptr_ardata->ptr_first)->ptr_elvalue, n_type, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, n_user_id, 0 /* reference */, ptr_ardata->replace_ref);

/* 	result = set_risdata_field(ptr_ardata->ptr_risdata, tofield, (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn); */
	if (result == 1) {
	  LOG_PRINT(LOG_WARNING, get_status_msg(801));
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	/* else: all fine */
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "notes")) {
      result = update_notes((ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->n_refdb_id, ptr_ardata->n_user_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->replace_ref);
      if (result == 1) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 2) {
	LOG_PRINT(LOG_WARNING, "update N1 failed");
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update N1 failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "availability")) {
      char* type;
      char* temp_avail;

      /* check whether we have a full string or one that relies on pdfroot */
      type = get_attr(ptr_ardata->ptr_first, "type");

      if (type && !strcmp(type, "useroot")) {
	if ((temp_avail = malloc(strlen((ptr_ardata->ptr_first)->ptr_elvalue)+6)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	
	/* skip adding PATH: to data that already contain this prefix
	   this was added erroneously by some previous versions */
	if (strncmp((ptr_ardata->ptr_first)->ptr_elvalue, "PATH:", 5)) {
	  strcpy(temp_avail, "PATH:");
	}
	else {
	  *temp_avail = '\0';
	}
	strcat(temp_avail, (ptr_ardata->ptr_first)->ptr_elvalue);

	result = update_avail(temp_avail, ptr_ardata->n_refdb_id, ptr_ardata->n_user_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->replace_ref);

	free(temp_avail);
      }
      else {
	/* full string, not a path */
	result = update_avail((ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->n_refdb_id, ptr_ardata->n_user_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->replace_ref);
      }

      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 2) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update AV failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "reprint")) {
      char* rptype;
      int n_rptype = 1;

      /* find out reprint type */
      rptype = get_attr(ptr_ardata->ptr_first, "status");
      if (!rptype || !strcmp(rptype, "NOTINFILE")) {
	n_rptype = 1; /* not in file */
      }
      else if (!strcmp(rptype, "INFILE")) {
	n_rptype = 0;
      }
      else if (!strcmp(rptype, "ONREQUEST")) {
	n_rptype = 2;
      }

      result = update_reprint(n_rptype, ptr_ardata->n_refdb_id, ptr_ardata->n_user_id, ptr_ardata->conn, ptr_ardata->date_buffer, ptr_ardata->replace_ref);
      if (result) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update RP failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "abstract") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = set_risdata_field(ptr_ardata->ptr_risdata, "abstract", (ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->conn);

      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }
    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "keyword") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      result = insert_keyword((ptr_ardata->ptr_first)->ptr_elvalue, ptr_ardata->n_refdb_id, ptr_ardata->conn, ptr_ardata->driver, ptr_ardata->drivername, 0, ptr_ardata->replace_ref);

      if (result == 1) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 2) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "query KW failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 3) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert KW failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 4) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "driver not supported\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      else if (result == 5) {
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert KW x failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
	(ptr_ardata->ndb_error)++;
	return;
      }
      /* else: all fine */
    }

    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "publication") && ptr_ardata->replace_ref != ADDREF_UPDATE_PERSONAL) {
      /* we've collected all journal name synonyms, if any */
      if ((ptr_ardata->perinfo).full || (ptr_ardata->perinfo).abbrev
	  || (ptr_ardata->perinfo).custabbrev1
	  || (ptr_ardata->perinfo).custabbrev2) {
	result = insert_periodical(&(ptr_ardata->perinfo), ptr_ardata->n_refdb_id, ptr_ardata->replace_ref, 0 /*nis_dummy*/, ptr_ardata->conn, ptr_ardata->drivername);

	if ((ptr_ardata->perinfo).full) {
	  free((ptr_ardata->perinfo).full);
	}
	if ((ptr_ardata->perinfo).abbrev) {
	  free((ptr_ardata->perinfo).abbrev);
	}
	if ((ptr_ardata->perinfo).custabbrev1) {
	  free((ptr_ardata->perinfo).custabbrev1);
	}
	if ((ptr_ardata->perinfo).custabbrev2) {
	  free((ptr_ardata->perinfo).custabbrev2);
	}

	if (result == 1) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, (char *)get_status_msg(801), &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 2) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "insert JX failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 3) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "driver not supported\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 4) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "select from t_periodical failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 5) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "read from t_periodical failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 6) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update JF failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 7) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update JO failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 8) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update J1 failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 9) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update J2 failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	else if (result == 10) {
	  if ((new_msgpool = mstrcat(ptr_ardata->msgpool, "update periodical failed\n", &(ptr_ardata->msgpool_len), 0)) == NULL) {
	    (ptr_ardata->nmem_error)++;
	    return;
	  }
	  else {
	    ptr_ardata->msgpool = new_msgpool;
	  }
	  (ptr_ardata->ndb_error)++;
	  return;
	}
	/* else: all fine */
      }
    }

    /* ------------------------------------------------------------ */
    else if (!strcmp(el, "entry")) {
      const char* citekey;
      int result;

      /* insert new citekey if required */
      if (!strncmp(ptr_ardata->real_citekey, "DUMMY", 5) && ptr_ardata->create_new) {
	citekey = get_unique_citekey(ptr_ardata->conn, ptr_ardata->first_author, atoi(ptr_ardata->ck_year), 0 /* ref */, ptr_ardata->replace_ref);
	
	if (citekey && set_risdata_field(ptr_ardata->ptr_risdata, "citekey", citekey, ptr_ardata->conn) != 0) {
	  if (citekey) {
	    free((char*)citekey);
	  }
	  (ptr_ardata->ndb_error)++;
	}
	strcpy(ptr_ardata->real_citekey, citekey);
	free((char*)citekey);
      }

      /* commit t_refdb_data */
      result = commit_risdata_fields(ptr_ardata->ptr_risdata, ptr_ardata->conn, ptr_ardata->replace_ref);
      if (result == 1) {
	(ptr_ardata->ndb_error)++;
      }
      else if (result == 2) {
	(ptr_ardata->nmem_error)++;
      }

      /* free risdata object */
      free_risdata(ptr_ardata->ptr_risdata);
      ptr_ardata->ptr_risdata = NULL;

      /* close transaction, if any */
      my_dbi_conn_commit(ptr_ardata->conn);
      
      if (insert_lilid(ptr_ardata->ptr_id_sentinel, ptr_ardata->n_refdb_id)) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
      }
  
      if (*(ptr_ardata->real_citekey)) { /* still empty if we update the reference */
/* 	sprintf(sql_command, "Citation key: %s\n", ptr_ardata->real_citekey); */
	sprintf(sql_command, "406:%s\n", ptr_ardata->real_citekey);

	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  LOG_PRINT(LOG_WARNING, get_status_msg(801));
	  (ptr_ardata->nmem_error)++;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}
      }

      if (ptr_ardata->ndb_error || ptr_ardata->nmem_error) {
	if (strcmp(my_dbi_conn_get_cap(ptr_ardata->conn, "transaction"), "t")) {
	  /* we have to delete the junk reference manually */
	  sprintf(sql_command, "DELETE FROM t_%srefdb WHERE refdb_citekey=\'DUMMY%d\'", prefix, getpid());
	  LOG_PRINT(LOG_DEBUG, sql_command);
	  dbires = dbi_conn_query(ptr_ardata->conn, sql_command);
	  if (!dbires) {
	    LOG_PRINT(LOG_INFO, "removing junk reference failed");
	  }
	  dbi_result_free(dbires);
	}
	else {
	  my_dbi_conn_rollback(ptr_ardata->conn);
	}
	my_dbi_conn_unlock(ptr_ardata->conn);
      }
      else {
	my_dbi_conn_unlock(ptr_ardata->conn);
	if (ptr_ardata->create_new) {
/* 	  sprintf(sql_command, "Adding input set "ULLSPEC" successful\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset)); */
	  sprintf(sql_command, "408:"ULLSPEC":%s:"ULLSPEC"\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), ptr_ardata->real_citekey, ptr_ardata->n_refdb_id);
	  (ptr_ardata->added_count)++;
	}
	else {
/* 	  sprintf(sql_command, "Updating input set "ULLSPEC" successful\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset)); */
	  sprintf(sql_command, "413:"ULLSPEC":%s:"ULLSPEC"\n", (unsigned long long)(ptr_ardata->set_count + nongeek_offset), ptr_ardata->real_citekey, ptr_ardata->n_refdb_id);
	  (ptr_ardata->updated_count)++;
	}
	if ((new_msgpool = mstrcat(ptr_ardata->msgpool, sql_command, &(ptr_ardata->msgpool_len), 0)) == NULL) {
	  LOG_PRINT(LOG_WARNING, get_status_msg(801));
	  (ptr_ardata->nmem_error)++;
	  return;
	}
	else {
	  ptr_ardata->msgpool = new_msgpool;
	}

	(ptr_ardata->set_count)++;
      }
    }
  }

/*   printf("removing %s from elstack\n", (ptr_ardata->ptr_first)->elname); */

  /* remove attributes of the current element from the list */
  if (ptr_ardata->depth && ptr_ardata->ptr_first) {
    ptr_attr_remove = (ptr_ardata->ptr_first)->ptr_attr_first;
    while (ptr_attr_remove) {
      (ptr_ardata->ptr_first)->ptr_attr_first = ((ptr_ardata->ptr_first)->ptr_attr_first)->ptr_next;
      free(ptr_attr_remove);
      ptr_attr_remove = (ptr_ardata->ptr_first)->ptr_attr_first;
    }
    
    /* free element value string */
    if ((ptr_ardata->ptr_first)->ptr_elvalue) {
      free((ptr_ardata->ptr_first)->ptr_elvalue);
    }

    /* remove current element from element stack */
    ptr_el_remove = ptr_ardata->ptr_first;
    ptr_ardata->ptr_first = (ptr_ardata->ptr_first)->ptr_next;
    if (ptr_el_remove) {
      free(ptr_el_remove);
    }
  }

  return;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  risx_char_handler(): handler for character data.

  void risx_char_handler has no return value

  void* ptr_data this is a ptr to "non-global" global data that all
             handlers share - will be cast to type struct addrisx_data*

  const char *string ptr to a string containing the char data
                     this string is not \0 terminated and could be
                     only a part of the character data of an element!

  int len length length of string

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void risx_char_handler(void *ptr_data, const char *string, int len) {
  struct addrisx_data* ptr_ardata;
  char* new_elvalue;
  char* buffer;

/*   printf("char handler found data:<<\n"); */

  ptr_ardata = (struct addrisx_data*)ptr_data;
  
  if (ptr_ardata->ndb_error || ptr_ardata->nmem_error || ptr_ardata->n_skip) {
    return;
  }

  /* get one byte extra for the terminating \0 */
  buffer = malloc(len+1);

  if (!buffer) {
    (ptr_ardata->nmem_error)++;
    return;
  }

  strncpy(buffer, string, len);
  buffer[len] = '\0';

  /* concatenate with existing elvalue. The latter will be of zero
     length if this is the first chunk */
  new_elvalue = mstrcat((ptr_ardata->ptr_first)->ptr_elvalue, buffer, &((ptr_ardata->ptr_first)->n_elvalue_len), 0);

  free(buffer);

  if (new_elvalue) {
    (ptr_ardata->ptr_first)->ptr_elvalue = new_elvalue;
  }
  else {
    (ptr_ardata->nmem_error)++;
  }
  return;
}
