home *** CD-ROM | disk | FTP | other *** search
- //
- // Copyright (c) 1997 Microsoft Corp. All Rights Reserved
-
- // votecount.cpp : Defines the initialization routines for the DLL.
- //
-
- #include "votecount.h"
- #include "votefile.h"
- #include "../../webbot.h"
- #include <string.h>
- #include <stdlib.h>
-
- #ifdef UNIX
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #else
- #include <direct.h>
- #include <io.h>
- #endif
-
-
-
- ////////////////////////////////////////////////////////////////////////
- // Utility URL and filename manipulation functions.
-
-
- // Extracts just the filename portion of the URL.
- // that is, a URL of "/simple/foo/default.htm" becomes "default.htm",
- // and "blah.html" would become "blah.html"
- const char* URLtoFileName(const char *URL)
- {
- if (!URL)
- return "";
-
- // Look for the last '/' in the URL:
- const char *last = URL;
- for (const char *p=URL; *p; p++)
- if (*p == '/')
- last = p+1;
- return last;
- }
-
-
-
- // Copies the PageURL directory name (the PageURL minus the page itself) into
- // the destination. It also translates the '/' character into the character
- // specified by translateChar. This is useful if the desired final form
- // is to contain '\' or ':' as the directory separator. If the PageURL
- // is NULL, it does nothing.
- // Returns the number of characters copied, not counting the '\0' at the end
- // NOTE: this routine assumes enough space has been allocated in the
- // destination buffer to hold the *entire* PageURL, not just enough up
- // to the '/' of the PageURL.
- //
- // Example: PageURL="Matt/simple/index.htm" and translateChar is '\' then
- // the result in dest is "Matt\simple"
-
- void CopyPageDirName(const char *PageURL, char *dest, char translateChar)
- {
- if (!PageURL)
- return;
- const char *pSource = PageURL;
- char *pDest = dest;
- char *last = pDest;
- for (; *pSource; pSource++, pDest++)
- {
- if (*pSource == '/')
- {
- last = pDest;
- *pDest = translateChar;
- }
- else
- *pDest = *pSource;
- }
-
- // last points to the last '/' in the PageURL, or the beginning of it if
- // there were no '/' in the string. Thus, close off the string at
- // this location.
-
- // if characters were copied then append a dir seperator to the end
- // of the whole thing. Otherwise, just close off the string
- if (last != dest)
- {
- *last = translateChar;
- *(last+1) = '\0';
- }
- else
- *last = '\0';
- }
-
-
- const char *SubWebName(CWebBotDict &bot)
- {
- // Returns the subweb name, taken from the WebURL.
- // Assumes WebURL is in the form
- // protocol://host/subweb
- //
- // Method to find the subweb: Scan for the first / which
- // does not have a / following it.
- const char *WebURL = bot.GetValue("WebURL");
- if (!WebURL)
- return "";
-
- const char *p;
- for (p = WebURL; *p; p++)
- {
- if (*p=='/')
- {
- if (*(p+1) != '/')
- return p;
- else
- p++; // Skip over next spot
- }
- }
- return p;
-
- }
-
-
-
-
- ///////////////////////////////////////////////////////////////////
- // Vote count file functions
-
- void CreateAndResetVoteCntFile(const char *VoteCntFile, long resetValue=0)
- {
- // Create a CVote object for dealing with the vote count file.
- // Waits until the file is available, then locks it. Times out
- // if the file does not become available in a certain amount of time.
- // If the file does not exist, it will create it.
-
- // If new vote types are added by end-users,
- // and they have different reset values, this parameter will come in
- // handy. For now, just stifle compiler warnings.
-
- (void)resetValue;
-
- CVote votefile(VoteCntFile, TRUE);
- votefile.SetVoteCount("vote1type", 0);
- votefile.SetVoteCount("vote2type", 0);
-
- // CVote destructor writes and unlocks the file
- }
-
-
- void HandleVoteCntFile(CWebBotDict &bot)
- {
- // Figures out the filename for the vote counter.
- // and makes sure it exists with a correct count according to the
- // reset key. If the reset key does not exist, and the file doesn't
- // exist, make a count beginning at 0.
-
- // The vote counter file name will be the name of the page with .vot
- // appended to the end, stored in the _private directory
-
- const char *PageURL = bot.GetValue("PageURL");
- const char *PageFileName = URLtoFileName(PageURL);
- const char *DocumentRoot = bot.GetValue("DocumentRoot");
-
- if (!PageURL || !DocumentRoot)
- return;
-
- // The idea is that the VoteCountFile is a filename which is relative to
- // the location of the .htm file which contains the counter tag.
- // In order to "mess around with" the vote counter file, we need to know
- // the absolute pathname to the file. The DocumentRoot tells us
- // where the root directory of the web is (e.g. c:\inetsrv\wwwroot\Kuan),
- // and the PageURL tells us what is the web-relative URL of the
- // .htm file which called us (e.g. simple/index.htm).
- // So, strip off the filename of the PageURL, and append that to
- // the end of the DocumentRoot, changing all '/' to the DIR_SEPARATOR
- // for this platform.
-
- // Create a buffer large enough:
- int DocumentRootLen = strlen(DocumentRoot);
- char *PageDirName = new char[DocumentRootLen + 1 + // +1 for DIR_SEPARATOR
- strlen(PageURL) + 1 + // +1 for DIR_SEPARATOR
- + 9 + // +9 for "_private/"
- strlen(PageFileName) + 5]; // +5 for ".vot"+'\0'
-
-
- // Put in the document root:
- strcpy(PageDirName, DocumentRoot);
-
- // Append the DIR_SEPARATOR
- PageDirName[DocumentRootLen] = DIR_SEPARATOR;
-
- // Append the PageURL, changing all '/' to the local machine's DIR_SEPARATOR
- // Also appends the DIR_SEPERATOR to the end of the string
- CopyPageDirName(PageURL, &PageDirName[DocumentRootLen+1], DIR_SEPARATOR);
-
- strcat(PageDirName, "_private/");
-
- // Check for existence of, and create directory
- if (access(PageDirName, 0) != 0)
- {
- #ifdef UNIX
- mkdir(PageDirName, 0777);
- #else
- mkdir(PageDirName);
- #endif
- }
-
- // Now append the Page filename
- strcat(PageDirName, PageFileName);
-
- // Now append the ".vot" ending
- strcat(PageDirName, ".vot");
-
- ////////////////////////////////////////////////////
- // Now buffer holds the filename of the vote count file.
-
- // If we are to reset it, do so:
- const char *reset;
- const char *resetValue;
- reset = bot.GetValue("B-Reset");
-
- if ( (reset) &&
- (*reset=='T') &&
- (resetValue = bot.GetValue("I-ResetValue"))
- )
-
- {
- // Only if reset key is TRUE, and there's a reset value
- CreateAndResetVoteCntFile(PageDirName, atol(resetValue));
- bot.SetValue("B-Reset", "FALSE");
- }
- else
- {
- // If the file doesn't exist then create it with a count of 0
- if (access(PageDirName, 0) != 0)
- CreateAndResetVoteCntFile(PageDirName, 0);
- }
-
- delete[] PageDirName;
- }
-
-
- const int QueryNumTranslations = 2;
- const char QueryTranslateFrom[QueryNumTranslations] = {' ', '\\'};
- const char *QueryTranslateTo[QueryNumTranslations] = {"+", "/"};
-
- const int URLNumTranslations = 2;
- const char URLTranslateFrom[URLNumTranslations] = {' ', '\\'};
- const char *URLTranslateTo[URLNumTranslations] = {"%20", "/"};
-
-
- char *URLEncode(const char *url,
- const char *translateFrom,
- const char **translateTo,
- int numTranslations)
- {
- // Note: Users of this function should delete the pointer themselves
- if (url == NULL)
- return NULL;
-
- // maximum size of the encoded string is the url's len*3. This assumes that
- // no TranslateTo string is more than 3 chars, which will always be
- // true for URL encoding
- char *encoded = new char[strlen(url)*3 + 1]; // +1 for '\0'
-
- char *currentTo = encoded;
- BOOL found;
- for (const char *currentFrom = url; *currentFrom; currentFrom++)
- {
- found = FALSE;
- for (int i = 0; i < numTranslations && !found; i++)
- {
- if (*currentFrom == translateFrom[i])
- {
- // Matches a char, copy over the translateTo for this char
- strcpy(currentTo, translateTo[i]);
- currentTo+=strlen(translateTo[i]);
- found = TRUE;
- }
- }
-
- if (!found)
- {
- // Wasn't a char to translate, just do plain vanilla copy
- *currentTo = *currentFrom;
- currentTo++;
- }
- }
- // Close it off
- *currentTo = '\0';
- return encoded;
- }
-
-
- /////////////////////////////////////////////////////////////////////
- // DLL Entry point for expanding the WebBot
-
-
- // cgi and form are unused, so they are commented out to prevent compiler
- // warnings.
- BeginWebBotExpand(votebot,ret,bot,cgi,form)
- {
- // Squelch compiler warnings
- (void)cgi;
- (void)form;
-
- // Take care of the vote count file
- HandleVoteCntFile(bot);
-
- // Create the HTML tag which will call the cgi program "votebot"
-
- // First, generate the PageDirName
- const char *PageURL = bot.GetValue("PageURL");
- if (!PageURL)
- PageURL = "";
-
- // The +2 is for the potentially extra '/' at the end, and for the '\0'
- char *PageDirName = new char[strlen(PageURL) + 2];
- CopyPageDirName(PageURL, PageDirName, '/');
-
- // Now generate the Page Filename
- const char *PageFileName = URLtoFileName(PageURL);
-
- // create the URL.
-
- // Method:
- // Create the URL without the query string in ret, URL encode it into "url"
- // Create the query string in ret, do a query string encoding into "query"
- // Clear ret, put in the MIME headers, append url and query
-
- // First generate URL:
- ret.Clear();
-
- ret.Append("/cgi-bin/votebot.exe");
- ret.Append(SubWebName(bot));
- ret.Append("/");
- ret.Append(PageDirName);
- ret.Append("?");
- char *url = URLEncode(ret.GetContents(),
- URLTranslateFrom,
- URLTranslateTo,
- URLNumTranslations);
-
- // Put in the MIME Links: header so that the explorer knows
- // that our WebBot is linking to the vote count file. That is, append
- // Links: _private/PageFilename.vot. But URL encode the filename
- ret.Clear();
- ret.Append("Links: ");
- ret.Append("_private/");
- char *EncodedPageFileName = URLEncode(PageFileName,
- URLTranslateFrom,
- URLTranslateTo,
- URLNumTranslations);
- ret.Append(EncodedPageFileName);
- ret.Append(".vot");
-
- // Put in the MIME WriteLinks: header so that the explorer knows
- // that our WebBot is writing to the vote count file. This will cause
- // the server extensions to set the permissions on this
- // file so that browsers can write to it.
- // WriteLinks: _private/PageFilename.vot.
-
- ret.Append("\nWriteLinks: ");
- ret.Append("_private/");
- ret.Append(EncodedPageFileName);
- ret.Append(".vot");
-
- // Put in the MIME Error: header to signify any setup errors
-
- const char *sztype = bot.GetValue("S-VOTETYPE");
- const char *szopt = bot.GetValue("S-VOTEOPT");
- if (!sztype || !szopt)
- ret.Append("\nError: A vote component is incorrectly configured. "
- "You must provide values for the \"S-VOTETYPE\" and "
- "\"S-VOTEOPT\" parameter(s).");
-
-
- // a blank like signifies the end of all MIME headers:
- #ifdef UNIX
- ret.Append("\r\n\r\n");
- #else
- ret.Append("\n\n");
- #endif
-
- // stick the vote submit form out there.
-
- // for ASP implementation:
- // ret.Append("\n<form method=\"POST\" action=\"asp/votebot.asp\">");
-
- // for CGI implementation:
- ret.Append("<form method=\"GET\" action=\"");
-
- // Append the name of the CGI executable (vote submission handler)
- ret.Append("/cgi-bin/votebot.exe");
- ret.Append(SubWebName(bot));
- ret.Append("/");
- ret.Append(PageDirName);
-
- ret.Append("\" target=\"_top\">\n<hr>");
- ret.Append("\n<input type=\"hidden\" name=\"Page\" value=\"");
- ret.Append(PageFileName);
-
- ret.Append("\">\n<div align=\"center\"><center><p>");
- ret.Append("How do you feel about the ");
-
- if (sztype && !strcmp(sztype,"OPINION"))
- ret.Append("opinion");
-
- else if (sztype && !strcmp(sztype,"PROPOSAL"))
- ret.Append("proposal");
-
- ret.Append(" expressed on this page?</p>");
- ret.Append("\n</center></div><div align=\"center\"><center><p><input");
- ret.Append("\ntype=\"radio\" value=\"V1\" checked name=\"Vote\">");
-
- if (szopt && !strcmp(szopt,"AGREE"))
- {
- ret.Append(" I agree! <input");
- ret.Append("\ntype=\"radio\" name=\"Vote\" value=\"V2\"> I disagree!");
- }
-
- else if (szopt && !strcmp(szopt,"YES/NO"))
- {
- ret.Append(" Yes! <input");
- ret.Append("\ntype=\"radio\" name=\"Vote\" value=\"V2\"> No!");
- }
-
- else if (szopt && !strcmp(szopt,"FOR/AGAINST"))
- {
- ret.Append(" For! <input");
- ret.Append("\ntype=\"radio\" name=\"Vote\" value=\"V2\"> Against!");
- };
-
- ret.Append("\n</p></center></div>");
- ret.Append("\n<div align=\"center\"><center><p><input type=\"submit\"");
- ret.Append("value=\"Cast Your Ballot!\" name=\"B1\"></p>");
- ret.Append("\n</center></div><hr>");
- ret.Append("\n</form>");
-
- delete[] PageDirName;
- delete[] EncodedPageFileName;
- delete[] url;
- }
- EndWebBotExpand
-
-
-
-