/*****************************************************************************
 *
 * FILE:	postal.cgi.c
 * DESCRIPTION:	Postal: CGI program to search the address with postcode
 * DATE:	Tue, Aug 28 2007
 * UPDATE:	Tue, Aug 28 2007
 * AUTHOR:	Kouichi ABE (WALL) / °¤Éô¹¯°ì
 * E-MAIL:	kouichi@MysticWALL.COM
 * URL:		http://www.MysticWALL.COM/
 * COPYRIGHT:	(c) 2007 °¤Éô¹¯°ì¡¿Kouichi ABE (WALL), All rights reserved.
 * COMPILE:	gcc -export-dynamic postal.cgi.c -o postal.cgi
 *		-I/usr/local/include -L/usr/local/lib
 *		-lcockatrice -lwkf -lmd
 * $Id: postal.cgi.c,v 1.1 2007/08/29 11:19:56 kouichi Exp $
 *
 *****************************************************************************/

#if	HAVE_CONFIG_H
#include "config.h"
#endif	/* HAVE_CONFIG_H */

#include <stdio.h>
#if	HAVE_STDLIB_H
#include <stdlib.h>
#endif	/* HAVE_STDLIB_H */
#if	HAVE_UNISTD_H
#include <unistd.h>
#endif	/* HAVE_UNISTD_H */
#if	HAVE_STRING_H
#include <string.h>
#endif	/* HAVE_STRING_H */
#include <cockatrice.h>

/*****************************************************************************
 *
 *	Program and Copyright
 *
 *****************************************************************************/
const char	Program[]   = "postal.cgi";
const char	Copyright[] =
	"Copyright (c) 2007 Kouichi ABE (WALL), All rights reserved.";

/*****************************************************************************
 *
 *	Macros and structures definition
 *
 *****************************************************************************/
/*
 * Numeric release version identifier:
 * MNNFFPPS: major minor fix patch status
 * The status nibble has one of the values 0 for development,
 * 1 to e for betas 1 to 14, and f for release.
 * The patch level is exactly that.
 */
#define	POSTAL_CGI_VERSION_NUMBER	0x10000000L
#define	POSTAL_CGI_VERSION		"Postal/1.0"
#define	POSTAL_CGI_VERSION_TEXT		POSTAL_CGI_VERSION " (2007/08/28)"
#define	POSTAL_CGI_VERSION_TEXT_LONG	"Postal 1.0, Tue, Aug 28 2007"

/*****************************************************************************/

#if	DEBUG
#define	POSTCODE_DB	"/home/kouichi/projects/postal/postcode.db"
#else
#define	POSTCODE_DB	"/usr/local/share/postal/postcode.db"
#endif	/* DEBUG */
#define	POSTCODE_LEN	(7)
#define	SQL_JAPAN \
	"SELECT prefecture,city,address FROM japan WHERE postcode=%s;"
#define	SQL_OFFICE \
	"SELECT prefecture,city,address,name FROM office WHERE postcode=%s;"

#define	XML_STRING \
	"<?xml version=\"1.0\" encoding=\"euc-jp\" standalone=\"yes\" ?>"

/*****************************************************************************
 *
 *	Local functions declaration
 *
 *****************************************************************************/
static int	postal(CGI * cgi);
static int	lookup(CGI * cgi, const char * sql, const char * postcode,
		       char ** address, char ** name);

/*****************************************************************************
 *
 *	Functions definition
 *
 *****************************************************************************/
static int
postal(cgi)
	register CGI *	cgi;
{
  int		status	 = -1;
  const char *	postcode = cgi->param("pc");

  if (postcode != NULL) {
    static const char	digits[] = "0123456789";
    size_t		len;
    size_t		pos;

    len = strlen(postcode);
    if (len != POSTCODE_LEN) {
      fprintf(stderr, "The length of %s is not 7.\n", postcode);
      return -1;
    }
    pos = strspn(postcode, digits);
    if (pos != POSTCODE_LEN) {
      fprintf(stderr, "%s has invalid character.\n", postcode);
      return -1;
    }

    if (cgi->database->open(POSTCODE_DB) == 0) {
      char *	address;
      char *	name = NULL;

      status = lookup(cgi, SQL_JAPAN, postcode, &address, NULL);
      if (status != 0) {
	status = lookup(cgi, SQL_OFFICE, postcode, &address, &name);
      }

      cgi->header("text/xml");
      fprintf(stdout, XML_STRING "<postcode>");
      if (status == 0) {
	fprintf(stdout,
		"<status>found</status>"
		"<address>%s</address>", address);
	free(address);
	if (name != NULL) {
	  fprintf(stdout, "<name>%s</name>", name);
	  free(name);
	}
      }
      else {
	fprintf(stdout, "<status>failed</status>");
      }
      fprintf(stdout, "</postcode>\n");

      status = cgi->database->close();
    }
  }

  return status;
}

static int
lookup(cgi, sql, postcode, address, name)
	register CGI *	cgi;
	const char *	sql;
	const char *	postcode;
	char **		address;
	char **		name;
{
  int		status = -1;
  char *	s;

  asprintf(&s, sql, postcode);
  if (s) {
    if (cgi->database->query(s) == 0) {
      register int	i;
      register int	n;
      const char **	val;

      n = cgi->database->fetch(&val);
      if (n >= 3) {
	asprintf(address, "%s%s%s", val[0], val[1], val[2]);
	if (*address != NULL) {
	  status = 0;
	}
	if (n == 4 && name != NULL) {
	  *name = strdup(val[3]);
	}
      }
      for (i = 0; i < n; i++) {
	free(val[i]);
      }
    }
  }

  return status;
}

int
main(argc, argv)
	int	argc;
	char	**argv;
{
  CGI *	cgi;
  int	status;

  cgi = newCGI(CC_MODULE_SQLITE3);
  if (cgi == NULL) {
    fprintf(stderr, "Error: %d\n", cgi_errno);
    return -1;
  }
  status = postal(cgi);
  cgi->done();

  return status;
}
