/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  backend-scrn.c defines the screen output backend of refdbd
  markus@mhoenicka.de 6-20-00

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

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

#include <string.h>
#include <syslog.h> /* for definitions of log message priorities */
#include <dbi/dbi.h>

#include "refdb.h"
#include "linklist.h"
#include "refdbd.h"
#include "backend.h"
#include "backend-scrn.h"
#include "writenote.h"
#include "strfncs.h"
#include "dbfncs.h"
#include "connect.h"

#ifndef HAVE_ATOLL
long long atoll(const char *str);
#endif

/* some globals */
extern int n_log_level; /* numeric version of log_level */

/* forward declaration of local functions */
static char* print_field_scrn(const char* item, struct renderinfo* ptr_rendinfo, const char* start_string);
static int add_partdata_scrn(char** ptr_buffer, size_t* ptr_buffer_len, struct renderinfo* ptr_rendinfo);
static int add_setdata_scrn(char** ptr_buffer, size_t* ptr_buffer_len, struct renderinfo* ptr_rendinfo);


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  prepare_render_scrn(): writes a header for the screen output of a
                         query

  int prepare_render_scrn returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int prepare_render_scrn(struct renderinfo* ptr_rendinfo) {
  /* we just make sure that we start with a clean string */
  (*(ptr_rendinfo->ptr_ref))[0] = '\0';
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  finish_render_scrn(): writes a footer for the screen output of a query

  int finish_render_scrn returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int finish_render_scrn(struct renderinfo* ptr_rendinfo) {
  /* nothing to do here */
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  render_scrn() renders a RIS dataset for screen display

  int render_scrn returns 0 if successful, >0 if failed

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int render_scrn(struct renderinfo* ptr_rendinfo) {
  int errcode; /* receives error code for periodical requests */
  int nhave_booktitle = 0;
  int render_res;
  int retval = 0;
  size_t buffer_len = 4096;
  char have_author = 0;
  char have_editor = 0;
  char id[32] = "";
  char avail_type[6];
  char date_buffer[256];
  char* item;
  char* new_ref;
  char* buffer;
  const char* citem;
  const char* type;
  struct REPRINT reprint;
  struct AUTHOR_INFO ainfo;
  dbi_result dbires;
  dbi_result orig_dbires;
  dbi_conn conn;

  if ((buffer = malloc(buffer_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    retval = 801;
    goto cleanup;
  }
  *buffer = '\0';

  if ((type = get_refdb_type(ptr_rendinfo->dbires)) == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    retval = 234;
    goto cleanup;
  }

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  /*----------------------------------------------------------------*/
  /* ID */
  get_refdb_id(ptr_rendinfo->dbires, id);

  if (is_in_list(ptr_rendinfo->dbires, ptr_rendinfo->username) == 1) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "ID*:", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  else {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "ID:", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  if (*id) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), id, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  else { /* reference has no ID */
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    retval = 234; /* this is bad and will hopefully never happen */
    goto cleanup;
  }

  if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\n", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    retval = 801;
    goto cleanup;
  }
  else {
    *(ptr_rendinfo->ptr_ref) = new_ref;
  }

  /*----------------------------------------------------------------*/
  /* citation key */
  citem = get_refdb_citekey(ptr_rendinfo->dbires);
  if (citem && *citem) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "Key: ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }

    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }

    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\n", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      retval = 801;
      goto cleanup;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* the part apparatus (analytic) */

  if (has_part_data(type)) {
    if ((retval = add_partdata_scrn(&buffer, &buffer_len, ptr_rendinfo)) != 0) {
      goto cleanup;
    }
    else {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	retval = 801;
	goto cleanup;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
    *buffer = '\0';
  }

  /*----------------------------------------------------------------*/
  /* the publication apparatus (monographic) */

  if (has_chapter_data(type)) {
    /* use a verbal separator to start the monographic data */
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "in: ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* authors */
  /* request authors */
  dbires = request_authors(conn, 2 /* publication */, NULL /* all roles */, NULL, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"));
  if (dbires == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  /* fetch all authors */
  while (get_author_parts(dbires, &ainfo) != NULL) {
    char role[70] = ""; /* role is 64, and then some */

    have_author++;
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ainfo.name, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
/*     printf("role went to %s<<\n", ainfo.role); */
    if (have_author > 1
	&& *(ainfo.role)
	&& strcmp(ainfo.role, "author")) {
/*       sprintf(role, "(%s)", ainfo.role); */
/*       if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), role, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { */
/* 	clean_request(dbires); */
/* 	LOG_PRINT(LOG_CRIT, get_status_msg(801)); */
/* 	return 801; */
/*       } */
/*       else { */
/* 	*(ptr_rendinfo->ptr_ref) = new_ref; */
/*       } */
    }
    else if (strcmp(ainfo.role, "author")){
      have_editor++;
    }
      
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ", ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  clean_request(dbires);

  if (have_editor) {
    if (have_editor == 1) {
      new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "(ed.)\n", ptr_rendinfo->ptr_ref_len, 2);
    }
    else {
      new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "(eds.)\n", ptr_rendinfo->ptr_ref_len, 2);
    }

    if (new_ref == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  else {
    if (!has_chapter_data(type) && !has_periodical_data(type)) {
      if (have_author) { /* eliminate the trailing comma after the last author */
	new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\n", ptr_rendinfo->ptr_ref_len, 2);
      }
      else {
	new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\n", ptr_rendinfo->ptr_ref_len, 0);
      }

      if (new_ref == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  if (has_periodical_data(type)) {
    /*----------------------------------------------------------------*/
    /* periodical */
    citem = get_periodical(dbi_result_get_conn(ptr_rendinfo->dbires), date_buffer, NULL, 4, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), NULL /* no frequency required */);
    if (citem == NULL && errcode != 1) {
      return 234;
    }
    else if (!errcode) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }

    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), " ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* book title */
  item = get_refdb_booktitle_copy(ptr_rendinfo->dbires);
  if (item != NULL) {
    nhave_booktitle++;
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)item, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* book title */
      free(item);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    free(item);

    /* insert a space to separate the title from the volume/issue info */
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), " ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      free(item);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* edition */
  citem = get_refdb_edition(ptr_rendinfo->dbires);
  if (citem != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "(", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* edition */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ".ed)", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  
  /*----------------------------------------------------------------*/
  /* volume */
  citem = get_refdb_volume(ptr_rendinfo->dbires);
  if (citem != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* volume */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  
  /*----------------------------------------------------------------*/
  /* issue */
  citem = get_refdb_issue(ptr_rendinfo->dbires);  
  if (citem != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "(", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* issue */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ")", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* startpage */
  citem = get_refdb_startpage(ptr_rendinfo->dbires);
  if (citem != NULL) {
    if (strcmp(type, "BOOK") == 0 || strcmp(type, "SER") == 0 ||
	strcmp(type, "THES") == 0 || strcmp(type, "RPRT") == 0 ||
	strcmp(type, "CHAP") == 0) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "pp. ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
    else {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ":", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }

    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* start page */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  
  /*----------------------------------------------------------------*/
  /* endpage */
  citem = get_refdb_endpage(ptr_rendinfo->dbires);
  if (citem != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "-", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)citem, ptr_rendinfo->ptr_ref_len, 0)) == NULL) { /* end page */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  
  /*----------------------------------------------------------------*/
  /* pubyear */
  if (get_refdb_pubyear(ptr_rendinfo->dbires, date_buffer) != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), " (", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }

    /* year */
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), date_buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }

    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ")", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* set data */
  if (has_set_data(type)) {
    if ((retval = add_setdata_scrn(&buffer, &buffer_len, ptr_rendinfo)) != 0) {
      goto cleanup;
    }
    else if (*buffer) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ", part of: ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	retval = 801;
	goto cleanup;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }

      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	retval = 801;
	goto cleanup;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
    *buffer = '\0';
  }

  /*----------------------------------------------------------------*/
  /* abstract */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N2") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "AB") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if ((item = get_refdb_abstract_copy(ptr_rendinfo->dbires)) != NULL) {
      if (print_field_scrn(item, ptr_rendinfo, "\nABSTRACT: ") == NULL) {
	free(item);
	return 801;
      }
      free(item);
    }
  }

  /*----------------------------------------------------------------*/
  /* address */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "AD") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if ((item = get_refdb_address_copy(ptr_rendinfo->dbires)) != NULL) {
      if (print_field_scrn(item, ptr_rendinfo, "\nADDRESS: ") == NULL) {
	free(item);
	return 801;
      }
      free(item);
    }
  }

  /*----------------------------------------------------------------*/
  /* reprint, availability  */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "RP") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if (get_reprint(ptr_rendinfo->dbires, &reprint, ptr_rendinfo->username, 4) != NULL
	&&reprint.reprint != NULL && *(reprint.reprint)) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\nREPRINT: ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), reprint.reprint, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
      if (reprint.date != NULL && *(reprint.date)) {
	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), " (", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}
	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), reprint.date, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}
	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ")", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}
      }
    }
    if (reprint.avail != NULL && *(reprint.avail)) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ": ", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }

      /* copy the relevant part of reprint.avail so we can safely
	 uppercase it */
      strncpy(avail_type, reprint.avail, 5);
      avail_type[5] = '\0';

      if (strncmp(strup(avail_type), "PATH:", 5) == 0) {
	if (*(ptr_rendinfo->pdfroot)) {
	  if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ptr_rendinfo->pdfroot, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	    LOG_PRINT(LOG_CRIT, get_status_msg(801));
	    return 801;
	  }
	  else {
	    *(ptr_rendinfo->ptr_ref) = new_ref;
	  }
	}
	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), reprint.avail+5, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}
      }
      else {
	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), reprint.avail, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}
      }
    }
  }

  /*----------------------------------------------------------------*/
  /* ISBN/ISSN */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "SN") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_issn(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nISSN: ") == NULL) {
      return 801;
    }
  }

  /*----------------------------------------------------------------*/
  /* URL, L1 through L4, DOI */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "UR") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "LX") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "DOI") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    int i;
    char link_tag[12];

    /* loop over all link types */
    for (i=0; i<6;i++) {
      if (!i) {
	strcpy(link_tag, "\nURL: ");
      }
      else if (i == 1) {
	strcpy(link_tag, "\nPDF: ");
      }
      else if (i == 2) {
	strcpy(link_tag, "\nFULLTEXT: ");
      }
      else if (i == 3) {
	strcpy(link_tag, "\nRELATED: ");
      }
      else if (i == 4) {
	strcpy(link_tag, "\nIMAGE: ");
      }
      else if (i == 5) {
	strcpy(link_tag, "\nDOI: ");
      }
      
      dbires = request_ulinks(conn, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), 0 /* ref entry */, i /* link type */, 0 /* is_temp */, ptr_rendinfo->username);
      if (dbires == NULL) {
	return 234;
      }

      while ((citem = get_ulink(dbires)) != NULL) {
	char* full_link;

	if (i>0 && i<5) {
	  full_link = add_root_to_link(citem, ptr_rendinfo->pdfroot);
	}
	else {
	  full_link = strdup(citem);
	}

	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), link_tag, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  clean_request(dbires);
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}

	if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), full_link, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
	  clean_request(dbires);
	  return 801;
	}
	else {
	  *(ptr_rendinfo->ptr_ref) = new_ref;
	}

	free(full_link);
      } /* end while */
      clean_request(dbires);
    } /* end for */
  }

  /*----------------------------------------------------------------*/
  /* publisher */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "PB") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_publisher(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nPUBLISHER: ") == NULL) {
      return 801;
    }
  }

  /*----------------------------------------------------------------*/
  /* city */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "CY") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_city(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCITY: ") == NULL) {
      return 801;
    }
  }

  /*----------------------------------------------------------------*/
  /* user fields */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "U1") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_user1(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nUSER1: ") == NULL) {
      return 801;
    }
  }

  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "U2") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_user2(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nUSER2: ") == NULL) {
      return 801;
    }
  }

  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "U3") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_user3(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nUSER3: ") == NULL) {
      return 801;
    }
  }

  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "U4") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_user4(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nUSER4: ") == NULL) {
      return 801;
    }
  }

  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "U5") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_user5(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nUSER5: ") == NULL) {
      return 801;
    }
  }

  /*----------------------------------------------------------------*/
  /* misc fields */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "MX") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    citem = get_refdb_typeofwork(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nTYPE OF WORK: ") == NULL) {
      return 801;
    }

    citem = get_refdb_area(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nAREA: ") == NULL) {
      return 801;
    }

    citem = get_refdb_ostype(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nOS TYPE: ") == NULL) {
      return 801;
    }

    citem = get_refdb_degree(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nDEGREE: ") == NULL) {
      return 801;
    }

    citem = get_refdb_runningtime(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nRUNNING TIME: ") == NULL) {
      return 801;
    }

    citem = get_refdb_classcodeintl(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCLASSCODE (INTL): ") == NULL) {
      return 801;
    }

    citem = get_refdb_classcodeus(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCLASSCODE (US): ") == NULL) {
      return 801;
    }

    citem = get_refdb_senderemail(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nEMAIL (SENDER): ") == NULL) {
      return 801;
    }

    citem = get_refdb_recipientemail(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nEMAIL (RECIPIENT): ") == NULL) {
      return 801;
    }

    citem = get_refdb_mediatype(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nMEDIA TYPE: ") == NULL) {
      return 801;
    }

    citem = get_refdb_numvolumes(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nNUMBER OF VOLUMES: ") == NULL) {
      return 801;
    }

    citem = get_refdb_computer(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCOMPUTER: ") == NULL) {
      return 801;
    }

    citem = get_refdb_conferencelocation(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCONFERENCE LOCATION: ") == NULL) {
      return 801;
    }

    citem = get_refdb_registrynum(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nREGISTRY NUMBER: ") == NULL) {
      return 801;
    }

    citem = get_refdb_classification(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCLASSIFICATION: ") == NULL) {
      return 801;
    }

    citem = get_refdb_section(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nSECTION: ") == NULL) {
      return 801;
    }

    citem = get_refdb_pamphletnum(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nPAMPHLET NUMBER: ") == NULL) {
      return 801;
    }

    citem = get_refdb_chapternum(ptr_rendinfo->dbires);
    if (print_field_scrn(citem, ptr_rendinfo, "\nCHAPTER NUMBER: ") == NULL) {
      return 801;
    }
  }


  /*----------------------------------------------------------------*/
  /* the notes */

  /* first the note which is attached to the reference */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "N1") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    if ((item = get_notes_copy(ptr_rendinfo->dbires, ptr_rendinfo->username)) != NULL) {
      if (print_field_scrn(item, ptr_rendinfo, "\nNOTES: ") == NULL) {
	free(item);
	return 801;
      }
      free(item);
    }
  }

  /* then look for additional notes linked with the record,
     keywords, authors, or periodicals */
  if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "NX") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
    /* see whether to include reference lists */
    if (strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "NL") != NULL
      || strstr((ptr_rendinfo->ptr_biblio_info)->format_string, "ALL") != NULL) {
      if ((dbires = request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires), atoll(id), REFERENCE|KEYWORD|AUTHOR|PERIODICAL, ptr_rendinfo->username, (ptr_rendinfo->ptr_clrequest)->share_default, 1/* include lists */)) == NULL) {
	/*       printf("request_notes_by_ref() failed\n"); */
	free_request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires));
	return 234;
      }
    }
    else {
      if ((dbires = request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires), atoll(id), REFERENCE|KEYWORD|AUTHOR|PERIODICAL, ptr_rendinfo->username, (ptr_rendinfo->ptr_clrequest)->share_default, 0/* exclude lists */)) == NULL) {
	/*       printf("request_notes_by_ref() failed\n"); */
	free_request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires));
	return 234;
      }
    }
    
    /* save original query result. This is legal as dbi_result is a
       pointer in disguise */
    orig_dbires = ptr_rendinfo->dbires;
    ptr_rendinfo->dbires = dbires;

    while (dbi_result_next_row(ptr_rendinfo->dbires) != 0) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\nXNOTE:\n", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	free_request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires));
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }

      if ((render_res = render_note(ptr_rendinfo)) != 0) {
	ptr_rendinfo->dbires = orig_dbires;
	clean_request(dbires);
	free_request_notes_by_ref(dbi_result_get_conn(ptr_rendinfo->dbires));
	return render_res;
      }
    }
    clean_request(dbires);
    free_request_notes_by_ref(dbi_result_get_conn(orig_dbires));
    ptr_rendinfo->dbires = orig_dbires;
  }

  /* finish with an empty line */
  if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), "\n\n", ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }
  else {
    *(ptr_rendinfo->ptr_ref) = new_ref;
  }

 cleanup:
  free(buffer);

  return retval;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_partdata_scrn(): writes part data into a buffer

  static int add_partdata_scrn returns 0 if ok or an error code > 0

  char** ptr_buffer ptr to a buffer that will receive the output. The
                buffer will be reallocated as needed

  size_t* ptr_buffer_len ptr to the length of buffer. Will be updated
                if buffer is reallocated

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  dbi_conn conn connection to the database

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int add_partdata_scrn(char** ptr_buffer, size_t* ptr_buffer_len, struct renderinfo* ptr_rendinfo) {
  int n_have_author = 0;
  char* item;
  char* new_buffer;
  const char* citem;
  dbi_conn conn;
  dbi_result dbires;

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  /*----------------------------------------------------------------*/
  /* authors */
  /* request authors */
  dbires = request_authors(conn, 1, NULL /* all roles */, NULL, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"));
  if (dbires == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  /* fetch all authors */
  while ((citem = get_author(dbires)) != NULL) {
    n_have_author = 1;
    if ((new_buffer = mstrcat(*ptr_buffer, (char*)citem, ptr_buffer_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }

    if ((new_buffer = mstrcat(*ptr_buffer, ", ", ptr_buffer_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
  }
  clean_request(dbires);

  if (n_have_author) { /* eliminate the trailing comma after the last author */
    new_buffer = mstrcat(*ptr_buffer, "\n", ptr_buffer_len, 2);
  }
  else {
    new_buffer = mstrcat(*ptr_buffer, "\n", ptr_buffer_len, 0);
  }
  
  if (new_buffer == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }
  else {
    *ptr_buffer = new_buffer;
  }
  
  /*----------------------------------------------------------------*/
  /* title */
  item = get_refdb_title_copy(ptr_rendinfo->dbires);
  if (item != NULL) {
    if ((new_buffer = mstrcat(*ptr_buffer, item, ptr_buffer_len, 0)) == NULL) { /* title */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(item);
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
    
    free(item);
    
    if ((new_buffer = mstrcat(*ptr_buffer, "\n", ptr_buffer_len, 0)) == NULL) {
      free(item);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_setdata_scrn(): writes set data into a buffer

  static int add_setdata_scrn returns 0 if ok or an error code > 0

  char** ptr_buffer ptr to a buffer that will receive the output. The
                buffer will be reallocated as needed

  size_t* ptr_buffer_len ptr to the length of buffer. Will be updated
                if buffer is reallocated

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  dbi_conn conn connection to the database

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int add_setdata_scrn(char** ptr_buffer, size_t* ptr_buffer_len, struct renderinfo* ptr_rendinfo) {
  int n_have_author = 0;
  char* item;
  char* new_buffer;
  const char* citem;
  dbi_conn conn;
  dbi_result dbires;

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  /*----------------------------------------------------------------*/
  /* authors */
  /* request authors */
  dbires = request_authors(conn, 3 /* set editors */, NULL /* all roles */, NULL, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"));
  if (dbires == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  /* fetch all authors */
  while ((citem = get_author(dbires)) != NULL) {
    n_have_author++;
    if ((new_buffer = mstrcat(*ptr_buffer, (char*)citem, ptr_buffer_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }

    if ((new_buffer = mstrcat(*ptr_buffer, ", ", ptr_buffer_len, 0)) == NULL) {
      clean_request(dbires);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
  }
  clean_request(dbires);

  if (n_have_author) { /* eliminate the trailing comma after the last author */
    if (n_have_author == 1) {
      new_buffer = mstrcat(*ptr_buffer, "(ed.): ", ptr_buffer_len, 2);
    }
    else {
      new_buffer = mstrcat(*ptr_buffer, "(eds.): ", ptr_buffer_len, 2);
    }
  
    if (new_buffer == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
  }
  
  /*----------------------------------------------------------------*/
  /* title */
  item = get_refdb_title_series_copy(ptr_rendinfo->dbires);
  if (item != NULL) {
    if ((new_buffer = mstrcat(*ptr_buffer, item, ptr_buffer_len, 0)) == NULL) { /* title */
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(item);
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
    
    free(item);
    
    if ((new_buffer = mstrcat(*ptr_buffer, "\n", ptr_buffer_len, 0)) == NULL) {
      free(item);
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return 801;
    }
    else {
      *ptr_buffer = new_buffer;
    }
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  print_field_scrn(): writes simple field contents to HTML output

  static char* print_field_scrn returns a ptr to the modified string. Due to
                         reallocation this may be different from the
			 ptr passed to this function in the ptr_rendinfo
			 structure which is also updated accordingly

  const char* item ptr to the contents of the field to write

  struct renderinfo* ptr_rendinfo ptr to a structure with the info
                             how the reference should be rendered

  const char* start_string ptr to a string to be printed before the 
                         field contents

 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* print_field_scrn(const char* item, struct renderinfo* ptr_rendinfo, const char* start_string) {
  char* new_ref;

  if (item != NULL) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)start_string, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), (char*)item, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      return NULL;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }
  return *(ptr_rendinfo->ptr_ref);
}
