/***************************************************************************
 *                                                                         *
 *   FILAGENT.CPP                                                          *
 *                                                                         *
 *   Copyright (c) 1998       Galacticomm, Inc.    All Rights Reserved.    *
 *                                                                         *
 *   Active HTML File Library Agent                                        *
 *   Implementation                                                        *
 *                                                                         *
 *                                                - Phil Henning 10/16/98  *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "galacth.h"
#include "dnf.h"
#include "phasedbg.h"
#include <list>
// file libraries

// ah file libraries
#include "filtvb.h"
#include "ahutil.h"
// synthesis classes
#include "syninita.h"
#include "syninval.h"
#include "synllibs.h"
#include "synlfils.h"
#include "syndlib.h"
#include "syndfil.h"
#include "synfdwn.h"
#include "synfup.h"
#include "syngfil.h"
#include "syndarc.h"
#include "synfpref.h"
#include "synolddl.h"
// MSG files
#include "galfilah.h"
using namespace std;

#define FILREV "$Revision: 11 $"

#define FILAHMODNAME "AH File Libs" // module name for genbb entries

filAgent* theFilAgent;             // the agent
HMCVFILE  filahmb;                 // file library active html msg file

static INT
amrfilah(                          // File Agent read-locker of lib files
CHAR *grp,                         //   group (Library name)
CHAR *fil);                        //   file name

INT (*amrold)(CHAR*,CHAR*);        // old am reading vector

CHAR* g_pszAnonul;                 // anonymous name to use for uploads

static
string
fixupRelative(                     // fixup a relative path
const CHAR* path,                  // path
const CHAR* prepend);              // string to prepend

MARKSOURCE(filagent);

extern "C" VOID EXPORT
init__galfilah(VOID)               // standard init routine
{
     theFilAgent=new filAgent;
}

filAgent::filAgent() : acthAgent("Active HTML Libraries","library")
                     , m_hfilkey(NULL)
{
     registerAgent(acthVersion);
     initAgent();
}

filAgent::~filAgent()
{
     finishAgent();
}

VOID
filAgent::initAgent()               // registry agent initialization
{
     ::filahmb=::opnmsg("GALFILAH.MCV");
     ::initMcvText();
     ::initTvars();
     initMcvOptions();
     initlibrsv();
     amrold=reserve->amreading;
     reserve->amreading=amrfilah;
}

VOID
filAgent::finishAgent()             // shutdown the agent
{
     if (m_hfilkey != NULL) {
          free(m_hfilkey);
     }
     ::finishMcvText();
     ::finishTvars();
     ::clsmsg(filahmb);
}

VOID
filAgent::initMcvOptions()          // init MCV file options
{
     ::setmbk(::filahmb);
     m_hfilkey=::stgopt(HLIBKEY);
     m_anondft=(::strlen(m_hfilkey) == 0 && ::ynopt(DFTANON));
     m_anonlib=(::strlen(m_hfilkey) == 0 && ::ynopt(LIBANON));
     m_maxlst=::numopt(MAXLSTC,1,32767);
     m_dftlst=::numopt(DFTLSTC,1,32767);
     INT deflord=::tokopt(DEFLORD,"DESCENDING","ASCENDING",NULL);
     if (deflord == 1) {
          m_deflord=ORDER_DESC;
     }
     else if (deflord == 2) {
          m_deflord=ORDER_ASCEND;
     }
     else {
          ::catastro("FILE LIBRARIES - Error in MCV Option \"DEFLORD\"");
     }
     INT defford=::tokopt(DEFFORD,"DESCENDING","ASCENDING",NULL);
     if (defford == 1) {
          m_defford=ORDER_DESC;
     }
     else if (defford == 2) {
          m_defford=ORDER_ASCEND;
     }
     else {
          ::catastro("FILE LIBRARIES - Error in MCV Option \"DEFFORD\"");
     }
     INT deftyp=::tokopt(DEFFTYP,"NAME","DATE","POPULARITY",NULL);
     if (deftyp == 1) {
          m_defftyp=STYPE_NAME;
     }
     else if (deftyp == 2) {
          m_defftyp=STYPE_DATE;
     }
     else if (deftyp == 3) {
          m_defftyp=STYPE_POPULARITY;
     }
     else {
          ::catastro("FILE LIBRARIES - Error in MCV Option \"DEFFTYP\"");
     }
     m_timeslice=(USHORT)::numopt(TIMSLC,1,1000);
     m_frameset=(::tokopt(DFTFRM,"NO-FRAMES","FRAMES",NULL) == 2);
     m_strRedirFrame=fixupRelative(::stpans(::rawmsg(REDFRM)),"/library/");
     m_strRedirNoFrame=fixupRelative(::stpans(::rawmsg(REDNOF)),"/library/");
     g_pszAnonul=::stpans(::stgopt(ANONUL));
     m_bReqEncoding=::ynopt(REQENC);
     ::rstmbk();
}

acthSynthesis*                      //   pointer to new synthesis obj
filAgent::newSynthesis(             // create a new registry synthesis
acthSession* ses)                   //   acthSession ptr
{
     INT narg=ses->urlargc();

     BEG_PHASE("fil->newSynth",0);
     if (narg > 0) {
          if ((narg == 2 || narg == 3) && ::sameas(ses->urlargv(0),"list")) {
               if (::sameas(ses->urlargv(1),"libs")) {
                    END_PHASE("fil->newSynth",1);
                    return(new synListLibs(ses,m_anonlib,2));
               }
               if (::sameas(ses->urlargv(1),"files")) {
                    END_PHASE("fil->newSynth",2);
                    return(new synListFiles(ses,true,2));
               }
          }
          if (narg == 3 && ::sameas(ses->urlargv(0),"download")) {
               END_PHASE("fil->newSynth",3);
               return(new synFileDwn(ses,true,0));
          }
          if (::sameas(ses->urlargv(0),"upload")) {
               END_PHASE("fil->newSynth",4);
               return(new synFileUp(ses,true,1));
          }
          if (::sameas(ses->urlargv(0),"prefs")) {
               END_PHASE("fil->newSynth",5);
               return(new synSetPrefs(ses,false,1));
          }
          if ((narg == 2 || narg == 3) && ::sameas(ses->urlargv(0),"view")) {
               if (::sameas(ses->urlargv(1),"lib")) {
                    END_PHASE("fil->newSynth",6);
                    return(new synLibDetail(ses,true,2));
               }
               if (::sameas(ses->urlargv(1),"file")) {
                    END_PHASE("fil->newSynth",7);
                    return(new synFileDetail(ses,true,2));
               }
               if (::sameas(ses->urlargv(1),"content")) {
                    END_PHASE("fil->newSynth",8);
                    return(new synArchiveDetail(ses,true,2));
               }
          }
          if ((narg == 2 || narg == 3) && ::sameas(ses->urlargv(0),"file")) {
               END_PHASE("fil->newSynth",9);
               return(new synGenericFile(ses,true,1));
          }
          // backwards compatability: /library/lib/filename
          if (narg == 2 && ::libfind(ses->urlargv(0)) != NULL) {
               END_PHASE("fil->newSynth",10);
               return(new synOldDownload(ses));
          }
     }
     if (narg == 0 || (narg == 1 && ::strchr(ses->urlargv(0),'.') != 0)) {
          END_PHASE("fil->newSynth",11);
          return(new synInitial(ses,m_anondft,0));
     }
     END_PHASE("fil->newSynth",12);
     return(new synInvalidURL(ses));
}

VOID
filAgent::LoadPrefs(                // Load preferences
const CHAR* uid,                    // User-ID, NULL for system default
pFILAHPREF pPref)                   // pointer to struct to receive prefs
{
     ASSERT(uid != NULL);
     ASSERT(pPref != NULL);

     ::memset(pPref,0,sizeof(FILAHPREF));
     ::stlcpy(pPref->userid,uid,UIDSIZ);
     ::stlcpy(pPref->modnam,FILAHMODNAME,MNMSIZ);
     ::dfaSetBlk(genbb);
     bool result=dfaAcqEQ(pPref,pPref,0);
     ::dfaRstBlk();
#if (AHPREFVER > 1)
     if (result && pPref.m_prefver < AHPREFVER) {
          switch (pPref.m_prefver) {
          case 1:
               /* add version 2 stuff */
          case 2:
               /* add version 3 stuff */
          case 3:
               /* add version 4 stuff */
          default:
               // unrecongnized version, clear out prefs
               SetDftPrefs(pPref);
          }
          pPref->m_prefver=AHPREFVER;
     }
