
#include <utility/hooks.h>

#include "sumstl.h"

#include <proto/locale.h>

#include <stdio.h>
#include <ctype.h>

#ifdef __SASC
#include <dos.h>
#endif

#include "umsfilter.h"
#include "date.h"

/* SMAKE */


struct MyHook   {
    struct MinNode      h_MinNode;
    ULONG               (*h_Entry)();   /* assembler entry point        */
    ULONG               (*h_SubEntry)();/* often HLL entry point        */
    char        *h_Data;        /* owner specific               */
};


// Version String
// --------------

static char VersionString[] = "$VER: sumsprint "VERSION;

static char UsageString[] = "\
     U=User       : user name.\n\
     P=Password   : user's password.\n\
    FI=Filter     : filter specification.\n\
    FO=Format     : format string (see documentation for details).\n\
  FILE=Formatfile : file that contains a format string.\n\
     O=SetOldFlag : if existing, read messages become old.\n\
     B=Backwards  : if existing, messages are scanned backwards.\n\
     S=Server     : server name.\n\n\
";


// Template
// --------

static char *TemplateString = "U=User=Name/A,P=Password/A,FI=Filter/A,FO=Format,FILE=Formatfile/K,O=SetOldFlag/S,B=Backwards/S,S=Server/K";
enum opts {
        OPT_USER, OPT_PASSWORD, OPT_FILTER, OPT_FORMAT, OPT_FORMATFILE, OPT_SETOLDFLAG, OPT_BACKWARDS, OPT_SERVER,
        OPT_COUNT};
static LONG opts[OPT_COUNT];


// Globals
// -------

extern struct DosLibrary *DOSBase;

struct Library *UMSBase = NULL;
struct Library *LocaleBase = NULL;
struct Locale *Locale = NULL;
UMSAccount acc = NULL;
char *TextFields[UMSNUMFIELDS];
struct MyMessageInfo
{
        LONG      msgi_HeaderLength; // 0  (offsets for keyword table)
        LONG      msgi_TextLength;   // 1
        LONG      msgi_Date;         // 2
        UMSMsgNum msgi_ChainUp;      // 3
        UMSMsgNum msgi_ChainDn;      // 4
        UMSMsgNum msgi_ChainLt;      // 5
        UMSMsgNum msgi_ChainRt;      // 6
        UMSSet    msgi_GlobalStatus; // 7
        UMSSet    msgi_UserStatus;   // 8
        UMSSet    msgi_LoginStatus;  // 9
        UMSMsgNum msgi_HardLink;     // 10
        UMSMsgNum msgi_SoftLink;     // 11
        LONG      msgi_MsgNum;       // 12
} MessageInfo;


#define KW_STRING 0
#define KW_NUMBER 1
#define KW_DATE   2
#define KW_QTEXT  3
#define KW_FLAG   4

