/********************************************************
 * File: mb_jam.c
 * Created at Sun Jan 28 22:10:30 MSK 2001 by raorn // raorn@binec.ru
 * JAM support
 * $Id: mb_jam.c,v 1.23 2002/02/11 13:25:30 raorn Exp $
 *******************************************************/
#include "crashecho.h"
#ifdef MSGBASE_JAM

#define MIN(a,b)  ((a)<(b)? (a):(b))

struct openbase {
  ulong lastuse;
  s_JamBase *Base_PS;
  struct jam_Area *area;
};

struct jam_Area {
  struct jam_Area *Next;
  struct Area *area;
  s_JamBase *Base_PS;
  ulong BaseNum;
  ulong OldNum;
  ulong OldHighWater;
  ulong HighWater;
  bool newmsg;
};

struct jbList jam_AreaList;
struct openbase *jam_openbases;

ulong jam_lastnum;
long jam_utcoffset;

s_JamBase *jam_openbase(struct jam_Area *area)
{
  int c;
  struct openbase *thisbase;
  mode_t oldumask;

  /* See if that area is already open */
  for (c = 0; c < config.cfg_jam_MaxOpen; c++)
    if (jam_openbases[c].area == area && jam_openbases[c].lastuse) {
      jam_openbases[c].lastuse = jam_lastnum++;
      return (jam_openbases[c].Base_PS);
    }

  /* We must open it now */
  /* Try to get an empty slot */
  thisbase = NULL;

  for (c = 0; c < config.cfg_jam_MaxOpen && !thisbase; c++)
    if (jam_openbases[c].lastuse == 0)
      thisbase = &jam_openbases[c];

  /* Otherwise, remove a slot that hasn't been used for a long time */
  if (!thisbase) {
    thisbase = &jam_openbases[0];

    for (c = 0; c < config.cfg_jam_MaxOpen; c++)
      if (jam_openbases[c].lastuse < thisbase->lastuse)
        thisbase = &jam_openbases[c];

    thisbase->lastuse = 0;
    JAM_CloseMB(thisbase->Base_PS);
  }

  /* Open area */
  if (JAM_OpenMB(area->area->Path, &thisbase->Base_PS)) {
    LogWrite(2, SYSTEMINFO, "Creating JAM messagebase \"%s\"", area->area->Path);

    oldumask = umask(config.cfg_MsgbaseUmask);
    if (JAM_CreateMB(area->area->Path, 1, &thisbase->Base_PS)) {
      umask(oldumask);
      LogWrite(1, SYSTEMERR, "Failed to create JAM messagebase \"%s\"", area->area->Path);
      return (NULL);
    }
    umask(oldumask);
  }

  /* Set the rest */
  thisbase->lastuse = jam_lastnum++;
  thisbase->area = area;

  return (thisbase->Base_PS);
}

struct jam_Area *jam_getarea(struct Area *area)
{
  struct jam_Area *ja;
  ulong num;
  s_JamBaseHeader Header_S;

  /* Check if area already exists */
  for (ja = (struct jam_Area *) jam_AreaList.First; ja; ja = ja->Next)
    if (ja->area == area) {
      if (!(ja->Base_PS = jam_openbase(ja)))
        return (NULL);

      return (ja);
    }

  /* This is the first time we use this area */
  if (!(ja = calloc(1, sizeof(struct jam_Area)))) {
    nomem = TRUE;
    return (FALSE);
  }

  jbAddNode(&jam_AreaList, (struct jbNode *) ja);
  ja->area = area;

  if (!(ja->Base_PS = jam_openbase(ja)))
    return (NULL);

  if (JAM_GetMBSize(ja->Base_PS, &num)) {
    LogWrite(1, TOSSINGERR, "Failed to get size of JAM area \"%s\"", area->Path);
    return (NULL);
  }

  ja->OldNum = num;

  if (JAM_ReadMBHeader(ja->Base_PS, &Header_S)) {
    LogWrite(1, TOSSINGERR, "Failed to read header of JAM area \"%s\"", area->Path);
    return (NULL);
  }

  ja->BaseNum = Header_S.BaseMsgNum;

  ja->OldHighWater = 0;
  ja->HighWater = 0;

  return (ja);
}

void jam_gethighwater(struct jam_Area *ja)
{
  uchar buf[200];
  FILE *fh;
  ulong num;

  snprintf(buf, 200, "%s.cmhw", ja->area->Path);

  if ((fh = fopen(buf, "rb"))) {
    if (fread(&num, sizeof(ulong), 1, fh)) {
      ja->HighWater = num;
      ja->OldHighWater = num;
    }

    fclose(fh);
  }
}

