/*****************************************************************************
 * HTICK --- FTN Ticker / Request Processor
 *****************************************************************************
 * Filelist generator routines.
 *
 * This file is part of HTICK, part of the Husky fidosoft project
 * http://husky.physcip.uni-stuttgart.de
 *
 * HTICK is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * HTICK is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with HTICK; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************
 * $Id: filelist.c,v 1.30 2002/06/10 05:37:15 mche Exp $
 *****************************************************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fidoconf/log.h>

#include <string.h>
#include <fidoconf/common.h>
#include <smapi/progprot.h>
#include <fidoconf/dirlayer.h>
#include <fidoconf/adcase.h>
#include <fidoconf/xstr.h>
#include <fidoconf/afixcmd.h>
#include "add_desc.h"
#include "global.h"
#include "version.h"
#include "filelist.h"
#include "toss.h"


unsigned long totalfilessize = 0;
unsigned int totalfilesnumber = 0;

/*
#define LenDesc 46

char** formatDesc(char **desc, int *count)
{
    int i;
    char *descLine=NULL;
    char *begin,*end;
    
    for(i = 0; i < (*count); i++ )
    {
        if(strlen(desc[i]) > LenDesc)
            break;
    }
    if(i == *count)
    {
        printf("%s\n",desc[0]);
        return desc;
    }

    for(i = 0; i < (*count); i++ )
    {
        if(strlen(desc[i]) < LenDesc)
            xstrcat(&desc[i],"\r");
        if(i == 0)
            xstrcat(&descLine,desc[i]);
        else
            xstrscat(&descLine, " " , desc[i],NULL);
        nfree(desc[i]);
    }
    begin = end =descLine; i = 0;
    while(*end)
    {
        if(end == "\r")
        {
            *end     = '\0';
            if(i == *count)
            {
                (*count)++;
                desc = srealloc(desc,sizeof(char *) * (*count) );
            }
            desc[i] = sstrdup(begin);
            begin = end = end + 1;
            i++;
            continue;
        }
        if(end-begin > LenDesc)
        {   
            end--;
            while(!isspace(*(end)) && end+1 > begin)
                end--;
            *end     = '\0';
            if(i == *count)
            {
                (*count)++;
                desc = srealloc(desc,sizeof(char *) * (*count) );
            }
            desc[i] = sstrdup(begin);
            begin = end = end + 1;
            i++;
            continue;
        }
        end++;
    }
    if(i == *count)
    {
        (*count)++;
        desc = srealloc(desc,sizeof(char *) * (*count) );
    }
    desc[i] = sstrdup(begin);
    printf("%s\n",descLine);
    nfree(descLine);
    return desc;
}
*/

void putFileInFilelist(FILE *f, char *filename, off_t size, int day, int month, int year, int countdesc, char **desc)
{
    int i;
    
    fprintf(f,"%-12s",filename);
    fprintf(f,"%8lu ",(unsigned long) size);
    fprintf(f, "%02u-", day);
    switch (month) {
    case 0: fprintf(f, "Jan");
        break;
    case 1: fprintf(f, "Feb");
        break;
    case 2: fprintf(f, "Mar");
        break;
    case 3: fprintf(f, "Apr");
        break;
    case 4: fprintf(f, "May");
        break;
    case 5: fprintf(f, "Jun");
        break;
    case 6: fprintf(f, "Jul");
        break;
    case 7: fprintf(f, "Aug");
        break;
    case 8: fprintf(f, "Sep");
        break;
    case 9: fprintf(f, "Oct");
        break;
    case 10: fprintf(f, "Nov");
        break;
    case 11: fprintf(f, "Dec");
        break;
    default:
        break;
    }
    fprintf(f, "-%02u", year % 100);
    if (countdesc == 0) fprintf(f," Description not avaliable\n");
    else {
        //desc = formatDesc(desc, &countdesc);
        for (i=0;i<countdesc;i++) {
            if (i == 0) fprintf(f," %s\n",desc[i]);
            else fprintf(f,"                               %s\n",desc[i]);
        }
    }
    return;
}

