#include "prefs.h"
#include <sys/types.h>
#include <sys/stat.h>

#ifdef LATTICE
#include <error.h>
#include <proto/dos.h>
#include <proto/exec.h>
#endif
#ifdef DICE
#include <errno.h>
#endif



static void ClearDirDisplay(int);
static void DisplayDirLine(int,int,struct MailItem *,int);
static void DisplayDirectory(int,int,int,int);
Prototype void NewDisplayDirectory(int,int,int,int,int);
Prototype void SaveFolder(BOOL,long,long);
Prototype void get_folder_data(long *,long *);
Prototype BOOL folder_changed(long,long);
Prototype struct MailItem *i_th(int);



extern int errno;



struct MailItem *i_th(int i)
{
  struct MailItem *m = MailList;
  while (--i)
    m = m->next;
  return(m);
}



void
SaveFolder(BOOL ask, long laenge, long datum)
{
    long pos;
    FILE *in,*keep,*store;
    struct MailItem *I;
    char Name[MAX_LINELENGTH];
    char Text[MAX_LINELENGTH];  /* large enough for a single line? */
    BOOL flags_written,folder_has_changed;
    BOOL tmp_AlwaysKeep,tmp_AlwaysDelete;
    int Number;
    int to_delete,to_store,to_keep;
    int save_num=1;
    char buffer[80];
    char TitleString[1024];

    tmp_AlwaysKeep = AlwaysKeep;
    tmp_AlwaysDelete = AlwaysDelete;

    sprintf(Name,"%s.o",FolderName);     /* name for backup */
    LockFile(Name);
    LockFile(FolderName);

    if (folder_changed(laenge,datum)) {
      status_msg("Folder has changed. Resynchronizing...",0L);
      get_folder_data(&laenge,&datum);
      if (!read_home_box() || !laenge || !datum) {
        status_msg("Resync failed. Folder not saved.",200L);
        clean_exit(5);
      }
    }

    remove(Name);                        /* remove backup */

    /* we need to know if there are none, or one, or more to delete/store */
    for (I=MailList,to_delete=0,to_store=0; I; I=I->next) {
      if (I->Status & DELETED)
        to_delete++;
      else if (I->Status & READ)
        to_store++;
    }

    if (ask) {
      if (to_delete) {
        char chr;
        sprintf(TBuffer,"\033[%d;%dH\033[JDelete message%s? (y/n) %c\b",
                         Win_Height-1,Win_Width-27+plural_pix(to_delete),
                         plural_s(to_delete),
                         tmp_AlwaysDelete?'y':'n');
        outline();
        do {
          flush_input();
          chr=getch();
          if (chr=='\r')
            chr=(tmp_AlwaysDelete?'y':'n');
        } while (chr!='y' && chr!='n');
        if (chr=='n') {
          putst("No.");
          tmp_AlwaysDelete = FALSE;
        }
        else {
          tmp_AlwaysDelete = TRUE;
          putst("Yes.");
        }
        Delay(25L);  /* just a moment */
      }

      /*
       * We need to determine if read messages
       * are to be stored or kept.
       * (unread messages are always kept)
       */

      if (to_store) {
        char chr;
        sprintf(TBuffer,"\033[%d;%dH\033[JMove read message%s to \"received\" folder? (y/n) %c\b",
                         Win_Height-1,Win_Width-51+plural_pix(to_store),
                         plural_s(to_store),
                         tmp_AlwaysKeep?'n':'y');
        outline();
        do {
          flush_input();
          chr=getch();
          if (chr=='\r')
            chr=(tmp_AlwaysKeep?'n':'y');
        } while (chr!='y' && chr!='n');
        if (chr=='n') {
          putst("No.");
          tmp_AlwaysKeep = TRUE;
        }
        else {
          tmp_AlwaysKeep = FALSE;
          putst("Yes.");
        }
        Delay(25L);  /* just a moment */
      }

    }

    if (tmp_AlwaysKeep)
      to_store = 0;

    if (!tmp_AlwaysDelete)
      to_delete = 0;

    to_keep=MaxArticle-to_delete-to_store;

    /*
     * Formulate message as to number of keeps, stores, and deletes.
     * This is only complex so that the message is good English.
     */

    if (to_keep > 0) {
      if (to_store > 0) {
        if (to_delete > 0)
          sprintf(buffer,
                "Keeping %d message%s, storing %d, and deleting %d.",
                to_keep, plural_s(to_keep), to_store, to_delete);
        else
          sprintf(buffer, "Keeping %d message%s and storing %d.",
            to_keep, plural_s(to_keep), to_store);
      } else {
        if (to_delete > 0)
          sprintf(buffer, "Keeping %d message%s and deleting %d.",
                  to_keep, plural_s(to_keep), to_delete);
        else
          sprintf(buffer, "Keeping %s.",
                  to_keep > 1 ? "all messages" : "message");
      }
    } else if (to_store > 0) {
      if (to_delete > 0)
        sprintf(buffer, "Storing %d message%s and deleting %d.",
                to_store, plural_s(to_store), to_delete);
      else
        sprintf(buffer, "Storing %s.",
                to_store > 1? "all messages" : "message");

    } else {
      if (to_delete > 0)
        sprintf(buffer, "Deleting all messages.");
      else
        buffer[0] = '\0';
    }

    /* folder has changed? */

    folder_has_changed = FALSE;
    for (I=MailList; I; I=I->next) {
      if (I->Status!=I->OldStatus)
        folder_has_changed = TRUE;
    }

    if (folder_has_changed)
      status_msg(buffer,0L);
    else {
      status_msg("Folder unchanged.",100L);
      return;
    }

    /*
     * Backups der Mailbox machen - auf diese Weise koennen geloeschte
     * Mails von Hand wieder zurueckgeholt werden
     */

    if (rename(FolderName,Name)) {
      fprintf(stderr,"elm: cannot rename folder to backup\n");
      UnLockFile(FolderName);
      UnLockFile(Name);
      return;
    }

    in=fopen(Name,"r");
    keep=fopen(FolderName,"w");

    if (tmp_AlwaysKeep) {
      store=keep;
    }
    else {
      store=fopen(ReceivedFolder,"a");
    }

    if ( !in || !keep || !store ) {
        char exec[256];
        fprintf(stderr,"elm: cannot open folder or backup\n");
        sprintf(exec,"COPY %s.o %s",FolderName,FolderName);
        Execute(exec,0L,0L);
        UnLockFile(FolderName);
        UnLockFile(Name);
        return;
    }

    for (Number=MaxArticle;Number>0;Number--) {
        FILE *out;

        flags_written=FALSE;

        if (ReverseSorting)
          I=i_th(Number);
        else
          I=i_th(MaxArticle-Number+1);

        /*
         * Wenn die Mail nicht geloescht werden soll, dann die Mail
         * versehen mit dem neuen Status in die Homebox zurueckschreiben
         */

        out = ((I->Status & READ) && !tmp_AlwaysKeep)?store:keep;

        if (!( (I->Status & DELETED) && tmp_AlwaysDelete )) {
            long todo;  /* bytes to do */
            BOOL goon;  /* go on saving */
            sprintf(TitleString,"Processing %s, message: %d of %d",FolderName,save_num++,to_keep);
            SetScreenTitle(TitleString);

            fseek(in,I->ArtikelStart,0);

/* -------------------------------------------------------------------------- */
            while((goon=getline(in,Text,&pos)) && (pos<I->TextStart)) {
              if (!flags_written && !strncmp(Text,"X-Status:",9)) {
                fprintf(out,"X-Status: O");
                if (I->Status & READ)      putc('R',out);
                if (I->Status & LOGGED)    putc('L',out);
                if (I->Status & ANSWERED)  putc('A',out);
                if (I->Status & FORWARDED) putc('F',out);
                if (I->Status & BOUNCED)   putc('B',out);
                putc('\n',out);
                flags_written=TRUE;
              }
              else if (!flags_written && !strlen(Text)) {
                  fprintf(out,"X-Status: O");
                  if (I->Status & READ)      putc('R',out);
                  if (I->Status & LOGGED)    putc('L',out);
                  if (I->Status & ANSWERED)  putc('A',out);
                  if (I->Status & FORWARDED) putc('F',out);
                  if (I->Status & BOUNCED)   putc('B',out);
                  fprintf(out,"\n\n");
                  flags_written=TRUE;
              }
              else
                fprintf(out,"%s\n",Text);
            }

            if (goon && pos<=I->ArtikelEnd) fprintf(out,"%s\n",Text);
/*
            if (todo = I->ArtikelEnd-I->TextStart) {
*/
            if (todo = I->ArtikelEnd-ftell(in)+1L) {
              while(todo>0) {
                long len = todo>FileBufferSize?FileBufferSize:todo;
                todo -= len;
                if (len=fread(FileBuffer,1L,len,in))
                  fwrite(FileBuffer,1L,len,out);
              }
            }
/*
            while(getline(in,Text,&pos) && (pos<=I->ArtikelEnd)) {
                if (pos<I->ArtikelEnd) {
            /*
             * Status-Zeile gefunden ? Dann in diese Zeile den neuen Status
             * einschreiben.
             */
                    if ((!flags_written) && (strncmp(Text,"X-Status:",9)==0)) {
                        fprintf(out,"X-Status: O");
                        if (I->Status & READ)      putc('R',out);
                        if (I->Status & LOGGED)    putc('L',out);
                        if (I->Status & ANSWERED)  putc('A',out);
                        if (I->Status & FORWARDED) putc('F',out);
                        if (I->Status & BOUNCED)   putc('B',out);
                        putc('\n',out);
                        flags_written=TRUE;
                    }
            /*
             * Noch keine X-Status-Zeile und schon den Message-Body
             * erreicht ? Wenn Status gesetzt ist, dann die X-Status-Zeile
             * schreiben, danach die Body-Zeile
             */
                    else if ((!flags_written) && (pos<=I->TextStart) && (strlen(Text)==0)) {
                        fprintf(out,"X-Status: O");
                        if (I->Status & READ)      putc('R',out);
                        if (I->Status & LOGGED)    putc('L',out);
                        if (I->Status & ANSWERED)  putc('A',out);
                        if (I->Status & FORWARDED) putc('F',out);
                        if (I->Status & BOUNCED)   putc('B',out);
                        putc('\n',out);
                        flags_written=TRUE;
                        fprintf(out,"%s\n",Text);
                    }
                    else
                        fprintf(out,"%s\n",Text);
                }
            }
*/
/* -------------------------------------------------------------------------- */

        }
    }
    fclose(in);
    fclose(keep);
    if (!tmp_AlwaysKeep) fclose(store);

    UnLockFile(FolderName);
    UnLockFile(Name);

    if (!KeepBackup) remove(Name);
}



