/*
 * make CC=gcc CFLAGS="-g -Wall" LDLIBS=-ldb history-db-write
 *
 * write history database to ~/.netscape/history.db with Berkeley UNIX DB in C
 *
 * Copyright (C) 1999,2000 Taiji Yamada
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <limits.h>
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)>(b))?(a):(b))
#define swap(a,b) do {\
  struct tmp_t { char t[sizeof(a)]; } tmp;\
  tmp = *(struct tmp_t*)&(a);\
  *(struct tmp_t*)&(a) = *(struct tmp_t*)&(b);\
  *(struct tmp_t*)&(b) = tmp;\
} while(0)
#define chendian32(p) do {\
  swap((p)[0],(p)[3]);\
  swap((p)[1],(p)[2]);\
} while (0)

#ifndef NO_DB185
#include "db.h" /* Berkeley UNIX DB library, db-1.85.tar.gz */
#else
#include "db_185.h" /* Berkeley UNIX DB library, db-2.7.7.tar.gz */
#endif

/*#define HISTORY_DB_NAME ".netscape/history.db"*/
char fsep = '\t'/*, rsep = '\n'*/;
int chendian_flag = 0;
int append_flag = 0;

time_t stamp_time(char *str) {
  struct tm tm;
  sscanf(str, "%d/%d/%d %d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
  tm.tm_year-= 1900;
  tm.tm_mon--;
  tm.tm_isdst = -1;
  return mktime(&tm);
}

int history_write_entry(DB *history, char *url, time_t last, time_t first, time_t count, time_t expire, char *title)
{
  DBT key, data;
  union { unsigned long i; unsigned char s[4]; } l, f, c, e;
  char *p;

  key.size = sizeof(char)*(strlen(url)+1);
  key.data = url;
  data.size = 4+4+4+4+sizeof(char)*(strlen(title)+1);
  data.data = malloc(data.size);
  l.i = last;
  f.i = first;
  c.i = count;
  e.i = expire;
  if (chendian_flag) {
    chendian32(l.s);
    chendian32(f.s);
    chendian32(c.s);
    chendian32(e.s);
  }
  p = (char *)data.data;
  memcpy(&p[0],l.s,4);
  memcpy(&p[4],f.s,4);
  memcpy(&p[8],c.s,4);
  memcpy(&p[12],e.s,4);
  memcpy(&p[16],title,sizeof(char)*(strlen(title)+1));

  if (append_flag) {
    DBT old_data;
    if (history->get(history, &key, &old_data, 0)==0)
      history->del(history, &key, 0);
  }
  if (history->put(history, &key, &data, 0)<0) return 0;
  free(data.data);
  return !0;
}

int history_fscan_write(FILE *fp, char *history_db)
{
  DB *history;
  char buf[8192];
    
  if (!(history=dbopen(history_db, O_RDWR|((!append_flag)?(O_CREAT|O_TRUNC):O_CREAT), 0600, DB_HASH, NULL))) {
    fprintf(stderr, "illegal database file (%s)\n", history_db);
    return 0;
  }
  while (fgets(buf, 8192, fp)!=NULL) {
    int i;
    char *p[6];
    char *url, *title, *last, *first, *expire, *count;
    time_t l, f, e;
    unsigned long c;

    p[0] = buf;
    for (i=5; i>1; i--) {
      p[i] = strrchr(p[0], fsep);
      if (p[i]==NULL || p[i]<=p[0]) goto CONTINUE;
      *p[i]++ = '\0';
    }
    p[i] = strchr(p[0], fsep);
    *p[i]++ = '\0';
    url=p[0]; title=p[1]; last=p[2]; first=p[3]; expire=p[4]; count=p[5];
    l = stamp_time(last);
    f = stamp_time(first);
    e = stamp_time(expire);
    c = strtoul(count, NULL, 10);

    if (!history_write_entry(history, url, l, f, c, e, title)) {
      history->close(history);
      return 0;
    }
  CONTINUE:
  }
  history->close(history);

  return !0;
}

int main(int argc, char *argv[])
{
  int i;
  char history_db[256] = "";
  int status;

  /*sprintf(history_db, "%s/%s", getenv("HOME"), HISTORY_DB_NAME);*/
  for (i=1; i<argc; i++)
    if (strcmp(argv[i],"-A")==0)
      append_flag = !0;
    else if (strcmp(argv[i],"-C")==0)
      chendian_flag = !0;
    else if (strcmp(argv[i],"-h")==0) {
      printf("usage: %s [-A] [-C] history.db|history.dat < stdin\n", argv[0]);
      printf("\t-A: append entries to database file\n");
      printf("\t-C: change endian type to database file\n");
      exit(0);
    } else
      strcpy(history_db, argv[i]);
#if defined(sparc)
  if (strcmp(strrchr(history_db,'.'),".dat")==0)
    chendian_flag = !0;
#endif
  status = history_fscan_write(stdin, history_db);
  return (status?0:-1);
}