void printFileArea(char *area_areaName, char *area_pathName, char *area_description, FILE *f, int bbs) {
    
    char *fileareapath=NULL, *fbbsname=NULL, *filename=NULL;
    char *fbbsline;
    DIR            *dir;
    struct dirent  *file;
    s_ticfile tic;
    struct stat stbuf;
    time_t fileTime;
    struct tm *locTime;
    unsigned int totalnumber = 0;
    unsigned long totalsize = 0;
    char **removeFiles = NULL;
    unsigned int removeCount = 0, i, Len;
    FILE *fbbs;
    char *token = "";
    int flag = 0;
    
    fileareapath = sstrdup(area_pathName);
    strLower(fileareapath);
    _createDirectoryTree(fileareapath);
    xstrscat(&fbbsname,fileareapath,"files.bbs",NULL);
    adaptcase(fbbsname);
    
    dir = opendir(fileareapath);
    if (dir == NULL) return;
    
    w_log( LL_INFO, "Processing: %s",area_areaName);
    
    while ((file = readdir(dir)) != NULL) {
        if (strcmp(file->d_name,".") == 0 || strcmp(file->d_name,"..") == 0)
            continue;
        nfree(filename);
        xstrscat(&filename,fileareapath,file->d_name,NULL);
        if (stricmp(filename, fbbsname) == 0) continue;
        if (!flag) {
            if (bbs) fprintf(f,"BbsArea: %s", area_areaName);
            else fprintf(f,"FileArea: %s", area_areaName);
            if (area_description!=NULL)
                fprintf(f," (%s)\n", area_description);
            else
                fprintf(f,"\n");
            fprintf(f,"-----------------------------------------------------------------------------\n");
            flag = 1;
        }
        memset(&tic,0,sizeof(tic));
        if (getDesc(fbbsname, file->d_name, &tic) == 1) {
            tic.desc=srealloc(tic.desc,(tic.anzdesc+1)*sizeof(*tic.desc));
            tic.desc[tic.anzdesc]=sstrdup("Description not avaliable");
            tic.anzdesc = 1;
            add_description(fbbsname, file->d_name, tic.desc, 1);
        }
        stat(filename,&stbuf);
        fileTime = stbuf.st_mtime > 0 ? stbuf.st_mtime : 0;
        locTime = localtime(&fileTime);
        totalsize += stbuf.st_size;
        totalnumber++;
        putFileInFilelist(f, file->d_name, stbuf.st_size, locTime->tm_mday, locTime->tm_mon, locTime->tm_year, tic.anzdesc, tic.desc);
        disposeTic(&tic);
    }
    if (flag) {
        fprintf(f,"-----------------------------------------------------------------------------\n");
        fprintf(f,"Total files in area: %4d, total size: %10lu bytes\n\n",totalnumber,totalsize);
    }
    if ( (fbbs = fopen(fbbsname,"r")) == NULL ) return;
    while ((fbbsline = readLine(fbbs)) != NULL) {
        if (*fbbsline == 0 || *fbbsline == 10 || *fbbsline == 13
            || *fbbsline == ' ' || *fbbsline == '\t' || *fbbsline == '>')
            continue;
        
        Len = strlen(fbbsline);
        if (fbbsline[Len-1]=='\n')
            fbbsline[--Len]=0;
        
        if (fbbsline[Len-1]=='\r')
            fbbsline[--Len]=0;
        
        token = strtok(fbbsline, " \t\0");
        
        if (token==NULL)
            continue;
        nfree(filename);
        xstrscat(&filename,fileareapath,token,NULL);
        adaptcase(filename);
        if (!fexist(filename)) {
            removeFiles = srealloc(removeFiles, sizeof(char *)*(removeCount+1));
            removeFiles[removeCount] = (char *) smalloc(strlen(strrchr(filename,PATH_DELIM)+1)+1);
            strcpy(removeFiles[removeCount], strrchr(filename,PATH_DELIM)+1);
            removeCount++;
        }
        nfree(fbbsline);
    }
    fclose(fbbs);
    if (removeCount > 0) {
        for (i=0; i<removeCount; i++) {
            removeDesc(fbbsname,removeFiles[i]);
            nfree(removeFiles[i]);
        }
        nfree(removeFiles);
    }
    totalfilessize += totalsize;
    totalfilesnumber += totalnumber;
    nfree(filename);
    return;
}

void filelist()
{
    FILE *f = NULL;
    FILE *d = NULL;
    unsigned int i;
    
    w_log( LL_INFO, "Start filelist...");
    
    if (flistfile == NULL) {
        w_log('6',"Not found output file");
        return;
    }
    
    if ( (f = fopen(flistfile,"w")) == NULL ) {
        w_log('6',"Could not open for write file %s",flistfile);
        return;
    }

    if(dlistfile)
    {
        if ( (d = fopen(dlistfile,"w")) == NULL ) {
            w_log('6',"Could not open for write file %s",dlistfile);
        }
    }
    for (i=0; i<config->fileAreaCount; i++) {
        if (config->fileAreas[i].pass != 1 && !(config->fileAreas[i].hide))
        {
            printFileArea(config->fileAreas[i].areaName, config->fileAreas[i].pathName, config->fileAreas[i].description, f, 0);
            if(d) fprintf(d, "%s\n",config->fileAreas[i].pathName);
        }
    }
    
    for (i=0; i<config->bbsAreaCount; i++) {
        printFileArea(config->bbsAreas[i].areaName, config->bbsAreas[i].pathName, config->bbsAreas[i].description, f, 1);
        if(d) fprintf(d, "%s\n",config->bbsAreas[i].pathName);
    }
    
    fprintf(f,"=============================================================================\n");
    fprintf(f,"Total files in filelist: %4d, total size: %10lu bytes\n",totalfilesnumber,totalfilessize);
    fprintf(f,"=============================================================================\n\n");
    
    fclose(f);
    if(d) fclose(d);
}