#endif // AHPREFVER > 1
     if (!result) {
          SetDftPrefs(pPref);
          SavePrefs(pPref);
     }
     return;
}

VOID
filAgent::SetDftPrefs(              // Set default prefs
pFILAHPREF pPref)                   //  ptr to struct to receive prefs
{
     ASSERT(pPref != NULL);

     pPref->m_lorder=m_deflord;
     pPref->m_forder=m_defford;
     pPref->m_frames=m_frameset;
     pPref->m_browse=m_defftyp;
     pPref->m_prefver=AHPREFVER;
}

VOID
filAgent::SavePrefs(                // Save prefs
pFILAHPREF pPref)                   //  ptr to struct to save
{
     ASSERT(pPref != NULL);
     dfaSetBlk(genbb);
     if (dfaAcqEQ(NULL,pPref,0)) {
          dfaUpdateV(pPref,sizeof(FILAHPREF));
     }
     else {
          dfaInsertV(pPref,sizeof(FILAHPREF));
     }
     dfaRstBlk();
}

LISTORDER
filAgent::LoadLibOrder(             // load library list order
const CHAR* uid)                    //   User-ID to get, NULL for sys default
{
     if (uid == NULL) {
          return(m_deflord);
     }

     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     return(filpref.m_lorder);
}

