#define UmsBase UMSBase

/*
** Make the generale purpose filter from filter.c to be
** a filter for the UMS message base.
**
** Defines a FilterSpec with certain keywords and a bithook
** for the actual filtering.
*/

/*
** 03-Jan-94 [kmel] Corrected FIL_ACTION_LOWER at case ID_DATE,
**                  because UMS only selects _younger_ messages
**                  compared with the defined date.
*/


#include <exec/types.h>

#include <utility/hooks.h>
#include <exec/memory.h>


#include <libraries/ums.h>
#include <clib/ums_protos.h>
#ifdef _DCC
#include <proto/ums.h>
#else
#include <pragmas/ums_pragmas.h>
#endif

#include <clib/exec_protos.h>
#ifdef _DCC
#include <proto/exec.h>
#else
#include <pragmas/exec_pragmas.h>
#endif

#include <clib/dos_protos.h>
#ifdef _DCC
#include <proto/dos.h>
#else
#include <pragmas/dos_pragmas.h>
#endif


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

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

/* SMAKE */


extern struct Library *UMSBase;
extern struct Library *DOSBase;


#define ID_STRING  1
#define ID_UFLAG   2
#define ID_GFLAG   3
#define ID_DATE    4
#define ID_AGE     5
#define ID_MSGNUM  6
#define ID_LAST    7


static BOOL chktrue(char *s)
{
	if (atol(s) || !stricmp(s,"yes") || !stricmp(s,"on") || !stricmp(s,"ja") || !stricmp(s,"ein") || !stricmp(s,"an"))
		return(TRUE);
	else
		return(FALSE);
}


static VOID SetFromHelp(UMSUserAccount acc,ULONG help,struct FilterHookPacket *fhp)
{
	UMSSelectTags(acc,
		UMSTAG_SelReadLocal , TRUE,
		UMSTAG_SelMask      , fhp->mask  | help,
		UMSTAG_SelMatch     , fhp->match | help,
		UMSTAG_SelWriteLocal, TRUE,
		UMSTAG_SelSet       , fhp->set,
		UMSTAG_SelUnset     , fhp->clear,
		TAG_DONE);

	UMSSelectTags(acc,
		UMSTAG_SelReadLocal , TRUE,
		UMSTAG_SelMask      , help,
		UMSTAG_SelMatch     , help,
		UMSTAG_SelWriteLocal, TRUE,
		UMSTAG_SelUnset     , help,
		TAG_DONE);
}



