/*****************************************************************************/ /* search.c Search VMS Mail folders and messages. By default uses it's own internal search, not VMS message select (at least for TO, FROM, CC, SUBJ and dates). Search tries to be a good citizen by allowing the administrator to configure the process priority during searches of the message body. See CONFIG.C for detail. If a search string begins with a caret ('^') character the regular expression search is invoked, otherwise it is treated as a space-delimitted keyword search (as with VMS Mail select). Because of the expense of regular expression search it can be disabled in soyMAIL configuration. REGEX EVALUATION ---------------- Uses the GNU RX1.5 regular expression package. Evaluation is done using case-insensitive, EGREP-compatible matching. A detailed tutorial on regular expression capabilities and usage is well beyond the scope of this document. This summary is only to serve as a quick mnemonic. soyMAIL regular expressions support the following set of operators. Operator Overview Description Usage ----------- ----- Match-self Operator Ordinary characters Match-any-character Operator . Concatenation Operator Juxtaposition. Repetition Operators * + ? {} Alternation Operator | List Operators [...] [^...] Grouping Operators (...) Back-reference Operator \digit Anchoring Operators ^ $ Backslash Operator Escape meta-character (e.g. \ ^ . $ | [ () The following operators are used to match one, or in conjunction with the repetition operators more, characters of the target string. These single and leading characters are reserved meta-characters and must be escaped using a leading backslash ("\") if required as a literal character in the matching pattern. Matching Operators Expression Purpose ---------- ------- ^ Match the beginning of the line . Match any character $ Match the end of the line | Alternation (or) [abc] Match only a, b or c [^abc] Match anything except a, b and c [a-z0-9] Match any character in the range a to z or 0 to 9 Repetition operators control the extent, or number, of whatever the matching operators match. These are also reserved meta-characters and must be escaped using a leading backslash if required as a literal character. Repetition Operators Expression Function ---------- -------- * Match 0 or more times + Match 1 or more times ? Match 1 or zero times {n} Match exactly n times {n,} Match at least n times {n,m} Match at least n but not more than m times Regular expression equivalents of these common wildcards asterisk ('*') .* question mark ('?') . percentage ('%') . COPYRIGHT --------- Copyright (C) 2005-2023 Mark G.Daniel This program, comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version. VERSION HISTORY --------------- 15-AUG-2007 MGD support searching against message flags 19-APR-2007 MGD SearchMessage() refine RFC822 header error processing 28-DEC-2006 MGD SearchGetString() modify to allow significant spaces 04-JUL-2005 MGD SearchPage() add results every "all hit(s)" 03-APR-2005 MGD support public access searching 27-JAN-2006 MGD bugfix; SearchKeyword() lower-case the keyword! 01-FEB-2005 MGD initial */ /*****************************************************************************/ #ifdef SOYMAIL_VMS_V7 #undef _VMS_V6_SOURCE #define _VMS_V6_SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif #pragma nomember_alignment /* standard C header files */ #include #include #include #include #include #include #include #include /* VMS related header files */ #include #include #include /* application header file */ #include #include #include #include #include #include "regex.h" #define FI_LI __FILE__, __LINE__ #define MAIL$M_NEWMSG 0x01 #define MAIL$M_REPLIED 0x02 #define MAIL$M_MARKED 0x80 /******************/ /* global storage */ /******************/ int SearchEpoch = 1978, /* ;-) */ SearchRegexCflags = REG_EXTENDED | REG_ICASE | REG_NOSUB, SearchRegexEflags = 0, SearchPrevPriority = -1; /********************/ /* external storage */ /********************/ extern BOOL Debug, WatchEnabled; extern int VmsVersion; extern short CurrentNumTime[]; extern char CommandLine[], SoftwareVn[], Utility[]; extern CONFIG_DATA SoyMailConfig; extern VMS_MAIL_USER VmsMailUser; /**************/ /* prototypes */ /**************/ int lib$sub_times (__unknown_params); int sys$bintim (__unknown_params); int sys$setpri (__unknown_params); /****************************************************************************/ /* */ BOOL SearchPageRequest (REQUEST_DATA *rdptr) { char *cptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchPageRequest()\n"); if (!SoyMailConfig.SearchEnabled) { StatusMessage (FI_LI, 1, "%s", LangFor("search_disabled")); if (rdptr->PrevPageIdent == PAGE_SEARCH) { SearchPage (rdptr); return (TRUE); } return (FALSE); } CGIVARNULL (cptr, "FORM_SEARCH_BTN"); if (cptr) { if (rdptr->PrevPageIdent != PAGE_SEARCH) ErrorExit (SS$_BUGCHECK, FI_LI); if (LangSame ("search_begin", cptr)) { if (rdptr->SearchData.SearchProblem) SearchPage (rdptr); else MessageFolderPage (rdptr); } else if (LangSame ("search_clear", cptr)) { memset (&rdptr->SearchData, 0, sizeof(SEARCH_DATA)); SearchPage (rdptr); } else ErrorExit (SS$_BUGCHECK, FI_LI); } else SearchPage (rdptr); return (TRUE); } /****************************************************************************/ /* Move required search criteria from the search structure into the VMS message structure to allow callable Mail to select the relevant items. */ void SearchCriteria (REQUEST_DATA *rdptr) { static char *MonthAbrev [] = { "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; SEARCH_DATA *srptr; VMS_MAIL_MSG *vmptr; VMS_MAIL_USER *muptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchCriteria()\n"); muptr = &VmsMailUser; srptr = &rdptr->SearchData; vmptr = &muptr->VmsMailMsg; if (!srptr->SelectNotSearch) return; /* there will always be room for these copies */ if (srptr->From[0]) vmptr->FromLength = (unsigned long)strcpy (vmptr->From, srptr->From); if (srptr->To[0]) vmptr->ToLength = (unsigned long)strcpy (vmptr->To, srptr->To); if (srptr->Cc[0]) vmptr->CcLength = (unsigned long)strcpy (vmptr->Cc, srptr->Cc); if (srptr->Subject[0]) vmptr->SubjectLength = (unsigned long)strcpy (vmptr->Subject, srptr->Subject); if (srptr->DateScope == SEARCH_DATE_SCOPE_SINCE) { vmptr->TimeSinceLength = sprintf (vmptr->TimeSince, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); } if (srptr->DateScope == SEARCH_DATE_SCOPE_BEFORE) { vmptr->TimeBeforeLength = sprintf (vmptr->TimeBefore, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); } if (srptr->DateScope == SEARCH_DATE_SCOPE_ON) { vmptr->TimeSinceLength = sprintf (vmptr->TimeSince, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); vmptr->TimeBeforeLength = sprintf (vmptr->TimeBefore, "%02.02d-%s-%04.04d 23:59:59", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); } vmptr->SelectMessageFlags = 0; if (srptr->Category == SEARCH_CATEGORY_NEWMSG) vmptr->SelectMessageFlags |= MAIL$M_NEWMSG; if (srptr->Category == SEARCH_CATEGORY_MARKED) vmptr->SelectMessageFlags |= MAIL$M_MARKED; if (srptr->Category == SEARCH_CATEGORY_REPLIED) vmptr->SelectMessageFlags |= MAIL$M_REPLIED; } /****************************************************************************/ /* Check for parameters from the search criteria page. Populate if present (means a new search is being initiated), otherwise propagate from previous request state search data (so they will be the defaults of the next search). */ void SearchPropagate (REQUEST_DATA *rdptr) { static char *MonthAbrev [] = { "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; BOOL ParamHit = FALSE; int retval, status; char *cptr, *sptr, *zptr, *CriPtr; char CriteriaString [512], TimeString [21]; $DESCRIPTOR (TimeStringDsc, TimeString); REQUEST_DATA *sdptr; SEARCH_DATA *srptr; VMS_MAIL_MSG *vmptr; VMS_MAIL_USER *muptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchPropagate()\n"); if (!SoyMailConfig.SearchEnabled) return; muptr = &VmsMailUser; srptr = &rdptr->SearchData; sdptr = (REQUEST_DATA*)rdptr->StateDataPtr; vmptr = &muptr->VmsMailMsg; if (rdptr->PrevPageIdent != PAGE_SEARCH) { /* propagate (any) previous search parameters from request to request */ memcpy (srptr, &sdptr->SearchData, sizeof(SEARCH_DATA)); return; } memset (srptr, 0, sizeof(SEARCH_DATA)); CriPtr = CriteriaString; CGIVARNULL (cptr, "FORM_SEARCH_VMS_SELECT"); if (cptr) srptr->SelectNotSearch = TRUE; else srptr->SelectNotSearch = FALSE; srptr->SearchProblem = FALSE; /*********************/ /* header parameters */ /*********************/ CGIVARNULL (cptr, "FORM_SEARCH_FROM"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->From, sizeof(srptr->From), &srptr->RegexFrom, "from"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("from"), srptr->From); } CGIVARNULL (cptr, "FORM_SEARCH_TO"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->To, sizeof(srptr->To), &srptr->RegexTo, "to"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("to"), srptr->To); } CGIVARNULL (cptr, "FORM_SEARCH_CC"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->Cc, sizeof(srptr->Cc), &srptr->RegexCc, "cc"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("cc"), srptr->Cc); } CGIVARNULL (cptr, "FORM_SEARCH_SUBJECT"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->Subject, sizeof(srptr->Subject), &srptr->RegexSubject, "subject"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("subject"), srptr->Subject); } /***************************/ /* message body parameters */ /***************************/ if (!SoyMailConfig.SearchHeaderOnly) { CGIVARNULL (cptr, "FORM_SEARCH_MESSAGE"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->Message, sizeof(srptr->Message), &srptr->RegexMessage, "message"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("search_message"), srptr->Message); } CGIVARNULL (cptr, "FORM_SEARCH_ATTACHMENT"); if (cptr && *cptr) { ParamHit = TRUE; SearchGetString (srptr, cptr, srptr->Attachment, sizeof(srptr->Attachment), &srptr->RegexAttachment, "attachment"); CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("search_attachment"), srptr->Attachment); } } if (!SoyMailConfig.SearchHeaderOnly || SoyMailConfig.MessageFlags) { srptr->Category = 0; CGIVARNULL (cptr, "FORM_SEARCH_CATEGORY"); if (cptr && *cptr) { srptr->Category = atoi(cptr); if (srptr->Category < SEARCH_CATEGORY_ANY || srptr->Category > SEARCH_CATEGORY__LAST) srptr->Category = SEARCH_CATEGORY_ANY; } switch (srptr->Category) { case 0 : cptr = NULL; break; case SEARCH_CATEGORY_ANY : cptr = NULL; break; case SEARCH_CATEGORY_HTML : cptr = LangFor("search_cat_html"); break; case SEARCH_CATEGORY_PLAIN : cptr = LangFor("search_cat_plain"); break; case SEARCH_CATEGORY_RAW : cptr = LangFor("search_cat_raw"); break; case SEARCH_CATEGORY_RFC : cptr = LangFor("search_cat_rfc"); break; case SEARCH_CATEGORY_WITH_ATT : cptr = LangFor("search_cat_with_att"); break; case SEARCH_CATEGORY_WITHOUT_ATT : cptr = LangFor("search_cat_without_att"); break; case SEARCH_CATEGORY_VMS : cptr = LangFor("search_cat_vms"); break; case SEARCH_CATEGORY_NEWMSG : /** cptr = LangFor("search_cat_newmsg"); break; **/ cptr = "Unread"; break; case SEARCH_CATEGORY_REPLIED : /** cptr = LangFor("search_cat_replied"); break; **/ cptr = "Replied-to"; break; case SEARCH_CATEGORY_MARKED : /** cptr = LangFor("search_cat_marked"); break; **/ cptr = "Marked"; break; default : cptr = "?"; } if (cptr) { ParamHit = TRUE; CriPtr += sprintf (CriPtr, "%s \"%s\"; ", LangFor("search_category"), cptr); } } /*******************/ /* date parameters */ /*******************/ CGIVARNULL (cptr, "FORM_SEARCH_DATE_SCOPE"); if (cptr && *cptr) { srptr->DateScope = atoi(cptr); if (srptr->DateScope < SEARCH_DATE_SCOPE_ANY || srptr->DateScope > SEARCH_DATE_SCOPE_ON) srptr->DateScope = SEARCH_DATE_SCOPE_ANY; } CGIVARNULL (cptr, "FORM_SEARCH_DATE_DAY"); if (cptr && *cptr) { srptr->DateDay = atoi(cptr); if (srptr->DateDay < 0 || srptr->DateDay > 31) srptr->DateDay = CurrentNumTime[2]; } CGIVARNULL (cptr, "FORM_SEARCH_DATE_MONTH"); if (cptr && *cptr) { srptr->DateMonth = atoi(cptr); if (srptr->DateMonth < 0 || srptr->DateMonth > 12) srptr->DateMonth = CurrentNumTime[1]; } CGIVARNULL (cptr, "FORM_SEARCH_DATE_YEAR"); if (cptr && *cptr) { srptr->DateYear = atoi(cptr); if (srptr->DateYear < SearchEpoch || srptr->DateYear > CurrentNumTime[0]) srptr->DateYear = CurrentNumTime[0]; } if (srptr->DateScope == SEARCH_DATE_SCOPE_BEFORE) { ParamHit = TRUE; sprintf (TimeString, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); status = sys$bintim (&TimeStringDsc, &srptr->BinTimeBefore); CriPtr += sprintf (CriPtr, "%s ", LangFor("search_date_before")); if (VMSok (status)) CriPtr += sprintf (CriPtr, "%02.02d-%s-%04.04d; ", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); else CriPtr += sprintf (CriPtr, "%%%08.08X; ", status); } else if (srptr->DateScope == SEARCH_DATE_SCOPE_SINCE) { ParamHit = TRUE; sprintf (TimeString, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); status = sys$bintim (&TimeStringDsc, &srptr->BinTimeSince); CriPtr += sprintf (CriPtr, "%s ", LangFor("search_date_since")); if (VMSok (status)) CriPtr += sprintf (CriPtr, "%02.02d-%s-%04.04d; ", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); else CriPtr += sprintf (CriPtr, "%%%08.08X; ", status); } else if (srptr->DateScope == SEARCH_DATE_SCOPE_ON) { ParamHit = TRUE; sprintf (TimeString, "%02.02d-%s-%04.04d 00:00:00", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); status = sys$bintim (&TimeStringDsc, &srptr->BinTimeSince); sprintf (TimeString, "%02.02d-%s-%04.04d 23:59:59", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); status = sys$bintim (&TimeStringDsc, &srptr->BinTimeBefore); CriPtr += sprintf (CriPtr, "%s ", LangFor("search_date_on")); if (VMSok (status)) CriPtr += sprintf (CriPtr, "%02.02d-%s-%04.04d; ", srptr->DateDay, MonthAbrev[srptr->DateMonth], srptr->DateYear); else CriPtr += sprintf (CriPtr, "%%%08.08X; ", status); } /******************/ /* end parameters */ /******************/ if (ParamHit) { /* not really a *search* parameter as such */ CGIVARNULL (cptr, "FORM_SEARCH_RESULTS"); if (cptr && isdigit(*cptr)) srptr->ResultsEvery = atol(cptr); /* stays in-progress until [open] or [newmail] buttons are used */ srptr->InProgress = TRUE; *CriPtr = '\0'; if (CriteriaString[0]) { /* just trim the trailing "; " */ *(CriPtr-2) = '\0'; zptr = (sptr = srptr->Criteria) + sizeof(srptr->Criteria)-1; for (cptr = CriteriaString; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; } } } /****************************************************************************/ /* Get a string search parameter and store it in the supplied search storage. If a regular expression compile it into the supplied regex structure. Issue appropriate status error. */ int SearchGetString ( SEARCH_DATA *srptr, char *StringPtr, char *SearchStringPtr, int SizeofSearchString, regex_t *RegexPtr, char *ParamName ) { int retval; char *cptr, *sptr, *zptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchGetString()\n"); cptr = StringPtr; if (*cptr == '^') { if (SoyMailConfig.SearchKeywordOnly) { srptr->SearchProblem = TRUE; StatusMessage (FI_LI, 1, "%s", LangFor("regex_disabled")); } else { retval = regcomp (RegexPtr, cptr+1, SearchRegexCflags); if (retval) { srptr->SearchProblem = TRUE; StatusMessage (FI_LI, 1, "%s "%s:"", LangFor("regex_expression"), LangFor(ParamName)); } } } zptr = (sptr = SearchStringPtr) + SizeofSearchString-1; while (*cptr && isspace(*cptr)) cptr++; while (*cptr && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; if (sptr > SearchStringPtr) sptr--; while (sptr > SearchStringPtr && isspace(*sptr)) sptr--; if (*sptr && !isspace(*sptr)) sptr++; *sptr = '\0'; if (Debug) fprintf (stdout, "|%s|\n", SearchStringPtr); return (sptr - SearchStringPtr); } /*****************************************************************************/ /* Provide the search parameters page. Use any previously entered an propagated from request to request. */ void SearchPage (REQUEST_DATA *rdptr) { int cnt; char *cptr, *sptr, *zptr; REQUEST_DATA *sdptr; SEARCH_DATA *srptr; USER_OPTIONS *uoptr; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchPage()\n"); sdptr = (REQUEST_DATA*)rdptr->StateDataPtr; srptr = &rdptr->SearchData; uoptr = &rdptr->UserOptions; if (rdptr->PrivateAccess || rdptr->PublicWildcard) cptr = rdptr->FolderName; else cptr = rdptr->PublicAccessString; StatusMessage (FI_LI, 0, "%s "%s" %s", LangFor("search"), HTML_ESCAPE(cptr), LangFor("page_opened")); if (rdptr->PrivateAccess) { MainMenuPageBegin (rdptr, PAGE_SEARCH); MainMenuBar (rdptr); } else { PublicPageBegin (rdptr, PAGE_SEARCH); PublicPageTitle (rdptr); } StatusInfoPanel (rdptr); if (!srptr->Category) srptr->Category = SEARCH_CATEGORY_ANY; if (!srptr->DateScope) srptr->DateScope = SEARCH_DATE_SCOPE_ANY; if (!srptr->ResultsEvery) srptr->ResultsEvery = uoptr->MessagesPerPage; fprintf (stdout, "\n\ \n", uoptr->MessagesPerPage); fprintf (stdout, "

