/* --------------------------------------------------- */
/* Source-file PLANER 1.0, (C) Wabnig Harald, 6.7.2002 */
/* --------------------------------------------------- */

#include "basis.h"

#include "plandb.h"

static DBHANDLE * pDB;

static char directory[1000];
static int changed = FALSE;

/* ------------- */

#define MAXSTRG   10000

#ifdef WIN32
#define PLAN_FILE  "\\plandb.pln"
#define PLAN_AFILE "a:\\plandb.pln"
#else

/* 21.12.2002 */
#include <termios.h>
#include <unistd.h>

#define PLAN_FILE  "plandb.pln"
#define PLAN_AFILE "aplandb.pln"
#endif

#include "planer.inc"

/* --------------------------------------------- */

static void print_help()
{
  fprintf(stdout, "(a)dd,(c)hange,(d)elete,(i)mport,(e)xport\n" \
                  "(f)ind,(l)ist,(1..6) days,(w)eek,(m)onth,a(t),(g)eneric search\n" \
                  "(done),(done at),(todo),(cd)change directory,(ls)list directory\n" \
                  "(s)ave,l(o)ad,stat(u)s,(n)ew password,clea(r) password,(h)elp,(q)uit\n\n");
}

static void print_status()
{
  PLANS Plans;
  TFDate date;
  char strg[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans);
  DATE_Now(&date);
  DATE_ToString(&date, strg, DATE_DDMMYYYY);
  if (PLANS_Count(&Plans, &iCount, pDB)) {
    fprintf(stdout, "%s (%s), %d entries\n", 
            strg, DATE_GetWeekdayStr(DATE_GetWeekday(&date)), iCount);
  } else {
    fprintf(stdout, "number of entries could not be determined!\n");
  }
}

