/*
  Update the message routes from message files
  (c) 1999 by Radek Burget OK2JBG
*/

#include <vector.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/stat.h>

#define MAIL_PATH "/var/ax25/mail"
#define LIST_PATH "/var/ax25/ulistd"
#define OUT_FILE "/var/ax25/mail_routes"

//-----------------------------------------------------------------------
// class addr
//-----------------------------------------------------------------------
class route_addr
{
  public:
    char call[10];
    char route[36];
    int count;
    int pcount;
    time_t ttime;

    route_addr();
    route_addr &operator = (const route_addr &);
};

route_addr &route_addr::operator = (const route_addr &src)
{
  strcpy(call, src.call);
  strcpy(route, src.route);
  count = src.count;
  pcount = src.pcount;
  ttime = src.ttime;
  return *this;
}

route_addr::route_addr()
{
  strcpy(call, "");
  strcpy(route, "");
  count = 0;
  pcount = 0;
  ttime = 0;
}


vector <route_addr> routes;


void add_record(char *call, char *route, time_t ntime)
{
  vector <route_addr>::iterator it;

  if (routes.empty())
  {
    route_addr newaddr;
    newaddr.count = 1;
    newaddr.ttime = ntime;
    strcpy(newaddr.call, call);
    strcpy(newaddr.route, route);
    routes.push_back(newaddr);
  }
  else
  {
    for (it = routes.begin(); it < routes.end(); it++)
      if (strcmp(it->call, call) == 0 && strcmp(it->route, route) != 0 &&
           ntime > it->ttime && it->ttime != -1)
        it->pcount = 0;

    it = routes.begin();
    while (it < routes.end() &&
           (strcmp(it->call, call) < 0 ||
            (strcmp(it->call, call) == 0 && strcmp(it->route, route) < 0)))
              it++;

    if (it < routes.end() && strcmp(call, it->call) == 0 && strcmp(route, it->route) == 0)
    {
      if (it->ttime != -1 && ntime > it->ttime) //not a forced bbs and new info
      {
        it->count++;
        it->pcount++;
        it->ttime = ntime;
      }
    }
    else
    {
      route_addr newaddr;
      strcpy(newaddr.call, call);
      strcpy(newaddr.route, route);
      newaddr.count = 1;
      newaddr.pcount = 1;
      newaddr.ttime = ntime;
      if (it < routes.end()) routes.insert(it, newaddr);
      else routes.push_back(newaddr);
    }
  }
}
    
//-----------------------------------------------------------------------

//read the database
void read_database()
{
  FILE *f = fopen(OUT_FILE, "r");
  if (f == NULL) return;
  while (!feof(f))
  {
    char line[256];
    char call[256];
    char route[256];
    int count, pcount;
    time_t ttime;
    route_addr newaddr;

    strcpy(line, "");
    fgets(line, 255, f);
    int n = sscanf(line, "%s %s %i %i %li", call, route, &count, &pcount, &ttime);
    if (n == 5)
    {
      strncpy(newaddr.call, call, 10);
      strncpy(newaddr.route, route, 35);
      newaddr.count = count;
      newaddr.ttime = ttime;
      newaddr.pcount = pcount;
      routes.push_back(newaddr);
    }
  }
}

//read the source path from the message
bool read_source_route(char *bbs, int num, char *route, time_t *ntime)
{
  char fname[256];
  char line[256], rline[256];

  sprintf(fname, "%s/%s/%i", MAIL_PATH, bbs, num);
  FILE *f = fopen(fname, "r");
  if (f == NULL) return false;

  strcpy(rline, "");
  do
  {
    fgets(line, 255, f);
    if (strncmp(line, "R:", 2) == 0) strcpy(rline, line);
  } while (strncmp(line, "R:", 2) == 0);

  char *p = strstr(rline, "@:");
  if (p == NULL) return false;
  p += 2;
  char *q = route;
  while (!isspace(*p))
  {
    *q = *p;
    p++;
    q++;
  }
  *q = '\0';
  fclose(f);

  //check the file time
  struct stat buf;
  if (stat(fname, &buf) == 0) *ntime = buf.st_mtime;

  return true;
}

//Update from the BBS message list
void update_bbs(char *bbsname)
{
  char bbs[35];
  FILE *f;
  char fname[1024];

  strncpy(bbs, bbsname, 34);
  for (char *p = bbs; *p; p++) *p = toupper(*p);

  sprintf(fname, "%s/%s", LIST_PATH, bbs);
  f = fopen(fname, "r");
  if (f == NULL)
  {
    fprintf(stderr, "Cannot open index file for %s\n", bbs);
    return;
  }

  while (!feof(f))
  {
    char line[256];
    char route[256];
    char flags[10];
    char size[20];
    char dest[36];
    char from[10];
    char zfrom[10];
    time_t ntime;
    int num;
    strcpy(line, "");
    fgets(line, 255, f);
    if (strlen(line) > 0)
    {
      sscanf(line, "%i %s %s %s %s %s", &num, flags, size, dest, from, zfrom);
      if (from[0] == '@') strcpy(from, zfrom);
      if (read_source_route(bbs, num, route, &ntime))
      {
        add_record(from, route, ntime);
      }
    }
  }

  fclose(f);
  return;
}


int main(int argc, char **argv)
{
  if (argc < 2)
  {
    printf("update_routes <BBS_CALL> [<BBS_CALL> ...]\n");
    return 1;
  }

  //read old data
  read_database();

  //fetch records from message files
  for (int i = 1; i < argc; i++)
    update_bbs(argv[i]);

  //write the database
  FILE *f = fopen(OUT_FILE, "w");
  if (f == NULL)
  {
    fprintf(stderr, "Cannot write to %s\n", OUT_FILE);
    return 1;
  }

  vector <route_addr>::iterator it;
  for (it = routes.begin(); it < routes.end(); it++)
    fprintf(f, "%s\t%s\t%i\t%i\t%li\n", it->call, it->route, it->count, it->pcount, it->ttime);

  fclose(f);

  return 0;
}

