/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  backend-risx.c defines the risx output backend of refdbd
  markus@mhoenicka.de 2003-03-25

  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 <stdio.h>
#include <dbi/dbi.h>

#include "refdb.h"
#include "linklist.h"
#include "tokenize.h"
#include "backend.h"
#include "backend-risx.h"
#include "strfncs.h"
#include "refdbd.h"
#include "cgi.h"
#include "dbfncs.h"
#include "risdb.h"
#include "authorinfo.h"
#include "xmlhelper.h"
#include "connect.h"

extern char refdblib[]; /* location of shareable files */

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

/* forward declaration of local functions */
static char* add_authors_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, int type, struct renderinfo* ptr_rendinfo, int* nhave_buffer_data, struct xmlindent* ptr_indent, unsigned long long refcount);
static char* add_pubinfo_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, struct renderinfo* ptr_rendinfo, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent);
static char* add_pubdate_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, int type, struct renderinfo* ptr_rendinfo, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent);
static char* add_reprint_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, struct renderinfo* ptr_rendinfo, char* username, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent);
static int indent_notbelow_risx(const char* name);
static int is_entry_risx(const char* name);

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  prepare_render_risx(): writes a header for the risx output of a
  query

  int prepare_render_risx 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_risx(struct renderinfo* ptr_rendinfo) {
  char* new_ref;
  char* header;
  char ns[PREFS_BUF_LEN+128];
  
  if ((header = assemble_header(ptr_rendinfo)) == NULL) {
    return 801;
  }

  new_ref = mstrcpy(*(ptr_rendinfo->ptr_ref), header, ptr_rendinfo->ptr_ref_len);
  free(header);

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

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(ns, "<%s:ris xmlns:%s=\"http://refdb.sourceforge.net/ns/risx\">\n", ptr_rendinfo->ptr_clrequest->namespace, ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    strcpy(ns, "<ris>\n");
  }

  new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), ns, ptr_rendinfo->ptr_ref_len, 0);

  if (new_ref == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }

  *(ptr_rendinfo->ptr_ref) = new_ref;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  finish_render_risx(): writes a footer for the risx output of a query

  int finish_render_risx 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_risx(struct renderinfo* ptr_rendinfo) {
  char* new_ref;
  char ns[PREFS_BUF_LEN+32];

  if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
    sprintf(ns, "\n</%s:ris>\n", ptr_rendinfo->ptr_clrequest->namespace);
  }
  else {
    strcpy(ns, "\n</ris>\n");
  }

  new_ref = mstrcpy(*(ptr_rendinfo->ptr_ref), ns, ptr_rendinfo->ptr_ref_len);

  if (new_ref == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }

  *(ptr_rendinfo->ptr_ref) = new_ref;

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  render_risx() renders a RIS dataset for RISX export

  int render_risx 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_risx(struct renderinfo* ptr_rendinfo) {
  int errcode; /* receives error code for periodical requests */
  int nhave_buffer_data = 0; /* 1 if buffer contains real data */
  size_t buffer_len;
  unsigned long long frequency;
  unsigned long long refcount;
  const char* item;
  const char* item1;
  char id[32] = "";
  char type[7] = "JOUR";
  char empty_string[1] = "";
  char date_buffer[256];
  char* new_ref;
  char* buffer;
  dbi_result dbires;
  dbi_conn conn;
  struct xmlindent xindent;

  /*initialize xindent */
  initialize_xmlindent(&xindent, 2, indent_notbelow_risx, is_entry_risx);

  conn = dbi_result_get_conn(ptr_rendinfo->dbires);

  if (get_refdb_id(ptr_rendinfo->dbires, id) == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(234));
    return 234;
  }

  /* get reference count for later use */
  refcount = get_reference_count(dbi_result_get_conn(ptr_rendinfo->dbires), NULL, 0 /* istemp */);

  /*----------------------------------------------------------------*/
  /* start entry with type, id, and citekey attributes */
  item = get_refdb_type(ptr_rendinfo->dbires);

  if (item && *item) {
    strncpy(type, item, 6);
    type[6] = '\0';
  }

  item1 = get_refdb_citekey(ptr_rendinfo->dbires);

  if (print_elstart_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "entry", "type", item, "id", id, "citekey", item1, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    return 801;
  }

  /* get some memory for the part/publication/set stuff */
  buffer_len = 4096;
  if ((buffer = malloc(buffer_len)) == NULL) {
    LOG_PRINT(LOG_CRIT, get_status_msg(801));
    return 801;
  }
  *buffer = '\0';

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

  if (has_part_data(type)) {
    if (print_elstart_x(&buffer, &buffer_len, "part", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer);
      return 801;
    }

    /* part title */
    item = get_refdb_title_copy(ptr_rendinfo->dbires);
    if (item != NULL) {
      if (print_element_x(item, &buffer, &buffer_len, "title", "type", "full", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	free((char*)item);
	return 801;
      }
      free((char*)item);
    }
    else {
      if (print_element_x(empty_string, &buffer, &buffer_len, "title", "type", "full", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	free((char*)item);
	return 801;
      }
    }
    nhave_buffer_data = 1;


    if (add_authors_risx(&buffer, &buffer_len, conn, 1 /* part authors */, ptr_rendinfo, &nhave_buffer_data, &xindent, refcount) == NULL) {
      free(buffer);
      return 801;
    }
    
    if (print_elend_x(&buffer, &buffer_len, "part", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer);
      return 801;
    }
    
    if (nhave_buffer_data) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	free(buffer);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }
  }

  /*----------------------------------------------------------------*/
  /* the publication apparatus (monographic) */
  nhave_buffer_data = 0;
  *buffer = '\0';

  if (print_elstart_x(&buffer, &buffer_len, "publication", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  if (has_periodical_data(type)) {
    int rel_frequency;
    char freqbuffer[64];

    /*----------------------------------------------------------------*/
    /* journal (full)*/
    if ((item = get_periodical(conn, date_buffer, NULL, 0, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), &frequency)) != NULL && *item) {
      rel_frequency = calculate_relative_frequency(frequency, refcount);
      snprintf(freqbuffer, 64, "%d", rel_frequency);

      nhave_buffer_data = 1;

      if (ptr_rendinfo->frequency) {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "full", "relfreq", freqbuffer, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
      else {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "full", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
    }
    
    /*----------------------------------------------------------------*/
    /* journal (abbrev)*/
    if ((item = get_periodical(conn, date_buffer, NULL, 3, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), &frequency)) != NULL && *item) {
      rel_frequency = calculate_relative_frequency(frequency, refcount);
      snprintf(freqbuffer, 64, "%d", rel_frequency);

      nhave_buffer_data = 1;
      if (ptr_rendinfo->frequency) {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "abbrev", "relfreq", freqbuffer, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
      else {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "abbrev", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
    }
  
    /*----------------------------------------------------------------*/
    /* journal (custabbrev1) */
    if ((item = get_periodical(conn, date_buffer, NULL, 1, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), &frequency)) != NULL && *item) {
      rel_frequency = calculate_relative_frequency(frequency, refcount);
      snprintf(freqbuffer, 64, "%d", rel_frequency);

      nhave_buffer_data = 1;
      if (ptr_rendinfo->frequency) {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "user1", "relfreq", freqbuffer, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
      else {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "user1", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
    }
  
    /*----------------------------------------------------------------*/
    /* journal (custabbrev2)*/
    if ((item = get_periodical(conn, date_buffer, NULL, 2, &errcode, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), &frequency)) != NULL && *item) {
      rel_frequency = calculate_relative_frequency(frequency, refcount);
      snprintf(freqbuffer, 64, "%d", rel_frequency);

      nhave_buffer_data = 1;
      if (ptr_rendinfo->frequency) {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "user2", "relfreq", freqbuffer, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
      else {
	if (print_element_x(item, &buffer, &buffer_len, "title", "type", "user2", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer);
	  return 801;
	}
      }
    }
  } /* end if has periodical data */
  
  item = NULL;

  /* booktitle is self-explanatory except for CONF where it translates to the conference title which belongs to pubinfo */
  if (strcmp(type, "CONF")) {
    item = get_refdb_booktitle_copy(ptr_rendinfo->dbires);

    if (item != NULL) {
      if (print_element_x(item, &buffer, &buffer_len, "title", "type", "full", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	free((char*)item);
	return 801;
      }
      free((char*)item);
    }
  }

  if (add_authors_risx(&buffer, &buffer_len, conn, 2, ptr_rendinfo, &nhave_buffer_data, &xindent, refcount) == NULL) {
    free(buffer);
    return 801;
  }

  /* pubinfo stuff */
  if (add_pubinfo_risx(&buffer, &buffer_len, conn, ptr_rendinfo, &nhave_buffer_data, &xindent) == NULL) {
    free(buffer);
    return 801;
  }


  if (print_elend_x(&buffer, &buffer_len, "publication", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  if (nhave_buffer_data) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_WARNING, get_status_msg(801));
      free(buffer);
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /*----------------------------------------------------------------*/
  /* the set apparatus (series) */
  nhave_buffer_data = 0;
  *buffer = '\0';

  if (print_elstart_x(&buffer, &buffer_len, "set", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  /* set title */
  if ((item = get_refdb_title_series_copy(ptr_rendinfo->dbires)) != NULL) {
    nhave_buffer_data = 1;

    if (print_element_x(item, &buffer, &buffer_len, "title", "type", "full", NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      return 801;
    }
    free((char*)item);
  }

  if (add_authors_risx(&buffer, &buffer_len, conn, 3, ptr_rendinfo, &nhave_buffer_data, &xindent, refcount) == NULL) {
    free(buffer);
    return 801;
  }

  if (print_elend_x(&buffer, &buffer_len, "set", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  if (nhave_buffer_data) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_WARNING, get_status_msg(801));
      free(buffer);
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  /* loop over all users */
  dbires = request_users(conn, NULL, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"));
  if (dbires == NULL) {
    return 234;
  }

  /* fetch users */
  while ((item1 = get_user(dbires)) != NULL) {
    int i;
    /* libinfo */
    nhave_buffer_data = 0;
    *buffer = '\0';

    if (print_elstart_x(&buffer, &buffer_len, "libinfo", "user", item1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer);
      clean_request(dbires);
      return 801;
    }

    /*----------------------------------------------------------------*/
    /* notes */ /* current user is in ptr_rendinfo->username */
    if ((item = get_notes_copy(ptr_rendinfo->dbires, (char*)item1)) != NULL) {
      nhave_buffer_data = 1;

      if (print_element_x(item, &buffer, &buffer_len, "notes", NULL, NULL, NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	free((char*)item);
	clean_request(dbires);
	return 801;
      }
      free((char*)item);
    }
    
    /* reprint stuff */
    if (add_reprint_risx(&buffer, &buffer_len, conn, ptr_rendinfo, (char*)item1, &nhave_buffer_data, &xindent) == NULL) {
      free(buffer);
      return 801;
    }

    /* L1 through L4. libinfo links are owned by a particular user */

    /* loop over all link types that may be owned by a user*/
    for (i=1; i<5;i++) {
      char ulink_type[10];
      dbi_result dbires;

      dbires = request_ulinks(conn, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), 0 /* ref entry */, i /* link type */, 0 /* is_temp */, item1);
      if (dbires == NULL) {
	return 801;
      }

      while ((item = get_ulink(dbires)) != NULL) {
	if (i == 1) {
	  strcpy(ulink_type, "pdf");
	}
	else if (i == 2) {
	  strcpy(ulink_type, "fulltext");
	}
	else if (i == 3) {
	  strcpy(ulink_type, "related");
	}
	else if (i == 4) {
	  strcpy(ulink_type, "image");
	}

	if (print_element_x(item, &buffer, &buffer_len, "link", "type", ulink_type, NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  clean_request(dbires);
	  return 801;
	}
      }

      clean_request(dbires);
    } /* end for */

    if (print_elend_x(&buffer, &buffer_len, "libinfo", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer);
      return 801;
    }

    if (nhave_buffer_data) {
      if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
	LOG_PRINT(LOG_WARNING, get_status_msg(801));
	free(buffer);
	return 801;
      }
      else {
	*(ptr_rendinfo->ptr_ref) = new_ref;
      }
    }

  } /* end while */

  clean_request(dbires);
  /* contents */
  nhave_buffer_data = 0;
  *buffer = '\0';

  if (print_elstart_x(&buffer, &buffer_len, "contents", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  /*----------------------------------------------------------------*/
  /* abstract */
  if ((item = get_refdb_abstract_copy(ptr_rendinfo->dbires)) != NULL) {
    nhave_buffer_data = 1;

    if (print_element_x(item, &buffer, &buffer_len, "abstract", NULL, NULL, NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(buffer);
      return 801;
    }
    free((char*)item);
  }

  /*----------------------------------------------------------------*/
  /* keywords */
  dbires = request_keywords(conn, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), 0, 0);
  if (dbires == NULL) {
    return 234;
  }

  /* fetch all keywords of this article */
  while ((item = get_extended_keyword(dbires, 0 /* not temp */, &frequency)) != NULL) {
    int rel_frequency;
    char freqbuffer[64];

    rel_frequency = calculate_relative_frequency(frequency, refcount);
    snprintf(freqbuffer, 64, "%d", rel_frequency);

    nhave_buffer_data = 1;

    if (ptr_rendinfo->frequency) {
      if (print_element_x(item, &buffer, &buffer_len, "keyword", "relfreq", freqbuffer, NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	clean_request(dbires);
	return 801;
      }
    }
    else {
      if (print_element_x(item, &buffer, &buffer_len, "keyword", NULL, NULL, NULL, NULL, &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer);
	clean_request(dbires);
	return 801;
      }
    }
  }
  clean_request(dbires);

  if (print_elend_x(&buffer, &buffer_len, "contents", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer);
    return 801;
  }

  if (nhave_buffer_data) {
    if ((new_ref = mstrcat(*(ptr_rendinfo->ptr_ref), buffer, ptr_rendinfo->ptr_ref_len, 0)) == NULL) {
      LOG_PRINT(LOG_WARNING, get_status_msg(801));
      free(buffer);
      return 801;
    }
    else {
      *(ptr_rendinfo->ptr_ref) = new_ref;
    }
  }

  free(buffer);

  /*----------------------------------------------------------------*/
  /* The End */

  if (print_elend_x(ptr_rendinfo->ptr_ref, ptr_rendinfo->ptr_ref_len, "entry", &xindent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    return 801;
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_authors_risx() prints out risx authors

  static char* add_authors_risx returns ptr to the buffer if successful,
  NULL if failed

  char** ptr_buffer ptr to ptr to buffer that will receive the output

  size_t* ptr_buffer_len ptr to var holding size of *ptr_buffer

  dbi_conn conn connection to database

  int type 1=primary author, 2=editor, 3=series editor

  struct renderinfo* ptr_renderinfo ptr to struct with render information

  int* ptr_nhave_buffer_data ptr to var which will be set to non-zero
                             if *ptr_buffer receives data

  struct xmlindent* ptr_indent ptr to struct with indent info

  unsigned long long refcount total number of refs in the database

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_authors_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, int type, struct renderinfo* ptr_rendinfo, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent, unsigned long long refcount) {
  unsigned long long frequency;
  dbi_result dbires;
  char* entitize_buf;
  const char* item;
  struct AUTHOR_INFO* ptr_ainfo;

  if ((ptr_ainfo = new_authorinfo()) == NULL) {
    return NULL;
  }

  dbires = request_authors(conn, type, NULL /* all roles */, NULL, 0, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"));
  if (dbires == NULL) {
    free_authorinfo(ptr_ainfo);
    return NULL;
  }

  /* fetch author parts */
  while (get_extended_author_parts(dbires, ptr_ainfo, 0 /* not temp */, &frequency)) {
    int rel_frequency;
    char freqbuffer[64];

    rel_frequency = calculate_relative_frequency(frequency, refcount);
    snprintf(freqbuffer, 64, "%d", rel_frequency);

    if (ptr_rendinfo->frequency) {
      if (print_elstart_x(ptr_buffer, ptr_buffer_len, "author", "role", ptr_ainfo->role, "relfreq", freqbuffer, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	clean_request(dbires);
	free_authorinfo(ptr_ainfo);
	return NULL;
      }
    }
    else {
      if (print_elstart_x(ptr_buffer, ptr_buffer_len, "author", "role", ptr_ainfo->role, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	clean_request(dbires);
	free_authorinfo(ptr_ainfo);
	return NULL;
      }
    }

    /* see whether we've got parts or only one author string */
    if (!*(ptr_ainfo->lastname) && !*(ptr_ainfo->firstname)
	&& !*(ptr_ainfo->middlename) && !*(ptr_ainfo->suffix)) {
      if ((entitize_buf = mstrdup(ptr_ainfo->name)) == NULL) {
	clean_request(dbires);
	free_authorinfo(ptr_ainfo);
	return NULL;
      }

      if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	clean_request(dbires);
	free(entitize_buf);
	free_authorinfo(ptr_ainfo);
	return NULL;
      }

      if (print_element_x(entitize_buf, ptr_buffer, ptr_buffer_len, "name", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	clean_request(dbires);
	free(entitize_buf);
	free_authorinfo(ptr_ainfo);
	return NULL;
      }
      free(entitize_buf);
    }
    else { /* if have nameparts */
      if (*(ptr_ainfo->lastname)) {
	*ptr_nhave_buffer_data = 1;
	if ((entitize_buf = mstrdup(ptr_ainfo->lastname)) == NULL) {
	  clean_request(dbires);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	  
	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  free(entitize_buf);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}

	if (print_element_x(entitize_buf, ptr_buffer, ptr_buffer_len, "lastname", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  clean_request(dbires);
	  free(entitize_buf);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	free(entitize_buf);
      }
	
      if (*(ptr_ainfo->firstname)) {
	*ptr_nhave_buffer_data = 1;
	if ((entitize_buf = mstrdup(ptr_ainfo->firstname)) == NULL) {
	  clean_request(dbires);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
      
	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  free(entitize_buf);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	
	if (print_element_x(entitize_buf, ptr_buffer, ptr_buffer_len, "firstname", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  clean_request(dbires);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	free(entitize_buf);
      }

      if (*(ptr_ainfo->middlename)) {
	*ptr_nhave_buffer_data = 1;
	for (item = strtok(ptr_ainfo->middlename, " "); item; item = strtok(NULL, " ")) {
	  if ((entitize_buf = mstrdup((char*)item)) == NULL) {
	    clean_request(dbires);
	    free_authorinfo(ptr_ainfo);
	    return NULL;
	  }
	    
	  if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	    free(entitize_buf);
	    free_authorinfo(ptr_ainfo);
	    return NULL;
	  }

	  if (print_element_x(entitize_buf, ptr_buffer, ptr_buffer_len, "middlename", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	    clean_request(dbires);
	    free_authorinfo(ptr_ainfo);
	    return NULL;
	  }
	  free(entitize_buf);
	} /* end while */
      }

      if (*(ptr_ainfo->suffix)) {
	*ptr_nhave_buffer_data = 1;
	if ((entitize_buf = mstrdup(ptr_ainfo->suffix)) == NULL) {
	  clean_request(dbires);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	  
	if (sgml_entitize(&entitize_buf, ptr_rendinfo->ref_format) == NULL) {
	  free(entitize_buf);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	  
	if (print_element_x(entitize_buf, ptr_buffer, ptr_buffer_len, "suffix", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  clean_request(dbires);
	  free_authorinfo(ptr_ainfo);
	  return NULL;
	}
	free(entitize_buf);
      }
    }
	
    if (print_elend_x(ptr_buffer, ptr_buffer_len, "author", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      clean_request(dbires);
      free_authorinfo(ptr_ainfo);
      return NULL;
    }
  } /* end while */

  
  clean_request(dbires);
  free_authorinfo(ptr_ainfo);
  return *ptr_buffer;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_pubinfo_risx() prints out risx pubinfo

  static char* add_pubinfo_risx returns ptr to the buffer if successful,
  NULL if failed

  char** ptr_buffer ptr to ptr to buffer that will receive the output

  size_t* ptr_buffer_len ptr to var holding size of *ptr_buffer

  dbi_conn conn connection to database

  struct renderinfo* ptr_renderinfo ptr to struct with render information

  int* ptr_nhave_buffer_data ptr to var which will be set to non-zero
                             if *ptr_buffer receives data

  struct xmlindent* ptr_indent ptr to struct with indent info

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_pubinfo_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, struct renderinfo* ptr_rendinfo, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent) {
  char* buffer1;
  char* new_ref;
  const char* type;
  const char* item;
  size_t buffer1_len;
  int nhave_data = 0;
  int i;

/*   printf("in add_pubinfo_risx\n"); */
  /* get some memory for the pubinfo stuff */
  buffer1_len = 4096;
  if ((buffer1 = malloc(buffer1_len)) == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(801));
    return NULL;
  }
  *buffer1 = '\0';

  if ((type = get_refdb_type(ptr_rendinfo->dbires)) == NULL) {
    free(buffer1);
    return NULL;
  }

  if (print_elstart_x(&buffer1, &buffer1_len, "pubinfo", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer1);
    return NULL;
  }

  if (add_pubdate_risx(&buffer1, &buffer1_len, conn, 1 /* primary */, ptr_rendinfo, &nhave_data, ptr_indent) == NULL) {
    free(buffer1);
    return NULL;
  }

  if (add_pubdate_risx(&buffer1, &buffer1_len, conn, 2 /* secondary */, ptr_rendinfo, &nhave_data, ptr_indent) == NULL) {
    free(buffer1);
    return NULL;
  }

  /*----------------------------------------------------------------*/
  /* volume */
  if ((item = get_refdb_volume(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "volume", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }
  else {
    if ((item = get_refdb_edition(ptr_rendinfo->dbires)) != NULL
	&& *item) {
      nhave_data = 1;
      if (print_element_x(item, &buffer1, &buffer1_len, "volume", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
  }



  /*----------------------------------------------------------------*/
  /* issue */
  if ((item = get_refdb_issue(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "issue", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }
  else if ((item = get_refdb_chapternum(ptr_rendinfo->dbires)) != NULL
	   && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "issue", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* conference title */
  if (!strcmp(type, "CONF")) {
    item = get_refdb_booktitle_copy(ptr_rendinfo->dbires);

    if (item != NULL) {
      if (print_element_x(item, &buffer1, &buffer1_len, "conftitle", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	free((char*)item);
	return NULL;
      }
      free((char*)item);
    }
  }

  /*----------------------------------------------------------------*/
  /* start page */
  if ((item = get_refdb_startpage(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "startpage", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* end page */
  if ((item = get_refdb_endpage(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "endpage", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* city */
  if ((item = get_refdb_city(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "city", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* publisher */
  if ((item = get_refdb_publisher(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "publisher", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* ISBN/ISSN */
  if ((item = get_refdb_issn(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "serial", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* address */
  if ((item = get_refdb_address_copy(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "address", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free((char*)item);
      free(buffer1);
      return NULL;
    }
    free((char*)item);
  }

  /*----------------------------------------------------------------*/
  /* user1 */
  if ((item = get_refdb_user1(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "userdef", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* user2 */
  if ((item = get_refdb_user2(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "userdef", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* user3 */
  if ((item = get_refdb_user3(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "userdef", "type", "3", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* user4 */
  if ((item = get_refdb_user4(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "userdef", "type", "4", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* user5 */
  if ((item = get_refdb_user5(ptr_rendinfo->dbires)) != NULL) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "userdef", "type", "5", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  /*----------------------------------------------------------------*/
  /* misc fields */
  if ((item = get_refdb_typeofwork(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (!strcmp(type, "THES")) {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
    else if (!strcmp(type, "PAT")) {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "3", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
    else {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
  }

  if ((item = get_refdb_area(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_ostype(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_degree(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_runningtime(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_classcodeintl(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_classcodeus(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_senderemail(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_recipientemail(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_mediatype(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (!strcmp(type, "MAP")) {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
    else if (!strcmp(type, "ELEC")
	     || !strcmp(type, "JOUR")) {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
    else {
      if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "3", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }
  }

  if ((item = get_refdb_numvolumes(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_computer(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_conferencelocation(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_registrynum(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_classification(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_section(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "2", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

  if ((item = get_refdb_pamphletnum(ptr_rendinfo->dbires)) != NULL
      && *item) {
    nhave_data = 1;
    if (print_element_x(item, &buffer1, &buffer1_len, "misc", "type", "1", NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }


  /*----------------------------------------------------------------*/
  /* URL, L1 through L4. Pubinfo links are not owned by a particular user */

  /* loop over all link types */
  for (i=0; i<6;i++) {
    char ulink_type[10];
    dbi_result dbires;

    dbires = request_ulinks(conn, my_dbi_result_get_idval(ptr_rendinfo->dbires, "refdb_id"), 0 /* ref entry */, i /* link type */, 0 /* is_temp */, "NULL");
    if (dbires == NULL) {
      return NULL;
    }

    while ((item = get_ulink(dbires)) != NULL) {
      nhave_data = 1;
      if (i == 0) {
	strcpy(ulink_type, "url");
      }
      else if (i == 1) {
	strcpy(ulink_type, "pdf");
      }
      else if (i == 2) {
	strcpy(ulink_type, "fulltext");
      }
      else if (i == 3) {
	strcpy(ulink_type, "related");
      }
      else if (i == 4) {
	strcpy(ulink_type, "image");
      }
      else if (i == 5) {
	strcpy(ulink_type, "doi");
      }
      if (print_element_x(item, &buffer1, &buffer1_len, "link", "type", ulink_type, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	clean_request(dbires);
	return NULL;
      }
    }

    clean_request(dbires);
  } /* end for */

  if (print_elend_x(&buffer1, &buffer1_len, "pubinfo", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer1);
    return NULL;
  }

  if (nhave_data) {
    /* promote have_data upstream */
    *ptr_nhave_buffer_data = 1;
    if ((new_ref = mstrcat(*ptr_buffer, buffer1, ptr_buffer_len, 0)) == NULL) {
      LOG_PRINT(LOG_WARNING, get_status_msg(801));
      free(buffer1);
      return NULL;
    }
    else {
      *ptr_buffer = new_ref;
    }
  }
  free(buffer1);

  return *ptr_buffer;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_pubdate_risx() prints out risx pubdate

  static char* add_pubdate_risx returns ptr to the buffer if successful,
  NULL if failed

  char** ptr_buffer ptr to ptr to buffer that will receive the output

  size_t* ptr_buffer_len ptr to var holding size of *ptr_buffer

  dbi_conn conn connection to database

  int type 1=primary, 2=secondary

  struct renderinfo* ptr_renderinfo ptr to struct with render information

  int* ptr_nhave_buffer_data ptr to var which will be set to non-zero
                             if *ptr_buffer receives data

  struct xmlindent* ptr_indent ptr to struct with indent info

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_pubdate_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, int type, struct renderinfo* ptr_rendinfo, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent) {
  char date_buffer[256] = "";
  char* buffer1;
  char* new_ref;
  char* slash;
  const char* item;
  size_t buffer1_len;
  int nhave_data = 0;
  int nhave_year = 0;
  int nhave_other = 0;
  char* slashes[3] = {NULL, NULL, NULL}; /* only the first three slashes are relevant, if at all */

/*   printf("in add_pubdate_risx\n"); */
  /* get some memory for the pubinfo stuff */
  buffer1_len = 4096;
  if ((buffer1 = malloc(buffer1_len)) == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(801));
    return NULL;
  }
  *buffer1 = '\0';

  if (type == 1) {
    if (print_elstart_x(&buffer1, &buffer1_len, "pubdate", "type", "primary", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
    item = get_refdb_pyother_info(ptr_rendinfo->dbires);
  }
  else {
    if (print_elstart_x(&buffer1, &buffer1_len, "pubdate", "type", "secondary", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
    item = get_refdb_secother_info(ptr_rendinfo->dbires);
  }

  if (item && *item) {
      int i = 0;
/*       printf("item went to:%s<<\n", item); */
      nhave_other++;
      slash = strchr(item, (int)'/');

    /* fill the slashes array with up to three slashes. Only the first three may be relevant, as the others would be part of the otherinfo string */
    while (slash != NULL && i < 3) {
      slashes[i] = slash;
      i++;
      if (*(slash+1)) {
	slash = strchr(slash+1, (int)'/');
      }
      else {
	break;
      }
    }
  }

  /*----------------------------------------------------------------*/
  /* pubyear */
  if (type == 1) {
    if (get_refdb_pubyear(ptr_rendinfo->dbires, date_buffer) != NULL
	&& strcmp(date_buffer, "nd")) {
      nhave_year = 1;
    }
  }
  else {
    if (get_refdb_secyear(ptr_rendinfo->dbires, date_buffer) != NULL
	&& strcmp(date_buffer, "nd")) {
      nhave_year = 1;
    }
  }

/*   printf("date_buffer went to:%s<<\n", date_buffer); */
  if (nhave_year || nhave_other) {
/*     printf("nhave_year=%d || nhave_other+%d went to TRUE\n", nhave_year, nhave_other); */
    nhave_data++;
    if (print_elstart_x(&buffer1, &buffer1_len, "date", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }

    if (nhave_year) {
      if (print_element_x(date_buffer, &buffer1, &buffer1_len, "year", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	free(buffer1);
	return NULL;
      }
    }

    if (nhave_other) {
      /* parse "other" string */
      if (slashes[0] && slashes[1] && slashes[1]-slashes[0] > 1) {
	/* have month */
	*(slashes[1]) = '\0';
	if (print_element_x(slashes[0]+1, &buffer1, &buffer1_len, "month", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer1);
	  return NULL;
	}
      }

      if (slashes[1] && ((slashes[2] && slashes[2]-slashes[1] > 1)
			 || (!slashes[2] && *(slashes[1]+1) != '\0' && (*(slashes[1]+2) == '\0' || *(slashes[1]+3) == '\0')))) {
	/* have day */
	if (slashes[2]) {
	  *(slashes[2]) = '\0';
	}
	if (print_element_x(slashes[1]+1, &buffer1, &buffer1_len, "day", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	  free(buffer1);
	  return NULL;
	}
      }
      

      if (! (slashes[2] && *(slashes[2]+1))) {
	nhave_other = 0;
      }
    }

/*     printf("finish pubyear\n"); */
    if (print_elend_x(&buffer1, &buffer1_len, "date", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }
/*   printf("now I'm here\n"); */
  /*----------------------------------------------------------------*/
  /* pubyear - other information */
  if (nhave_other) {
    nhave_data = 1;
    if (print_element_x(slashes[2]+1, &buffer1, &buffer1_len, "otherinfo", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      free(buffer1);
      return NULL;
    }
  }

/*   printf("finish pubyearother\n"); */
  if (print_elend_x(&buffer1, &buffer1_len, "pubdate", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
    free(buffer1);
    return NULL;
  }

  if (nhave_data) {
    if ((new_ref = mstrcat(*ptr_buffer, buffer1, ptr_buffer_len, 0)) == NULL) {
      LOG_PRINT(LOG_WARNING, get_status_msg(801));
      free(buffer1);
      return NULL;
    }
    else {
      *ptr_buffer = new_ref;
    }
  }

  if (nhave_data) {
    (*ptr_nhave_buffer_data)++;
  }

  free(buffer1);
  return *ptr_buffer;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_reprint_risx() prints out risx reprint info

  static char* add_reprint_risx returns ptr to the buffer if successful,
  NULL if failed

  char** ptr_buffer ptr to ptr to buffer that will receive the output

  size_t* ptr_buffer_len ptr to var holding size of *ptr_buffer

  dbi_conn conn connection to database

  struct renderinfo* ptr_renderinfo ptr to struct with render information

  char* username name of user 

  int* ptr_nhave_buffer_data ptr to var which will be set to non-zero
                             if *ptr_buffer receives data

  struct xmlindent* ptr_indent ptr to struct with indent info

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static char* add_reprint_risx(char** ptr_buffer, size_t* ptr_buffer_len, dbi_conn conn, struct renderinfo* ptr_rendinfo, char* username, int* ptr_nhave_buffer_data, struct xmlindent* ptr_indent) {
  struct REPRINT reprint;
  char attribute[10];
  size_t path_skip = 0;

  if (get_reprint(ptr_rendinfo->dbires, &reprint, username, 4)
      && reprint.reprint != NULL && *(reprint.reprint)) {
    *ptr_nhave_buffer_data = 1;
    if (!strcmp(reprint.reprint, "NOT IN FILE")) {
      strcpy(attribute, "NOTINFILE");
    }
    else if (!strcmp(reprint.reprint, "ON REQUEST")) {
      strcpy(attribute, "ONREQUEST");
    }
    else {
      strcpy(attribute, "INFILE");
    }
    
    if (!strcmp(attribute, "ONREQUEST") && reprint.date != NULL) {
      char year[5];
      char month[3];
      char day[3];

      strncpy(year, reprint.date, 4);
      year[4] = '\0';
      strncpy(month, reprint.date+5, 2);
      month[2] = '\0';
      strncpy(day, reprint.date+8, 2);
      day[2] = '\0';

      if (print_elstart_x(ptr_buffer, ptr_buffer_len, "reprint", "status", attribute, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }

      if (print_elstart_x(ptr_buffer, ptr_buffer_len, "date", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }

      if (print_element_x(year, ptr_buffer, ptr_buffer_len, "year", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }

      if (print_element_x(month, ptr_buffer, ptr_buffer_len, "month", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }

      if (print_element_x(day, ptr_buffer, ptr_buffer_len, "day", NULL, NULL, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }


      if (print_elend_x(ptr_buffer, ptr_buffer_len, "date", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }

      if (print_elend_x(ptr_buffer, ptr_buffer_len, "reprint", ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }
    }
    else {
      if (print_element_x("", ptr_buffer, ptr_buffer_len, "reprint", "status", attribute, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
	return NULL;
      }
    }
  }

  if (reprint.avail != NULL && *(reprint.avail)) {
    if (!strncmp(reprint.avail, "PATH:", 5)) {
      strcpy(attribute, "useroot");
      path_skip = 5;
    }
    else {
      strcpy(attribute, "full");
    }

    if (print_element_x(reprint.avail+path_skip, ptr_buffer, ptr_buffer_len, "availability", "type", attribute, NULL, NULL, ptr_indent, ptr_rendinfo->ptr_clrequest->namespace) == NULL) {
      return NULL;
    }
  }
  return *ptr_buffer;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  indent_notbelow_risx(): checks whether or not to indent below the current
                     element

  static int indent_notbelow returns 1 if not to indent, 0 if to indent

  const char* name ptr to element name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int indent_notbelow_risx(const char* name)
{
  if (!strcmp(name, "date")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  is_entry_risx(): checks whether an element starts a new entry

  static int is_entry_risx returns 1 if entry starts, 0 if not

  const char* name ptr to element name

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static int is_entry_risx(const char* name) {
  if (!strcmp(name, "entry")) {
    return 1;
  }
  else {
    return 0;
  }
}
