// --------------------------------------------------------------------
//        S q b a s e . c p p 
//                                                                     
//        Fido messages tracker                            
//        Message bases. Squish and JAM base format.
// --------------------------------------------------------------------
//        Copyright (c) 1998-2000 by Fyodor Ustinov                         
//                                FIDONet 2:5020/79                      
//                                                                     
//        All rights reserved.                                         
// --------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include <smapi/msgapi.h>
#include "constant.hpp"
#include "vars.hpp"
#include "log.hpp"
#include "nodelist.hpp"
#include "utils.hpp"
#include "msg.hpp"
#include "msgbase.hpp"
#include "sqbase.hpp"
#include "aka.hpp"



static time_t dosftime(struct _stamp &time) {
struct tm mytime;

memset(&mytime, 0, sizeof(struct tm)); /* added by VRP 20000731 */
mytime.tm_mday=time.date.da;
mytime.tm_mon =time.date.mo-1;
mytime.tm_year=time.date.yr+80;
mytime.tm_hour=time.time.hh;
mytime.tm_min =time.time.mm;
mytime.tm_sec =time.time.ss*2;

return mktime(&mytime);
}

static void dosttime(struct _stamp &time, time_t t) {
struct tm *mytime;

   mytime = localtime(&t);
time.date.da = mytime->tm_mday;
time.date.mo = mytime->tm_mon + 1;
time.date.yr = mytime->tm_year - 80;
time.time.hh = mytime->tm_hour;
time.time.mm = mytime->tm_min;
time.time.ss = mytime->tm_sec / 2;

}


SQUISH::SQUISH() {
   CHP = 515;
   DirName = NULL;
   MsgNum = 0;
   tMsgNum = 0;
   MaxNum = 0;
   Area = NULL;
   PrevIsDel = FALSE;
}

SQUISH::SQUISH(char _bType) {
   CHP = 515;
   DirName = NULL;
   MsgNum = 0;
   tMsgNum = 0;
   MaxNum = 0;
   Area = NULL;
   PrevIsDel = FALSE;
   bType = _bType;
}

SQUISH::~SQUISH() {
   Clear();
   CHP = 516;
}
// ---------------------------

void SQUISH::Clear(void) {
   CHP = 51700;
   if (DirName != NULL) {
      CHP = 51701;
      free(DirName);
      CHP = 51702;
      DirName = NULL;
   }
   CHP = 51703;
   if (Area != NULL) {
      CHP = 51704;
      MsgCloseArea(Area);
      CHP = 51705;
      Area = NULL;
   }
   MsgNum = 0;
   tMsgNum = 0;
   MaxNum = 0;
   PrevIsDel = FALSE;
   CHP = 51706;
}

// ---------------------------

int SQUISH::Open(void) {
int TypeOfBase;

   if (bType == '$') {
      TypeOfBase = (MSGTYPE_SQUISH | MSGTYPE_NOTH);
   } else {
      TypeOfBase = (MSGTYPE_JAM | MSGTYPE_NOTH);
   }
   CHP = 51710;
   Area = MsgOpenArea((byte *)DirName+1,MSGAREA_NORMAL,TypeOfBase);
   if (Area == NULL) {
      Log.Level(LOGE) << "SQUISH.Open: Unable to open message base '" << DirName
                      << "', code: "  << (uint) msgapierr 
                      << ", errno: " << errno << EOL;
      return FALSE;
   }
   return TRUE;
}
// ---------------------------

int SQUISH::Close(void) {
   CHP = 51720;
   if (Area != NULL) {
      MsgCloseArea(Area);
      Area = NULL;
   }
   return TRUE;
}   
// ---------------------------

int SQUISH::Set(char *Dir, int BaseType) {
int TypeOfBase;

   CHP = 518;
   BaseType = BaseType;
   CHP = 51801;
   Clear();
   CHP = 51802;
   if (*Dir != '$' && *Dir != '@') {
      return FALSE;
   }
   if (bType == '$') {
      TypeOfBase = (MSGTYPE_SQUISH | MSGTYPE_NOTH);
   } else {
      TypeOfBase = (MSGTYPE_JAM | MSGTYPE_NOTH);
   }
   CHP = 51803;
   msgapierr = 0;
   if (CreateMissingBase) {
      CHP = 51804;
      Area = MsgOpenArea((byte *)Dir+1,MSGAREA_CRIFNEC,TypeOfBase);
      CHP = 51805;
      if (Area == NULL) {
         Log.Level(LOGD) << "SQUISH.Set: Unable to create message base '" << Dir 
                         << "', code: "  << (uint) msgapierr 
                         << ", errno: " << errno << EOL;
      }
   } else {
      CHP = 51806;
      Area = MsgOpenArea((byte *)Dir+1,MSGAREA_NORMAL,TypeOfBase);
      CHP = 51807;
      if (Area == NULL) {
         Log.Level(LOGD) << "SQUISH.Set: Unable to open message base '" << Dir 
                         << "', code: "  << (uint) msgapierr 
                         << ", errno: " << errno << EOL;
      }
   }
   if (Area == NULL) {
      return FALSE;
   }
   CHP = 51808;
   MsgCloseArea(Area);
   CHP = 51809;
   Area = NULL;
   if (MsgValidate(TypeOfBase,(byte *)Dir+1) != 1) {
      return FALSE;
   }
   CHP = 51810;
   DirName = strdup(Dir);
   CHP = 51811;
   CheckMem(DirName);
   CHP = 51812;
   return TRUE;
}

