#!/usr/bin/perl my $bFound = 0; my $sDir; foreach $sDir (@INC) { if ($sDir eq ".") { $bFound = 1; last; } } if (!$bFound) { push (@INC, "."); } push (@INC, "cgi-bin"); require al000001; require ao000001; use strict; $::prog_name = "SearchScript"; $::prog_name = $::prog_name; $::prog_ver = '$Revision: 71 $ '; $::prog_ver = substr($::prog_ver, 11); $::prog_ver =~ s/ \$//; my $nFILEVERSION = 1; $::MATCH_WHOLE_WORDS_ONLY = $::FALSE; $::ANY_PRICE_BAND = -1; $::INTERSECT = 0; $::UNION = 1; $::MAX_RETRY_COUNT = 10; $::RETRY_SLEEP_DURATION = 1; my $sPath = Init(); my ($status, $sError); my %MatchWords; my %UsedValues; my %InputArrays; my @ResultsStack; my $bValidSearch = 0; my $bPriceSearch = $::FALSE; my $TRUE_RESULT = 1; my $FALSE_RESULT = 0; my $SKIP_RESULT = -1; my $UI_TEXTBOX = 0; my $UI_RADIOBUTTON = 1; my $UI_CHECKBOX = 2; my $UI_DROPDOWNLIST = 3; my $UI_LIST = 4; my $sSearchNum = ''; my $sSearchFile = $sPath . "customsearch"; if (exists $::g_InputHash{PRODREF}) { my $sProdRef = ACTINIC::DecodeText($::g_InputHash{PRODREF}, $ACTINIC::FORM_URL_ENCODED); my $sHTML = DirectLinkToProduct($sPath, $sProdRef); ACTINIC::PrintPage($sHTML, ""); exit; } elsif (exists $::g_InputHash{SECTIONID}) { my $sSection = ACTINIC::DecodeText($::g_InputHash{SECTIONID}, $ACTINIC::FORM_URL_ENCODED); my $sHTML = DisplayDirectLinkPage($sSection); $::g_bLoginPage = $::TRUE; ACTINIC::PrintPage($sHTML, ""); exit; } if (exists $::g_InputHash{SN}) { $sSearchNum = $::g_InputHash{SN}; unless ($sSearchNum =~ /^\d*$/) { my $filelog = ACTINIC::GetPhrase(-1, 325, $sSearchNum); SearchError($filelog, $sPath); exit; } } $sSearchFile .= "$sSearchNum.fil"; unless (open SFILE, "<$sSearchFile") { my $filelog = ACTINIC::GetPhrase(-1, 21, $sSearchFile, $!); SearchError($filelog, $sPath); exit; } my @SearchCmd = ; close SFILE; my $nFileVersion = shift (@SearchCmd); unless ($nFileVersion == $nFILEVERSION) { my $filelog = ACTINIC::GetPhrase(-1, 326, $nFILEVERSION, $nFileVersion); SearchError($filelog, $sPath); exit; } my $sLine; foreach $sLine (@SearchCmd) { chomp $sLine; my ($sCmd, $sParam1, $sParam2) = split ('!', $sLine); my $sValue1 = ''; if ($sParam1) { if (exists $::g_InputHash{$sParam1}) { $sValue1 = $::g_InputHash{$sParam1}; } } $sValue1 =~ s/^\s*//o; $sValue1 =~ s/\s*$//o; my $sValue2 = ''; if ($sParam2) { if (exists $::g_InputHash{$sParam2}) { $sValue2 = $::g_InputHash{$sParam2}; } } if ($sCmd eq 'Text') { my $bText = $::UNION; if ($sValue2 eq 'A') { $bText = $::INTERSECT; } elsif ($sValue2 ne 'O') { my $sError = ACTINIC::GetPhrase(-1, 244); SearchError($sError, $sPath); exit; } if ($sValue1 eq '') { next; } $bValidSearch = 1; my $rTextHits = {}; ($status, $sError) = SearchText($sPath, \$sValue1, $bText, $rTextHits); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } if (scalar (keys %$rTextHits)) { push @ResultsStack, [$TRUE_RESULT, $rTextHits]; my @matches = split (' ', $sValue1); my $word; foreach $word (@matches) { $MatchWords{$word} = 1; } } else { push @ResultsStack, [$FALSE_RESULT]; } } elsif ($sCmd eq 'Price') { $bPriceSearch = $::TRUE; my $rPriceHits = {}; my $nPriceBand = $sValue1; if (defined $nPriceBand && ($nPriceBand != $::ANY_PRICE_BAND)) { $bValidSearch = 1; ($status, $sError) = SearchPrice($sPath, $nPriceBand, $rPriceHits); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } if (scalar (keys %$rPriceHits)) { push @ResultsStack, [$TRUE_RESULT, $rPriceHits]; } else { push @ResultsStack, [$FALSE_RESULT]; } } else { push @ResultsStack, [$SKIP_RESULT]; } } elsif ($sCmd eq 'And') { if ($#ResultsStack < 1) { } else { my $rArray1 = pop @ResultsStack; my $rArray2 = pop @ResultsStack; if (${$rArray1}[0] == $SKIP_RESULT) { push @ResultsStack, $rArray2; } elsif (${$rArray2}[0] == $SKIP_RESULT) { push @ResultsStack, $rArray1; } elsif ((${$rArray1}[0] == $FALSE_RESULT) or (${$rArray2}[0] == $FALSE_RESULT)) { push @ResultsStack, [$FALSE_RESULT]; } else { my $rJoins = {}; JoinHashes(${$rArray1}[1], ${$rArray2}[1], $::INTERSECT, $rJoins); if (scalar (keys %$rJoins)) { push @ResultsStack, [$TRUE_RESULT, $rJoins]; } else { push @ResultsStack, [$FALSE_RESULT]; } } } } elsif ($sCmd eq 'Or') { if ($#ResultsStack < 1) { } else { my $rArray1 = pop @ResultsStack; my $rArray2 = pop @ResultsStack; if (${$rArray1}[0] == $FALSE_RESULT) { push @ResultsStack, $rArray2; } elsif (${$rArray2}[0] == $FALSE_RESULT) { push @ResultsStack, $rArray1; } elsif (${$rArray1}[0] == $SKIP_RESULT) { if (${$rArray2}[0] == $SKIP_RESULT) { push @ResultsStack, [$SKIP_RESULT]; } else { push @ResultsStack, $rArray2; } } elsif (${$rArray2}[0] == $SKIP_RESULT) { push @ResultsStack, $rArray1; } else { my $rJoins = {}; JoinHashes(${$rArray1}[1], ${$rArray2}[1], $::UNION, $rJoins); if (scalar (keys %$rJoins)) { push @ResultsStack, [$TRUE_RESULT, $rJoins]; } else { push @ResultsStack, [$FALSE_RESULT]; } } } } elsif (($sCmd eq 'Text Property') or ($sCmd eq 'Integer') or ($sCmd eq 'Date')) { unless (exists $$::g_pSearchSetup{$sParam1}) { my $sError = ACTINIC::GetPhrase(-1, 327, $sParam1); SearchError($sError, $sPath); exit; } my $rBlobParam = $$::g_pSearchSetup{$sParam1}; unless (scalar (keys %InputArrays)) { ($status, $sError) = ParseSearchInput(\%InputArrays); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } } my $rPropertyHits = {}; my $sValuem = ''; my @sMulti = (); if ($InputArrays{$sParam1}) { @sMulti = @{$InputArrays{$sParam1}}; } while (@sMulti) { $sValuem = shift @sMulti; if (($sValuem eq '') and (!$$rBlobParam{Optional})) { my $sError = ACTINIC::GetPhrase(-1, 328, $$rBlobParam{Label}); SearchError($sError, $sPath); exit; } if (($sValuem eq 'on') and ($$rBlobParam{UIType} == $UI_CHECKBOX)) { $sValuem = ''; } if (exists $UsedValues{$sParam1}) { if (($UsedValues{$sParam1} != $sValuem) and (!$$rBlobParam{MultiSelect})) { my $sError = ACTINIC::GetPhrase(-1, 329, $$rBlobParam{Label}); SearchError($sError, $sPath); exit; } } $UsedValues{$sParam1} = $sValuem; if (($sCmd eq 'Integer') && ($sValuem ne '')) { unless ($sValuem =~ /^[-+]?\d+$/o) { my $sError = ACTINIC::GetPhrase(-1, 330, $sValuem, $$rBlobParam{Label}); SearchError($sError, $sPath); exit; } } elsif (($sCmd eq 'Date') && $sValuem) { unless ($sValuem =~ /\d{8}/o) { my $sError = ACTINIC::GetPhrase(-1, 331, $sValuem, $$rBlobParam{Label}); SearchError($sError, $sPath); exit; } } else { } if ($sValuem ne '') { $bValidSearch = 1; ($status, $sError) = SearchProperty($sPath, $sParam1, $sValuem, $rPropertyHits); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } } else { @sMulti = (); } } if ($sValuem eq '') { push @ResultsStack, [$SKIP_RESULT]; } elsif (scalar (keys %$rPropertyHits)) { push @ResultsStack, [$TRUE_RESULT, $rPropertyHits]; } else { push @ResultsStack, [$FALSE_RESULT]; } } elsif ($sCmd eq 'Section') { my $rSectionHits = {}; if ($sValue1) { $bValidSearch = 1; ($status, $sError) = SearchSection($sPath, $sValue1, $rSectionHits); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } if (scalar (keys %$rSectionHits)) { push @ResultsStack, [$TRUE_RESULT, $rSectionHits]; } else { push @ResultsStack, [$FALSE_RESULT]; } } else { push @ResultsStack, [$SKIP_RESULT]; } } else { my $sError = ACTINIC::GetPhrase(-1, 332, $sCmd, $sSearchFile); SearchError($sError, $sPath); exit; } } my %NullSet; my $rhashResults = \%NullSet; if ($#ResultsStack == -1) { } elsif ($#ResultsStack == 0) { my $rArray = pop @ResultsStack; if (${$rArray}[0] == $TRUE_RESULT) { $rhashResults = ${$rArray}[1]; } else { } } else { my $pLine; my @ResultHashes; foreach $pLine (@ResultsStack) { my ($nStatus, $rhashtemp) = @{$pLine}; if (($nStatus == $FALSE_RESULT) and ($::g_InputHash{GB} eq 'A')) { @ResultHashes = (); last; } elsif ($nStatus != $TRUE_RESULT) { next; } else { push @ResultHashes, $rhashtemp; } if ($#ResultHashes == -1) { $rhashResults = \%NullSet; } else { $rhashResults = shift @ResultHashes; my $bJoin = ($::g_InputHash{GB} eq 'A') ? $::INTERSECT : $::UNION; while (@ResultHashes) { my $rPrevious = $rhashResults; my $rCurrent = shift @ResultHashes; JoinHashes($rPrevious, $rCurrent, $bJoin, $rhashResults); } } } } if (!$bValidSearch) { my $sError; my $sStart = ACTINIC::EncodeText2(ACTINIC::GetPhrase(-1, 113), $::FALSE); if ($bPriceSearch && $::g_InputHash{ACTION}) { $sError = ACTINIC::GetPhrase(-1, 245); } else { $sError = ACTINIC::GetPhrase(-1, 2085); } SearchError($sError, $sPath); exit; } my $nPageNumber = $::g_InputHash{PN}; my @StringTemp = keys %MatchWords; my $sWords = join (' ', @StringTemp); ($status, $sError) = DisplayResults($sPath, $rhashResults, $nPageNumber, $sWords); if ($status != $::SUCCESS) { SearchError($sError, $sPath); exit; } exit; sub Init { my ($status, $sError, $unused); ($status, $sError, $::g_OriginalInputData, $unused, %::g_InputHash) = ACTINIC::ReadAndParseInput(); if ($::SUCCESS != $status) { ACTINIC::TerminalError($sError); } ($status, $sError, @::g_PageList) = ACTINIC::ProcessReferencePageData(%::g_InputHash); if ($status != $::SUCCESS) { ACTINIC::TerminalError($sError); } my $sPath = ACTINIC::GetPath(); ACTINIC::SecurePath($sPath); if (!$sPath) { ACTINIC::TerminalError("Path not found."); } if (!-e $sPath || !-d $sPath) { ACTINIC::TerminalError("Invalid path."); } ($status, $sError) = ACTINIC::ReadPromptFile($sPath); if ($status != $::SUCCESS) { ACTINIC::ReportError($sError, $sPath); } ($status, $sError) = ACTINIC::ReadSetupFile($sPath); if ($status != $::SUCCESS) { ACTINIC::ReportError($sError, $sPath); } ($status, $sError) = ACTINIC::ReadSearchSetupFile($sPath); if ($status != $::SUCCESS) { ACTINIC::ReportError($sError, $sPath); } ($status, $sError) = ACTINIC::ReadCatalogFile($sPath); if ($status != $::SUCCESS) { ACTINIC::ReportError($sError, $sPath); } ($status, $sError, $::g_sWebSiteUrl, $::g_sContentUrl) = ACTINIC::GetWebSiteURL(@::g_PageList); if ($status != $::SUCCESS) { ACTINIC::TerminalError($sError); } my ($sUserDigest, $sBaseFile); $sUserDigest = $ACTINIC::B2B->Get('UserDigest'); if (!$sUserDigest) { ($sUserDigest, $sBaseFile) = ACTINIC::CaccGetCookies(); $ACTINIC::B2B->Set('UserDigest',$sUserDigest); $ACTINIC::B2B->Set('BaseFile', $sBaseFile); } if ($sUserDigest) { $sBaseFile = $ACTINIC::B2B->Get('BaseFile'); ($::g_sWebSiteUrl, $::g_sContentUrl) = ($sBaseFile, $sBaseFile); $::g_PageList[0] = $sBaseFile; } elsif( $::g_InputHash{BASE} ) { ($::g_sWebSiteUrl, $::g_sContentUrl) = ($::g_InputHash{BASE}, $::g_InputHash{BASE}); $::g_PageList[0] = $::g_InputHash{BASE}; } return ($sPath); } sub ParseSearchInput { my ($rhashResults) = @_; my @EncodedInput = split (/[&=]/, $::g_OriginalInputData); if ($#EncodedInput % 2 != 1) { return ($::FAILURE, "Bad input string \"" . $::g_OriginalInputData . "\". Argument count " . $#EncodedInput . ".\n", '', '', 0, 0); } my ($key, $value); while (@EncodedInput) { $key = ACTINIC::DecodeText(shift @EncodedInput, $ACTINIC::FORM_URL_ENCODED); $value = ACTINIC::DecodeText(shift @EncodedInput, $ACTINIC::FORM_URL_ENCODED); if (exists $$rhashResults{$key}) { push @{$$rhashResults{$key}}, $value; } else { $$rhashResults{$key} = [$value]; } } return ($::SUCCESS, ''); } sub SearchText { my ($sPath, $psSearchString, $bJoin, $rhashResults) = @_; my $sWordCharacters = ACTINIC::GetPhrase(-1, 239); my $sSplitString = "[^\Q$sWordCharacters\E]"; $$psSearchString =~ s/$sSplitString/ /g; my $sStopList = ACTINIC::GetPhrase(-1, 238); $$psSearchString =~ s/\s+/ /go; $$psSearchString = lc $$psSearchString; $sStopList = lc $sStopList; $$psSearchString =~ tr/[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ]/[àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ]/; $sStopList =~ tr/[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ]/[àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ]/; my @listPreliminarySearchWords = split(/ +/, $$psSearchString); my ($sWord, @listSearchWords); foreach $sWord (@listPreliminarySearchWords) { if ($sWord eq '' || $sStopList =~ /\b$sWord\b/) { next; } push (@listSearchWords, $sWord); } $$psSearchString = join(' ', @listSearchWords); if (!@listSearchWords) { return ($::SUCCESS); } my ($status, $sError) = OpenTextIndex($sPath, \*INDEX); if ($status != $::SUCCESS) { return($status, $sError); } my (@HitLists, $rhash); foreach $sWord (@listSearchWords) { $rhash = {}; ($status, $sError) = WordSearch($sWord, 2, \*INDEX, $rhash); # do the search - the 2 is the number of bytes into the file where the index begins (after the 2 byte version number) if ($status != $::SUCCESS) { close (INDEX); return ($status, $sError); } push (@HitLists, $rhash); } close (INDEX); my ($rhashCurrent, $rhashNext, $rhashLast); $rhashLast = shift @HitLists; foreach $rhashCurrent (@HitLists) { $rhashNext = {}; JoinHashes($rhashLast, $rhashCurrent, $bJoin, $rhashNext); $rhashLast = $rhashNext; } %$rhashResults = %$rhashLast; return ($::SUCCESS); } sub SearchSection { my ($sPath, $nSectionID, $rhashResults) = @_; undef %$rhashResults; if (!$nSectionID) { return ($::SUCCESS); } my ($status, $sError) = OpenTextIndex($sPath, \*INDEX); if ($status != $::SUCCESS) { return($status, $sError); } my $sWord = sprintf('!@%8.8x', $nSectionID); ($status, $sError) = WordSearch($sWord, 2, \*INDEX, $rhashResults); # do the search - the 2 is the number of bytes into the file where the index begins (after the 2 byte version number) if ($status != $::SUCCESS) { close (INDEX); return ($status, $sError); } close (INDEX); return ($::SUCCESS); } sub SearchProperty { my ($sPath, $sPropertyName, $sPropertyValue, $rhashResults) = @_; $sPropertyName =~ s/^S_(.*)_\d+$/$1/; if ((!$sPropertyName) or ($sPropertyValue eq '')) { return ($::SUCCESS); } my ($status, $sError) = OpenTextIndex($sPath, \*INDEX); if ($status != $::SUCCESS) { return($status, $sError); } my $sWord = "!!$sPropertyName!$sPropertyValue"; ($status, $sError) = WordSearch($sWord, 2, \*INDEX, $rhashResults); # do the search - the 2 is the number of bytes into the file where the index begins (after the 2 byte version number) if ($status != $::SUCCESS) { close (INDEX); return ($status, $sError); } close (INDEX); return ($::SUCCESS); } sub OpenTextIndex { my ($sPath, $rFile) = @_; my ($status, $sError); my $nRetryCount = $::MAX_RETRY_COUNT; $status = $::SUCCESS; my $sFileName = $sPath . "oldtext.fil"; my $nExpected = 257; while ($nRetryCount--) { unless (open ($rFile, "<$sFileName")) { $sError = $!; sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 246, $sFileName, $sError); next; } binmode $rFile; my $sBuffer; unless (read($rFile, $sBuffer, 4) == 4) { $sError = $!; close ($rFile); return ($::FAILURE, ACTINIC::GetPhrase(-1, 252, $sError)); } my ($nVersion) = unpack("n", $sBuffer); if ($nVersion != $nExpected) { close($rFile); sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 259, $nExpected, $nVersion); next; } last; } if ($status != $::SUCCESS) { return($status, $sError); } return ($::SUCCESS); } sub WordSearch { my ($sWord, $nLocation, $rFile, $rhashProdRefs) = @_; my ($nDependencies, $nCount, $nRefs, $sRefs, $sBuff, $sFragment, $sAnchor); my ($nIndex, $sSeek, $nHere, $nLength, $sNext, $nRead); unless (seek($rFile, $nLocation, 0)) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 247, $!)); } unless (read($rFile, $sBuff, 2) == 2) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } ($nCount) = unpack("n", $sBuff); for ($nIndex = 0; $nIndex < $nCount; $nIndex++) { unless (read($rFile, $sBuff, 2) == 2) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } ($nLength) = unpack("n", $sBuff); unless (read ($rFile, $sAnchor, $nLength) == $nLength) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } unless (read($rFile, $sBuff, 1) == 1) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } ($nRefs) = unpack("C", $sBuff); $sRefs = ""; if ($nRefs > 0) { unless (read($rFile, $sRefs, $nRefs) == $nRefs) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } } if ($sWord eq "") { $$rhashProdRefs{$sAnchor} = $$rhashProdRefs{$sAnchor} . $sRefs; } } unless (read($rFile, $sBuff, 2) == 2) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } $nDependencies = unpack("n", $sBuff); for ($nIndex = 0; $nIndex < $nDependencies; $nIndex++) { unless (read($rFile, $sBuff, 1) == 1) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } $nLength = unpack("C", $sBuff); unless (read($rFile, $sFragment, $nLength) == $nLength) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } unless (read($rFile, $sSeek, 4) == 4) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 248, $!)); } unless ($::MATCH_WHOLE_WORDS_ONLY) { $sFragment = substr($sFragment, 0, length($sWord)); } my $sQuotedFragment = quotemeta($sFragment); if ($sWord =~ m/^$sQuotedFragment/i) { $sNext = $'; $nHere = tell($rFile); my ($status, $sError) = WordSearch($sNext, unpack("N", $sSeek), $rFile, $rhashProdRefs); if ($status != $::SUCCESS) { return ($status, $sError); } unless (seek($rFile, $nHere, 0)) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 247, $!)); } } if ($sFragment gt $sWord) { last; } } return ($::SUCCESS); } sub SearchPrice { my ($sPath, $nPriceBand, $rhashProdRefs) = @_; if ($nPriceBand == $::ANY_PRICE_BAND) { return ($::SUCCESS); } my $nRetryCount = $::MAX_RETRY_COUNT; my ($status, $sError); my $nExpectedVersion = 0; while ($nRetryCount--) { ($status, $sError) = ACTINIC::ReadConfigurationFile($sPath . "priceband.fil"); if ($status != $::SUCCESS) { sleep $::RETRY_SLEEP_DURATION; $sError .= ACTINIC::GetPhrase(-1, 256); next; } if ($nPriceBand >= $#$::g_pPriceBand) { sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 249); next; } if ($::gnPriceBandVersion != $nExpectedVersion) { sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 257, $nExpectedVersion, $::gnPriceBandVersion); next; } last; } if ($status != $::SUCCESS) { return($status, $sError); } my $nLowerBound = $$::g_pPriceBand[$nPriceBand]; my $nUpperBound = $$::g_pPriceBand[$nPriceBand + 1]; $nRetryCount = $::MAX_RETRY_COUNT; $status = $::SUCCESS; my $sFileName = $sPath . "oldprice.fil"; my $nExpected = 0; while ($nRetryCount--) { unless (open (INDEX, "<$sFileName")) { sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 250, $sFileName, $!); next; } binmode INDEX; my $sBuffer; unless (read(INDEX, $sBuffer, 2) == 2) { $sError = $!; close (INDEX); return ($::FAILURE, ACTINIC::GetPhrase(-1, 252, $sError)); } my ($nVersion) = unpack("N", $sBuffer); if ($nVersion != $nExpected) { close(INDEX); sleep $::RETRY_SLEEP_DURATION; $status = $::FAILURE; $sError = ACTINIC::GetPhrase(-1, 258, $nExpected, $nVersion); next; } last; } if ($status != $::SUCCESS) { return($status, $sError); } unless (seek (INDEX, $nLowerBound, 0)) { $sError = $!; close (INDEX); return ($::FAILURE, ACTINIC::GetPhrase(-1, 251, $sError)); } my $nBytesToRead = $nUpperBound - $nLowerBound; my $sBuffer; unless (read(INDEX, $sBuffer, $nBytesToRead) == $nBytesToRead) { $sError = $!; close (INDEX); return ($::FAILURE, ACTINIC::GetPhrase(-1, 252, $sError)); } close (INDEX); %$rhashProdRefs = map {$_ => 0} split(/!/, $sBuffer); return ($::SUCCESS); } sub ProductSearch { my ($sProductReference, $rFile, $sFilename, $rhashProduct) = @_; undef %$rhashProduct; my ($Status, $sMessage, $sValue) = ACTINIC::IndexSearch($sProductReference, 2, $rFile, $sFilename); if ($Status != $::SUCCESS) { return ($Status, $sMessage); } unless ($sValue =~ /^(\S+) (\d+) (\d+) (\S+) (\d+) (.+)/s) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 255, $sValue)); } $$rhashProduct{CURRENCY} = $1; $$rhashProduct{DECIMALS} = $2; $$rhashProduct{PRICE} = $3; $$rhashProduct{ANCHOR} = $4; my $nLength = $5; my $sBuffer = $6; $$rhashProduct{NAME} = substr($sBuffer, 0, $nLength); substr($sBuffer, 0, $nLength + 1) = ''; unless ($sBuffer =~ /^(\d+) (.+)/s) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 255, $sValue)); } $nLength = $1; $sBuffer = $2; $$rhashProduct{DESCRIPTION} = substr($sBuffer, 0, $nLength); substr($sBuffer, 0, $nLength + 1) = ''; unless ($sBuffer =~ /^(\d+) (.+)/s) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 255, $sValue)); } $nLength = $1; $sBuffer = $2; $$rhashProduct{SECTION} = substr($sBuffer, 0, $nLength); substr($sBuffer, 0, $nLength + 1) = ''; my $rhashProperties = {}; my $sProperty; until ($sBuffer !~ /^(\d+) (.+)/s) { $nLength = $1; $sBuffer = $2; $sProperty = substr($sBuffer, 0, $nLength); unless ($sProperty =~ /([^!]+)!(.*)/) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 255, $sValue)); } $$rhashProperties{$1} .= $2 . "!"; substr($sBuffer, 0, $nLength + 1) = ''; } $$rhashProduct{PROPERTIES} = $rhashProperties; return ($::SUCCESS); } sub JoinHashes { my ($rhash1, $rhash2, $bOperation, $rhashOutput) = @_; undef %$rhashOutput; if ($bOperation == $::INTERSECT) # AND join (INTERSECTION) { foreach (keys %$rhash1) { $$rhashOutput{$_} = 0 if exists $$rhash2{$_}; } } else # OR join (UNION) { %$rhashOutput = %$rhash1; foreach (keys %$rhash2) { $$rhashOutput{$_} = 0; } } } sub SearchError { my ($sMessage, $sPath) = @_; my $sLastPage = $::g_PageList[0]; my $sLocalPage = ActinicOrder::GetLastPage(); if (!defined $sLocalPage) { $sLocalPage = $sLastPage; if (!defined $sLocalPage) { $sLocalPage = ACTINIC::GetReferrer(); } } push (@::g_PageList, $sLocalPage); push (@::g_PageList, $sLocalPage); my ($status, $sError, $sHTML) = ACTINIC::BounceToPageEnhanced(5, ACTINIC::GetPhrase(-1, 1962) . $sMessage . ACTINIC::GetPhrase(-1, 1970) . ACTINIC::GetPhrase(-1, 2047), '', \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, $::g_pSetupBlob, $sLocalPage, \%::g_InputHash, $::FALSE); if ($status != $::SUCCESS) { ACTINIC::ReportError($sMessage, ACTINIC::GetPath()); } ACTINIC::UpdateDisplay($sHTML, $::g_OriginalInputData, \@::g_PageList); } sub DisplayResults { my ($sPath, $rhashResults, $nPageNumber, $sSearchStrings) = @_; my @Results = sort keys %$rhashResults; if ($#Results == -1) { return ($::NOTFOUND, ACTINIC::GetPhrase(-1, 267)); } my $sFilename = $sPath . "results.html"; unless (open (TFFILE, "<$sFilename")) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 21, $sFilename, $!)); } my ($sHTML); { local $/; $sHTML = ; } close (TFFILE); my $sUrl = $::g_PageList[0]; if( $sUrl ) { my $sReferer = $sUrl; $sUrl =~ s/\/[^\/]*$/\//; my $sStart = ACTINIC::EncodeText2(ACTINIC::GetPhrase(-1, 113), $::FALSE); $sHTML =~ s/\?ACTION\=$sStart/\?ACTION\=$sStart\&BASE\=$sUrl/g; my ($status, $sMessage, $sPrevQuery, $sPageHistory) = ACTINIC::PrepareRefPageData($::g_OriginalInputData, \@::g_PageList, $::FALSE); my $sReplace = "\n" . "\n"; $sHTML =~ s/(]*>)/$1$sReplace/gi; } unless ($sHTML =~ /(.*?)<\/Actinic:SEARCH_RESULTS>/si) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 262)); } my $sRepeatXML = $1; my ($nMin, $nMax); my $nResultsLimit = $$::g_pSearchSetup{SEARCH_RESULTS_PER_PAGE}; my $bResultsLimited = (0 != $nResultsLimit); if (!$bResultsLimited) { $nMin = 0; $nMax = $#Results + 1; } else { $nMin = $nPageNumber * $nResultsLimit; $nMax = ($nPageNumber + 1) * $nResultsLimit; } if ($nMax > $#Results + 1) { $nMax = $#Results + 1; } my ($status, $sError, $sResults) = SearchResultsParser($sPath, $sRepeatXML, \@Results, $nMin, $nMax, $sSearchStrings); if ($status != $::SUCCESS) { return ($status, $sError); } $sHTML =~ s/.*?<\/Actinic:SEARCH_RESULTS>/$sResults/si; my $sSummary = ACTINIC::GetPhrase(-1, 264, $nMin + 1, $nMax, ($#Results + 1)); my $sContinue; if ($bResultsLimited) { my $sCustomNumber = ''; if (exists $::g_InputHash{SN}) { $sCustomNumber = "&SN=$::g_InputHash{SN}"; } my $sCustomSection = ''; if (exists $::g_InputHash{SX}) { $sCustomSection = "&SX=$::g_InputHash{SX}"; } my $sScript = sprintf('%s?TB=%s&SS=%s%s%s&PR=%s', $::g_sSearchScript, $::g_InputHash{TB}, ACTINIC::EncodeText2($::g_InputHash{SS}, $::FALSE), $sCustomNumber, $sCustomSection, $::g_InputHash{PR}); my $sPathAndHistory = "&REFPAGE=" . ACTINIC::EncodeText2($::g_PageList[0], $::FALSE) . ($::g_InputHash{SHOP} ? "&SHOP=" . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) : ""); my $sLinkFormat = ''; my $sLink; if (0 != $nPageNumber) { $sLink = $sScript . "&PN=" . ($nPageNumber - 1) . $sPathAndHistory; $sLink = sprintf($sLinkFormat, $sLink); $sContinue .= $sLink . ACTINIC::GetPhrase(-1, 265, $nResultsLimit) . ""; # add the "Last 20" link } my $nPage; my $nMaxPageCount = ActinicOrder::RoundTax(($#Results + 1) / $nResultsLimit, $ActinicOrder::CEILING); my $sPageLabel; for ($nPage = 0; $nPage < $nMaxPageCount; $nPage++) { $sPageLabel = ($nPage * $nResultsLimit + 1) . '-' . ((($nPage + 1) * $nResultsLimit) > ($#Results + 1) ? $#Results + 1 : ($nPage + 1) * $nResultsLimit); $sLink = $sScript . "&PN=" . $nPage . $sPathAndHistory; $sLink = sprintf($sLinkFormat, $sLink); if ($nPage == $nPageNumber) { $sContinue .= " " . $sPageLabel; } else { $sContinue .= " " . $sLink . $sPageLabel . ""; } } if ($nMaxPageCount != $nPageNumber + 1) { $sLink = $sScript . "&PN=" . ($nPageNumber + 1) . $sPathAndHistory; $sLink = sprintf($sLinkFormat, $sLink); $sContinue .= " " . $sLink . ACTINIC::GetPhrase(-1, 266, $nResultsLimit) . ""; # add the "Next 20" link } if (1 == $nMaxPageCount) { undef $sContinue; } } $ACTINIC::B2B->ClearXML(); $ACTINIC::B2B->SetXML('S_SUMMARY',$sSummary); $ACTINIC::B2B->SetXML('S_CONTINUE',$sContinue); $sHTML = ACTINIC::ParseXML($sHTML); if( !$ACTINIC::B2B->Get('UserDigest') ) { my $sURL = ACTINIC::EncodeText2($::g_sWebSiteUrl . "search.html", $::FALSE); $sHTML =~ s/(\<\s*A\s*HREF[^>?]+\?)/$1ACTINIC_REFERRER=$sURL&/gi; ($status, $sError, $sHTML) = ACTINIC::MakeLinksAbsolute($sHTML, $::g_sWebSiteUrl, $::g_sContentUrl); } else { my $sBaseFile = $ACTINIC::B2B->Get('BaseFile'); my $smPath = ($sBaseFile) ? $sBaseFile : $::g_sContentUrl; my $sCgiUrl = $::g_sAccountScript; $sCgiUrl .= ($::g_InputHash{SHOP} ? '?SHOP=' . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) . '&' : '?'); $sCgiUrl .= 'PRODUCTPAGE='; my $sURL = ACTINIC::EncodeText2($sCgiUrl . "search.html", $::FALSE); $sHTML =~ s/(\<\s*A\s*HREF[^>?]+\?)/$1ACTINIC_REFERRER=$sURL&/gi; ($status, $sError, $sHTML) = ACTINIC::MakeLinksAbsolute($sHTML, $sCgiUrl, $smPath); } if ($status != $::SUCCESS) { return ($status, $sError); } my $sRef = ACTINIC::EncodeText2(ACTINIC::GetLastNonScript(\@::g_PageList), $::FALSE); $sHTML =~ s/(['"]\&ACTINIC_REFERRER\=["']\s*\+)\s*escape\(location\.href\)/$1\'$sRef\'/; ACTINIC::PrintPage($sHTML, undef, $::FALSE); return ($::SUCCESS); } sub SearchResultsParser { my ($sPath, $sResultMarkup, $rarrResults, $nMin, $nMax, $sSearchStrings) = @_; my $rFile = \*PRODUCTINDEX; my $sFilename = $sPath . "oldprod.fil"; my ($status, $sError) = ACTINIC::InitIndex($sFilename, $rFile, 257); if ($status != $::SUCCESS) { return($status, $sError); } my $sScript; if ($$::g_pSearchSetup{SEARCH_SHOW_HIGHLIGHT}) { my ($sPrevQuery, $sPageHistory); ($status, $sError, $sPrevQuery, $sPageHistory) = ACTINIC::PrepareRefPageData($::g_OriginalInputData, \@::g_PageList, $::FALSE); if ($status != $::SUCCESS) { } if ($ACTINIC::B2B->Get('UserDigest')) { $sScript = sprintf('%s?REFPAGE=%s&WD=%s%s&PRODUCTPAGE=', $::g_sAccountScript, ACTINIC::EncodeText2($::g_PageList[0], $::FALSE), ACTINIC::EncodeText2($sSearchStrings, $::FALSE), ($::g_InputHash{SHOP} ? "&SHOP=" . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) : "")); } else { $sScript = sprintf('%s?REFPAGE=%s&WD=%s%s&PREVQUERY=%s&PN=', $::g_sSearchHighLightScript, ACTINIC::EncodeText2($::g_PageList[0], $::FALSE), ACTINIC::EncodeText2($sSearchStrings, $::FALSE), ($::g_InputHash{SHOP} ? "&SHOP=" . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) : ""), ACTINIC::EncodeText2($sPrevQuery, $::FALSE)); } } else { if ($ACTINIC::B2B->Get('UserDigest')) { $sScript = sprintf('%s?REFPAGE=%s&WD=%s%s&PRODUCTPAGE=', $::g_sAccountScript, ACTINIC::EncodeText2($::g_PageList[0], $::FALSE), ACTINIC::EncodeText2($sSearchStrings, $::FALSE), ($::g_InputHash{SHOP} ? "&SHOP=" . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) : "")); } } my $nCount; my $sHTML; my $sTemp; my %Product; for ($nCount = $nMin; $nCount < $nMax; $nCount++) { ($status, $sError) = ProductSearch($$rarrResults[$nCount], $rFile, $sFilename, \%Product); if ($status == $::FAILURE) { ACTINIC::CleanupIndex($rFile); return($status, $sError); } if ($status == $::NOTFOUND) { ACTINIC::CleanupIndex($rFile); return($status, ACTINIC::GetPhrase(-1, 263)); } $ACTINIC::B2B->SetXML('S_ITEM', ($nCount + 1)); if ($$::g_pSearchSetup{SEARCH_SHOW_HIGHLIGHT} && $sSearchStrings) { $Product{ANCHOR} =~ /([^\#]*)(.*)/; my $sAnchor = $2; $ACTINIC::B2B->SetXML('S_LINK', sprintf('', $sScript . ACTINIC::EncodeText2($Product{ANCHOR}, $::FALSE) . $sAnchor)); } else { $ACTINIC::B2B->SetXML('S_LINK', sprintf('', $Product{ANCHOR})); } $sTemp = ""; if ($$::g_pSearchSetup{SEARCH_SHOW_NAME}) { ($status, $sTemp) = ACTINIC::ProcessEscapableText($Product{NAME}); if ($status != $::SUCCESS) { ACTINIC::CleanupIndex($rFile); return($status, $sTemp); } } else { $sTemp = ACTINIC::GetPhrase(-1, 278); } $ACTINIC::B2B->SetXML('S_PNAME', $sTemp); $sTemp = ""; if ($$::g_pSearchSetup{SEARCH_SHOW_SECTION}) { ($status, $sTemp) = ACTINIC::ProcessEscapableText($Product{SECTION}); if ($status != $::SUCCESS) { ACTINIC::CleanupIndex($rFile); return($status, $sTemp); } $sTemp = "($sTemp)"; } $ACTINIC::B2B->SetXML('S_SNAME', $sTemp); $sTemp = ""; if ($$::g_pSearchSetup{SEARCH_SHOW_DESCRIPTION}) { ($status, $sTemp) = ACTINIC::ProcessEscapableText($Product{DESCRIPTION}); if ($status != $::SUCCESS) { ACTINIC::CleanupIndex($rFile); return($status, $sTemp); } } $ACTINIC::B2B->SetXML('S_DESCR', $sTemp); $sTemp = ""; if ($$::g_pSearchSetup{SEARCH_SHOW_PRICE} && $$::g_pSetupBlob{PRICES_DISPLAYED} && $Product{PRICE} != 0) { ($status, $sError, $sTemp) = ActinicOrder::FormatPrice($Product{PRICE}, $::TRUE, $::g_pCatalogBlob); if ($status != $::SUCCESS) { ACTINIC::CleanupIndex($rFile); return($status, $sError); } } $ACTINIC::B2B->SetXML('S_PRICE', $sTemp); $sTemp = ""; if ($$::g_pSearchSetup{SEARCH_SHOW_PROPERTY}) { my ($sKey, $sValue); my $Props = $Product{PROPERTIES}; while (($sKey, $sValue) = each(%$Props)) { $sKey =~ s/\d$//; $sValue =~ s/!$//g; $sValue =~ s/!/, /g; $sTemp .= "$sKey: $sValue
"; } } $ACTINIC::B2B->SetXML('S_PROP', $sTemp); $sHTML .= ACTINIC::ParseXML($sResultMarkup); } ACTINIC::CleanupIndex($rFile); return ($::SUCCESS, undef, $sHTML); } sub DirectLinkToProduct { my ($sPath, $sProdRef) = @_; my %Product; my $rFile = \*PRODUCTINDEX; my $sFilename = $sPath . "oldprod.fil"; my ($status, $sError) = ACTINIC::InitIndex($sFilename, $rFile, 257); if ($status != $::SUCCESS) { ACTINIC::TerminalError($sError); } ($status, $sError) = ProductSearch($sProdRef, $rFile, $sFilename, \%Product); if ($status == $::FAILURE) { ACTINIC::CleanupIndex($rFile); SearchError($sError, $sPath); } if ($status == $::NOTFOUND) { ACTINIC::CleanupIndex($rFile); my ($status, $sError, $sHTML) = ACTINIC::BounceToPageEnhanced(5, ACTINIC::GetPhrase(-1, 1962) . ACTINIC::GetPhrase(-1, 1965, $sProdRef) . ACTINIC::GetPhrase(-1, 1970) . ACTINIC::GetPhrase(-1, 2048), '', \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, $::g_pSetupBlob, ACTINIC::GetReferrer(), \%::g_InputHash, $::FALSE); return($sHTML); } my $sLink = $Product{ANCHOR}; ACTINIC::CleanupIndex($rFile); return(DisplayDirectLinkPage($sLink)); } sub DisplayDirectLinkPage { my $sLink = shift @_; my $sBaseFile = $ACTINIC::B2B->Get('BaseFile'); my $sReferrer = ACTINIC::GetReferrer(); my $sCgiUrl = $::g_sAccountScript; $sCgiUrl .= ($::g_InputHash{SHOP} ? '?SHOP=' . ACTINIC::EncodeText2($::g_InputHash{SHOP}, $::FALSE) . '&' : '?'); if (!defined $::g_InputHash{ACTINIC_REFERRER}) { $sReferrer =~ s/\/[^\/]*$/\//; $sReferrer =~ /[^\/]\/([^\/]+)\/$/; my $sLastDir = $1; if ($$::g_pSetupBlob{CATALOG_URL} !~ /$sLastDir\/$/ || !defined $sLastDir) { if ($$::g_pSetupBlob{CATALOG_URL} =~ /$sLastDir\/([^\/]+)\/$/) { $sReferrer .= $1 . "/"; $::g_sContentUrl = $sReferrer; push (@::g_PageList, $sReferrer); } } } if ($ACTINIC::B2B->Get('UserDigest')) { $sLink = !$$::g_pSetupBlob{USE_FRAMES} ? $sCgiUrl . "PRODUCTPAGE=" . $sLink . "&ACTINIC_REFERRER=" . ACTINIC::EncodeText2($sReferrer, $::FALSE): $sCgiUrl . "MAINFRAMEURL=" . ACTINIC::EncodeText2($sLink, $::FALSE) . "&ACTINIC_REFERRER=" . ACTINIC::EncodeText2($sReferrer, $::FALSE); } else { if ($$::g_pSetupBlob{B2B_MODE} && !$::g_InputHash{NOLOGIN}) { my @Response = ACTINIC::TemplateFile(ACTINIC::GetPath() . $$::g_pSetupBlob{B2B_LOGONPAGE}); if ($Response[0] != $::SUCCESS) { ACTINIC::TerminalError($Response[1]); } $sLink =~ /([^\#]*)(.*)/; my $sAnchor = $2; my $sReplace = $$::g_pSetupBlob{USE_FRAMES} ? "" : ""; $sReplace .= ""; $Response[2] =~ s/]+ACTION\s*=\s*["|'])($::g_sAccountScript)(["|'][^>]+>)/)/$1$sReplace$2/gi; return($Response[2]); } else { $sLink = $::g_sContentUrl . $sLink; } } my $sHTML = ""; $sHTML .= ""; return($sHTML); }