struct Keyword
{
        char *name;
        char *format;
        LONG type;
        LONG code;
} Keywords[] =
{
        { "MsgText"      ,"%s",KW_STRING,UMSCODE_MsgText      },

        { "FromName"     ,"%s",KW_STRING,UMSCODE_FromName     },
        { "FromAddr"     ,"%s",KW_STRING,UMSCODE_FromAddr     },
        { "ToName"       ,"%s",KW_STRING,UMSCODE_ToName       },
        { "ToAddr"       ,"%s",KW_STRING,UMSCODE_ToAddr       },
        { "MsgID"        ,"%s",KW_STRING,UMSCODE_MsgID        },
        { "CreationDate" ,"%s",KW_STRING,UMSCODE_CreationDate },
        { "ReceiveDate"  ,"%s",KW_STRING,UMSCODE_ReceiveDate  },
        { "ReferID"      ,"%s",KW_STRING,UMSCODE_ReferID      },
        { "Group"        ,"%s",KW_STRING,UMSCODE_Group        },
        { "Subject"      ,"%s",KW_STRING,UMSCODE_Subject      },
        { "Attributes"   ,"%s",KW_STRING,UMSCODE_Attributes   },
        { "Comments"     ,"%s",KW_STRING,UMSCODE_Comments     },
        { "Organization" ,"%s",KW_STRING,UMSCODE_Organization },
        { "Distribution" ,"%s",KW_STRING,UMSCODE_Distribution },
        { "Folder"       ,"%s",KW_STRING,UMSCODE_Folder       },
        { "FidoID"       ,"%s",KW_STRING,UMSCODE_FidoID       },
        { "MausID"       ,"%s",KW_STRING,UMSCODE_MausID       },
        { "ReplyGroup"   ,"%s",KW_STRING,UMSCODE_ReplyGroup   },
        { "ReplyName"    ,"%s",KW_STRING,UMSCODE_ReplyName    },
        { "ReplyAddr"    ,"%s",KW_STRING,UMSCODE_ReplyAddr    },
        { "LogicalToName","%s",KW_STRING,UMSCODE_LogicalToName},
        { "LogicalToAddr","%s",KW_STRING,UMSCODE_LogicalToAddr},
        { "FileName"     ,"%s",KW_STRING,UMSCODE_FileName     },
        { "RFCMsgNum"    ,"%s",KW_STRING,UMSCODE_RFCMsgNum    },

        { "FidoText"     ,"%s",KW_STRING,UMSCODE_FidoText     },
        { "ErrorText"    ,"%s",KW_STRING,UMSCODE_ErrorText    },
        { "Newsreader"   ,"%s",KW_STRING,UMSCODE_Newsreader   },

        { "RFCAttr"      ,"%s",KW_STRING,UMSCODE_RfcAttr      },
        { "FTNAttr"      ,"%s",KW_STRING,UMSCODE_FtnAttr      },
        { "ZerAttr"      ,"%s",KW_STRING,UMSCODE_ZerAttr      },
        { "MausAttr"     ,"%s",KW_STRING,UMSCODE_MausAttr     },

        { "TempFileName" ,"%s",KW_STRING,UMSCODE_TempFileName },

        { "CDate","%d-%b-%y %X",KW_DATE,UMSCODE_CreationDate },
        { "IDate","%d-%b-%y %X",KW_DATE,UMSCODE_ReceiveDate  },

        { "MsgNum"      ,"%ld"  ,KW_NUMBER,12 },
        { "ChainUp"     ,"%ld"  ,KW_NUMBER, 3 },
        { "ChainDown"   ,"%ld"  ,KW_NUMBER, 4 },
        { "ChainLeft"   ,"%ld"  ,KW_NUMBER, 5 },
        { "ChainRight"  ,"%ld"  ,KW_NUMBER, 6 },
        { "HardLink"    ,"%ld"  ,KW_NUMBER,10 },
        { "SoftLink"    ,"%ld"  ,KW_NUMBER,11 },

        { "GlobalStatus","%08lx",KW_FLAG, 7 },
        { "UserStatus"  ,"%08lx",KW_FLAG, 8 },
        { "LoginStatus" ,"%08lx",KW_FLAG, 9 },

        { "QuoteText","> ",KW_QTEXT,UMSCODE_MsgText },

        { NULL,0,0 }
};

char *DefaultFormat = "\
Group..: <Group>\n\
From...: <FromName> (<FromAddr>)\n\
To.....: <ToName> (<ToAddr>)\n\
Subject: <Subject>\n\
\n\
<MsgText>\n\
";

static char filteradd[] = " AND readaccess=1 AND viewaccess=1";

#define FILTERADDSTR  filteradd
#define NULLFILTERSTR (&filteradd[5])
#define FILTERADDLEN  35


// Functions
// ---------

LONG PrintMessage(char *format);


// CTRL-C Stuff
// ------------

int brk(void)
{
        return(0);
}

#define ABORTED (SetSignal(0,0) & SIGBREAKF_CTRL_C)


// Main Function
// -------------