// ---------------------------

int SQUISH::Next(void) {
HMSG fh;

   Log.Level(LOGD) << "(1) SQUISH.Next: MsgNum == " << MsgNum
                   << " tMsgNum == "  << tMsgNum << EOL;
   CHP = 519;
   if (Area == NULL) {
      return FALSE;
   }
   CHP = 520;
   if (PrevIsDel == FALSE) {
      MsgNum ++;
   } else {
      PrevIsDel = FALSE;
   }
   tMsgNum++;

   CHP = 520001;
   while (MsgNum <= MsgGetHighMsg(Area)) {
      Log.Level(LOGD) << "(W) SQUISH.Next: MsgNum == " << MsgNum
                      << " tMsgNum == "  << tMsgNum << EOL;
      CHP = 520002;
      fh = MsgOpenMsg(Area,MOPEN_READ,MsgNum);
      CHP = 520003;
      if (fh != NULL) {
         CHP = 520004;
         MsgCloseMsg(fh);
         CHP = 520005;
         return TRUE;
      }
      CHP = 520006;
      if (msgapierr != 0 && msgapierr != MERR_NOENT) {
         return TRUE;
      }
      CHP = 520007;
      MsgNum++;
      CHP = 520008;
   }

   CHP = 521;
   return FALSE;
}

// ---------------------------

int SQUISH::Rewind(void) {
   if (Area == NULL) {
//      Log.Level(LOGD) << "Base not opened!!! " << EOL;
      CHP = 524;
      return FALSE;
   }
   CHP = 522;
   Log.Level(LOGD) << "-------- Rewind base --------" << EOL;
   Log.Level(LOGD) << "Base name: " << DirName <<  EOL;
   CHP = 523;
   CHP = 525;
   Log.Level(LOGD) << "High message number: " << (int) MsgGetHighMsg(Area) << EOL;
   if (MsgGetHighMsg(Area) == 0) {
      CHP = 526;
      return FALSE;
   }
   MsgNum = 0;
   tMsgNum = 0;
   PrevIsDel = FALSE;
   CHP = 527;
   return Next();
}

// ---------------------------

int SQUISH::Renumber(void) {
   CHP = 528;
   return TRUE;   
}

// ---------------------------

int SQUISH::DeleteMsg(void) {
   CHP = 530;
   if (MsgKillMsg(Area,MsgNum) != 0) {
      CHP = 531;
      Log.Level(LOGD) << "SQUISH.DeleteMsg: Unable to delete message '" << MessageName() 
                      << "', code: "  << (uint) msgapierr 
                      << ", errno: " << errno << EOL;
      return FALSE;
   }
//   if (bType == '$') { // Squish base. No need move to next message
      PrevIsDel = TRUE;
//   }
   CHP = 532;
   return TRUE;
}

// ---------------------------

char *SQUISH::ReadToMem(void) {
   CHP = 533;
   CHP = 534;
   return NULL;
}

// ---------------------------

char *SQUISH::MessageName(void) {
static char Buff[2048];

   CHP = 535;
   sprintf(Buff,"%s#%u(%u)",DirName,tMsgNum,MsgNum);
   CHP = 536;
   return Buff;
}

// ---------------------------

int SQUISH::WriteFromMem(char *Buff) {
   CHP = 537;
   CHP = 538;
   Buff = Buff;
   return FALSE;
}

// ---------------------------