void jam_writehighwater(struct jam_Area *ja)
{
  uchar buf[200];
  FILE *fh;
  ulong num;
  mode_t oldumask;

  snprintf(buf, 200, "%s.cmhw", ja->area->Path);

  num = ja->HighWater;

  oldumask = umask(config.cfg_MsgbaseUmask);
  if ((fh = fopen(buf, "wb"))) {
    fwrite(&num, sizeof(ulong), 1, fh);
    fclose(fh);
  }
  umask(oldumask);
}

bool jam_beforefunc(void)
{
  time_t t1, t2;
  struct tm *tp;

  jbNewList(&jam_AreaList);

  if (config.cfg_jam_MaxOpen == 0)
    config.cfg_jam_MaxOpen = 5;

  if (!(jam_openbases=calloc(1, config.cfg_jam_MaxOpen * sizeof(struct openbase)))) {
    nomem = TRUE;
    return (FALSE);
  }

  /* Some timezone tricks */
  t1 = time(NULL);
  tp = gmtime(&t1);
  tp->tm_isdst = -1;
  t2 = mktime(tp);
  jam_utcoffset = t2 - t1;

  jam_lastnum = 1;

  return (TRUE);
}

bool jam_afterfunc(bool success)
{
  int c;
  struct jam_Area *ja;

  if (success && (config.cfg_jam_Flags & CFG_JAM_HIGHWATER))
    for (ja = (struct jam_Area *) jam_AreaList.First; ja; ja = ja->Next)
      if (ja->HighWater != ja->OldHighWater)
        jam_writehighwater(ja);

  for (c = 0; c < config.cfg_jam_MaxOpen; c++)
    if (jam_openbases[c].lastuse)
      JAM_CloseMB(jam_openbases[c].Base_PS);

  free(jam_openbases);

  if (success && config.cfg_jam_FlagsDir[0]) {
    FILE *fh;
    uchar buf[100];

    MakeFullPath(config.cfg_jam_FlagsDir, "import.jam", buf, 100);

    if((fh=fopen(buf, "ab")) == NULL){
      fprintf(stderr, "Failed to open %s\n", buf);
      fprintf(stderr, "Error: %s\n", strerror(errno));
      return (FALSE);
    }

    for (ja = (struct jam_Area *) jam_AreaList.First; ja; ja = ja->Next)
      if (ja->newmsg)
        fprintf(fh, "%s\n", ja->area->Tagname);

    fclose(fh);
  }

  jbFreeList(&jam_AreaList);

  return (TRUE);
}

bool jam_nomem;

void jam_addfield(s_JamSubPacket * SubPacket_PS, ulong fieldnum,
                  uchar * fielddata)
{
  s_JamSubfield Subfield_S;

  Subfield_S.LoID = fieldnum;
  Subfield_S.HiID = 0;
  Subfield_S.DatLen = strlen(fielddata);
  Subfield_S.Buffer = fielddata;

  if (JAM_PutSubfield(SubPacket_PS, &Subfield_S) == JAM_NO_MEMORY)
    jam_nomem = TRUE;
}

struct flag {
  uchar *name;
  ulong jamflagbit;
  ulong fidoflagbit;
};

struct flag jam_flagarray[] = {
  {"PVT", MSG_PRIVATE, FLAG_PVT},
  {"HLD", MSG_HOLD, FLAG_HOLD},
  {"CRA", MSG_CRASH, FLAG_CRASH},
  {"K/S", MSG_KILLSENT, FLAG_KILLSENT},
  {"SNT", MSG_SENT, FLAG_SENT},
  {"RCV", MSG_READ, FLAG_RECD},
  {"A/S", MSG_ARCHIVESENT, 0,},
  {"DIR", MSG_DIRECT, 0},
/*{"ZON", MSG_GATE, 0},*/
/*{"HUB", 0, 0},*/
  {"FIL", MSG_FILEATTACH, FLAG_FILEATTACH},
  {"FRQ", MSG_FILEREQUEST, FLAG_FILEREQ},
  {"IMM", MSG_IMMEDIATE, 0},
/*{"XMA", 0, 0},*/
  {"KFS", MSG_KILLFILE, 0},
  {"TFS", MSG_TRUNCFILE, 0},
  {"LOK", MSG_LOCKED, 0},
  {"RRQ", MSG_RECEIPTREQ, FLAG_RREQ},
  {"CFM", MSG_CONFIRMREQ, 0},
/*{"HIR", 0, 0},*/
/*{"COV", 0, 0},*/
/*{"SIG", 0, 0},*/
/*{"LET", 0, 0},*/
/*{"FAX", 0, 0},*/
  {"FPU", MSG_FPU, 0},
  {"", MSG_LOCAL, FLAG_LOCAL},
  {"", MSG_INTRANSIT, FLAG_INTRANSIT},
  {"", MSG_ORPHAN, FLAG_ORPHAN},
  {NULL, 0, 0}
};

