/********************************************************
 * File: toss.c
 * Created at Sun Jan 28 22:10:33 MSK 2001 by raorn // raorn@binec.ru
 * TOSS
 * $Id: toss.c,v 1.11 2002/10/28 00:11:07 raorn Exp $
 *******************************************************/
#include "crashecho.h"

bool Compare(uchar * str, uchar * recog)
{
  ulong c, d;
  uchar comp;
  uchar buf[5];

  d = 0;

  for (c = 0; d < strlen(recog); c++) {
    if (recog[d] == '$') {
      strncpy(buf, &recog[d + 1], 2);
      buf[2] = 0;
      comp = hextodec(buf);
      if (str[c] != comp)
        return (FALSE);
      d += 3;
    } else {
      if (str[c] != recog[d] && recog[d] != '?')
        return (FALSE);
      d++;
    }
  }

  return (TRUE);
}

struct Packer *DetectPacker(uchar * file)
{
  FILE *fh;
  uchar buf[40];
  struct Packer *tmppacker;

  if (!(fh = fopen(file, "rb"))) {
    LogWrite(1, SYSTEMERR, "Unable to open %s", file);
    LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
    return (NULL);
  }

  fread(buf, 40, 1, fh);
  fclose(fh);

  for (tmppacker = (struct Packer *) config.PackerList.First; tmppacker; tmppacker = tmppacker->Next)
    if (Compare(buf, tmppacker->Recog))
      return (tmppacker);

  return (NULL);
}

void LogTossResults(void)
{
  struct Area *area;

  printf("\n");

  for (area = (struct Area *) config.AreaList.First; area; area = area->Next) {
    if (ctrlc)
      return;

    if (area->NewDupes)
      LogWrite(3, TOSSINGINFO, "Area %s -- %lu messages (%lu dupes)",
               area->Tagname, area->NewTexts, area->NewDupes);

    else if (area->NewTexts)
      LogWrite(3, TOSSINGINFO, "Area %s -- %lu messages", area->Tagname,
               area->NewTexts);
  }

  printf("\n");

  LogWrite(1, TOSSINGINFO, "   Total ->     Read messages: %6lu     Written messages: %6lu", toss_total, toss_written);
  LogWrite(1, TOSSINGINFO, "Imported -> Imported messages: %6lu        Carbon copies: %6lu", toss_import, toss_cc);
  LogWrite(1, TOSSINGINFO, "     Bad ->      Bad messages: %6lu   Duplicate messages: %6lu", toss_bad, toss_dupes);

  printf("\n");
}

bool UnpackDir(uchar *dir, uchar *dest)
{
  struct Packer *tmppacker;
  uchar buf[200], buf2[200];
  int arcres, arcrc;
  struct jbList ArcFEList;
  struct FileEntry *fe;

  LogWrite(6, TOSSINGINFO, "In UnpackDir(%s, %s)", dir, dest);

  if (!ReadDir(dir, &ArcFEList, IsArc)) {
    LogWrite(1, SYSTEMERR, "Failed to read directory \"%s\"", dir);
    LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));
    return (FALSE);
  }

  LogWrite(2, TOSSINGINFO, "Unpacking arcmail bundles in %s...", dir);

  SortFEList(&ArcFEList);

  for (fe = (struct FileEntry *) ArcFEList.First; fe; fe = fe->Next) {
    MakeFullPath(dir, fe->Name, buf, 200);

    if (fe->Size == 0) {
      LogWrite(1, TOSSINGINFO, "Deleting zero length bundle %s", fe->Name);
      unlink(buf);
      continue;
    }

    if (!(tmppacker = (struct Packer *) DetectPacker(buf))) {
      LogWrite(1, TOSSINGINFO, "Failed to recognize archive type of %s", fe->Name);
      BadFile(buf);
      continue;
    }

    printf("\n");
    LogWrite(2, TOSSINGINFO, "Unarchiving %s using %s", fe->Name, tmppacker->Name);
    printf("\n");

    /* TODO ``UNPACKMASK *.[Pp][Kk][Tt]'' config keyword */
    ExpandPacker(tmppacker->Unpacker, buf2, 200, buf, "");

    LogWrite(6, DEBUG, "Executing `%s'", buf2);
    arcres = ChDirExecute(dest, buf2, &arcrc);
    printf("\n");

    if (arcres == -1) {
      LogWrite(1, SYSTEMERR, "Can't unpack %s into \"%s\"", fe->Name, dest);
      exitprg = TRUE; /* XXX no need */
      jbFreeList(&ArcFEList);
      return (FALSE);
    }

    if (arcres || arcrc) {
      if (arcres)
        LogWrite(1, SYSTEMERR, "Unarchiving failed: %lu", arcrc);
      else
        LogWrite(1, SYSTEMERR, "Unarchiving failed");
      BadFile(buf);
      continue;
    }

    unlink(buf);
  }

  jbFreeList(&ArcFEList);

  return (TRUE);
}

bool TossDir(uchar * dir, bool no_security, bool no_echomail)
{
  struct FileEntry *fe;
  struct jbList PktFEList;
  uchar buf[200];

  LogWrite(3, ACTIONINFO, "Tossing packets in %s...", dir);

  /* Search for pkt files */
  if (!ReadDir(dir, &PktFEList, IsPkt)) {
    LogWrite(1, SYSTEMERR, "Failed to read directory \"%s\"", dir);
    LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno));

    return (FALSE);
  }

  SortFEList(&PktFEList);

  if (nomem) {
    jbFreeList(&PktFEList);
    return (FALSE);
  }

  /* Process pkt files */
  for (fe = (struct FileEntry *) PktFEList.First; fe; fe = fe->Next) {
    MakeFullPath(dir, fe->Name, buf, 200);

    if (!ReadPkt(buf, fe, HandleMessage, no_security, no_echomail)) {
      jbFreeList(&PktFEList);
      return (FALSE);
    }

    unlink(buf);
  }

  jbFreeList(&PktFEList);

  return TRUE;
}


syntax highlighted by Code2HTML, v. 0.9.1