int main(int argc,char *argv[])
{
        char *filter;
        char *format = DefaultFormat;
        char *language=NULL;
        int erg = RETURN_ERROR, umserr;
        int nr=0;
        int oldtag = UMSTAG_RNoUpdate;
        int direction = 1;
        int fi;
        struct RDArgs *args_ptr;

        onbreak(brk);

        if (argc<2 || *argv[1] == '?')
        {
                fprintf(stderr,"\33[1m%s\33[0m, written by Stefan Stuntz, Public Domain.\n\nTemplate: %s\n%s",&VersionString[6],TemplateString,UsageString);
        }

        {
                int i;

                for (i=0; i<OPT_COUNT; i++)
                opts[i]=NULL;
        }

        if (args_ptr = ReadArgs(TemplateString, opts, NULL))
        {
                if (opts[OPT_FORMATFILE])
                {
                        FILE *f;
                        int len;
                        if (f=fopen((char *)opts[OPT_FORMATFILE],"rb"))
                        {
                                fseek(f,0,2);
                                len=ftell(f);
                                fseek(f,0,0);
                                if (!(len>0 && (format=calloc(1,len+1)) && fread(format,1,len,f)==len))
                                        format = DefaultFormat;
                                fclose(f);
                        }
                        else
                        {
                                fprintf(stderr,"\7Format file \"%s\" not found.\n",opts[OPT_FORMATFILE]);
                                FreeArgs(args_ptr);
                                return(20);
                        }
                }
                else
                        if (opts[OPT_FORMAT])
                                format = (char *)opts[OPT_FORMAT];

                if (opts[OPT_SETOLDFLAG])
                        oldtag    = TAG_IGNORE;

                if (opts[OPT_BACKWARDS])
                        direction = -1;

                if (!strnicmp(format,"LANGUAGE: ",10))
                {
                        language = format+10;
                        if (!(format=strchr(language,'\n')))
                        {
                                fprintf(stderr,"\7Invalid language spec in format file.");
                                FreeArgs(args_ptr);
                                return(20);
                        }
                        *format++=0;
                }

                if (!(filter = malloc(strlen((char *)(opts[OPT_FILTER]))+FILTERADDLEN)))
                {
                        fprintf(stderr,"\7Out of memory.\n");
                        FreeArgs(args_ptr);
                        return(20);
                }

                if (opts[OPT_FILTER] && *(char *)opts[OPT_FILTER])
                {
                        strcpy(filter,(char *)opts[OPT_FILTER]);
                        strcat(filter,FILTERADDSTR);
                }
                else
                {
                        strcpy(filter,NULLFILTERSTR);
                }

                if (LocaleBase = OpenLibrary("locale.library",38))
                        Locale = OpenLocale(language);

                if (UMSBase = OpenLibrary(UMSNAME,UMSVERSION))
                {
                        if (acc = UMSRLogin((char *)opts[OPT_SERVER],(char *)opts[OPT_USER],(char *)opts[OPT_PASSWORD]))
                        {
                                if (!(fi = UmsFilterExpression(filter,acc,0,0,1)))
                                {
                                        erg = RETURN_OK;
                                        while (nr = UMSSearchTags(acc,
                                                    UMSTAG_SearchLast     ,nr,
                                                    UMSTAG_SearchLocal    ,TRUE,
                                                    UMSTAG_SearchMask     ,1,
                                                    UMSTAG_SearchMatch    ,1,
                                                                        UMSTAG_SearchDirection,direction,
                                                    TAG_DONE))
                                        {
                                                if (ABORTED)
                                                {
                                                        fprintf(stderr,"\7*** User break.\n");
                                                        erg = RETURN_WARN;
                                                        break;
                                                }

                                                if (umserr=UMSReadMsgTags(acc,
                                                    UMSTAG_RMsgNum    ,nr,
                                                    UMSTAG_RMsgInfo   ,&MessageInfo,
                                                    UMSTAG_RTextFields,TextFields,
                                                    UMSTAG_RReadAll   ,TRUE,
                                                    oldtag            ,TRUE,
                                                    TAG_DONE))
                                                {
                                                        if (!TextFields[UMSCODE_Group] || !*TextFields[UMSCODE_Group])
                                                                TextFields[UMSCODE_Group]="Netmail";
                                                        MessageInfo.msgi_MsgNum = nr;
                                                        if ( PrintMessage(format) ) {
                                                                erg = RETURN_WARN;
                                                                UMSFreeMsg(acc,nr);
                                                                break;
                                                        }
                                                        UMSFreeMsg(acc,nr);
                                                }
                                                else
                                                {
                                                        fprintf(stderr,"UMS-Error %d: %s\n",UMSErrNum(acc),UMSErrTxt(acc));
                                                        erg = RETURN_WARN;
                                                        /* kludge for bad behavior of UMSSearchTags() */
                                                        if ( umserr==UMSERR_ServerTerminated ) {
                                                                erg = RETURN_ERROR;
                                                                break;
                                                        }
                                                }
                                        }
                                }
                                else printf("\7Expression Error %ld\n",fi);

                                UMSLogout(acc);
                        }
                        else fprintf(stderr,"\7UMS-Login failed.\n");

                        CloseLibrary(UMSBase);
                }
                else fprintf(stderr,"\7Could not open ums.library V10.\n");

                if (LocaleBase)
                {
                        if (Locale) CloseLocale(Locale);
                        CloseLibrary(LocaleBase);
                }

                FreeArgs(args_ptr);
        }
        else
        {
                PrintFault(IoErr(), NULL);
                return(RETURN_ERROR);
        }

        return(erg);
}


struct Keyword *FindKeyword(char *name)
{
        struct Keyword *k;

        for (k=Keywords;k->name;k++)
        {
                if (!stricmp(name,k->name)) return(k);
        }
        return(NULL);
}


#ifdef _DCC
VOID DatePutCharFunc(__A0 struct MyHook *h, __A1 UBYTE c, __A2 struct Locale *loc)
{
        *h->h_Data++=c;
}
#else
VOID __asm DatePutCharFunc(register __a0 struct MyHook *h,register __a1 UBYTE c,register __a2 struct Locale *loc)
{
        *h->h_Data++ = c;
}
#endif


