
/*
** 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.
**
** 02-May-94 [MS]   corrected search for constant expressions on
**                  header fields without index
*/


#include "sumstl.h"

#include <stdio.h>

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

extern struct Library *UMSBase;
extern struct DosLibrary *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(UMSAccount 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 UMSAccount acc, __A1 struct FilterHookPacket *fhp)
#else
static LONG __saveds __asm bitfunc(register __a0 struct Hook *hook, register __a2 UMSAccount 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,'*'))
					{
						UMSMsgNum nr=0L;

						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, 2L,
				   		         TAG_DONE))
						{
							UMSSelectTags(acc,
								UMSTAG_SelWriteLocal, TRUE,
								UMSTAG_SelStart     , nr,
								UMSTAG_SelStop      , nr+1,
								UMSTAG_SelSet       , FIL_LASTBIT,
								TAG_DONE);
						}
					}
					else
					{
						if (UMSSelectTags(acc,
							UMSTAG_SelQuick     , TRUE,
							UMSTAG_SelWriteLocal, TRUE,
							UMSTAG_SelSet       , FIL_LASTBIT,
							(ULONG)fhp->udata   , fhp->data,
							TAG_DONE)==0L)
							if (UMSErrNum(acc)==UMSERR_MissingIndex)
							{
								UMSMsgNum nr=0L;

								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, 2L,
					   		         TAG_DONE))
								{
									UMSSelectTags(acc,
									UMSTAG_SelWriteLocal, TRUE,
									UMSTAG_SelStart     , nr,
									UMSTAG_SelStop      , nr+1,
									UMSTAG_SelSet       , FIL_LASTBIT,
									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        },
	{ "ReplyGroup"   , ID_STRING , (APTR)UMSTAG_WReplyGroup    },
	{ "ReplyName"    , ID_STRING , (APTR)UMSTAG_WReplyName     },
	{ "ReplyAddr"    , ID_STRING , (APTR)UMSTAG_WReplyAddr     },
	{ "LogicalToName", ID_STRING , (APTR)UMSTAG_WLogicalToName },
	{ "LogicalToAddr", ID_STRING , (APTR)UMSTAG_WLogicalToAddr },
	{ "RFCMsgNum"    , ID_STRING , (APTR)UMSTAG_WRFCMsgNum     },

	{ "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,UMSAccount acc,ULONG mask,ULONG match,ULONG setbit)
{
	return(FilterExpression((struct Hook *)&bithook,UmsFilterSpec,str,acc,mask,match,setbit));
}