/* report generation */


char *formDescStr(char *desc)
{
   char *keepDesc, *newDesc, *tmp, *ch, *buff=NULL;

   keepDesc = sstrdup(desc);

   if (strlen(desc) <= 50) {
      return keepDesc;
   }

   newDesc = (char*)scalloc(1, sizeof(char));

   tmp = keepDesc;

   ch = strtok(tmp, " \t\r\n");
   while (ch) {
      if (strlen(ch) > 54 && !buff) {
		  newDesc = (char*)srealloc(newDesc, strlen(newDesc)+55);
		  strncat(newDesc, ch, 54);
		  xstrscat(&newDesc, "\r", print_ch(24, ' '), NULL);
		  ch += 54;
      } else {
		  if (buff && strlen(buff)+strlen(ch) > 54) {
			  xstrscat(&newDesc, buff, "\r", print_ch(24, ' '), NULL);
			  nfree(buff);
		  } else {
			  xstrscat(&buff, ch, " ", NULL);
			  ch = strtok(NULL, " \t\r\n");
		  }
      }
   }
   if (buff && strlen(buff) != 0) {
	   xstrcat(&newDesc, buff);
   } nfree (buff);

   nfree(keepDesc);

   return newDesc;
}

char *formDesc(char **desc, int count)
{
    char *buff=NULL, *tmp;
    int i;
    
    for (i = 0; i < count; i++ ) {
        tmp = formDescStr(desc[i]);
        if (i == 0) {
            xstrscat(&buff, tmp , "\r", NULL);
        } else {
            xstrscat(&buff, print_ch(24, ' '), tmp, "\r", NULL);
        }
        nfree(tmp);
    }
    return buff;
}

void freeFReport(s_newfilereport *report)
{
   unsigned int i;
   nfree(report->fileName);
   for (i = 0; i < report->filedescCount; i++) {
      nfree(report->fileDesc[i]);
   } /* endfor */
   nfree(report->fileDesc);
}

static int compare_filereport(const void *a, const void *b)
{
   const s_newfilereport* r1 = *(s_newfilereport**)a;
   const s_newfilereport* r2 = *(s_newfilereport**)b;

   if( ( r1->useAka->zone  > r2->useAka->zone ) &&
      ( r1->useAka->net   > r2->useAka->net   ) &&
      ( r1->useAka->node  > r2->useAka->node  ) &&
      ( r1->useAka->point > r2->useAka->point )     )
      return 1;
   else if( ( r1->useAka->zone  < r2->useAka->zone  ) &&
      ( r1->useAka->net   < r2->useAka->net   ) &&
      ( r1->useAka->node  < r2->useAka->node  ) &&
      ( r1->useAka->point < r2->useAka->point )    )
      return -1;
   else if( stricmp( r1->areaName, r2->areaName ) > 0)
      return 1;
   else if( stricmp( r1->areaName, r2->areaName ) < 0)
      return -1;
   else if( stricmp( r1->fileName, r2->fileName ) > 0)
      return 1;
   else if( stricmp( r1->fileName, r2->fileName ) < 0)
      return -1;
   return 0;
}

