home *** CD-ROM | disk | FTP | other *** search
- /*
- ** SEARCH
- **
- ** This is a simple ISAPI search DLL that takes a set of words
- ** to search for in the "query" parameter, and displays all files
- ** that match the keywords.
- **
- ** Important! The search occurs from the location of the search.dll
- ** and below. The search.dll will only work properly if placed in
- ** the root of your documents directory.
- **
- ** Confidential Property of Tod Sambar
- ** (c) Copyright Tod Sambar 1998
- ** All rights reserved.
- **
- **
- ** History:
- ** Chg# Date Description Resp
- ** ---- ------- ------------------------------------------------------- ----
- ** 20MAR98 Created sambar
- */
-
- #include <windows.h>
- #include <httpext.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdarg.h>
-
- /*
- ** Globals
- */
- #define PAGE_END "<P><B>Done.</B>\n</BODY></HTML>\n"
- #define INVALID_FORMAT "<B>Invalid search syntax.</B><P><I>search?query=foo&logic=AND</I>"
- #define NO_RESULTS "<P><B>No results matching search request.</B>"
-
- /*
- ** Local Prototypes
- */
- static DWORD search_error(EXTENSION_CONTROL_BLOCK *pECB, CHAR *errorstr);
- static void search_find(EXTENSION_CONTROL_BLOCK *pECB,
- CHAR *docdir, CHAR *urldir,
- CHAR kwords[10][256], int numkwords, int any,
- int *nump);
- static short search_match(CHAR *filename, CHAR kwords[10][256],
- int numkwords, int any);
- static void escape_to_ascii(CHAR *buf, int buflen);
- static short get_param(CHAR *params, CHAR *arg, CHAR *buf, int buflen);
- static short get_next(CHAR *head, CHAR *buffer, CHAR **tailp);
-
-
- /*
- ** GetExtensionVersion
- **
- ** ISAPI/Win32 API method to ensure compatibility with the Server.
- */
- BOOL WINAPI
- GetExtensionVersion(HSE_VERSION_INFO *pVer)
- {
- pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
-
- lstrcpyn(pVer->lpszExtensionDesc, "Sambar Server ISAPI Search extension.",
- HSE_MAX_EXT_DLL_NAME_LEN);
-
- return TRUE;
- }
-
- /*
- ** HttpExtensionProc
- **
- ** Called in response to the client request.
- **
- ** Format:
- ** search?query="<word1> <word2>... <wordN>"&logic="AND">
- ** or
- ** search?query="<word1> <word2>... <wordN>"&logic="OR">
- */
- DWORD WINAPI
- HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
- {
- int any;
- int num;
- int numkwords;
- int found;
- DWORD buflen;
- CHAR *head;
- CHAR *params;
- CHAR tmp[256];
- CHAR kwords[10][256];
- CHAR buffer[2048];
- CHAR urldir[512];
-
- /* Get the GET/POST data */
- params = NULL;
- if (!stricmp(pECB->lpszMethod, "GET"))
- {
- /* Set the parameters list to the QUERY_STRING data */
- params = pECB->lpszQueryString;
- }
- else /* POST */
- {
- /* Note: cbTotalBytes = cbAvailable in the Sambar Server */
- if(pECB->cbTotalBytes > 0)
- params = pECB->lpbData;
- }
-
- if (params == NULL)
- return (search_error(pECB, INVALID_FORMAT));
-
- /* Get the "query" and "logic" parameters */
- if (!get_param(params, "logic", tmp, 255))
- return (search_error(pECB, INVALID_FORMAT));
-
- if (stricmp(tmp, "and"))
- any = 1;
- else
- any = 0;
-
- if (!get_param(params, "query", tmp, 255))
- return (search_error(pECB, INVALID_FORMAT));
-
- /* Parse the query into a list. */
- head = tmp;
- numkwords = 0;
- while ((numkwords < 10) && get_next(head, kwords[numkwords], &head))
- {
- _strupr(kwords[numkwords]);
- numkwords++;
- }
-
- wsprintf(buffer,
- "Content-Type: text/html\r\n"
- "\r\n"
- "<head><title>Sambar ISAPI Search</title></head>\n"
- "<body><h1>Sambar ISAPI Search</h1>\n"
- "<hr><P>Keywords: %s</P>\n", tmp);
-
- buflen = lstrlen(buffer);
-
- if (!pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
- "200 OK", &buflen, (LPDWORD)buffer))
- {
- pECB->dwHttpStatusCode = 500;
- return HSE_STATUS_ERROR;
- }
-
- /*
- ** Search for the keywords.
- */
- num = 0;
-
- /*
- ** Get the document root to search from.
- */
- GetModuleFileName(GetModuleHandle("search.dll"), buffer, 1024);
- buflen = strlen(buffer) - strlen("\\search.dll");
- buffer[buflen] = '\0';
-
- /*
- ** Get the URL path
- */
- buflen = 512;
- if (!pECB->GetServerVariable(pECB->ConnID, "URL", urldir, &buflen))
- {
- buflen = lstrlen(NO_RESULTS);
- pECB->WriteClient(pECB->ConnID, NO_RESULTS, &buflen, 0);
- pECB->dwHttpStatusCode = 200;
- return HSE_STATUS_SUCCESS;
- }
-
- /* Strip off to the last "directory" symbol. */
- found = 0;
- buflen = strlen(urldir);
- while ((!found) && (buflen > 0))
- {
- if ((urldir[buflen - 1] == '/') || (urldir[buflen - 1] == '/'))
- found = 1;
-
- buflen--;
- }
-
- urldir[buflen] = '\0';
-
- search_find(pECB, buffer, urldir, kwords, numkwords, any, &num);
-
- if (num == 0)
- {
- buflen = lstrlen(NO_RESULTS);
- pECB->WriteClient(pECB->ConnID, NO_RESULTS, &buflen, 0);
- }
-
- buflen = lstrlen(PAGE_END);
- pECB->WriteClient(pECB->ConnID, PAGE_END, &buflen, 0);
-
- pECB->dwHttpStatusCode = 200;
-
- return HSE_STATUS_SUCCESS;
- }
-
- /*
- ** search_find
- **
- ** Recursively search from the directory in which the search.dll
- ** is located and below returning files that match the query
- ** criteria.
- */
- static void
- search_find(EXTENSION_CONTROL_BLOCK *pECB, CHAR *docdir, CHAR *urldir,
- CHAR kwords[10][256], int numkwords, int any, int *nump)
- {
- DWORD buflen;
- HANDLE hFile;
- WIN32_FIND_DATA findData;
- CHAR buffer[2048];
- CHAR newurl[2048];
-
- /*
- ** Loop through all the files from the root directory.
- */
- sprintf(buffer, "%s\\*.htm", docdir);
- hFile = FindFirstFile(buffer, &findData);
- while (hFile != INVALID_HANDLE_VALUE)
- {
- /* Search file handle... */
- sprintf(buffer, "%s\\%s", docdir, findData.cFileName);
- if (search_match(buffer, kwords, numkwords, any))
- {
- *nump = *nump + 1;
- sprintf(buffer, "<A HREF=\"%s/%s\">%s/%s</A><BR>\n",
- urldir, findData.cFileName, urldir, findData.cFileName);
- buflen = lstrlen(buffer);
- pECB->WriteClient(pECB->ConnID, buffer, &buflen, 0);
- }
-
- if (!FindNextFile(hFile, &findData))
- break;
- }
-
- FindClose(hFile);
-
- sprintf(buffer, "%s\\*.html", docdir);
- hFile = FindFirstFile(buffer, &findData);
- while (hFile != INVALID_HANDLE_VALUE)
- {
- /* Search file handle... */
- sprintf(buffer, "%s\\%s", docdir, findData.cFileName);
- if (search_match(buffer, kwords, numkwords, any))
- {
- *nump = *nump + 1;
- sprintf(buffer, "<A HREF=\"%s/%s\">%s/%s</A><BR>\n",
- urldir, findData.cFileName, urldir, findData.cFileName);
- buflen = lstrlen(buffer);
- pECB->WriteClient(pECB->ConnID, buffer, &buflen, 0);
- }
-
- if (!FindNextFile(hFile, &findData))
- break;
- }
-
- FindClose(hFile);
-
- sprintf(buffer, "%s\\*.txt", docdir);
- hFile = FindFirstFile(buffer, &findData);
- while (hFile != INVALID_HANDLE_VALUE)
- {
- /* Search file handle... */
- sprintf(buffer, "%s\\%s", docdir, findData.cFileName);
- if (search_match(buffer, kwords, numkwords, any))
- {
- *nump = *nump + 1;
- sprintf(buffer, "<A HREF=\"%s/%s\">%s/%s</A><BR>\n",
- urldir, findData.cFileName, urldir, findData.cFileName);
- buflen = lstrlen(buffer);
- pECB->WriteClient(pECB->ConnID, buffer, &buflen, 0);
- }
-
- if (!FindNextFile(hFile, &findData))
- break;
- }
-
- FindClose(hFile);
-
- /*
- ** Recurse the directory(s)
- */
- sprintf(buffer, "%s\\*.*", docdir);
- hFile = FindFirstFile(buffer, &findData);
- while (hFile != INVALID_HANDLE_VALUE)
- {
- if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
- (strcmp(findData.cFileName, ".") != 0) &&
- (strcmp(findData.cFileName, "..") != 0))
- {
- sprintf(buffer, "%s\\%s", docdir, findData.cFileName);
- sprintf(newurl, "%s/%s", urldir, findData.cFileName);
- search_find(pECB, buffer, newurl, kwords, numkwords, any, nump);
- }
-
- if (!FindNextFile(hFile, &findData))
- break;
- }
-
- FindClose(hFile);
-
- return;
- }
-
- /*
- ** search_match
- **
- ** Determine if the file matches the search criteria provided.
- */
- static short
- search_match(CHAR *filename, CHAR kwords[10][256], int numkwords, int any)
- {
- int i;
- int matched;
- FILE *hFile;
- short match[10];
- CHAR buffer[2048];
-
- hFile = fopen(filename, "r");
- if (hFile == NULL)
- return (0);
-
- matched = 0;
- for (i = 0; i < numkwords; i++)
- match[i] = 0;
-
- while (fgets(buffer, 2048, hFile) != NULL)
- {
- _strupr(buffer);
-
- /* Match found? */
- for (i = 0; i < numkwords; i++)
- {
- if (strstr(buffer, kwords[i]) != NULL)
- {
- if (any)
- {
- fclose(hFile);
- return (1);
- }
-
- if (!match[i])
- {
- match[i] = 1;
- matched++;
- }
- }
- }
-
- /* All words matched... */
- if (matched == numkwords)
- {
- fclose(hFile);
- return (1);
- }
- }
-
- fclose(hFile);
-
- return 0;
- }
-
- /*
- ** search_error
- **
- ** Report a failure of the search interface.
- */
- static DWORD
- search_error(EXTENSION_CONTROL_BLOCK *pECB, CHAR *errorstr)
- {
- DWORD buflen;
- CHAR buffer[2048];
-
- /* Prepare the response header */
- wsprintf(buffer,
- "Content-Type: text/html\r\n"
- "\r\n"
- "<head><title>Sambar ISAPI Search</title></head>\n"
- "<body><h1>Sambar ISAPI Search</h1>\n"
- "<hr><P>%s</P>\n"
- "</body></html>\n", errorstr);
-
- buflen = lstrlen(buffer);
-
- if (!pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER,
- "200 OK", &buflen, (LPDWORD)buffer))
- {
- pECB->dwHttpStatusCode = 500;
- return HSE_STATUS_ERROR;
- }
-
- pECB->dwHttpStatusCode = 200;
-
- return HSE_STATUS_SUCCESS;
- }
-
- /*
- **
- ** Parameter Processing...
- **
- */
-
- static CHAR
- hex_to_ascii(CHAR *cval)
- {
- CHAR c;
-
- c = (cval[0] >= 'A' ? ((cval[0] & 0xDF) - 'A') + 10 : (cval[0] - '0'));
- c *= 16;
- c += (cval[1] >= 'A' ? ((cval[1] & 0xDF) - 'A') + 10 : (cval[1] - '0'));
-
- return c;
- }
-
- static void
- escape_to_ascii(CHAR *buf, int buflen)
- {
- int i, j;
-
- for (i = 0, j = 0; j < buflen; ++i, ++j)
- {
- if ((buf[i] = buf[j]) == '%' )
- {
- buf[i] = hex_to_ascii(&buf[j+1]);
- j+=2;
- }
- }
-
- buf[i] = '\0';
- }
-
- /*
- ** GET_PARAM
- **
- */
- static short
- get_param(CHAR *params, CHAR *arg, CHAR *buf, int buflen)
- {
- int i;
- int len;
- CHAR *head;
- CHAR *tail;
-
- /*
- ** Find the value passed in by the client for some particular
- ** parameter within the query string.
- */
- head = strstr(params, arg);
- if (!head)
- return (0);
-
- /* Increment past the equals sign... */
- head += strlen(arg) + 1;
-
- /* Now determine the length of the value string. */
- tail = strchr(head, '&');
- if (tail)
- len = tail - head;
- else
- len = strlen(head);
-
- /* Fail if we have zero lenght string. */
- if ((len <= 0) || (len > buflen))
- return (0);
-
- strncpy(buf, head, len);
- buf[len] = '\0';
-
- /*
- ** Now replace "+" characters with " " characters and
- ** "%xx" (hexadecemal) to the ASCII representation.
- */
- for (i = 0; i < len; i++)
- {
- if (buf[i] == '+')
- buf[i] = ' ';
- }
-
- escape_to_ascii(buf, len);
-
- return (1);
- }
-
- static short
- get_next(CHAR *head, CHAR *buffer, CHAR **tailp)
- {
- int hlen;
- int blen;
- CHAR end;
-
- hlen = 0;
- end = ' ';
-
- while (isspace(head[hlen]))
- hlen++;
-
- if (head[hlen] == '\0')
- return (0);
-
- if ((head[hlen] == '"') || (head[hlen] == '\''))
- {
- end = head[hlen];
- hlen++;
- }
-
- blen = 0;
- while ((head[hlen] != '\0') && (head[hlen] != end))
- {
- buffer[blen] = head[hlen];
- hlen++;
- blen++;
- }
-
- buffer[blen] = '\0';
- *tailp = &head[hlen];
-
- return (1);
- }
-