static void process_add()
{
  PLANS Plans, Plans1;
  TFDate date;
  char title[MAXSTRG], contents[MAXSTRG];

  PLANS_Init(&Plans); PLANS_Init(&Plans1);
  if (! read_date  ("# At:        ", &date, 1)) {
    return;
  }
  COPY_FDate(Plans.fdaAt, date);
  if (! read_string("# Title:     ", title, 35, 1)) {
    return;
  }
  COPY_FChar_35(Plans.fszTitle, title);
  if (! read_string("# Contents:  ", contents, 80, 0)) {
    return;
  }
  COPY_FChar_80(Plans.fszContents, contents);
  if (! read_string("# Comment 1: ", contents, 80, 0)) {
    return;
  }
  COPY_FChar_80(Plans.fszComment1, contents);
  if (! read_string("# Comment 2: ", contents, 80, 0)) {
    return;
  }
  COPY_FChar_80(Plans.fszComment2, contents);
  COPY_FChar_1(Plans.fcDone, 'n');

  PLANS_Assign(&Plans1, &Plans);
  while (PLANS_SelectLk(&Plans1, pDB)) {
    if (! change_string("# Title: ", Make_Reduce_String(Plans.fszTitle), title, 35)) {
      Free_ValueStrings();
      return;
    }
    if (title[0] != '\0') {
      COPY_FChar_35(Plans.fszTitle, title);
      COPY_FChar_35(Plans1.fszTitle, title);
    }
    Free_ValueStrings();
  }
  if (! PLANS_Insert(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Insert!\n");
    return;
  } 
  fprintf(stdout, "item added\n");
  changed = TRUE;
}

static void print_plans(PLANS * pPlans)
{
  if (CMP_FChar_1(pPlans->fcDone, 'y')) 
    fprintf(stdout, "DONE");

  fprintf(stdout, " %s (%s): %s\n", Make_FEDateString(&pPlans->fdaAt), 
                                    DATE_GetWeekdayStr(DATE_GetWeekday(&pPlans->fdaAt)),
                                    Make_Reduce_String(pPlans->fszTitle));
  if (! CMP_FChar_80(pPlans->fszContents, DEF_FChar_80)) {
    fprintf(stdout, "  Contents:   %s\n", Make_Reduce_String(pPlans->fszContents));
  }
  if (! CMP_FChar_80(pPlans->fszComment1, DEF_FChar_80)) {
    fprintf(stdout, "  Comment 1:  %s\n", Make_Reduce_String(pPlans->fszComment1));
  }
  if (! CMP_FChar_80(pPlans->fszComment2, DEF_FChar_80)) {
    fprintf(stdout, "  Comment 2:  %s\n", Make_Reduce_String(pPlans->fszComment2));
  }
  Free_ValueStrings();
}

static void print_plans_title(PLANS * pPlans)
{
  if (CMP_FChar_1(pPlans->fcDone, 'y')) 
    fprintf(stdout, "[-");
  else
    fprintf(stdout, "[!");

  fprintf(stdout, " %s: %s]\t", Make_FEDateString(&pPlans->fdaAt), 
                                 Make_Reduce_String(pPlans->fszTitle));
  Free_ValueStrings();
}

static void process_find_list(int kz_list)
{
  PLANS Plans;
  TFDate date, to;
  char title[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans);
  if (! read_date("# From:  ", &date, 0)) {
    return;
  }
  if (! read_date("# To:    ", &to, 0)) {
    return;
  }
  /*
  if (DATE_IsDefault(&date)) {
    DATE_Now(&Plans.fdaAt);
    if (! read_string("# Title? ", title, 35, 1)) {
      return;
    }
  } else {
    COPY_FDate(Plans.fdaAt, date);
    if (! read_string("# Title? ", title, 35, 0)) {
      return;
    }
  }
  */
  if (DATE_IsDefault(&date)) {
    DATE_Now(&Plans.fdaAt);
  } else {
    COPY_FDate(Plans.fdaAt, date);
  }
  if (! read_string("# Title? ", title, 35, 0)) {
    return;
  }

  Make_SearchString_Size(title, 35);
  COPY_FChar_35(Plans.fszTitle, title);
  iCount = 0;
  if (! PLANS_Select_Title_Date(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Select_Title!\n");
  } else {
    char ch = ' ';

    while (PLANS_Fetch_Title_Date(&Plans, pDB)) {
      if (! DATE_IsDefault(&to) && DATE_Compare(&to, &Plans.fdaAt) < 0) 
        continue;
      if (ch != ' ' && ch != Plans.fszTitle[0])
        fprintf(stdout, "\n");
      if (kz_list) 
        print_plans_title(&Plans);
      else
        print_plans(&Plans);
      ch = Plans.fszTitle[0];
      iCount++;
    }
    if (iCount > 0) 
      fprintf(stdout, "\n");
  }
  fprintf(stdout, "found %d items\n", iCount);
}

static void process_show_days(int days)
{
  PLANS Plans;
  TFDate date;
  char title[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans);
  DATE_Now(&date);
  DATE_Now(&Plans.fdaAt);
  if (! read_string("# Title? ", title, 35, 0)) {
    return;
  }
  Make_SearchString_Size(title, 35);
  COPY_FChar_35(Plans.fszTitle, title);
  iCount = 0;
  if (! PLANS_Select_Title_Date(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Select_Title!\n");
  } else {
    char ch = ' ';

    while (PLANS_Fetch_Title_Date(&Plans, pDB)) {
      if (DATE_Compare(&date, &Plans.fdaAt) > 0 && Plans.fcDone != 'n') 
        continue;
      if (DATE_Diff(&date, &Plans.fdaAt) > days) 
        continue;
      if (ch != ' ' && ch != Plans.fszTitle[0])
        fprintf(stdout, "\n");
      print_plans(&Plans);
      ch = Plans.fszTitle[0];
      iCount++;
    }
    if (iCount > 0) 
      fprintf(stdout, "\n");
  }
  fprintf(stdout, "found %d items\n", iCount);
}

static void process_show_date()
{
  PLANS Plans;
  TFDate date;
  char title[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans);
  if (! read_date("# At: ", &date, 0)) {
    return;
  }
  if (DATE_IsDefault(&date)) {
    DATE_Now(&Plans.fdaAt);
    if (! read_string("# Title? ", title, 35, 1)) {
      return;
    }
  } else {
    COPY_FDate(Plans.fdaAt, date);
    if (! read_string("# Title? ", title, 35, 0)) {
      return;
    }
  }
  Make_SearchString_Size(title, 35);
  COPY_FChar_35(Plans.fszTitle, title);
  iCount = 0;
  if (! PLANS_Select_Title_Date_Acc(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Select_Title!\n");
  } else {
    char ch = ' ';

    while (PLANS_Fetch_Title_Date_Acc(&Plans, pDB)) {
      if (ch != ' ' && ch != Plans.fszTitle[0])
        fprintf(stdout, "\n");
      print_plans(&Plans);
      ch = Plans.fszTitle[0];
      iCount++;
    }
    if (iCount > 0) 
      fprintf(stdout, "\n");
  }
  fprintf(stdout, "found %d items\n", iCount);
}

static void process_change()
{
  PLANS Plans, Plans1;
  TFDate date;
  char title[MAXSTRG], contents[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans); PLANS_Init(&Plans1);
  if (! read_date("# At: ", &date, 0)) {
    return;
  }
  do {
    if (! read_string("# Title? ", title, 35, 1)) {
      return;
    }
    COPY_FChar_35(Plans.fszTitle, title);
    if (PLANS_SelectLk(&Plans, pDB)) {
      iCount = 1;
      print_plans_title(&Plans);
      fprintf(stdout, "\n");
    } else {
      Make_SearchString_Size(title, 35);
      COPY_FChar_35(Plans.fszTitle, title);
      iCount = 0;
      if (DATE_IsDefault(&date)) {
        if (! PLANS_Select_Title(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      } else {
        COPY_FDate(Plans.fdaAt, date);
        if (! PLANS_Select_Title_Date_Acc(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title_Date_Acc(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      }
    }
  } while (iCount != 1);

  if (! change_date("# At: ", &Plans.fdaAt, &date, 0)) {
    Free_ValueStrings();
    return;
  }
  if (! DATE_IsDefault(&date)) {
    COPY_FDate(Plans.fdaAt, date);
  }
  Free_ValueStrings();
  do {
    if (! change_string("# Title: ", Make_Reduce_String(Plans.fszTitle), title, 35)) {
      Free_ValueStrings();
      return;
    }
    if (title[0] != '\0') {
      COPY_FChar_35(Plans.fszTitle, title);
    }
    Free_ValueStrings();
  } while (CMP_FChar_35(Plans.fszTitle, DEF_FChar_35));

  if (! change_string("# Contents: ", Make_Reduce_String(Plans.fszContents), contents, 80)) {
    Free_ValueStrings();
    return;
  }
  if (contents[0] != '\0') {
    COPY_FChar_80(Plans.fszContents, contents);
  }
  Free_ValueStrings();
  if (! change_string("# Comment 1: ", Make_Reduce_String(Plans.fszComment1), contents, 80)) {
    Free_ValueStrings();
    return;
  }
  if (contents[0] != '\0') {
    COPY_FChar_80(Plans.fszComment1, contents);
  }
  Free_ValueStrings();
  if (! change_string("# Comment 2: ", Make_Reduce_String(Plans.fszComment2), contents, 80)) {
    Free_ValueStrings();
    return;
  }
  if (contents[0] != '\0') {
    COPY_FChar_80(Plans.fszComment2, contents);
  }
  Free_ValueStrings();

  PLANS_Assign(&Plans1, &Plans);
  while (PLANS_SelectLk(&Plans1, pDB)) {
    if (CMP_FSurrogat(Plans1.fszPLANS_Id, Plans.fszPLANS_Id)) 
      break;
    if (! change_string("# Title: ", Make_Reduce_String(Plans.fszTitle), title, 35)) {
      Free_ValueStrings();
      return;
    }
    if (title[0] != '\0') {
      COPY_FChar_35(Plans.fszTitle, title);
      COPY_FChar_35(Plans1.fszTitle, title);
    }
    Free_ValueStrings();
  } 
  if (! PLANS_Update(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Update!\n");
    return;
  }
  fprintf(stdout, "item changed\n");
  changed = TRUE;
}

static void process_delete()
{
  PLANS Plans;
  TFDate date;
  char title[MAXSTRG];
  char ch;
  int iCount;

  PLANS_Init(&Plans);
  if (! read_date("# At: ", &date, 0)) {
    return;
  }
  do {
    if (! read_string("# Title? ", title, 35, 1)) {
      return;
    }
    COPY_FChar_35(Plans.fszTitle, title);
    if (PLANS_SelectLk(&Plans, pDB)) {
      iCount = 1;
      print_plans_title(&Plans);
      fprintf(stdout, "\n");
    } else {
      Make_SearchString_Size(title, 35);
      COPY_FChar_35(Plans.fszTitle, title);
      iCount = 0;
      if (DATE_IsDefault(&date)) {
        if (! PLANS_Select_Title(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      } else {
        COPY_FDate(Plans.fdaAt, date);
        if (! PLANS_Select_Title_Date_Acc(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title_Date_Acc(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      }
    }
  } while (iCount != 1);

  fprintf(stdout, "Are you sure? (y/n) ");
  while (ch = getchar()) {
    while (getchar() != '\n');
    if (ch == 'y') break;
    if (ch == 'n') return;
  }

  if (! PLANS_Delete(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Delete!\n");
    return;
  }
  fprintf(stdout, "item deleted\n");
  changed = TRUE;
}

static void process_save()
{
  if (! GRP_Data_Save (pDB, PLAN_FILE, "PLANSDAT")) {
    fprintf(stderr, "error saving plandb to file '%s'!\n", PLAN_FILE);
  } else {
    fprintf(stdout, "plandb saved to file '%s'!\n", PLAN_FILE);
    changed = FALSE;
  }
}

static void process_load()
{
  MPLANS MPlans;
  PLANS Plans, * pPlans;
  MPASSWD MPasswd;
  PASSWD Passwd, * pPasswd;
  List ls;
  char dir[MAXSTRG], strg[MAXSTRG], str1[MAXSTRG], * pstr;
  char ch;
  int iCount;
  int i;

  strcpy(dir, directory);
  do {
    if (! change_string("# Directory? ", Make_Reduce_String(dir), strg, 80)) {
      Free_ValueStrings();
      return;
    }
    if (strg[0] != '\0') {
      if (strcmp(dir, "q") == 0)
        return;
      strcpy(dir, strg);
    }
    Free_ValueStrings();

    if (! exists_directory(dir)) {
      continue;
    }
    ls = genfnpatternlist(dir, "*.pln");
    iCount = lsnumber(&ls);
    if (iCount == 0) {
      fprintf(stdout, "no planer-file in directory '%s'!\n", dir);
      continue;
    } else {
      sortfnlist(&ls);
      lsinitread(&ls);
      while (lsread(&ls, (void**) &pstr)) {
        strcpy(strg, pstr);
        strg[strlen(pstr) - 4] = '\0';
        fprintf(stdout, "[%s]\t", strg);
        strcpy(strg, pstr);
      }
      fprintf(stdout, "\n");
    }
    lsfreeall(&ls);
    fprintf(stdout, "Correct directory? (y/n/q) ");
    while (ch = getchar()) {
      if (ch == '\n') break;
      while (getchar() != '\n');
      if (ch == 'y' || ch == 'Y' || ch == 'n') break;
      if (ch == 'q') return;
    }
    if (ch == 'n') 
      continue;
    break;
  } while (1 == 1);
  if (iCount == 1) {
    if (dir[strlen(dir) - 1] == '\\' || dir[strlen(dir) - 1] == '/')
      sprintf(str1, "%s%s", dir, strg);
    else 
      sprintf(str1, "%s/%s", dir, strg);
  } else {
    do {
      if (! change_string("# File? ", strg, str1, 80)) {
        return;
      }
      if (str1[0] != '\0') {
        if (strcmp(str1, "q") == 0)
          return;
        strcpy(strg, str1);
      }
      if (dir[strlen(dir) - 1] == '\\' || dir[strlen(dir) - 1] == '/')
        sprintf(str1, "%s%s", dir, strg);
      else 
        sprintf(str1, "%s/%s", dir, strg);
      if (! exists_file(str1)) {
        continue;
      }
      break;
    } while (1 == 1);
  }
  /* store tables */
  MPLANS_Init(&MPlans);
  PLANS_Init(&Plans);
  if (PLANS_Select(&Plans, pDB)) 
  while (PLANS_Fetch(&Plans, pDB)) {
    MPLANS_Add(&MPlans, &Plans);
  }
  MPASSWD_Init(&MPasswd);
  PASSWD_Init(&Passwd);
  if (PASSWD_Select(&Passwd, pDB)) 
  while (PASSWD_Fetch(&Passwd, pDB)) {
    MPASSWD_Add(&MPasswd, &Passwd);
  }

  /* open planer-file */
  if (! GRP_Data_Load (pDB, str1, "PLANSDAT")) {
    fprintf(stderr, "error loading file '%s'!\n", str1);
  } else {
    fprintf(stdout, "file '%s' loaded successfully!\n", str1);
    changed = TRUE;
  }
  /* reload PASSWD-table */
  PASSWD_DeleteAll(pDB);
  for (i = 0; i < MPasswd.iCount; i++) {
    pPasswd = MPASSWD_GetPtr(&MPasswd, i);
    PASSWD_Insert(pPasswd, pDB);
  }
  /* add stored tables */
  for (i = 0; i < MPlans.iCount; i++) {
    pPlans = MPLANS_GetPtr(&MPlans, i);
    PLANS_Assign(&Plans, pPlans);
    if (! PLANS_SelectLk(&Plans, pDB)) {
      PLANS_Insert(pPlans, pDB);
    } else {
      COPY_FSurrogat(pPlans->fszPLANS_Id, Plans.fszPLANS_Id);
      PLANS_Update(pPlans, pDB);
      fprintf(stdout, "entry '%s' not loaded because already existing!\n", 
              Make_Reduce_String(pPlans->fszTitle));
    }
  }
  MPLANS_Free(&MPlans);
  MPASSWD_Free(&MPasswd);
}

static void process_generic()
{
  char sql[MAXSTRG];
  int cnt;

  do {
    if (! read_string("# SQL-command? ", sql, 160, 1)) {
      if (strcmp(sql, "q") == 0) 
        return;
      continue;
    }
    if (! DB_Exec_SQL(pDB, sql, &cnt, TRUE)) {
      DB_Print_Error_String();
    } else if (cnt < 0) {
      fprintf(stdout, "not all rows evaluated!\n");
    }
  } while (1 == 1);
}

static void process_change_directory()
{
  char dir[MAXSTRG], strg[MAXSTRG];

  strcpy(dir, directory);
  do {
    if (! change_string("# Directory? ", Make_Reduce_String(dir), strg, 80)) {
      Free_ValueStrings();
      return;
    }
    if (strg[0] != '\0') {
      if (strcmp(dir, "q") == 0)
        return;
      strcpy(dir, strg);
    }
    Free_ValueStrings();

    if (! exists_directory(dir)) {
      fprintf(stdout, "directory '%s' not found!\n", dir);
      continue;
    }
    break;
  } while (1 == 1);
  strcpy(directory, dir);
}

static void process_list_directory()
{
  List ls;
  char strg[MAXSTRG], * pstr;
  int iCount;

  ls = genfilelist(directory, "*");
  iCount = lsnumber(&ls);
  if (iCount == 0) {
    fprintf(stdout, "no files in directory '%s'!\n", directory);
  } else {
    sortfnlist(&ls);
    lsinitread(&ls);
    while (lsread(&ls, (void**) &pstr)) {
      fprintf(stdout, "[%s]\t", pstr);
      strcpy(strg, pstr);
    }
    fprintf(stdout, "\n");
  }
  lsfreeall(&ls);
}

static void process_export()
{
  char * data;
  int size;

  if (! GRP_Data_Save (pDB, PLAN_FILE, "PLANSDAT")) {
    fprintf(stderr, "error exporting file '%s'!\n", PLAN_FILE);
    return;
  } else {
    changed = FALSE;
  }
  if ((data = read_binfile(PLAN_FILE, &size)) == NULL) {
    fprintf(stderr, "error exporting file '%s'!\n", PLAN_FILE);
    return;
  }
  if (! write_binfile(PLAN_AFILE, data, size)) {
    fprintf(stderr, "error exporting file '%s'!\n", PLAN_AFILE);
  } else {
    fprintf(stderr, "file '%s' exported successfully!\n", PLAN_AFILE);
  }
  free(data);
}

static void process_import()
{
  MPLANS MPlans;
  PLANS Plans, * pPlans;
  MPASSWD MPasswd;
  PASSWD Passwd, * pPasswd;
  int i;

  if (! exists_file(PLAN_AFILE)) {
    fprintf(stderr, "error importing file '%s'!\n", PLAN_AFILE);
    return;
  }
  /* store tables */
  MPLANS_Init(&MPlans);
  PLANS_Init(&Plans);
  if (PLANS_Select(&Plans, pDB)) 
  while (PLANS_Fetch(&Plans, pDB)) {
    MPLANS_Add(&MPlans, &Plans);
  }
  MPASSWD_Init(&MPasswd);
  PASSWD_Init(&Passwd);
  if (PASSWD_Select(&Passwd, pDB)) 
  while (PASSWD_Fetch(&Passwd, pDB)) {
    MPASSWD_Add(&MPasswd, &Passwd);
  }
  changed = TRUE;
  /* open planer-file */
  if (! GRP_Data_Load (pDB, PLAN_AFILE, "PLANSDAT")) {
    MPLANS_Free(&MPlans);
    fprintf(stderr, "error loading file '%s'!\n", PLAN_AFILE);
    return;
  }
  if (PLANS_Select(&Plans, pDB)) 
  while (PLANS_Fetch(&Plans, pDB)) {
    for (i = 0; i < MPlans.iCount; i++) {
      pPlans = MPLANS_GetPtr(&MPlans, i);
      if (PLANS_CmpLk(pPlans, &Plans))
        break;
    }
    if (i == MPlans.iCount)
      fprintf(stdout, "'%s: %s' loaded\n", 
              Make_FEDateString(&Plans.fdaAt), 
              Make_Reduce_String(Plans.fszTitle));
  }
  /* add stored tables */
  /* reload PASSWD-table */
  PASSWD_DeleteAll(pDB);
  for (i = 0; i < MPasswd.iCount; i++) {
    pPasswd = MPASSWD_GetPtr(&MPasswd, i);
    PASSWD_Insert(pPasswd, pDB);
  }
  for (i = 0; i < MPlans.iCount; i++) {
    pPlans = MPLANS_GetPtr(&MPlans, i);
    PLANS_Assign(&Plans, pPlans);
    if (! PLANS_SelectLk(&Plans, pDB)) {
      PLANS_Insert(pPlans, pDB);
    } else {
      COPY_FSurrogat(pPlans->fszPLANS_Id, Plans.fszPLANS_Id);
      PLANS_Update(pPlans, pDB);
    }
  }
  MPLANS_Free(&MPlans);
  MPASSWD_Free(&MPasswd);
  fprintf(stdout, "file '%s' loaded successfully!\n", PLAN_AFILE);
}

static void process_new_password()
{
  PASSWD Passwd, Passwd1;
  char password[MAXSTRG], strg[MAXSTRG];
  int iCount;

  PASSWD_Init(&Passwd);
  PASSWD_Init(&Passwd1);
  strcpy(password, "");
  if (PASSWD_Select(&Passwd, pDB))
  while (PASSWD_Fetch(&Passwd, pDB)) {
    if (Passwd.fsSubnummer == 1) {
      strcpy(password, Passwd.fszPassword);
      PASSWD_Assign(&Passwd1, &Passwd);
    }
  }
  if (! read_password("# New Password: ", strg, 35, 4)) {
    return;
  }
  if (strcmp(password, "") == 0) {
    PASSWD_Init(&Passwd);
    COPY_FChar_35(Passwd.fszPassword, strg);
    COPY_FShort(Passwd.fsSubnummer, 1);
    if (! PASSWD_Insert(&Passwd, pDB)) {
      fprintf(stdout, "error inserting password - password not stored!\n");
    } else {
      changed = TRUE;
    }
  } else {
    COPY_FChar_35(Passwd1.fszPassword, strg);
    if (! PASSWD_Update_Password(&Passwd1, &iCount, pDB) || iCount == 0) {
      fprintf(stdout, "error changing password - password not changed!\n");
      return;
    } else {
      changed = TRUE;
    }
  }
  fprintf(stdout, "password changed\n");
}

static void process_clear_password()
{
  PASSWD_DeleteAll(pDB);
  changed = TRUE;
  fprintf(stdout, "password cleared\n");
}

static void process_set_done(int done)
{
  PLANS Plans, Plans1;
  TFDate date;
  char title[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans); PLANS_Init(&Plans1);
  if (! read_date("# At: ", &date, 0)) {
    return;
  }
  do {
    if (! read_string("# Title? ", title, 35, 1)) {
      return;
    }
    COPY_FChar_35(Plans.fszTitle, title);
    if (PLANS_SelectLk(&Plans, pDB)) {
      iCount = 1;
      print_plans_title(&Plans);
      fprintf(stdout, "\n");
    } else {
      Make_SearchString_Size(title, 35);
      COPY_FChar_35(Plans.fszTitle, title);
      iCount = 0;
      if (DATE_IsDefault(&date)) {
        if (! PLANS_Select_Title(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      } else {
        COPY_FDate(Plans.fdaAt, date);
        if (! PLANS_Select_Title_Date_Acc(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Select_Title!\n");
        } else {
          while (PLANS_Fetch_Title_Date_Acc(&Plans, pDB)) {
            print_plans_title(&Plans);
            iCount++;
          }
          if (iCount > 0) 
            fprintf(stdout, "\n");
        }
      }
    }
  } while (iCount != 1);

  if (done) 
    COPY_FChar_1(Plans.fcDone, 'y');
  else
    COPY_FChar_1(Plans.fcDone, 'n');
  if (! PLANS_Update(&Plans, pDB)) {
    DB_Print_Error_String();
    fprintf(stderr, "db-error in PLANS_Update!\n");
    return;
  }
  fprintf(stdout, "item changed\n");
  changed = TRUE;
}

static void process_set_done_at()
{
  PLANS Plans, Plans1;
  TFDate date;
  char title[MAXSTRG];
  int iCount;

  PLANS_Init(&Plans); PLANS_Init(&Plans1);
  if (! read_date("# At: ", &date, 1)) {
    return;
  }
  if (! read_string("# Title? ", title, 35, 0)) {
    return;
  }
  COPY_FChar_35(Plans.fszTitle, title);
  if (PLANS_SelectLk(&Plans, pDB)) {
    iCount = 1;
    print_plans_title(&Plans);
    fprintf(stdout, "\n");
  } else {
    Make_SearchString_Size(title, 35);
    COPY_FChar_35(Plans.fszTitle, title);
    iCount = 0;
    COPY_FDate(Plans.fdaAt, date);
    if (! PLANS_Select_Title_Date_Acc(&Plans, pDB)) {
      DB_Print_Error_String();
      fprintf(stderr, "db-error in PLANS_Select_Title!\n");
    } else {
      while (PLANS_Fetch_Title_Date_Acc(&Plans, pDB)) {
        if (DATE_Compare(&date, &Plans.fdaAt) != 0)
          continue;
        print_plans_title(&Plans);
        COPY_FChar_1(Plans.fcDone, 'y');
        if (! PLANS_Update(&Plans, pDB)) {
          DB_Print_Error_String();
          fprintf(stderr, "db-error in PLANS_Update!\n");
          return;
        }
        iCount++;
      }
      if (iCount > 0) 
        fprintf(stdout, "\n");
    }
  }
  fprintf(stdout, "item changed\n");
  changed = TRUE;
}

static void process()
{
  char strg[MAXSTRG];
  int i;

  do {
    fprintf(stdout, "> ");
    if (scan_string("qhtacdflsgoienywm123456ur ", strg) <= 0) {
      continue;
    }
    /* skip spaces at end of command */
    i = strlen(strg) - 1;
    while (i >= 0 && isspace(strg[i])) i--;
    strg[i + 1] = '\0';
    if (strcmp(strg, "q") == 0) {
      break;
    } else if (strcmp(strg, "h") == 0) {
      print_help();
    } else if (strcmp(strg, "u") == 0) {
      print_status();
    } else if (strcmp(strg, "a") == 0) {
      process_add();
    } else if (strcmp(strg, "c") == 0) {
      process_change();
    } else if (strcmp(strg, "d") == 0) {
      process_delete();
    } else if (strcmp(strg, "f") == 0) {
      process_find_list(FALSE);
    } else if (strcmp(strg, "l") == 0) {
      process_find_list(TRUE);
    } else if (strcmp(strg, "s") == 0) {
      process_save();
    } else if (strcmp(strg, "o") == 0) {
      process_load();
    } else if (strcmp(strg, "g") == 0) {
      process_generic();
    } else if (strcmp(strg, "cd") == 0) {
      process_change_directory();
    } else if (strcmp(strg, "ls") == 0) {
      process_list_directory();
    } else if (strcmp(strg, "i") == 0) {
      process_import();
    } else if (strcmp(strg, "e") == 0) {
      process_export();
    } else if (strcmp(strg, "n") == 0) {
      process_new_password();
    } else if (strcmp(strg, "r") == 0) {
      process_clear_password();
    } else if (strcmp(strg, "1") == 0) {
      process_show_days(0);
    } else if (strcmp(strg, "w") == 0) {
      process_show_days(6);
    } else if (strcmp(strg, "m") == 0) {
      process_show_days(30);
    } else if (strcmp(strg, "2") == 0) {
      process_show_days(1);
    } else if (strcmp(strg, "3") == 0) {
      process_show_days(2);
    } else if (strcmp(strg, "4") == 0) {
      process_show_days(3);
    } else if (strcmp(strg, "5") == 0) {
      process_show_days(4);
    } else if (strcmp(strg, "6") == 0) {
      process_show_days(5);
    } else if (strcmp(strg, "t") == 0) {
      process_show_date();
    } else if (strcmp(strg, "todo") == 0 || strcmp(strg, "done") == 0) {
      process_set_done(strcmp(strg, "done") == 0);
    } else if (strcmp(strg, "done at") == 0) {
      process_set_done_at();
    } else {
      fprintf(stdout, "unknown command!\n");
    }
  } while (1 == 1);
}

/*
static void process_password()
{
  MPASSWD MPasswd;
  PASSWD Passwd, * pPasswd;
  char password[MAXSTRG], strg[MAXSTRG];
  int i, iCount;

  MPASSWD_Init(&MPasswd);
  PASSWD_Init(&Passwd);
  strcpy(password, "");
  if (PASSWD_Select(&Passwd, pDB))
  while (PASSWD_Fetch(&Passwd, pDB)) {
    if (Passwd.fsSubnummer == 1) {
      strcpy(password, Passwd.fszPassword);
    } else {
      MPASSWD_Add(&MPasswd, &Passwd);
    }
  }
  if (strcmp(password, "") == 0) {
    return;
    / *
    if (! read_password("# New Password: ", strg, 35, 4)) {
      process_save();
      exit(1);
    }
    PASSWD_Init(&Passwd);
    COPY_FChar_35(Passwd.fszPassword, strg);
    COPY_FShort(Passwd.fsSubnummer, 1);
    if (! PASSWD_Insert(&Passwd, pDB)) {
      fprintf(stdout, "error inserting password - password not stored!\n");
    }
    changed = TRUE;
    * /
  } else {
    if (MPasswd.iCount > 0) {
      fprintf(stdout, "%d wrong passwords tried:\n", MPasswd.iCount);
      for (i = 0; i < MPasswd.iCount; i++) {
        pPasswd = MPASSWD_GetPtr(&MPasswd, i);
        fprintf(stdout, "  %s at %s\n",
                Make_Reduce_String(pPasswd->fszPassword),
                Make_DatiString(&pPasswd->fdtAt));
      }
    }

    iCount = 0;
    do {
      if (iCount > 0) {
        fprintf(stdout, "invalid password!\n");
        COPY_FChar_35(Passwd.fszPassword, strg);
        COPY_FShort(Passwd.fsSubnummer, iCount + 1);
        Get_Timestamp(&Passwd.fdtAt);
        PASSWD_Insert(&Passwd, pDB);
        changed = TRUE;
      }
      if (! read_password("# Password: ", strg, 35, 4)) {
        process_save();
        exit(1);
      }
      if (iCount == 1 && MPasswd.iCount > 0) {
        PASSWD_Delete_Wrong(&Passwd, &i, pDB);
        changed = TRUE;
      }
      iCount++;
    } while (! CMP_FChar_35(password, strg));

    if (iCount > 1) {
      PASSWD_Delete_Wrong(&Passwd, &i, pDB);
      changed = TRUE;
    }
  }
  fprintf(stdout, "password ok\n");
}
*/

static void process_password()
{
  MPASSWD MPasswd;
  PASSWD Passwd, * pPasswd;
  char password[MAXSTRG], strg[MAXSTRG];
  int i, iCount;

  MPASSWD_Init(&MPasswd);
  PASSWD_Init(&Passwd);
  strcpy(password, "");
  if (PASSWD_Select(&Passwd, pDB))
  while (PASSWD_Fetch(&Passwd, pDB)) {
    if (Passwd.fsSubnummer == 1) {
      strcpy(password, Passwd.fszPassword);
    } else {
      MPASSWD_Add(&MPasswd, &Passwd);
    }
  }
  if (strcmp(password, "") == 0) {
    return;
    /*
    if (! read_password("# New Password: ", strg, 35, 4)) {
      process_save();
      exit(1);
    }
    PASSWD_Init(&Passwd);
    COPY_FChar_35(Passwd.fszPassword, strg);
    COPY_FShort(Passwd.fsSubnummer, 1);
    if (! PASSWD_Insert(&Passwd, pDB)) {
      fprintf(stdout, "error inserting password - password not stored!\n");
    }
    changed = TRUE;
    */
  } else {
    if (MPasswd.iCount > 0) {
      fprintf(stdout, "%d wrong passwords tried:\n", MPasswd.iCount);
      for (i = 0; i < MPasswd.iCount; i++) {
        pPasswd = MPASSWD_GetPtr(&MPasswd, i);
        fprintf(stdout, "  at %s\n", Make_DatiString(&pPasswd->fdtAt));
      }
    }

    iCount = 0;
    do {
      if (iCount > 0) {
        fprintf(stdout, "invalid password!\n");
        COPY_FChar_35(Passwd.fszPassword, strg);
        COPY_FShort(Passwd.fsSubnummer, iCount + 1);
        Get_Timestamp(&Passwd.fdtAt);
        PASSWD_Insert(&Passwd, pDB);
        changed = TRUE;
      }
      if (! read_password("# Password: ", strg, 35, 4)) {
        process_save();
        exit(1);
      }
      /*
      if (iCount == 1 && MPasswd.iCount > 0) {
        PASSWD_Delete_Wrong(&Passwd, &i, pDB);
        changed = TRUE;
      }
      */
      iCount++;
    } while (! CMP_FChar_35(password, strg));

    if (MPasswd.iCount > 0/*iCount > 1*/) {
      fprintf(stdout, "%d wrong passwords tried:\n", MPasswd.iCount);
      for (i = 0; i < MPasswd.iCount; i++) {
        pPasswd = MPASSWD_GetPtr(&MPasswd, i);
        fprintf(stdout, "  %s at %s\n",
                Make_Reduce_String(pPasswd->fszPassword),
                Make_DatiString(&pPasswd->fdtAt));
      }
      PASSWD_Delete_Wrong(&Passwd, &i, pDB);
      changed = TRUE;
    }
  }
  fprintf(stdout, "password ok\n");
}

/* ------------- */

#define TABLE_PLANS    "CREATE TABLE PLANS ("\
                       "  PLANS_ID CHARACTER(8),"\
                       "  AT DATE,"\
                       "  TITLE CHARACTER(35),"\
                       "  CONTENTS CHARACTER(80),"\
                       "  COMMENT1 CHARACTER(80),"\
                       "  COMMENT2 CHARACTER(80),"\
                       "  DONE CHARACTER(1)"\
                       ");"
#define INDEX_XPLANS01 "CREATE UNIQUE INDEX XPLANS01 ON PLANS ("\
                       "  PLANS_ID"\
                       ");"
#define INDEX_XPLANS02 "CREATE UNIQUE INDEX XPLANS02 ON PLANS ("\
                       "  TITLE,"\
                       "  AT"\
                       ");"

#define TABLE_PASSWD    "CREATE TABLE PASSWD ("\
                        "  PASSWD_ID CHARACTER(8),"\
                        "  PASSWORD CHARACTER(35),"\
                        "  SUBNUMMER SMALLINT,"\
                        "  AT TIMESTAMP"\
                        ");"
#define INDEX_XPASSWD01 "CREATE UNIQUE INDEX XPASSWD01 ON PASSWD ("\
                        "  PASSWD_ID"\
                        ");"
#define INDEX_XPASSWD02 "CREATE UNIQUE INDEX XPASSWD02 ON PASSWD ("\
                        "  SUBNUMMER"\
                        ");"

/* ------------- */

int main (int argc, char *argv[])
{
  fprintf(stdout, "Planer 1.1, (C) Wabnig Harald, 12.07.2003\n");

  strcpy(directory, "\\");

#ifdef SPEEDY1
  if (! Speedy1_Init("", "PLANDB")) {
    fprintf(stderr, "Speedy1_Init error!\n");
    exit(1);
  }
#endif
  /* Connect to database "PLANDB" */
  DB_Set_Error_String();
  if (! DBHANDLE_Init(&pDB, "PLANDB")) {
    DB_Print_Error_String();
    fprintf(stderr, "DBHANDLE_Init error!\n");
    exit(1);
  }

  /* Create database-tables/indices if necessary */

  if (! DB_Exists_Table(pDB, "PLANS")) {
    if (! DB_Create_Table(pDB, TABLE_PLANS)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Table 'PLANS' error!\n");
      exit(1);
    }
  }
  if (! DB_Exists_Index(pDB, "XPLANS01")) {
    if (! DB_Create_Index(pDB, INDEX_XPLANS01)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Index 'XPLANS01' error!\n");
      exit(1);
    }
  }
  if (! DB_Exists_Index(pDB, "XPLANS02")) {
    if (! DB_Create_Index(pDB, INDEX_XPLANS02)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Index 'XPLANS02' error!\n");
      exit(1);
    }
  }

  if (! DB_Exists_Table(pDB, "PASSWD")) {
    if (! DB_Create_Table(pDB, TABLE_PASSWD)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Table 'PASSWD' error!\n");
      exit(1);
    }
  }
  if (! DB_Exists_Index(pDB, "XPASSWD01")) {
    if (! DB_Create_Index(pDB, INDEX_XPASSWD01)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Index 'XPASSWD01' error!\n");
      exit(1);
    }
  }
  if (! DB_Exists_Index(pDB, "XPASSWD02")) {
    if (! DB_Create_Index(pDB, INDEX_XPASSWD02)) {
      DB_Print_Error_String();
      fprintf(stderr, "DB_Create_Index 'XPASSWD02' error!\n");
      exit(1);
    }
  }

  /* ----------------------- */

  /* read database */

  changed = FALSE;
  if (exists_file(PLAN_FILE)) {
    PLANS Plans;
    TFDate date;

    if (! GRP_Data_Load (pDB, PLAN_FILE, "PLANSDAT")) {
      fprintf(stdout, "error reading phone-db from file '%s'!\n", PLAN_FILE);
    }
    /* migrate */
    PLANS_Init(&Plans);
    DATE_Now(&date);
    if (PLANS_Select(&Plans, pDB)) 
    while (PLANS_Fetch(&Plans, pDB)) {
      if (CMP_FChar_1(Plans.fcDone, '0')) {
        if (DATE_Compare(&date, &Plans.fdaAt) > 0) 
          COPY_FChar_1(Plans.fcDone, 'y');
        else
          COPY_FChar_1(Plans.fcDone, 'n');
        PLANS_Update(&Plans, pDB);
        changed = TRUE;
      }
    }
  }

  process_password();

  fprintf(stdout, "\n");
  print_status();
  fprintf(stdout, "\n");
  print_help();

  process();

  if (changed)
    process_save();

  exit(0);
}