ulong mmAttr2JAM(ulong mm_attr)
{
  int c;
  ulong jam_attr = 0;

  for (c = 0; jam_flagarray[c].name; c++)
    if (mm_attr & jam_flagarray[c].fidoflagbit)
      jam_attr |= jam_flagarray[c].jamflagbit;

  return jam_attr;
}

/*ulong JAM2mmAttr(ulong jam_attr)*/
/*{*/
/*}*/

ulong jam_findflag(uchar * name)
{
  int c;

  for (c = 0; jam_flagarray[c].name; c++)
    if (stricmp(jam_flagarray[c].name, name) == 0)
      return (jam_flagarray[c].jamflagbit);

  return (0);
}

bool jam_importfunc(struct MemMessage * mm, struct Area * area)
{
  struct TextChunk *chunk;
  struct Path *pathnode;
  struct jam_Area *ja;
  s_JamSubPacket *SubPacket_PS;
  s_JamMsgHeader Header_S;
  uchar buf[100], domain[20], newflags[100], flag[10];
  ulong c, f, jbcpos, linebegin, linelen;
  uchar *msgtext;
  ulong msgsize, msgpos;
  int res;
  bool hasorigin;
  struct Node4D n4d;

  /* Get an area to write to */
  if (!(ja = jam_getarea(area)))
    return (FALSE);

  /* Start import */
  ja->newmsg = TRUE;

  JAM_ClearMsgHeader(&Header_S);

  if (!(SubPacket_PS = JAM_NewSubPacket())) {
    nomem = TRUE;
    return (FALSE);
  }

  /* Allocate memory to store message text in */
  msgpos = 0;
  msgsize = 0;
  msgtext = NULL;

  for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next)
    if (chunk->Data)
      msgsize += strlen(chunk->Data);

  if (msgsize != 0) {
    if (!(msgtext = malloc(msgsize))) {
      LogWrite(1, SYSTEMERR, "Out of memory");
      JAM_DelSubPacket(SubPacket_PS);
      return (FALSE);
    }
  }

  /* Do header */
  Header_S.DateProcessed = time(NULL);
  Header_S.DateWritten = FidoToTime(mm->DateTime);

  /* Damned time zones... dates should be in local time in JAM */
  Header_S.DateProcessed -= jam_utcoffset;
  Header_S.DateWritten -= jam_utcoffset;

  Header_S.Cost = mm->Cost;
  Header_S.MsgIdCRC = JAM_Crc32(mm->MSGID, strlen(mm->MSGID));
  Header_S.ReplyCRC = JAM_Crc32(mm->REPLY, strlen(mm->REPLY));

  /* Add header fields */
  if (mm->From[0])
    jam_addfield(SubPacket_PS, JAMSFLD_SENDERNAME, mm->From);

  if (mm->To[0])
    jam_addfield(SubPacket_PS, JAMSFLD_RECVRNAME, mm->To);

  if (mm->Subject[0])
    jam_addfield(SubPacket_PS, JAMSFLD_SUBJECT, mm->Subject);

  /* Addresses in netmail */
  if (mm->Area[0] == 0) {
    Print4D(&mm->OrigNode, buf, 100);
    jam_addfield(SubPacket_PS, JAMSFLD_OADDRESS, buf);

    Print4D(&mm->DestNode, buf, 100);
    jam_addfield(SubPacket_PS, JAMSFLD_DADDRESS, buf);
  }

  /* Header attributes */
  Header_S.Attribute = mmAttr2JAM(mm->Attr);

  if (mm->Attr & FLAG_FILEATTACH) {
    Header_S.Attribute |= MSG_FILEATTACH;

    c = 0;

    while (mm->Subject[c] != 0) {
      f = 0;
      while (mm->Subject[c] != 0 && mm->Subject[c] != 32 && mm->Subject[c] != ',' && f < 80)
        buf[f++] = mm->Subject[c++];

      buf[f] = 0;

      while (mm->Subject[c] == 32 || mm->Subject[c] == ',')
        c++;

      if (buf[0] != 0)
        jam_addfield(SubPacket_PS, JAMSFLD_ENCLFILE, buf);
    }
  }

  if (mm->Attr & FLAG_FILEREQ) {
    Header_S.Attribute |= MSG_FILEREQUEST;

    c = 0;

    while (mm->Subject[c] != 0) {
      f = 0;
      while (mm->Subject[c] != 0 && mm->Subject[c] != 32 && mm->Subject[c] != ',' && f < 80)
        buf[f++] = mm->Subject[c++];

      buf[f] = 0;

      while (mm->Subject[c] == 32 || mm->Subject[c] == ',')
        c++;

      if (buf[0] != 0)
        jam_addfield(SubPacket_PS, JAMSFLD_ENCLFREQ, buf);
    }
  }

  /* Echomail/netmail attribute */
  if (mm->Area[0] == 0)
    Header_S.Attribute |= MSG_TYPENET;
  else
    Header_S.Attribute |= MSG_TYPEECHO;

  /* Separate kludges from text */
  hasorigin = FALSE;

  if (msgsize != 0)
    for (chunk = (struct TextChunk *) mm->TextChunks.First; chunk; chunk = chunk->Next)
      if (chunk->Data)
        for (c = 0; chunk->Data[c];) {
          linebegin = msgpos;

          while (chunk->Data[c] != 13 && chunk->Data[c]) {
            if (chunk->Data[c] != 10)
              msgtext[msgpos++] = chunk->Data[c];

            c++;
          }

          if (chunk->Data[c] == 13 && chunk->Data[c])
            msgtext[msgpos++] = chunk->Data[c++];

          linelen = msgpos - linebegin;

          if (linelen != 0) {
            if (linelen >= 5 && strncmp(&msgtext[linebegin], "\001PID:", 5) == 0) {
              mystrncpy(buf, &msgtext[linebegin + 5], MIN(100, linelen - 5));
              stripleadtrail(buf);
              jam_addfield(SubPacket_PS, JAMSFLD_PID, buf);
              msgpos = linebegin;
            } else if (linelen >= 7 && strncmp(&msgtext[linebegin], "\001MSGID:", 7) == 0) {
              mystrncpy(buf, &msgtext[linebegin + 7], MIN(100, linelen - 7));
              stripleadtrail(buf);
              jam_addfield(SubPacket_PS, JAMSFLD_MSGID, buf);
              msgpos = linebegin;
            } else if (linelen >= 7 && strncmp(&msgtext[linebegin], "\001REPLY:", 7) == 0) {
              mystrncpy(buf, &msgtext[linebegin + 7], MIN(100, linelen - 7));
              stripleadtrail(buf);
              jam_addfield(SubPacket_PS, JAMSFLD_REPLYID, buf);
              msgpos = linebegin;
            } else if (linelen > 5 && strncmp(&msgtext[linebegin], "\001Via ", 5) == 0) {
              mystrncpy(buf, &msgtext[linebegin + 5], MIN(100, linelen - 5));
              stripleadtrail(buf);
              jam_addfield(SubPacket_PS, JAMSFLD_TRACE, buf);
              msgpos = linebegin;
            } else if (linelen >= 7 && strncmp(&msgtext[linebegin], "\001FLAGS:", 7) == 0) {
              mystrncpy(buf, &msgtext[linebegin + 7], MIN(100, linelen - 7));
              stripleadtrail(buf);

              jbcpos = 0;
              newflags[0] = 0;

              while (jbstrcpy(flag, buf, 10, &jbcpos)) {
                ulong flagbit;

                if ((flagbit = jam_findflag(flag))) {
                  Header_S.Attribute |= flagbit;
                } else {
                  strcat(newflags, flag);
                  strcat(newflags, " ");
                }
              }

              stripleadtrail(newflags);

              if (newflags[0] != 0)
                jam_addfield(SubPacket_PS, JAMSFLD_FLAGS, newflags);

              msgpos = linebegin;
            } else if (linelen >= 5 && strncmp(&msgtext[linebegin], "\001INTL", 5) == 0) {
              /* Remove this kludge */
              msgpos = linebegin;
            } else if (linelen >= 5 && strncmp(&msgtext[linebegin], "\001TOPT", 5) == 0) {
              /* Remove this kludge */
              msgpos = linebegin;
            } else if (linelen >= 5 && strncmp(&msgtext[linebegin], "\001FMPT", 5) == 0) {
              /* Remove this kludge */
              msgpos = linebegin;
            } else if (msgtext[linebegin] == 1) {
              mystrncpy(buf, &msgtext[linebegin + 1], MIN(100, linelen - 1));
              stripleadtrail(buf);
              jam_addfield(SubPacket_PS, JAMSFLD_FTSKLUDGE, buf);
              msgpos = linebegin;
            } else {
              if (!hasorigin && linelen > 11 && strncmp(&msgtext[linebegin], " * Origin: ", 11) == 0) {
                mystrncpy(buf, &msgtext[linebegin + 11], MIN(100, linelen - 11));
                stripleadtrail(buf);

                if (ExtractAddress(buf, &n4d, domain)) {
                  hasorigin = TRUE;

                  if (n4d.Zone == 0)
                    n4d.Zone = mm->PktOrig.Zone;
                  Print4D(&n4d, buf, 100);
                  jam_addfield(SubPacket_PS, JAMSFLD_OADDRESS, buf);
                }
              }
            }
          }
        }

  /* Seen-by */
  if ((area->Flags & AREA_IMPORTSEENBY) && mm->Area[0]) {
    uchar *buf;
    ulong c, d;

    if ((buf = mmMakeSeenByBuf(&mm->SeenBy))) {
      c = 0;

      while (buf[c] != 0) {
        d = c;

        while (buf[d] != 0 && buf[d] != 13)
          d++;

        if (buf[d] == 13) {
          buf[d++] = 0;
          jam_addfield(SubPacket_PS, JAMSFLD_SEENBY2D, &buf[c + 9]);
        }

        c = d;
      }
    }

    free(buf);
  }

  /* Path */
  for (pathnode = (struct Path *) mm->Path.First; pathnode; pathnode = pathnode->Next)
    for (c = 0; c < pathnode->Paths; c++)
      jam_addfield(SubPacket_PS, JAMSFLD_PATH2D, pathnode->Path[c]);

  if (jam_nomem) {
    LogWrite(1, SYSTEMERR, "Out of memory");
    JAM_DelSubPacket(SubPacket_PS);
    if (msgsize)
      free(msgtext);
    return (FALSE);
  }

  /* Write message */
  if (JAM_LockMB(ja->Base_PS, 10)) {
    LogWrite(1, SYSTEMERR, "Timeout when trying to lock JAM messagebase \"%s\"", area->Path);
    JAM_DelSubPacket(SubPacket_PS);
    if (msgsize)
      free(msgtext);
    return (FALSE);
  }

  res = JAM_AddMessage(ja->Base_PS, &Header_S, SubPacket_PS, msgpos == 0 ? NULL : msgtext, msgpos);

  JAM_UnlockMB(ja->Base_PS);
  JAM_DelSubPacket(SubPacket_PS);
  if (msgsize)
    free(msgtext);

  if (res) {
    LogWrite(1, SYSTEMERR, "Failed to write message to JAM messagebase \"%s\"", area->Path);
    return (FALSE);
  }

  return (TRUE);
}