int SQUISH::ReadMsg(cMSG &m) {
HMSG fh;
XMSG rm;
char *Ctrl;
char *Body;
int CtrlLen;
int BodyLen;
char *tmt, *tmt2;

   CHP = 539;
   Log.Level(LOGD) << "MSGAPI::ReadMsg CHP == " <<  CHP << EOL;
   fh = MsgOpenMsg(Area,MOPEN_READ,MsgNum);
//   if (fh == NULL) fh = SpecialOpen();
   CHP = 540;
   Log.Level(LOGD) << "MSGAPI::ReadMsg CHP == " <<  CHP << EOL;
   if (fh == NULL) {
      Log.Level(LOGD) << "MSGAPI:MsgOpenMsg: Unable to open message '" << MessageName() 
                      << "', code: "  << (uint) msgapierr 
                      << ", errno: " << errno << EOL;
      errno = 0;
      CHP = 541;
      return FALSE;
   }
   CHP = 542;
   Log.Level(LOGD) << "MSGAPI::ReadMsg CHP == " <<  CHP << EOL;
   m.Clear();
   CHP = 543;
   Log.Level(LOGD) << "MSGAPI::ReadMsg CHP == " <<  CHP << EOL;
   CtrlLen = MsgGetCtrlLen(fh);
   CHP = 544;
   Log.Level(LOGD) << "MSGAPI::ReadMsg CHP == " <<  CHP << EOL;
   BodyLen = MsgGetTextLen(fh);
   CHP = 545;
   Log.Level(LOGD) << "MSGAPI::ReadMsg BodyLen == " <<  BodyLen << EOL;
   Ctrl = (char *) malloc(CtrlLen+1);
   CheckMem(Ctrl);
   CHP = 546;
   memset(Ctrl,0,CtrlLen+1);
   CHP = 547;
   Body = (char *) malloc(BodyLen+1);
   CheckMem(Body);
   CHP = 548;
   memset(Body,0,BodyLen+1);
   CHP = 549;
   if (MsgReadMsg(fh,&rm,0,BodyLen,(byte *)Body,CtrlLen,(byte *)Ctrl) == (unsigned int)-1) {
      CHP = 550;
      errno = 0;
      free(Ctrl);
      free(Body);
      MsgCloseMsg(fh);
      return FALSE;
   }
   Log.Level(LOGD) << "MSGAPI::ReadMsg Body == " <<  Body << EOL;
   CHP = 551;
   ConvertControlInfo((byte *)Ctrl,&rm.orig,&rm.dest);
   CHP = 552;
   strncpy(m._FromName,(char *)rm.from,36);
   strncpy(m._ToName,(char *)rm.to,36);
   strncpy(m._Subject,(char *)rm.subj,72);
   m._Time = dosftime(rm.date_written);
//   m._Time = sToTime((char *)rm.__ftsc_date);
   m._FromAddr.Zone(rm.orig.zone);
   m._FromAddr.Net(rm.orig.net);
   m._FromAddr.Node(rm.orig.node);
   m._FromAddr.Point(rm.orig.point);
   m._ToAddr.Zone(rm.dest.zone);
   m._ToAddr.Net(rm.dest.net);
   m._ToAddr.Node(rm.dest.node);
   m._ToAddr.Point(rm.dest.point);
   if (rm.orig.zone == 0 && UseOwnZone) {
      m._FromAddr.Zone(FA_ANYMASK);
      m._FromAddr.Zone(GetMyAka(m._FromAddr).Zone());
   }
   if (rm.dest.zone == 0 && UseOwnZone) {
      m._ToAddr.Zone(FA_ANYMASK);
      m._ToAddr.Zone(GetMyAka(m._ToAddr).Zone());
   }
   if (m._ToAddr.Net() == 0 && m._ToAddr.Node() == 0) {
      m._ToAddr = GetMyAka(m._FromAddr);
   }

   Log.Level(LOGD) << "MSGAPI::ReadMsg FromAddr == " <<  m._FromAddr << EOL;
   Log.Level(LOGD) << "MSGAPI::ReadMsg ToAddr   == " <<  m._ToAddr << EOL;
   SetMsgAttr((unsigned short&)rm.attr,m);
   if (rm.attr & MSGSCANNED) m.fScanned = 1;
   if (rm.attr & MSGLOCKED)  m.fLok = 1;

   m._ReplyTo = rm.replyto;
   CHP = 553;

   tmt = Ctrl;
   while(*tmt != '\0') {
      tmt2 = strchr(tmt+1,'\1');
      if (tmt2 != NULL) {
         *tmt2 = '\0';
      }
      m.AddKludge(tmt);
      if (tmt2 != NULL) {
         *tmt2 = '\1';
      } else {
         break;
     }
   }
   CHP = 554;
   tmt = Body;
   m.ParseMem(tmt);
   CHP = 555;
   MsgCloseMsg(fh);
   CHP = 556;
   free(Ctrl);
   free(Body);
   CHP = 557;
   return TRUE;
}