\ \n\ \n\ \n\ \ \n\ \ \n\ \ \n\ \ \n", LangFor("from"), HTML_ESCAPE(srptr->From), LangFor("to"), HTML_ESCAPE(srptr->To), LangFor("cc"), HTML_ESCAPE(srptr->Cc), LangFor("subject"), HTML_ESCAPE(srptr->Subject)); if (SoyMailConfig.SearchHeaderOnly) { if (SoyMailConfig.MessageFlags) { fprintf (stdout, "\n\ \ \n\ \ \n", stdout); } fprintf (stdout, "\n\ \n\ \
%s
\ %s:\n\  \n\ \  \n\ \  \n\ \ \n\
\ %s:\
\ %s:\
\ %s:\
\ %s:\
\ %s:\n\
\ %s:\
\ %s:\
\ %s:\n\ \n", stdout); cptr = TrnLnm ("SOYMAIL_VMS_SELECT", NULL, 0); if (cptr && toupper(*cptr) == 'T') fputs ("", stdout); else if (cptr) fprintf (stdout, "  ", srptr->SelectNotSearch ? " checked" : ""); fputs ("
\ %s:\n\ \n\
\  \n\ \n\
\n\ \n", LangFor("search_results"), srptr->ResultsEvery == 999999 ? " selected" : "", LangFor("all"), LangFor("search_hits"), uoptr->MessagesPerPage, srptr->ResultsEvery == uoptr->MessagesPerPage ? " selected" : "", uoptr->MessagesPerPage, LangFor("search_hits"), srptr->ResultsEvery == 5 ? " selected" : "", LangFor("search_hits"), srptr->ResultsEvery == 1 ? " selected" : "", LangFor("search_hits"), LangFor("search_begin"), CLICK_STARTWORKING, LangFor("search_clear")); if (rdptr->PrivateAccess) MainMenuPageEnd (rdptr); else PublicPageEnd (rdptr); } /****************************************************************************/ /* Apply the search parameters. */ BOOL SearchMessage ( VMS_MAIL_MSG *vmptr, SEARCH_DATA *srptr ) { int status; int64 ScratchTime64; MIME_DATA *mdptr; /*********/ /* begin */ /*********/ if (WatchEnabled) WatchThis ("SEARCH !AZ !UL \ \"!AZ\" \"!AZ\" \"!AZ\" \"!AZ\" \"!AZ\" \"!AZ\"", srptr->SelectNotSearch ? "false" : "true", srptr->Category, srptr->From, srptr->To, srptr->Cc, srptr->Subject, srptr->Message, srptr->Attachment); if (!SoyMailConfig.SearchEnabled) return (TRUE); /* if nothing to search for */ if (srptr->Category == SEARCH_CATEGORY_ANY && !srptr->Message[0] && !srptr->Attachment[0]) { if (srptr->SelectNotSearch) return (TRUE); if (!srptr->Cc[0] && !srptr->From[0] && !srptr->Subject[0] && !srptr->To[0] && !srptr->BinTimeBefore[0] && !srptr->BinTimeBefore[1] && !srptr->BinTimeSince[0] && !srptr->BinTimeSince[1]) return (TRUE); } /*********/ /* start */ /*********/ srptr->SearchCount++; if (!srptr->LastIdSearched) srptr->LastIdSearched = vmptr->MessageId; srptr->FirstIdSearched = vmptr->MessageId; /**************/ /* VMS header */ /**************/ if (srptr && !srptr->SelectNotSearch) { if (srptr && srptr->Cc[0]) if (!SearchKeyword (vmptr->Cc, srptr->Cc, &srptr->RegexCc)) srptr = NULL; if (srptr && srptr->From[0]) if (!SearchKeyword (vmptr->From, srptr->From, &srptr->RegexFrom)) srptr = NULL; if (srptr && srptr->Subject[0]) if (!SearchKeyword (vmptr->Subject, srptr->Subject, &srptr->RegexSubject)) srptr = NULL; if (srptr && srptr->To[0]) if (!SearchKeyword (vmptr->To, srptr->To, &srptr->RegexTo)) srptr = NULL; if (srptr && (srptr->BinTimeBefore[0] || srptr->BinTimeBefore[1])) { status = lib$sub_times (&srptr->BinTimeBefore, &vmptr->BinDate, &ScratchTime64); if (Debug) fprintf (stdout, "lib$sub_times() %%X%08.08X\n", status); if (VMSnok (status)) srptr = NULL; } if (srptr && (srptr->BinTimeSince[0] || srptr->BinTimeSince[1])) { status = lib$sub_times (&vmptr->BinDate, &srptr->BinTimeSince, &ScratchTime64); if (Debug) fprintf (stdout, "lib$sub_times() %%X%08.08X\n", status); if (VMSnok (status)) srptr = NULL; } if (srptr && srptr->Category == SEARCH_CATEGORY_NEWMSG) if (!(vmptr->MessageFlags & MAIL$M_NEWMSG)) srptr = NULL; if (srptr && srptr->Category == SEARCH_CATEGORY_MARKED) if (!(vmptr->MessageFlags & MAIL$M_MARKED)) srptr = NULL; if (srptr && srptr->Category == SEARCH_CATEGORY_REPLIED) if (!(vmptr->MessageFlags & MAIL$M_REPLIED)) srptr = NULL; } /********************/ /* parse the header */ /********************/ if (srptr) { /* just skip it if there is a problem processing the RFC822 header */ if (!InetMailParseHeader (vmptr)) if (vmptr->LooksLikeRfc) return (FALSE); } /*******************/ /* some categories */ /*******************/ /* it is safe to return before any MIME processing */ if (srptr && srptr->Category == SEARCH_CATEGORY_RFC && !vmptr->LooksLikeRfc) srptr = NULL; if (srptr && srptr->Category == SEARCH_CATEGORY_VMS && vmptr->LooksLikeRfc) srptr = NULL; if (srptr && srptr->Category == SEARCH_CATEGORY_RAW) if (!SearchKeyword (vmptr->BodyPtr, srptr->Message, &srptr->RegexMessage)) srptr = NULL; /*************/ /* continue? */ /*************/ /* eliminate processing the body by checking if it's necssary */ if (srptr && srptr->Category == SEARCH_CATEGORY_ANY && !srptr->Message[0] && !srptr->Attachment[0]) { if (srptr) srptr->HitCount++; if (WatchEnabled) WatchThis ("!AZHIT!!", srptr == NULL ? "NO " : ""); /***************/ /* finish here */ /***************/ return (srptr != NULL); } /*************************/ /* dealing with the body */ /*************************/ if (SearchPrevPriority == -1 && SoyMailConfig.SearchPriority >= 0 && SoyMailConfig.SearchPriority <= 4) { /* not been set yet and is configured to be */ status = sys$setpri (0, 0, SoyMailConfig.SearchPriority, &SearchPrevPriority, 0, 0); if (VMSnok (status)) ErrorExit (status, FI_LI); atexit (SearchRestorePriority); } if (srptr) MessageBodyProcess (vmptr); /*******************/ /* more categories */ /*******************/ if (srptr && srptr->Category != SEARCH_CATEGORY_ANY) { if (srptr && srptr->Category == SEARCH_CATEGORY_WITH_ATT) { for (mdptr = vmptr->MimeDataPtr; mdptr; mdptr = mdptr->NextMimePtr) if (mdptr->NamePtr) break; if (!mdptr) srptr = NULL; } if (srptr && srptr->Category == SEARCH_CATEGORY_WITHOUT_ATT) { for (mdptr = vmptr->MimeDataPtr; mdptr; mdptr = mdptr->NextMimePtr) if (mdptr->NamePtr) break; if (mdptr) srptr = NULL; } if (srptr && srptr->Category == SEARCH_CATEGORY_HTML) { mdptr = MessageBodyIdentify (vmptr, OPTIONS_READ_PLAIN0_HTML1); if (!mdptr) srptr = NULL; } if (srptr && srptr->Category == SEARCH_CATEGORY_PLAIN) { mdptr = MessageBodyIdentify (vmptr, OPTIONS_READ_PLAIN1_HTML0); if (!mdptr) srptr = NULL; } } if (srptr && srptr->Category != SEARCH_CATEGORY_RAW) { if (srptr && srptr->Message[0]) { /* search message text */ mdptr = MessageBodyIdentify (vmptr, OPTIONS_READ_PLAIN1_HTML0); if (mdptr) { if (MimeDecProcessPart (mdptr)) if (!SearchKeyword (mdptr->PartContentPtr, srptr->Message, &srptr->RegexMessage)) srptr = NULL; } if (!mdptr) srptr = NULL; } } /*******************/ /* attachment name */ /*******************/ if (srptr && srptr->Attachment[0]) { /* search for attachment */ for (mdptr = vmptr->MimeDataPtr; mdptr; mdptr = mdptr->NextMimePtr) { if (!mdptr->NamePtr) continue; if (SearchKeyword (mdptr->NamePtr, srptr->Attachment, &srptr->RegexAttachment)) break; } if (!mdptr) srptr = NULL; } /************/ /* finished */ /************/ /* free all allocated memory used in the MIME parse */ if (vmptr->MimeDataPtr) MimeDecParseFree (vmptr->MimeDataPtr); if (srptr) srptr->HitCount++; if (WatchEnabled) WatchThis ("!AZHIT!!", srptr == NULL ? "NO " : ""); return (srptr != NULL); } /****************************************************************************/ /* Check the first characters of the keyword for a caret ('^'). If so invoke the independent regular expression search implemented by the GNU REGEX.C module. If not a caret search for the supplied keyword using our own inimitable, lightweight, keyword search code (which should behave the same way as VMS Mail's keyword select). */ BOOL SearchKeyword ( char *TextPtr, char *KeywordPtr, regex_t *RegexPtr ) { int retval; char ch; char *cptr, *sptr, *tptr, *zptr; char KeywordLoCase [64]; regex_t regexp; /*********/ /* begin */ /*********/ if (WatchEnabled) WatchThis ("!AZ \'!AZ\'", *KeywordPtr == '^' ? "REGEX" : "KEYWORD", KeywordPtr); if (*KeywordPtr == '^') { if (!RegexPtr) { /* only ConfigLoad() use, should not happen with message searches! */ RegexPtr = ®exp; retval = regcomp (RegexPtr, KeywordPtr+1, SearchRegexCflags); if (retval) { if (WatchEnabled) WatchThis ("REGEX PROBLEM"); return (FALSE); } } retval = regexec (RegexPtr, TextPtr, 0, 0, SearchRegexEflags); if (retval) return (FALSE); return (TRUE); } zptr = (sptr = KeywordLoCase) + sizeof(KeywordLoCase) - 1; for (cptr = KeywordPtr; *cptr && sptr < zptr; *sptr++ = tolower(*cptr++)); *sptr = '\0'; ch = KeywordLoCase[0]; for (tptr = TextPtr; *tptr; tptr++) { if (tolower(*tptr) != ch) continue; sptr = tptr + 1; cptr = KeywordLoCase + 1; while (*cptr && *sptr && *cptr == tolower(*sptr)) { sptr++; cptr++; } if (*cptr) continue; return (TRUE); } return (FALSE); } /****************************************************************************/ /* If changed during search then restore it (explicitly called or via atexit()). */ void SearchRestorePriority () { int status; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchRestorePriority()\n"); if (SearchPrevPriority >= 0 && SearchPrevPriority <= 6) { status = sys$setpri (0, 0, SearchPrevPriority, 0, 0, 0); if (VMSnok (status)) ErrorExit (status, FI_LI); SearchPrevPriority = -1; } } /****************************************************************************/ /* Called from ParseCommandLine() to provide a command-line regular expression checker. Try your matches out before before putting them into the configuration! $ SOYMAIL /REGEX "" "" */ void SearchRegexCheck (char *StringPtr) { int retval; char *cptr, *sptr, *zptr; char expbuf [256], txtbuf [256]; regex_t regexp; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "SearchRegexCheck() |%s|\n", StringPtr); for (cptr = StringPtr; *cptr && isspace(*cptr); cptr++); zptr = (sptr = txtbuf) + sizeof(txtbuf)-1; if (*cptr != '\"') exit (SS$_BADPARAM); cptr++; while (*cptr && *cptr != '\"' && sptr < zptr) { if (*cptr == '\\' && *(cptr+1)) cptr++; *sptr++ = *cptr++; } *sptr = '\0'; if (*cptr) cptr++; while (*cptr && isspace(*cptr)) cptr++; zptr = (sptr = expbuf) + sizeof(expbuf)-1; if (*cptr != '\"') exit (SS$_BADPARAM); cptr++; if (*cptr != '^') *sptr++ = '^'; while (*cptr && *cptr != '\"' && sptr < zptr) { if (*cptr == '\\' && *(cptr+1)) cptr++; *sptr++ = *cptr++; } *sptr = '\0'; retval = regcomp (®exp, expbuf+1, SearchRegexCflags); if (retval) { fprintf (stdout, "%%%s-E-REGEX, invalid regular expression\n", Utility); exit (SS$_BADPARAM | STS$M_INHIB_MSG); } fprintf (stdout, "%%%s-I-REGEX, \"%s\" by \"%s\" %s\n", Utility, txtbuf, expbuf, SearchKeyword (txtbuf, expbuf, ®exp) ? "TRUE" : "FALSE"); exit (SS$_NORMAL); } /*****************************************************************************/