VOID
filAgent::SaveLibOrder(             // save library list order
const CHAR* uid,                    //   User-ID to save
LISTORDER neworder)                 //   the new list order
{
     if (uid == NULL) {
          return;
     }
     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     if (filpref.m_lorder != neworder) {
          filpref.m_lorder=neworder;
          SavePrefs(&filpref);
     }
}


LISTORDER
filAgent::LoadFileOrder(            // load file list forder
const CHAR* uid)                    //   User-ID to get, NULL for sys default
{
     if (uid == NULL) {
          return(m_defford);
     }

     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     return(filpref.m_forder);
}

VOID
filAgent::SaveFileOrder(            // save file list order
const CHAR* uid,                    //   User-ID to save
LISTORDER neworder)                 //   the new list order
{
     if (uid == NULL) {
          return;
     }
     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     if (filpref.m_forder != neworder) {
          filpref.m_forder=neworder;
          SavePrefs(&filpref);
     }
}

SEARCHTYPE
filAgent::LoadSearchType(           // load search type
const CHAR* uid)                    //   User-ID to get, NULL for sys default
{
     if (uid == NULL) {
          return(m_defftyp);
     }
     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     return(filpref.m_browse);
}

VOID
filAgent::SaveSearchType(           // save search type
const CHAR* uid,                    //   User-ID to save
SEARCHTYPE newtype)                 //   new search type
{
     if (uid == NULL) {
          return;
     }
     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     if (filpref.m_browse != newtype) {
          filpref.m_browse=newtype;
          SavePrefs(&filpref);
     }
}

bool
filAgent::LoadFramePref(            // load frame preference
const CHAR* uid)                    //   User-ID to get, NULL for sys default
{
     if (uid == NULL) {
          return(m_frameset);
     }

     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     return(filpref.m_frames);
}

VOID
filAgent::SaveFramePref(            // save frame preference
const CHAR* uid,                    //   User-ID to save
bool bFrames)                       //   new frames preference
{
     if (uid == NULL) {
          return;
     }
     FILAHPREF filpref;
     LoadPrefs(uid,&filpref);
     if (filpref.m_frames != bFrames) {
          filpref.m_frames=bFrames;
          SavePrefs(&filpref);
     }
}

static INT
amrfilah(                          // File Agent read-locker of lib files
CHAR *grp,                         //   group (Library name)
CHAR *fil)                         //   file name
{
     list<readingInfo *>::iterator ri;

     for (ri=readingList.begin() ; ri != readingList.end() ; ri++) {
          if (sameas(grp,(*ri)->m_libname)
           && sameas(fil,(*ri)->m_filname)) {
               return((*ri)->m_unum);
          }
     }
     return((*amrold)(grp,fil));
}

static
string
fixupRelative(                     // fixup a relative path
const CHAR* path,                  // path
const CHAR* prepend)               // string to prepend
{
     ASSERT(path != NULL);
     ASSERT(prepend != NULL);
     string result("");

     if (strlen(path) > 0 && !isProtocol(path) && *path != '/') {
          result+=prepend;
     }
     result+=path;
     return(result);
}

bool
ahHasLibKey(                            // has lib key?
acthUserID* user,                       // User-ID
const struct fllib *libptr,             // ptr to lib
const CHAR* keyname)                    // keyname
{
     ASSERT(keyname != NULL);
     ASSERT(libptr != NULL);
     return(ahIsFlop(user,libptr)
        || (user == NULL && *keyname == '\0')
        || (user != NULL && !sameto("_LIBOP",keyname)
             && user->hasKey(keyname)));
}

bool
ahIsFlop(                               // is user an operator at all?
acthUserID* user,                       // User
const struct fllib *libptr)             // ptr to lib
{
     if (libptr == NULL) {
          return(false);
     }
     if (user == NULL) {
          return(false);
     }
     return(user->hasKey(flsysop)
         || (libptr->libop[0] != '\0' && user->hasKey(libptr->libop))
         || sameas(user->userid(),libptr->primary));
}

LISTORDER
LoadDftOrder(                           // load default order
const CHAR* uid)                        // User-ID
{
     return(theFilAgent->LoadLibOrder(uid));
}

VOID
SaveDftOrder(                           // save default order
const CHAR* uid,                        // User-ID
LISTORDER neworder)                     // new order
{
     theFilAgent->SaveLibOrder(uid,neworder);
}

bool
isChildOf(                              // is lib a child of a lib?
const CHAR* libname,                    // lib to check
const struct fllib *libptr)             // alleged parent lib
{
     for (int i=0; i < FLNMCATS ; i++) {
          if (sameas(libname,libptr->cat[i])) {
               return(true);
          }
     }
     return(false);
}

LONG
dnlPrice(                               // price of download, one file + size
LONG siz,                               //   size of file
const struct fllib *libptr,             //   library info
acthUserID* usr)                        //   User-ID
{
     LONG chg=libptr->dlchge+libptr->kdlchge*(siz/1024);
     return(usr == NULL ? chg : (usr->hasKey(nochgkey) ? 0 : chg));
}