// ---------------------------

int SQUISH::WriteOneMsg(unsigned int Num, cMSG &m) {
HMSG fh;
char *Ctrl;
int  CtrlLen;
char *Body;
int BodyLen;
XMSG rm;
char *tmt, *tmt2;

   CHP = 558;
   fh = MsgOpenMsg(Area,MOPEN_CREATE,Num);
   CHP = 559;
   if (fh == NULL) {
      CHP = 560;
      return FALSE;
   }
   CHP = 560;
   memset(&rm,0,sizeof(XMSG));
   strncpy((char *)rm.from,m._FromName,36);
   strncpy((char *)rm.to,m._ToName,36);
   strncpy((char *)rm.subj,m._Subject,72);
   strncpy((char *)rm.__ftsc_date,FromTime(m._Time),20);
   CHP = 561;
   dosttime(rm.date_written,m._Time);
   dosttime(rm.date_arrived,time(NULL));
   rm.orig.zone = m._FromAddr.Zone();
   rm.orig.net = m._FromAddr.Net();
   rm.orig.node = m._FromAddr.Node();
   rm.orig.point = m._FromAddr.Point();
   rm.dest.zone = m._ToAddr.Zone();
   rm.dest.net = m._ToAddr.Net();
   rm.dest.node = m._ToAddr.Node();
   rm.dest.point = m._ToAddr.Point();
   SetMsgAttr(m,(unsigned short&)rm.attr);
   if (m.fScanned) {
      rm.attr |= MSGSCANNED;
   }
   if (m.fLok) {
      rm.attr |= MSGLOCKED;
   }
   rm.replyto = m._ReplyTo;
   CHP = 561;

   Ctrl = NULL; 
   CHP = 562;
   m.Normalise();
   PrepKluChain(Ctrl,m,TRUE);
   CHP = 563;
   tmt = tmt2 = Ctrl;
   if (Ctrl != NULL) {
      CHP = 564;
      do {
         if (*tmt2 == '\r') tmt2++;
         *tmt = *tmt2;
         tmt++;
         tmt2++;
      } while (*(tmt-1) != '\0');
      CtrlLen = strlen(Ctrl);
   } else {
      CHP = 565;
      CtrlLen = 0;
   }
   Body = NULL;
   CHP = 566;
   if (!m.fEmpty && m.Body() != NULL) {
      char c;
      CHP = 567;
      Body = strdup(m.Body());
      CheckMem(Body);
      CHP = 568;
      if ((c = Body[strlen(Body)-1]) != '\r' && c != '\n') {
         CHP = 569;
         Log.Level(LOGD) << "MSGAPI::WriteOneMsg: last char == '" << (int) c << "'(" << c << ") " << EOL;
         Log.Level(LOGD) << "MSGAPI::WriteOneMsg: Add tail newline. " << EOL;
         AddKluToChain(Body, "\0", NULL);
         CHP = 570;
      }
   }
   CHP = 571;
   CHP = 572;
   PrepKluChain(Body,m,FALSE);
   if (Body != NULL) {
      CHP = 578;
      BodyLen = strlen(Body);
   } else {
      CHP = 579;
      BodyLen = 0;
   }
   CHP = 580;
   Log.Level(LOGD) << "BodyLen: " << BodyLen <<  EOL;
   if (MsgWriteMsg(fh,0,&rm,(byte *)(Body == NULL ? " " : Body),BodyLen+1,BodyLen+1,CtrlLen+1,(byte *)Ctrl) != 0) {
      CHP = 581;
      if (Ctrl != NULL) free(Ctrl);
      if (Body != NULL) free(Body);
      return FALSE;
   }
   CHP = 582;
   MsgCloseMsg(fh);
   CHP = 583;
// printf("--> '%s'\n",Ctrl);
   if (Ctrl != NULL) free(Ctrl);
   CHP = 584;
   if (Body != NULL) free(Body);
   CHP = 585;
   return TRUE;
}

// ---------------------------

int SQUISH::WriteMsg(cMSG &m) {
   return WriteOneMsg(MsgNum,m);
}

// ---------------------------

int SQUISH::WriteNewMsg(cMSG &m) {
int Num;
   Num = 0;
   return WriteOneMsg(Num,m);
}

// ---------------------------

void SQUISH::Print(void) {
#ifdef _DEBUG
   printf("---------------- MSGASMSG -------------------\n");
   if (DirName != NULL) printf("Directory == '%s'\n",DirName);
   printf("Current Msg number == '%u'\n",tMsgNum);
#endif
}


syntax highlighted by Code2HTML, v. 0.9.1