LONG PrintMessage(char *format)
{
        static char buf[50];
        char *c = format;
        char *ob,*cb,*fmt;
        int len;
        struct Keyword *k;

        while (*c)
        {
                if (*c=='<')
                {
                        ob=c;
                        if (!(cb=strchr(ob+1,'>'))) break;
                        c=cb+1;
                        if ((len=cb-ob-1)>49) break;
                        strncpy(buf,ob+1,len); buf[len]=0;
                        if (fmt=strchr(buf,',')) *fmt++=0;
                        if (k=FindKeyword(buf))
                        {
                                if (!fmt) fmt=k->format;
                                if (k->type==KW_STRING)
                                {
                                        printf(fmt,TextFields[k->code] ? TextFields[k->code] : "");
                                }
                                else if (k->type==KW_NUMBER)
                                {
                                        printf(fmt,((LONG *)&MessageInfo)[k->code]);
                                }
                                else if (k->type==KW_FLAG)
                                {
                                        if ( *fmt!='%' )
                                        {
                                                char    *scan,*cfstart=fmt,output[34],*pptr;
                                                ULONG   p,flags=((LONG *)&MessageInfo)[k->code];

                                                if ( pptr=strchr(fmt,'%') )
                                                {
                                                        scan=pptr-1;
                                                        fmt=pptr;
                                                }
                                                else
                                                {
                                                        scan=fmt+strlen(fmt)-1;
                                                        fmt="%s";
                                                }

                                                pptr=output;
                                                p=1;
                                                while ( scan>=cfstart )
                                                {
                                                        if ( *scan!='-' )
                                                        {
                                                                if ( flags&p )
                                                                {
                                                                        *pptr++=toupper(*scan);
                                                                }
                                                                else
                                                                {
                                                                        if ( isupper(*scan) )
                                                                                *pptr++='-';
                                                                }
                                                        }
                                                        scan--;
                                                        p<<=1;
                                                }
                                                *pptr='\0';
                                                printf(fmt,output);
                                        }
                                        else
                                        {
                                                printf(fmt,((LONG *)&MessageInfo)[k->code]);
                                        }
                                }
                                else if (k->type==KW_DATE && Locale)
                                {
                                        LONG secs;
                                        char *dstr = TextFields[UMSCODE_CreationDate] ? TextFields[UMSCODE_CreationDate] : "";

                                        if (k->code == UMSCODE_CreationDate)
                                        {
                                                secs = DateToSeconds(dstr);
                                        }
                                        else
                                        {
                                                if (!(secs = MessageInfo.msgi_Date)) secs=1;
                                        }

                                        if (secs)
                                        {
                                                struct DateStamp ds;
                                                static char buf[256];
                                                struct MyHook hook = {{0,0},(APTR)DatePutCharFunc,NULL,buf };

                                                ds.ds_Days   = secs/(24*60*60);
                                                ds.ds_Minute = (secs%(24*60*60))/60;
                                                ds.ds_Tick   = (secs%60)*50;

                                                FormatDate(Locale,fmt,&ds,&hook);
                                                printf("%s",buf);
                                        }
                                        else
                                                printf("%s",dstr);
                                }
                                else if (k->type==KW_QTEXT)
                                {
                                        char *str = TextFields[k->code] ? TextFields[k->code] : "";
                                        int pos=0,npos;

                                        while (*str)
                                        {
                                                if (pos==0) printf("%s",fmt);

                                                switch (*str)
                                                {
                                                        case '\r':      putchar('\n');
                                                                                        pos=0;
                                                                                        if (*++str=='\n') str++;
                                                                                        break;

                                                        case '\n':      putchar('\n');
                                                                                        pos=0;
                                                                                        if (*++str=='\r') str++;
                                                                                        break;

                                                        case '\t':  npos = pos + 8 - (pos%8);
                                                                                        while (pos!=npos) { putchar(' '); pos++; }
                                                                                        str++;
                                                                                        if (++pos>79) { putchar('\n'); pos=0; }
                                                                                        break;

                                                        default:                putchar(*str);
                                                                                        str++;
                                                                                        if (++pos>79) { putchar('\n'); pos=0; }
                                                                                        break;
                                                }
                                        }
                                }
                        }
                        else
                                fprintf(stderr,"\7Unknown Keyword: %s\n",buf);
                }
                else if (*c=='\\')
                {
                        if (!(*++c)) break;
                        switch (*c)
                        {
                                case '\^': putchar('^');  break;
                                case '\\': putchar('\\'); break;
                                case 'n' : putchar('\n'); break;
                                case 'r' : putchar('\r'); break;
                                case 't' : putchar('\t'); break;
                                case 'f' : putchar('\f'); break;
                                case '<' : putchar('<');  break;
                                case '>' : putchar('>');  break;
                                case 'e' : putchar(27);   break;
                                default  : putchar(*c);   break;
                        }
                        c++;
                }
                else if (*c=='^')
                {
                        if (!(*++c)) break;
                        putchar(*c & (~64));
                        c++;
                }
                else
                {
                        putchar(*c);
                        c++;
                }
                if ( ABORTED ) {
                        puts("\n*** User break");
                        return 5;
                }
        }
        return 0;
}