void
NewDisplayDirectory(int page,int MaxArt,int Akt,int Mode,int MsgPerPage)
{
    static int LastAkt = -1;
    static int LastPage = -1;
    int hi;
    int p20;    /* page*MsgPerPage */
    int f;

    if (!MaxArt) return;

    putst("\033[0 p");   /* cursor off */
    p20=page*MsgPerPage;
    if ( (p20+MsgPerPage) > MaxArt)                /* Seite nur teilweise gefuellt */
        hi=MaxArt;                         /* Dann nur bis MaxArticle dar- */
    else                                   /* stellen */
        hi=p20+MsgPerPage;

    if ((Mode==FULL) || (LastPage!=page)){ /* Seitenwechsel ? */
        DisplayDirectory(page,hi,Akt,MsgPerPage);
        LastPage=page;                     /* Aktuelle position und */
    }
    else {                                 /* Modus update und gleiche Seite */
        if ( (Akt< p20) || (Akt >p20+MsgPerPage))
            DisplayDirectory(page,hi,Akt,MsgPerPage);
        else {
            f=(LastAkt-(p20))+1;
            if(LastAkt>0)                  /* letzten Eintrag normal dar- */
                DisplayDirLine(f,LastAkt,i_th(LastAkt),0);   /* stellen */
            f=(Akt-(p20))+1;
            DisplayDirLine(f,Akt,i_th(Akt),1); /* Neue Position revers */
        }
    }                                      /* Seite merken          */
    LastAkt=Akt;                           /* darstellen            */
    putst("\033[ p");   /* cursor on */
}