#ifdef _DCC
__geta4 static LONG bitfunc(__A0 struct Hook *hook, __A2 UMSUserAccount acc, __A1 struct FilterHookPacket *fhp)
#else
static LONG __saveds __asm bitfunc(register __a0 struct Hook *hook, register __a2 UMSUserAccount acc, register __a1 struct FilterHookPacket *fhp)
#endif
{
	LONG res = FIL_ERROR_MISC;

/* printf("func: mask %08lx match %08lx set %08lx clear %08lx action %ld data %s\n",fhp->mask,fhp->match,fhp->set,fhp->clear,fhp->action,fhp->data); */

	switch (fhp->action)
	{
		case FIL_ACTION_BITS:
		{
			UMSSelectTags(acc,
				UMSTAG_SelReadLocal , TRUE,
				UMSTAG_SelMask      , fhp->mask ,
				UMSTAG_SelMatch     , fhp->match,
				UMSTAG_SelWriteLocal, TRUE,
				UMSTAG_SelSet       , fhp->set,
				UMSTAG_SelUnset     , fhp->clear,
				TAG_DONE);

			res = FIL_ERROR_OK;
		}
		break;

		case FIL_ACTION_EQUAL:
		{
			switch (fhp->uid)
			{
				case ID_STRING:
				{
					if (strchr(fhp->data,'#') || strchr(fhp->data,'?') || strchr(fhp->data,'*'))
					{
						int nr=0;

						while (nr = UMSSearchTags(acc,
						            UMSTAG_SearchLast   , nr,
						            UMSTAG_SearchLocal  , TRUE,
						            UMSTAG_SearchMask   , fhp->mask ,
						            UMSTAG_SearchMatch  , fhp->match,
										(ULONG)fhp->udata   , fhp->data,
										UMSTAG_SearchPattern, 2,
				   		         TAG_DONE))
						{
							UMSSelectTags(acc,
								UMSTAG_SelWriteLocal, TRUE,
								UMSTAG_SelStart     , nr,
								UMSTAG_SelStop      , nr+1,
								UMSTAG_SelSet       , FIL_LASTBIT,
								TAG_DONE);
						}
					}
					else
					{
						UMSSelectTags(acc,
							UMSTAG_SelQuick     , TRUE,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelSet       , FIL_LASTBIT,
							(ULONG)fhp->udata   , fhp->data,
							TAG_DONE);
					}

					SetFromHelp(acc,FIL_LASTBIT,fhp);

					res = FIL_ERROR_OK;
				}
				break;

				case ID_GFLAG:
				case ID_UFLAG:
				{
					UMSSelectTags(acc,
						fhp->uid==ID_GFLAG ? UMSTAG_SelReadGlobal : TAG_IGNORE, TRUE,
						UMSTAG_SelWriteLocal, TRUE,
						UMSTAG_SelMask      , (ULONG)fhp->udata,
						UMSTAG_SelMatch     , chktrue(fhp->data) ? (ULONG)fhp->udata : 0,
						UMSTAG_SelSet       , FIL_LASTBIT,
						TAG_DONE);

					SetFromHelp(acc,FIL_LASTBIT,fhp);

					res = FIL_ERROR_OK;
				}
				break;

				case ID_AGE:
				case ID_DATE:
				{
					LONG secs = fhp->uid==ID_DATE ? DateToSeconds(fhp->data) : (CurrentSeconds()/(24*60*60) - atol(fhp->data))*(24*60*60);

					if (secs>0)
					{
						UMSSelectTags(acc,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelDate      , secs,
							UMSTAG_SelSet       , FIL_LASTBIT,
							TAG_DONE);

						UMSSelectTags(acc,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelDate      , secs + 24*60*60-1,
							UMSTAG_SelUnset     , FIL_LASTBIT,
							TAG_DONE);

						SetFromHelp(acc,FIL_LASTBIT,fhp);

						res = FIL_ERROR_OK;
					}
				}
				break;

				case ID_MSGNUM:
				{
					UMSSelectTags(acc,
						UMSTAG_SelWriteLocal, TRUE,
						UMSTAG_SelStart     , atol(fhp->data),
						UMSTAG_SelStop      , atol(fhp->data)+1,
						UMSTAG_SelSet       , FIL_LASTBIT,
						TAG_DONE);

					SetFromHelp(acc,FIL_LASTBIT,fhp);

					res = FIL_ERROR_OK;
				}
				break;
			}
		}
		break;

		case FIL_ACTION_LOWER:
		{
			switch (fhp->uid)
			{
				case ID_AGE:
				{
					LONG secs = (CurrentSeconds()/(24*60*60) - atol(fhp->data))*(24*60*60);

					if (secs>0)
					{
						UMSSelectTags(acc,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelDate      , secs + 24*60*60,
							UMSTAG_SelSet       , fhp->set,
							UMSTAG_SelUnset     , fhp->clear,
							TAG_DONE);

						res = FIL_ERROR_OK;
					}
				}
				break;

				case ID_DATE:
				{
					LONG secs = DateToSeconds(fhp->data);

					if (secs>0)
					{
						UMSSelectTags(acc,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelMask      , 0,
							UMSTAG_SelMatch     , 0,
							UMSTAG_SelSet       , FIL_LASTBIT,
							TAG_DONE);

						UMSSelectTags(acc,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelDate      , secs,
							UMSTAG_SelUnset     , FIL_LASTBIT,
							TAG_DONE);

						SetFromHelp(acc,FIL_LASTBIT,fhp);

						res = FIL_ERROR_OK;
					}
				}
				break;

				case ID_MSGNUM:
				{
					UMSSelectTags(acc,
						UMSTAG_SelWriteLocal, TRUE,
						UMSTAG_SelStart     , 0,
						UMSTAG_SelStop      , atol(fhp->data),
						UMSTAG_SelSet       , FIL_LASTBIT,
						TAG_DONE);

					SetFromHelp(acc,FIL_LASTBIT,fhp);

					res = FIL_ERROR_OK;
				}
				break;

				default:
				{
					res = FIL_ERROR_INVALIDRELATION;
				}
				break;
			}
		}
		break;

		default:
		{
			res = FIL_ERROR_INVALIDRELATION;
		}
		break;
	}
	return(res);
}


static const struct Hook bithook = { { NULL,NULL },(VOID *)bitfunc,NULL,NULL };