void reportNewFiles()
{
   unsigned  int       b,  fileCount;
   unsigned  int i, c;
   UINT32    fileSize;
   s_message *msg;
   char      *tmp=NULL;
   FILE      *echotosslog;
   char      *annArea;

   if (cmAnnounce) annArea = announceArea;
   else if (config->ReportTo != NULL && (!cmAnnFile)) annArea = config->ReportTo;
        else return;

   // sort newFileReport
   qsort( (void*)newFileReport, newfilesCount, sizeof(s_newfilereport*), 
       compare_filereport); 
   /* post report about new files to annArea */
   for (c = 0; c < config->addrCount && newfilesCount != 0; c++) {
      msg = NULL;
      for (i = 0; i < newfilesCount; i++) {
         if (newFileReport[i] != NULL) {
            if (newFileReport[i]->useAka == &(config->addr[c])) {
               if (msg == NULL) {
                   if (getNetMailArea(config, annArea) != NULL) {
                       msg = makeMessage(newFileReport[i]->useAka,
                           newFileReport[i]->useAka,
                           versionStr, config->sysop, "New Files", 1,
                           config->filefixKillReports);
                       msg->text = createKludges(
                           config->disableTID,NULL,
                           newFileReport[i]->useAka,
                           newFileReport[i]->useAka,
                           versionStr);
                   } else {
                     msg = makeMessage(newFileReport[i]->useAka,
                        newFileReport[i]->useAka,
                        versionStr, "All", "New Files", 0,
                        config->filefixKillReports);
                     msg->text = createKludges(
                                     config->disableTID,annArea, 
                                     newFileReport[i]->useAka, 
                                     newFileReport[i]->useAka,
                                     versionStr);
                  } /* endif */
                  xstrcat(&(msg->text), "\001FLAGS NPD\r");
               } /* endif */
               fileCount = fileSize = 0;

               xscatprintf(&(msg->text), "\r>Area : %s", newFileReport[i]->areaName);
               
               if(newFileReport[i]->areaDesc)
                   xscatprintf(&(msg->text), " : %s", newFileReport[i]->areaDesc);

               xscatprintf(&(msg->text), "\r %s\r", print_ch(77, '-'));


               if(strlen(newFileReport[i]->fileName) > 12)
                   xscatprintf(&(msg->text)," %s\r%23ld ",
                                 newFileReport[i]->fileName,
                                 newFileReport[i]->fileSize
                               );
               else
                   xscatprintf(&(msg->text)," %-12s %9ld ",
                                newFileReport[i]->fileName, 
                                newFileReport[i]->fileSize
                                );

               tmp = formDesc(newFileReport[i]->fileDesc, newFileReport[i]->filedescCount);
               xstrcat(&(msg->text),tmp);
               if (config->originInAnnounce) {
                   xscatprintf(&(msg->text), "%sOrig: %u:%u/%u.%u\r",print_ch(24, ' '),
                       newFileReport[i]->origin.zone,newFileReport[i]->origin.net,
                       newFileReport[i]->origin.node,newFileReport[i]->origin.point);
               }
               if (tmp == NULL || tmp[0] == 0) xstrcat(&(msg->text),"\r");
               nfree(tmp);
               fileCount++;
               fileSize += newFileReport[i]->fileSize;
               for (b = i+1; b < newfilesCount; b++) {
                  if (newFileReport[b] != NULL && newFileReport[i] != NULL &&
                      newFileReport[b]->useAka == &(config->addr[c]) &&
                      stricmp(newFileReport[i]->areaName,
                      newFileReport[b]->areaName) == 0) {
                      if(strlen(newFileReport[b]->fileName) > 12)
                          xscatprintf(&(msg->text)," %s\r%23ld ",
                          newFileReport[b]->fileName,
                          newFileReport[b]->fileSize
                          );
                      else
                          xscatprintf(&(msg->text)," %-12s %9ld ",
                          newFileReport[b]->fileName, 
                          newFileReport[b]->fileSize
                          );
                      
                      tmp = formDesc(newFileReport[b]->fileDesc, newFileReport[b]->filedescCount);
                      
                      xstrcat(&(msg->text),tmp);
                      if (config->originInAnnounce) {
                          xscatprintf(&(msg->text), "%sOrig: %u:%u/%u.%u\r",print_ch(24, ' '),
                              newFileReport[b]->origin.zone,newFileReport[b]->origin.net,
                              newFileReport[b]->origin.node,newFileReport[b]->origin.point);
                      }
                      if (tmp == NULL || tmp[0] == 0) xstrcat(&(msg->text),"\r");
                      nfree(tmp);
                      fileCount++;
                      fileSize += newFileReport[b]->fileSize;
                      freeFReport(newFileReport[b]); newFileReport[b] = NULL;
                  } else {
                  } /* endif */
               } /* endfor */
               xscatprintf(&(msg->text), " %s\r", print_ch(77, '-'));
               xscatprintf(&(msg->text), " %u bytes in %u file(s)\r", fileSize, fileCount);
               freeFReport(newFileReport[i]); newFileReport[i] = NULL;
            } else {
            } /* endif */
         } /* endif */
      } /* endfor */
      if (msg) {
         writeMsgToSysop(msg, annArea);
         freeMsgBuffers(msg);
         nfree(msg);
      } else {
      } /* endif */
   } /* endfor */
   if (newFileReport) {
      nfree(newFileReport);
      if (config->echotosslog != NULL) {
         echotosslog = fopen (config->echotosslog, "a");
         if (echotosslog != NULL) {
            fprintf(echotosslog,"%s\n",annArea);
            fclose(echotosslog);
         }
      }
   }
}