static void
ClearDirDisplay(int MsgPerPage)
{
  register int line=2;
  register int i;

  for(i=0;i<MsgPerPage;i++) {
    sprintf(TBuffer,"\033[%d;1H\033[K",line++);
    outline();
  }
}



static void
DisplayDirectory(int page,int hi,int Aktuell,int MsgPerPage)
{
    register int j;
    register int pos=2;
    ClearDirDisplay(MsgPerPage);
    for (j=(page*MsgPerPage);j<hi;j++) {
        if (j==Aktuell-1)
            DisplayDirLine(pos,j+1,i_th(j+1),1);
        else
            DisplayDirLine(pos,j+1,i_th(j+1),0);
        pos++;
    }
}



static void
DisplayDirLine(int Zeile,int Nummer,struct MailItem *I,int Mode)
{
    char linenum[10];
    char stat;
    char *name = NULL;

    sprintf(TBuffer,"\033[%d;1H ",Zeile);  /* Goto line pos */
    outline();

    if (Mode==1) putst(REVERSE_ON);

    sprintf(linenum,"(%ld)",I->Lines);
    if (I->Status&DELETED)
      stat='D';
    else if (I->Status&READ)
      stat=' ';
    else if (I->Status&OLD)
      stat='O';
    else
      stat='N';

    if (I->FromName || !I->From) {
      if (I->FromName && strcmp(RealName,I->FromName)) {
        name = I->FromName;
      }
      else {
        if (I->ToName) {
          if (name=malloc(strlen(I->ToName)+4)) {
            sprintf(name,"To %s",I->ToName);
          }
        }
        else if (I->To) {
          if (name=malloc(strlen(I->To)+4)) {
            sprintf(name,"To %s",I->To);
          }
        }
      }
    }
    else
      name = I->From;

    if (!name) name = "(none)";

    sprintf(TBuffer,"%c%c%c%c%c%c %-3d  %-6.6s  %-20.20s %-6.6s %-*.*s",
            (I->Status & LOGGED)    ? 'L':' ',
            stat,
            (I->Urgent)      ? 'U':' ',
            (I->Status & ANSWERED)  ? 'A':' ',
            (I->Status & FORWARDED) ? 'F':' ',
            (I->Status & BOUNCED)   ? 'B':' ',
            Nummer,
            I->Date,
            name,
            linenum,
            Win_Width-50,
            Win_Width-50,
            I->Subject?I->Subject:"(none)"
           );

    outline();
    if (Mode==1) putst(PLAIN_TEXT);
}



void get_folder_data(long *laenge,long *datum)
{
    struct stat s;
    long try = 0L;
    while(stat(FolderName,&s)) {
      char msg[80];
      if (errno!=EBUSY) {          /* resource is busy? */
        fprintf(stderr,"elm: error scanning folder, code %d\n",errno);
        *laenge=0L;
        *datum=0L;
        return;
      }
      sprintf(msg,"Folder is busy. Stand by. Resynchronizing... try #%ld",++try);
      status_msg(msg,0L);
      Delay(100L);
    }
    *laenge=s.st_size;
    *datum=s.st_mtime;
}



BOOL folder_changed(long laenge,long datum)
{
    struct stat s;
    long try = 0L;
    while(stat(FolderName,&s)) {
      char msg[80];
      if (errno!=EBUSY) {          /* resource is busy? */
        fprintf(stderr,"elm: error scanning folder, code %d\n",errno);
        return(TRUE);
      }
      sprintf(msg,"Folder is busy. Stand by. Resynchronizing... try #%ld",++try);
      status_msg(msg,0L);
      Delay(100L);
    }
    return (s.st_size!=laenge || s.st_mtime!=datum);
}