struct FilterSpec UmsFilterSpec[] =
{
	{ "MsgText"     , ID_STRING , (APTR)UMSTAG_WMsgText       },
	{ "FromName"    , ID_STRING , (APTR)UMSTAG_WFromName      },
	{ "FromAddr"    , ID_STRING , (APTR)UMSTAG_WFromAddr      },
	{ "ToName"      , ID_STRING , (APTR)UMSTAG_WToName        },
	{ "ToAddr"      , ID_STRING , (APTR)UMSTAG_WToAddr        },
	{ "MsgID"       , ID_STRING , (APTR)UMSTAG_WMsgID         },
	{ "CreationDate", ID_STRING , (APTR)UMSTAG_WCreationDate  },
	{ "ReceiveDate" , ID_STRING , (APTR)UMSTAG_WReceiveDate   },
	{ "ReferID"     , ID_STRING , (APTR)UMSTAG_WReferID       },
	{ "Group"       , ID_STRING , (APTR)UMSTAG_WGroup         },
	{ "Subject"     , ID_STRING , (APTR)UMSTAG_WSubject       },
	{ "Attributes"  , ID_STRING , (APTR)UMSTAG_WAttributes    },
	{ "Comments"    , ID_STRING , (APTR)UMSTAG_WComments      },
	{ "Organization", ID_STRING , (APTR)UMSTAG_WOrganization  },
	{ "Distribution", ID_STRING , (APTR)UMSTAG_WDistribution  },
	{ "Folder"      , ID_STRING , (APTR)UMSTAG_WFolder        },

	{ "Archive"     , ID_UFLAG  , (APTR)UMSUSTATF_Archive     },
	{ "Junk"        , ID_UFLAG  , (APTR)UMSUSTATF_Junk        },
	{ "PostPoned"   , ID_UFLAG  , (APTR)UMSUSTATF_PostPoned   },
	{ "Selected"    , ID_UFLAG  , (APTR)UMSUSTATF_Selected    },
	{ "Old"         , ID_UFLAG  , (APTR)UMSUSTATF_Old         },
	{ "WriteAccess" , ID_UFLAG  , (APTR)UMSUSTATF_WriteAccess },
	{ "ReadAccess"  , ID_UFLAG  , (APTR)UMSUSTATF_ReadAccess  },
	{ "ViewAccess"  , ID_UFLAG  , (APTR)UMSUSTATF_ViewAccess  },
	{ "Owner"       , ID_UFLAG  , (APTR)UMSUSTATF_Owner       },

	{ "UFlag0"      , ID_UFLAG  , (APTR)(1<<0 )               },
	{ "UFlag1"      , ID_UFLAG  , (APTR)(1<<1 )               },
	{ "UFlag2"      , ID_UFLAG  , (APTR)(1<<2 )               },
	{ "UFlag3"      , ID_UFLAG  , (APTR)(1<<3 )               },
	{ "UFlag4"      , ID_UFLAG  , (APTR)(1<<4 )               },
	{ "UFlag5"      , ID_UFLAG  , (APTR)(1<<5 )               },
	{ "UFlag6"      , ID_UFLAG  , (APTR)(1<<6 )               },
	{ "UFlag7"      , ID_UFLAG  , (APTR)(1<<7 )               },
	{ "UFlag8"      , ID_UFLAG  , (APTR)(1<<8 )               },
	{ "UFlag9"      , ID_UFLAG  , (APTR)(1<<9 )               },
	{ "UFlagA"      , ID_UFLAG  , (APTR)(1<<10)               },
	{ "UFlagB"      , ID_UFLAG  , (APTR)(1<<11)               },
	{ "UFlagC"      , ID_UFLAG  , (APTR)(1<<12)               },
	{ "UFlagD"      , ID_UFLAG  , (APTR)(1<<13)               },
	{ "UFlagE"      , ID_UFLAG  , (APTR)(1<<14)               },
	{ "UFlagF"      , ID_UFLAG  , (APTR)(1<<15)               },

	{ "Deleted"     , ID_GFLAG  , (APTR)UMSGSTATF_Deleted     },
	{ "Expired"     , ID_GFLAG  , (APTR)UMSGSTATF_Expired     },
	{ "Exported"    , ID_GFLAG  , (APTR)UMSGSTATF_Exported    },
	{ "Orphan"      , ID_GFLAG  , (APTR)UMSGSTATF_Orphan      },
	{ "Link"        , ID_GFLAG  , (APTR)UMSGSTATF_Link        },
	{ "Hardlink"    , ID_GFLAG  , (APTR)UMSGSTATF_HardLink    },

	{ "Age"         , ID_AGE    , 0                           },
	{ "Date"        , ID_DATE   , 0                           },
	{ "MsgNum"      , ID_MSGNUM , NULL                        },

	{ NULL          , NULL      , NULL                        }
};


LONG UmsFilterExpression(char *str,UMSUserAccount acc,ULONG mask,ULONG match,ULONG setbit)
{
	return(FilterExpression((struct Hook *)&bithook,UmsFilterSpec,str,acc,mask,match,setbit));
}