void jam_makekludge(struct MemMessage *mm, uchar * pre, uchar * data, ulong len)
{
  uchar *buf;

  if (!(buf = malloc(strlen(pre) + len + 10))) /* A few bytes extra */
    return;

  strcpy(buf, pre);
  if (len && data)
    mystrncpy(&buf[strlen(buf)], data, len + 1);
  strcat(buf, "\015");
  mmAddLine(mm, buf, MM_ADD);

  free(buf);
}

/*struct ViaLine {*/
/*  struct ViaLine *Next;*/
/*  uchar *buf;*/
/*};*/

bool jam_ExportJAMNum(struct Area *area, ulong num, bool(*acceptfunc) (struct MemMessage *mm), bool(*handlefunc) (struct MemMessage * mm))
{
  struct MemMessage *mm;
  struct jam_Area *ja;
  uchar *msgtext;
/*  struct jbList ViaList;*/
/*  struct ViaLine *tmpvia;*/
  uchar buf[200], domain[20];
  int res, c;
  s_JamSubPacket *SubPacket_PS;
  s_JamMsgHeader Header_S;
  s_JamSubfield *Field_PS;
  struct Node4D n4d;
  bool hasaddr;
  uchar flagsbuf[200], filesubject[200];
/*  ushort oldattr;*/
  bool gotarea = FALSE, gotfrom = FALSE;

  LogWrite(6, SYSTEMINFO, "In jam_ExportJAMNum(\"%s\", %d, ...)", area->Tagname, num);

  /* Open the area */
  if (!(ja = jam_getarea(area)))
    return (FALSE);

  memset(&Header_S, 0, sizeof(s_JamMsgHeader));
  res = JAM_ReadMsgHeader(ja->Base_PS, num - ja->BaseNum, &Header_S, &SubPacket_PS);

  if (res) {
    if (res == JAM_NO_MESSAGE) {
      /* Message no longer exists */
      LogWrite(6, SYSTEMINFO, "In jam_ExportJAMNum(): No message");
      return (TRUE);
    } else {
      LogWrite(1, TOSSINGERR, "Failed to read message #%lu in JAM messagebase \"%s\"", num, area->Path);
      return (TRUE);
    }
  }

  /* Check if deleted or locked */
  if (Header_S.Attribute & MSG_DELETED || Header_S.Attribute & MSG_LOCKED) {
    /* Message deleted or locked */
    LogWrite(6, SYSTEMINFO, "In jam_ExportJAMNum(): Deleted or locked");
    JAM_DelSubPacket(SubPacket_PS);
    return (TRUE);
  }

  /* Allocate message structure */
  if (!(mm = mmAlloc())) {
    JAM_DelSubPacket(SubPacket_PS);
    return (FALSE);
  }

  if (area->AreaType == AREATYPE_NETMAIL)
    mm->Area[0]=0;
  else
    strcpy(mm->Area, area->Tagname);

  mm->msgnum = num;

  /* Subfields */
  flagsbuf[0] = 0;
  filesubject[0] = 0;
  hasaddr = FALSE;
/*  jbNewList(ViaList);*/

  for (Field_PS = JAM_GetSubfield(SubPacket_PS); Field_PS; Field_PS = JAM_GetSubfield(NULL)) {
    switch (Field_PS->LoID) {
    case JAMSFLD_OADDRESS:
      mystrncpy(buf, Field_PS->Buffer, Field_PS->DatLen + 1);

      if (Parse5D(buf, &n4d, domain)) {
        mm->OrigNode.Zone = n4d.Zone;
        mm->OrigNode.Net = n4d.Net;
        mm->OrigNode.Node = n4d.Node;
        mm->OrigNode.Point = n4d.Point;
      }
      break;

    case JAMSFLD_DADDRESS:
      mystrncpy(buf, Field_PS->Buffer, Field_PS->DatLen + 1);

      if (hasaddr) {
        LogWrite(1, TOSSINGERR, "Warning: Multiple DADDRESS not supported by CrashEcho");
      } else {
        hasaddr = TRUE;

        if (Parse5D(buf, &n4d, domain)) {
          mm->DestNode.Zone = n4d.Zone;
          mm->DestNode.Net = n4d.Net;
          mm->DestNode.Node = n4d.Node;
          mm->DestNode.Point = n4d.Point;
        }
      }
      break;

    case JAMSFLD_SENDERNAME:
      mystrncpy(buf, Field_PS->Buffer, Field_PS->DatLen + 1);
      mystrncpy(mm->From, buf, 36);
      break;

    case JAMSFLD_RECVRNAME:
      mystrncpy(buf, Field_PS->Buffer, Field_PS->DatLen + 1);
      mystrncpy(mm->To, buf, 36);
      break;

    case JAMSFLD_MSGID:
      jam_makekludge(mm, "\001MSGID: ", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_REPLYID:
      jam_makekludge(mm, "\001REPLY: ", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_SUBJECT:
      mystrncpy(buf, Field_PS->Buffer, Field_PS->DatLen + 1);
      mystrncpy(mm->Subject, buf, 72);
      break;

    case JAMSFLD_PID:
      jam_makekludge(mm, "\001PID: ", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_TRACE:
      /* FIXME Add ^aVia's at the end of message */
      jam_makekludge(mm, "\001Via ", Field_PS->Buffer, Field_PS->DatLen);
      /* FIXME acceptfunc will be called before @Via appended */
/*      if ((tmpvia=calloc(1, sizeof(struct ViaList))) != NULL) {*/
/*        uchar *tmpbuf;*/

        /* Alloc Datlen + 5 (@Via) + 1 (CR) + 1 (NUL) bytes */
/*        if ((tmpbuf=calloc(1, Field_PS->DatLen+5+1+1))) {*/
/*          strcpy(tmpbuf, "\001Via ");*/
/*          memcpy(tmpbuf+5, Field_PS->Buffer, Field_PS->DatLen);*/
          /* tmpbuf already zeroed after calloc */
/*          strcat(tmpbuf, "\015");*/

/*          tmpvia->buf = tmpbuf;*/
/*          jbAddNode(ViaList, tmpvia);*/
/*        }*/
/*      }*/
      break;

    case JAMSFLD_ENCLFILE:
      if (filesubject[0])
        LogWrite(1, TOSSINGERR, "Warning: Multiple ENCLOSEDFILE not supported by CrashEcho");
      else
        mystrncpy(filesubject, Field_PS->Buffer, Field_PS->DatLen + 1);
      break;

    case JAMSFLD_ENCLFREQ:
      LogWrite(1, TOSSINGERR, "Warning: ENCLOSEDFREQ not supported by CrashEcho");
      break;

    case JAMSFLD_ENCLFWALIAS:
      LogWrite(1, TOSSINGERR, "Warning: ENCLOSEDFILEWALIAS not supported by CrashEcho");
      break;

    case JAMSFLD_ENCLFILEWC:
      LogWrite(1, TOSSINGERR, "Warning: ENCLOSEDFILEWCARD with wildcards not supported by CrashEcho");
      break;

    case JAMSFLD_ENCLINDFILE:
      LogWrite(1, TOSSINGERR, "Warning: ENCLOSEDINDIRECTFILE not supported by CrashEcho");
      break;

    case JAMSFLD_FTSKLUDGE:
      /*      if (nowdoing == DOING_TOSSBAD) {*/ /* } (to make vim hapy :-) */
      if (area->AreaType == AREATYPE_BAD) {
        ulong len;

        len = Field_PS->DatLen;
        if (!gotfrom && len > 5 && !strncmp(Field_PS->Buffer, "FROM:", 5)) {
          struct Node4D node;
          uchar buf2[100];

          mystrncpy(buf2, &Field_PS->Buffer[5], (len - 5 > 99 ? 99 : len - 5) + 1);
          stripleadtrail(buf2);

          if (Parse4D(buf2, &node))
            Copy4D(&mm->PktOrig, &node);

          /* Skip this kludge */
          gotfrom = TRUE;
          break;
        } else if (!gotarea && len > 5 && !strncmp(Field_PS->Buffer, "AREA:", 5)) {
          mystrncpy(mm->Area, &Field_PS->Buffer[5], (len - 5 > 79 ? 79 : len - 5) + 1);
          /* Strip spaces from area name... */
          stripleadtrail(mm->Area);
          gotarea = TRUE;
          /* ... and skip this kludge */
          break;
        } else if (len >= 7 && !strncmp(Field_PS->Buffer, "REASON:", 7))
          /* Just skip this kludge */
          break;
      }
      jam_makekludge(mm, "\001", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_SEENBY2D:
      jam_makekludge(mm, "SEEN-BY: ", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_PATH2D:
      jam_makekludge(mm, "\001PATH: ", Field_PS->Buffer, Field_PS->DatLen);
      break;

    case JAMSFLD_FLAGS:
      strcpy(flagsbuf, "\001FLAGS: ");
      mystrncpy(&flagsbuf[8], Field_PS->Buffer, Field_PS->DatLen + 1);
      /* Don't add until attributes from header has been added */
      break;
    }
  }

  if (filesubject[0]) {
    mm->Attr |= FLAG_FILEATTACH;
    mystrncpy(mm->Subject, filesubject, 72);
  }

  /* Message header */
  MakeFidoDate(Header_S.DateWritten + jam_utcoffset, mm->DateTime);
  mm->Cost = Header_S.Cost;

  for (c = 0; jam_flagarray[c].name; c++)
    if (Header_S.Attribute & jam_flagarray[c].jamflagbit) {
      if (jam_flagarray[c].fidoflagbit) {
        mm->Attr |= jam_flagarray[c].fidoflagbit;
      } else if (jam_flagarray[c].name[0] && strlen(flagsbuf) < 90) {
        if (flagsbuf[0] == 0)
          strcpy(flagsbuf, "\001FLAGS: ");
        else
          strcat(flagsbuf, " ");

        strcat(flagsbuf, jam_flagarray[c].name);
      }
    }

  if (flagsbuf[0]) {
    strcat(flagsbuf, "\015");
    mmAddLine(mm, buf, MM_KLUDGE);
  }

/*  oldattr = mm->Attr;*/

  /* Add own kludges */
  if (area->AreaType == AREATYPE_NETMAIL) {
    if (mm->OrigNode.Zone != mm->DestNode.Zone || (config.cfg_Flags & CFG_FORCEINTL)) {
      snprintf(buf, 200, "\001INTL %u:%u/%u %u:%u/%u\015", mm->DestNode.Zone,
              mm->DestNode.Net, mm->DestNode.Node, mm->OrigNode.Zone,
              mm->OrigNode.Net, mm->OrigNode.Node);

      mmAddLine(mm, buf, MM_HEAD);
    }

    if (mm->OrigNode.Point) {
      snprintf(buf, 200, "\001FMPT %u\015", mm->OrigNode.Point);
      mmAddLine(mm, buf, MM_HEAD);
    }

    if (mm->DestNode.Point) {
      snprintf(buf, 200, "\001TOPT %u\015", mm->DestNode.Point);
      mmAddLine(mm, buf, MM_HEAD);
    }
  }

  JAM_DelSubPacket(SubPacket_PS);

  if ((*acceptfunc) (mm)) {
    LogWrite(6, SYSTEMINFO, "In jam_ExportJAMNum(): Message accepted");
    /* Read message text */
    msgtext = NULL;

    if (Header_S.TxtLen) {
      if (!(msgtext = malloc(Header_S.TxtLen))) {
        nomem = TRUE;
        mmFree(mm);
        return (FALSE);
      }

      res = JAM_ReadMsgText(ja->Base_PS, Header_S.TxtOffset, Header_S.TxtLen, msgtext);

      if (res) {
        LogWrite(1, TOSSINGERR, "Failed to read message #%lu in JAM messagebase \"%s\"", num, area->Path);
        free(msgtext);
        mmFree(mm);
        return (FALSE);
      }
    }

    if (msgtext) {
      mmAddBuf(&mm->TextChunks, msgtext, Header_S.TxtLen, MM_ADD);
      free(msgtext);
    }

    if (!(*handlefunc) (mm)) {
      mmFree(mm);
      return (FALSE);
    }

    if (mm->Changed) {
      LogWrite(6, SYSTEMINFO, "In jam_ExportJAMNum(): Updating %d", num);
      /* Update attributes */
      Header_S.Attribute = mmAttr2JAM(mm->Attr);

      if (mm->Deleted)
        Header_S.Attribute |= MSG_DELETED;

      if (mm->Deleted && (config.cfg_jam_Flags & CFG_JAM_HARDDELETE)) {
        if (JAM_LockMB(ja->Base_PS, 10)) {
          LogWrite(1, SYSTEMERR, "Timeout when trying to lock JAM messagebase \"%s\"", area->Path);
          mmFree(mm);
          return (FALSE);
        }

        JAM_DeleteMessage(ja->Base_PS, num - ja->BaseNum);

        JAM_UnlockMB(ja->Base_PS);
      } else {
        Header_S.DateProcessed = time(NULL);
        Header_S.DateProcessed -= jam_utcoffset;

        if (JAM_LockMB(ja->Base_PS, 10)) {
          LogWrite(1, SYSTEMERR, "Timeout when trying to lock JAM messagebase \"%s\"", area->Path);
          mmFree(mm);
          return (FALSE);
        }

        JAM_ChangeMsgHeader(ja->Base_PS, num - ja->BaseNum, &Header_S);

        JAM_UnlockMB(ja->Base_PS);
      }
    }
  }

  mmFree(mm);
  return (TRUE);
}

/*bool jam_exportfunc(struct Area * area, bool(*handlefunc) (struct MemMessage * mm))*/
bool jam_scanfunc (struct Area * area, bool usehw, bool ignorehw, ulong max, struct jbList *msglist, bool(*acceptfunc) (struct MemMessage * mm), bool(*handlefunc) (struct MemMessage * mm))
{
  ulong start, end;
  struct jam_Area *ja;

  /* Open the area */
  if (!(ja = jam_getarea(area))) {
    if (nomem)
      return (FALSE);
    /* Area did not exist and could not be created. Go on anyway. */
    return (TRUE);
  }

  if (usehw && config.cfg_jam_Flags & CFG_JAM_HIGHWATER)
    jam_gethighwater(ja);

  /* ignorehw doesn't make any sense in JAM base */
  if (ja->HighWater)
    start = ja->HighWater + 1;
  else
    start = ja->BaseNum;

  if (start < ja->BaseNum)
    start = ja->BaseNum;

  if (max != 0 && ja->OldNum > max)
    start = ja->BaseNum + ja->OldNum - max;

  end = ja->BaseNum + ja->OldNum;

  if (msglist) {
    struct MsgEntry *tmpmsg;

    for (tmpmsg = (struct MsgEntry *) msglist->First; tmpmsg; tmpmsg = tmpmsg->Next) {
      if (tmpmsg->num < ja->BaseNum)
        /* Skip it... */
        continue;

      if (!jam_ExportJAMNum(area, tmpmsg->num, acceptfunc, handlefunc))
        return (FALSE);

      if (ctrlc)
        return (FALSE);
    }
  } else {
    while (start < end) {
      if (!jam_ExportJAMNum(area, start, acceptfunc, handlefunc))
        return (FALSE);

      if (ctrlc)
        return (FALSE);

      start++;
    }
  }

  if (usehw)
    ja->HighWater = end - 1;

  return (TRUE);
}

/*{*/
/*  ulong start;*/
/*  struct jam_Area *ja;*/

  /* Open the area */
/*  if (!(ja = jam_getarea(area)))*/
/*    return (FALSE);*/

/*  start = ja->BaseNum;*/

/*  if (max != 0 && ja->OldNum > max)*/
/*    start = ja->BaseNum + ja->OldNum - max;*/

/*  while (start < ja->BaseNum + ja->OldNum) {*/
/*    if (!jam_ExportJAMNum(area, start, handlefunc))*/
/*      return (FALSE);*/

/*    if (ctrlc)*/
/*      return (FALSE);*/

/*    start++;*/
/*  }*/

/*  return (TRUE);*/
/*}*/
#endif


syntax highlighted by Code2HTML, v. 0.9.1