httpsvc.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:46k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * httpsvc.cxx
  3.  *
  4.  * Classes for service applications using HTTP as the user interface.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: httpsvc.cxx,v $
  30.  * Revision 1.54  2000/05/02 02:58:49  robertj
  31.  * Fixed MSVC warning about unused parameters.
  32.  *
  33.  * Revision 1.53  2000/05/02 02:01:18  craigs
  34.  * Changed stricmp and added implementation of PServiceMacro::Translate
  35.  *
  36.  * Revision 1.52  2000/05/02 01:50:37  robertj
  37.  * Rewrite of PServiceMacro so does not use malloc (indirectly).
  38.  *
  39.  * Revision 1.51  2000/01/27 00:35:52  robertj
  40.  * Fixed benign warning about uninitialised variables in MSVC optimised compile.
  41.  *
  42.  * Revision 1.50  1999/08/07 06:50:52  robertj
  43.  * Removed silly (and incorrect) warning.
  44.  *
  45.  * Revision 1.49  1999/04/24 05:16:26  robertj
  46.  * Fixed incorrect date in copyright notice.
  47.  *
  48.  * Revision 1.48  1998/11/30 05:37:46  robertj
  49.  * New directory structure
  50.  *
  51.  * Revision 1.47  1998/11/24 23:05:14  robertj
  52.  * Fixed extra *** in demo message
  53.  *
  54.  * Revision 1.46  1998/11/16 07:23:15  robertj
  55.  * More PPC GNU compatibility.
  56.  *
  57.  * Revision 1.45  1998/11/16 06:50:40  robertj
  58.  * Fixed PPC GNU compiler compatibility.
  59.  *
  60.  * Revision 1.44  1998/10/31 12:49:25  robertj
  61.  * Added read/write mutex to the HTTP space variable to avoid thread crashes.
  62.  *
  63.  * Revision 1.43  1998/10/29 11:58:52  robertj
  64.  * Added ability to configure the HTTP threads stack size.
  65.  *
  66.  * Revision 1.42  1998/10/29 11:31:57  robertj
  67.  * Fixed default URL to have lower case and spaceless product name.
  68.  * Increased HTTP stack size.
  69.  *
  70.  * Revision 1.41  1998/10/15 01:53:35  robertj
  71.  * GNU compatibility.
  72.  *
  73.  * Revision 1.40  1998/10/13 14:06:24  robertj
  74.  * Complete rewrite of memory leak detection code.
  75.  *
  76.  * Revision 1.39  1998/09/23 06:22:15  robertj
  77.  * Added open source copyright license.
  78.  *
  79.  * Revision 1.38  1998/09/18 01:47:23  robertj
  80.  * Fixed bug that made files with signature on first line fail on unix systems.
  81.  *
  82.  * Revision 1.37  1998/08/20 06:01:02  robertj
  83.  * Improved internationalisation, registrationpage override.
  84.  *
  85.  * Revision 1.36  1998/04/21 02:43:40  robertj
  86.  * Fixed conditional around wrong way for requiring signature on HTML files.
  87.  *
  88.  * Revision 1.35  1998/04/01 01:55:41  robertj
  89.  * Fixed bug for automatically including GIF file in HTTP name space.
  90.  *
  91.  * Revision 1.34  1998/03/23 03:21:40  robertj
  92.  * Fixed missing invalid case in register page.
  93.  *
  94.  * Revision 1.33  1998/03/20 03:18:15  robertj
  95.  * Added special classes for specific sepahores, PMutex and PSyncPoint.
  96.  *
  97.  * Revision 1.32  1998/03/17 10:14:39  robertj
  98.  * Rewrite of registration page to allow for HTML file override.
  99.  *
  100.  * Revision 1.31  1998/03/09 07:17:48  robertj
  101.  * Added IP peer/local number macros.
  102.  * Set GetPageGraphic reference to GIF file to be at lop level directory.
  103.  *
  104.  * Revision 1.30  1998/02/16 00:14:09  robertj
  105.  * Added ProductName and BuildDate macros.
  106.  * Major rewrite of application info passed in PHTTPServiceProcess constructor.
  107.  *
  108.  * Revision 1.29  1998/02/03 06:22:45  robertj
  109.  * Allowed PHTTPServiceString to be overridden by html file after ';'.
  110.  *
  111.  * Revision 1.28  1998/01/26 02:49:19  robertj
  112.  * GNU support.
  113.  *
  114.  * Revision 1.27  1998/01/26 02:12:14  robertj
  115.  * GNU warnings.
  116.  *
  117.  * Revision 1.26  1998/01/26 00:45:44  robertj
  118.  * Added option flags to ProcessMacros to automatically load from file etc.
  119.  * Assured that all service HTTP resources are overidable with file, using ; URL field.
  120.  * Added a number of extra #equival macros.
  121.  * Added "Pty. Ltd." to company name.
  122.  *
  123.  * Revision 1.25  1997/11/10 12:40:05  robertj
  124.  * Changed SustituteEquivalSequence so can override standard macros.
  125.  *
  126.  * Revision 1.24  1997/11/04 06:02:46  robertj
  127.  * Allowed help gif file name to overridable in PServiceHTML, so can be in subdirectory.
  128.  *
  129.  * Revision 1.23  1997/10/30 10:21:26  robertj
  130.  * Added ability to customise regisration text by application.
  131.  *
  132.  * Revision 1.22  1997/08/28 14:19:40  robertj
  133.  * Fixed bug where HTTP directory was not processed for macros.
  134.  *
  135.  * Revision 1.20  1997/08/20 08:59:58  craigs
  136.  * Changed macro handling to commonise #equival sequence
  137.  *
  138.  * Revision 1.19  1997/07/26 11:38:22  robertj
  139.  * Support for overridable pages in HTTP service applications.
  140.  *
  141.  * Revision 1.18  1997/07/08 13:11:44  robertj
  142.  * Added standard header and copyright macros to service HTML.
  143.  *
  144.  * Revision 1.17  1997/06/16 13:20:15  robertj
  145.  * Fixed bug where PHTTPThread crashes on exit.
  146.  *
  147.  * Revision 1.16  1997/05/16 12:07:21  robertj
  148.  * Added operating system and version to hidden fields on registration form.
  149.  *
  150.  * Revision 1.15  1997/03/02 03:40:59  robertj
  151.  * Added error logging to standard HTTP Service HTTP Server.
  152.  *
  153.  * Revision 1.14  1997/02/05 11:54:54  robertj
  154.  * Added support for order form page overridiing.
  155.  *
  156.  * Revision 1.13  1997/01/28 11:45:19  robertj
  157.  * .
  158.  *
  159.  * Revision 1.13  1997/01/27 10:22:37  robertj
  160.  * Numerous changes to support OEM versions of products.
  161.  *
  162.  * Revision 1.12  1997/01/03 06:33:23  robertj
  163.  * Removed slash from operating system version string, so says Windows NT rather than Windows/NT
  164.  *
  165.  * Revision 1.11  1996/11/16 10:50:26  robertj
  166.  * ??
  167.  *
  168.  * Revision 1.10  1996/11/04 03:58:23  robertj
  169.  * Changed to accept separate copyright and manufacturer strings.
  170.  *
  171.  * Revision 1.8  1996/10/08 13:08:29  robertj
  172.  * Changed standard graphic to use PHTML class.
  173.  *
  174.  * Revision 1.7  1996/09/14 13:09:33  robertj
  175.  * Major upgrade:
  176.  *   rearranged sockets to help support IPX.
  177.  *   added indirect channel class and moved all protocols to descend from it,
  178.  *   separating the protocol from the low level byte transport.
  179.  *
  180.  * Revision 1.6  1996/08/25 09:39:00  robertj
  181.  * Prevented registration if no user etc entered.
  182.  *
  183.  * Revision 1.5  1996/08/19 13:39:55  robertj
  184.  * Fixed race condition in system restart logic.
  185.  *
  186.  * Revision 1.4  1996/08/08 13:36:39  robertj
  187.  * Fixed Registation page so no longer has static link, ie can be DLLed.
  188.  *
  189.  * Revision 1.3  1996/07/15 10:36:48  robertj
  190.  * Added registration info to bottom of order form so can be faxed to us.
  191.  *
  192.  * Revision 1.2  1996/06/28 13:21:30  robertj
  193.  * Fixed nesting problem in tables.
  194.  * Fixed PConfig page always restarting.
  195.  *
  196.  * Revision 1.1  1996/06/13 13:33:34  robertj
  197.  * Initial revision
  198.  *
  199.  */
  200. #ifdef __GNUC__
  201. #pragma implementation "httpsvc.h"
  202. #endif
  203. #include <ptlib.h>
  204. #include <ptclib/httpsvc.h>
  205. #include <ptlib/sockets.h>
  206. #define new PNEW
  207. #define HOME_PAGE  "http://www.equival.com"
  208. #define EMAIL      "equival@equival.com.au"
  209. #define EQUIVALENCE "Equivalence Pty. Ltd."
  210. PHTTPServiceProcess::PHTTPServiceProcess(const Info & inf)
  211.   : PServiceProcess(inf.manufacturerName, inf.productName,
  212.                     inf.majorVersion, inf.minorVersion, inf.buildStatus, inf.buildNumber),
  213.     productKey(inf.productKey),
  214.     securedKeys(inf.securedKeyCount, inf.securedKeys),
  215.     signatureKey(inf.signatureKey),
  216.     compilationDate(inf.compilationDate),
  217.     manufacturersHomePage(inf.manufHomePage != NULL ? inf.manufHomePage : HOME_PAGE),
  218.     manufacturersEmail(inf.email != NULL ? inf.email : EMAIL),
  219.     productNameHTML(inf.productHTML != NULL ? inf.productHTML : inf.productName)
  220. {
  221.   if (inf.gifHTML != NULL)
  222.     gifHTML = inf.gifHTML;
  223.   else {
  224.     gifHTML = psprintf("<img src="/%s" alt="%s!"", inf.gifFilename, inf.productName);
  225.     if (inf.gifWidth != 0 && inf.gifHeight != 0)
  226.       gifHTML += psprintf(" width=%i height=%i", inf.gifWidth, inf.gifHeight);
  227.     gifHTML += " align=absmiddle>";
  228.   }
  229.   if (inf.gifFilename != NULL)
  230.     httpNameSpace.AddResource(new PServiceHTTPFile(inf.gifFilename, GetFile().GetDirectory()+inf.gifFilename));
  231.   restartThread = NULL;
  232.   httpListeningSocket = NULL;
  233. }
  234. PHTTPServiceProcess::~PHTTPServiceProcess()
  235. {
  236.   ShutdownListener();
  237. }
  238. PHTTPServiceProcess & PHTTPServiceProcess::Current() 
  239. {
  240.   PHTTPServiceProcess & process = (PHTTPServiceProcess &)PProcess::Current();
  241.   PAssert(process.IsDescendant(PHTTPServiceProcess::Class()), "Not a HTTP service!");
  242.   return process;
  243. }
  244. BOOL PHTTPServiceProcess::ListenForHTTP(WORD port, PINDEX stackSize)
  245. {
  246.   if (httpListeningSocket != NULL &&
  247.       httpListeningSocket->GetPort() == port &&
  248.       httpListeningSocket->IsOpen())
  249.     return TRUE;
  250.   return ListenForHTTP(new PTCPSocket(port), stackSize);
  251. }
  252. BOOL PHTTPServiceProcess::ListenForHTTP(PSocket * listener, PINDEX stackSize)
  253. {
  254.   if (httpListeningSocket != NULL)
  255.     ShutdownListener();
  256.   httpListeningSocket = PAssertNULL(listener);
  257.   if (!httpListeningSocket->Listen())
  258.     return FALSE;
  259.   if (stackSize > 1000)
  260.     new PHTTPServiceThread(stackSize, *this, *httpListeningSocket, httpNameSpace);
  261.   return TRUE;
  262. }
  263. void PHTTPServiceProcess::ShutdownListener()
  264. {
  265.   if (httpListeningSocket == NULL)
  266.     return;
  267.   if (!httpListeningSocket->IsOpen())
  268.     return;
  269.   httpListeningSocket->Close();
  270.   httpThreadClosed.Wait();
  271.   delete httpListeningSocket;
  272.   httpListeningSocket = NULL;
  273. }
  274. PString PHTTPServiceProcess::GetCopyrightText()
  275. {
  276.   PHTML html(PHTML::InBody);
  277.   html << "Copyright &copy;"
  278.        << compilationDate.AsString("yyyy") << " by "
  279.        << PHTML::HotLink(HOME_PAGE)
  280.        << EQUIVALENCE
  281.        << PHTML::HotLink()
  282.        << ", "
  283.        << PHTML::HotLink("mailto:" EMAIL)
  284.        << EMAIL
  285.        << PHTML::HotLink();
  286.   return html;
  287. }
  288. PString PHTTPServiceProcess::GetPageGraphic()
  289. {
  290.   PHTML html(PHTML::InBody);
  291.   html << PHTML::TableStart()
  292.        << PHTML::TableRow()
  293.        << PHTML::TableData()
  294.        << gifHTML
  295.        << PHTML::TableData()
  296.        << GetOSClass() << ' ' << GetOSName()
  297.        << " Version " << GetVersion(TRUE)
  298.        << PHTML::BreakLine()
  299.        << "By "
  300.        << PHTML::HotLink(manufacturersHomePage) << GetManufacturer() << PHTML::HotLink()
  301.        << ", "
  302.        << PHTML::HotLink("mailto:" + manufacturersEmail) << manufacturersEmail << PHTML::HotLink()
  303.        << PHTML::TableEnd();
  304.   return html;
  305. }
  306. void PHTTPServiceProcess::GetPageHeader(PHTML & html)
  307. {
  308.   GetPageHeader(html, GetName());
  309. }
  310. void PHTTPServiceProcess::GetPageHeader(PHTML & html, const PString & title)
  311. {
  312.   html << PHTML::Title(title) 
  313.        << PHTML::Body()
  314.        << GetPageGraphic();
  315. }
  316. void PHTTPServiceProcess::BeginRestartSystem()
  317. {
  318.   if (restartThread == NULL) {
  319.     restartThread = PThread::Current();
  320.     OnConfigChanged();
  321.   }
  322. }
  323. void PHTTPServiceProcess::CompleteRestartSystem()
  324. {
  325.   if (restartThread == NULL)
  326.     return;
  327.   
  328.   if (restartThread != PThread::Current())
  329.     return;
  330.   httpNameSpace.StartWrite();
  331.   if (Initialise("RestarttInitialisation"))
  332.     restartThread = NULL;
  333.   httpNameSpace.EndWrite();
  334.   if (restartThread != NULL)
  335.     Terminate();
  336. }
  337. void PHTTPServiceProcess::AddRegisteredText(PHTML &)
  338. {
  339. }
  340. void PHTTPServiceProcess::AddUnregisteredText(PHTML &)
  341. {
  342. }
  343. BOOL PHTTPServiceProcess::SubstituteEquivalSequence(PHTTPRequest &, const PString &, PString &)
  344. {
  345.   return FALSE;
  346. }
  347. //////////////////////////////////////////////////////////////
  348. PHTTPServiceThread::PHTTPServiceThread(PINDEX stackSize,
  349.                                        PHTTPServiceProcess & app,
  350.                                        PSocket & listeningSocket,
  351.                                        PHTTPSpace & http)
  352.   : PThread(stackSize, AutoDeleteThread),
  353.     process(app),
  354.     listener(listeningSocket),
  355.     httpNameSpace(http)
  356. {
  357.   myStackSize = stackSize;
  358.   Resume();
  359. }
  360. void PHTTPServiceThread::Main()
  361. {
  362.   if (!listener.IsOpen()) {
  363.     process.httpThreadClosed.Signal();
  364.     return;
  365.   }
  366.   // get a socket when a client connects
  367.   PHTTPServer server(httpNameSpace);
  368.   if (!server.Accept(listener)) {
  369.     if (server.GetErrorCode() != PChannel::Interrupted)
  370.       PSYSTEMLOG(Error, "Accept failed for HTTP: " << server.GetErrorText());
  371.     if (listener.IsOpen())
  372.       new PHTTPServiceThread(myStackSize, process, listener, httpNameSpace);
  373.     else
  374.       process.httpThreadClosed.Signal();
  375.     return;
  376.   }
  377.   new PHTTPServiceThread(myStackSize, process, listener, httpNameSpace);
  378.   // process requests
  379.   while (server.ProcessCommand())
  380.     ;
  381.   // always close after the response has been sent
  382.   server.Close();
  383.   // if a restart was requested, then do it
  384.   process.CompleteRestartSystem();
  385. }
  386. //////////////////////////////////////////////////////////////
  387. PConfigPage::PConfigPage(PHTTPServiceProcess & app,
  388.                          const PString & title,
  389.                          const PString & section,
  390.                          const PHTTPAuthority & auth)
  391.   : PHTTPConfig(title, section, auth),
  392.     process(app)
  393. {
  394. }
  395. PConfigPage::PConfigPage(PHTTPServiceProcess & app,
  396.                          const PString & section,
  397.                          const PHTTPAuthority & auth)
  398.   : PHTTPConfig(section.ToLower() + ".html", section, auth),
  399.     process(app)
  400. {
  401. }
  402. void PConfigPage::OnLoadedText(PHTTPRequest & request, PString & text)
  403. {
  404.   PServiceHTML::ProcessMacros(request, text,
  405.                               baseURL.AsString(PURL::PathOnly).Mid(1),
  406.                               PServiceHTML::LoadFromFile);
  407.   PHTTPConfig::OnLoadedText(request, text);
  408.   PServiceHTML::ProcessMacros(request, text, "", PServiceHTML::NoOptions);
  409. }
  410. BOOL PConfigPage::OnPOST(PHTTPServer & server,
  411.                          const PURL & url,
  412.                          const PMIMEInfo & info,
  413.                          const PStringToString & data,
  414.                          const PHTTPConnectionInfo & connectInfo)
  415. {
  416.   PHTTPConfig::OnPOST(server, url, info, data, connectInfo);
  417.   return FALSE;    // Make sure we break any persistent connections
  418. }
  419. BOOL PConfigPage::Post(PHTTPRequest & request,
  420.                        const PStringToString & data,
  421.                        PHTML & reply)
  422. {
  423.   PServiceHTML::ProcessMacros(request, reply,
  424.                               baseURL.AsString(PURL::PathOnly).Mid(1),
  425.                               PServiceHTML::LoadFromFile);
  426.   PSYSTEMLOG(Debug3, "Post to " << request.url << 'n' << data);
  427.   BOOL retval = PHTTPConfig::Post(request, data, reply);
  428.   OnLoadedText(request, reply);
  429.   if (request.code == PHTTP::OK)
  430.     process.BeginRestartSystem();
  431.   return retval;
  432. }
  433. BOOL PConfigPage::GetExpirationDate(PTime & when)
  434. {
  435.   // Well and truly before now....
  436.   when = PTime(0, 0, 0, 1, 1, 1980);
  437.   return TRUE;
  438. }
  439. //////////////////////////////////////////////////////////////
  440. PConfigSectionsPage::PConfigSectionsPage(PHTTPServiceProcess & app,
  441.                                          const PURL & url,
  442.                                          const PHTTPAuthority & auth,
  443.                                          const PString & prefix,
  444.                                          const PString & valueName,
  445.                                          const PURL & editSection,
  446.                                          const PURL & newSection,
  447.                                          const PString & newTitle,
  448.                                          PHTML & heading)
  449.   : PHTTPConfigSectionList(url, auth, prefix, valueName,
  450.                            editSection, newSection, newTitle, heading),
  451.     process(app)
  452. {
  453. }
  454. void PConfigSectionsPage::OnLoadedText(PHTTPRequest & request, PString & text)
  455. {
  456.   PServiceHTML::ProcessMacros(request, text,
  457.                               baseURL.AsString(PURL::PathOnly).Mid(1),
  458.                               PServiceHTML::LoadFromFile);
  459.   PHTTPConfigSectionList::OnLoadedText(request, text);
  460. }
  461. BOOL PConfigSectionsPage::OnPOST(PHTTPServer & server,
  462.                                  const PURL & url,
  463.                                  const PMIMEInfo & info,
  464.                                  const PStringToString & data,
  465.                                  const PHTTPConnectionInfo & connectInfo)
  466. {
  467.   PHTTPConfigSectionList::OnPOST(server, url, info, data, connectInfo);
  468.   return FALSE;    // Make sure we break any persistent connections
  469. }
  470. BOOL PConfigSectionsPage::Post(PHTTPRequest & request,
  471.                                const PStringToString & data,
  472.                                PHTML & reply)
  473. {
  474.   BOOL retval = PHTTPConfigSectionList::Post(request, data, reply);
  475.   if (request.code == PHTTP::OK)
  476.     process.BeginRestartSystem();
  477.   return retval;
  478. }
  479. BOOL PConfigSectionsPage::GetExpirationDate(PTime & when)
  480. {
  481.   // Well and truly before now....
  482.   when = PTime(0, 0, 0, 1, 1, 1980);
  483.   return TRUE;
  484. }
  485. //////////////////////////////////////////////////////////////
  486. PRegisterPage::PRegisterPage(PHTTPServiceProcess & app,
  487.                              const PHTTPAuthority & auth)
  488.   : PConfigPage(app, "register.html", "Secured Options", auth),
  489.     process(app)
  490. {
  491. }
  492. PString PRegisterPage::LoadText(PHTTPRequest & request)
  493. {
  494.   if (fields.GetSize() > 0)
  495.     return PConfigPage::LoadText(request);
  496.   PString mailURL = "mailto:" + process.GetEMailAddress();
  497.   PString orderURL = mailURL;
  498.   PString tempURL = mailURL;
  499.   if (process.GetHomePage() == HOME_PAGE) {
  500.     orderURL = "https://home.equival.com.au/purchase.html";
  501.     tempURL = "http://www.equival.com/" + process.GetName().ToLower() + "/register.html";
  502.     tempURL.Replace(" ", "", TRUE);
  503.   }
  504.   PServiceHTML regPage(process.GetName() & "Registration", NULL);
  505.   regPage << "<!--#registration start Permanent-->"
  506.              "Your registration key is permanent.<p>"
  507.              "Do not change your registration details or your key will not "
  508.              "operate correctly.<p>"
  509.              "If you need to "
  510.           << PHTML::HotLink(orderURL)
  511.           << "upgrade"
  512.           << PHTML::HotLink()
  513.           << " or "
  514.           << PHTML::HotLink(mailURL)
  515.           << "change"
  516.           << PHTML::HotLink()
  517.           << " your registration, then you may enter the new values sent "
  518.           << " to you from "
  519.           << process.GetManufacturer()
  520.           << " into the fields "
  521.              "below, and then press the Accept button.<p>"
  522.           << PHTML::HRule()
  523.           << "<!--#registration end Permanent-->"
  524.              "<!--#registration start Temporary-->"
  525.              "Your registration key is temporary and will expire on "
  526.              "<!--#registration ExpiryDate-->.<p>"
  527.              "Do not change your registration details or your key will not "
  528.              "operate correctly.<p>"
  529.              "You may "
  530.           << PHTML::HotLink(orderURL)
  531.           << "order a permanent key"
  532.           << PHTML::HotLink()
  533.           << " and enter the new values sent to you from "
  534.           << process.GetManufacturer()
  535.           << " into the fields below, and then press the Accept button.<p>"
  536.           << PHTML::HRule()
  537.           << "<!--#registration end Temporary-->"
  538.              "<!--#registration start Expired-->"
  539.              "Your temporary registration key has expired.<p>"
  540.              "You may "
  541.           << PHTML::HotLink(orderURL)
  542.           << "order a permanent key"
  543.           << PHTML::HotLink()
  544.           << " and enter the new values sent to you from "
  545.           << process.GetManufacturer()
  546.           << " into the fields below, and then press the Accept button.<P>"
  547.           << PHTML::HRule()
  548.           << "<!--#registration end Expired-->";
  549.   PSecureConfig securedConf(process.GetProductKey(), process.GetSecuredKeys());
  550.   PString prefix;
  551.   if (securedConf.GetValidation() != PSecureConfig::IsValid) 
  552.     prefix = securedConf.GetPendingPrefix();
  553.   AddFields(prefix);
  554.   Add(new PHTTPStringField("Validation", 40));
  555.   BuildHTML(regPage, InsertIntoHTML);
  556.   regPage << "<!--#registration start Invalid-->"
  557.              "You have entered the values sent to you from "
  558.           << process.GetManufacturer()
  559.           << " incorrectly. Please enter them again. Note, "
  560.           << PHTML::Emphasis() << PHTML::Strong() << "all" << PHTML::Strong() << PHTML::Emphasis()
  561.           << "the fields must be entered "
  562.           << PHTML::Emphasis() << PHTML::Strong() << "exactly" << PHTML::Strong() << PHTML::Emphasis()
  563.           << " as they appear in the e-mail from "
  564.           << process.GetManufacturer()
  565.           << ". We strongly recommend using copy and paste of all the fields, and then "
  566.              "press the Accept button."
  567.              "<!--#registration end Invalid-->"
  568.              "<!--#registration start Default-->"
  569.              "You may "
  570.           << PHTML::HotLink(orderURL)
  571.           << "order a permanent key"
  572.           << PHTML::HotLink()
  573.           << " or "
  574.           << PHTML::HotLink(tempURL)
  575.           << "obtain a temporary key"
  576.           << PHTML::HotLink()
  577.           << " and enter the values sent to you from "
  578.           << process.GetManufacturer()
  579.           << " into the fields above, and then press the Accept button.<p>"
  580.              "<!--#registration end Default-->"
  581.           << PHTML::HRule()
  582.           << PHTML::Heading(3) << "Disclaimer" << PHTML::Heading(3)
  583.           << PHTML::Paragraph() << PHTML::Bold()
  584.           << "The information and code herein is provided "as is" "
  585.              "without warranty of any kind, either expressed or implied, "
  586.              "including but not limited to the implied warrenties of "
  587.              "merchantability and fitness for a particular purpose. In "
  588.              "no event shall " << process.GetManufacturer() << " be liable "
  589.              "for any damages whatsoever including direct, indirect, "
  590.              "incidental, consequential, loss of business profits or special "
  591.              "damages, even if " << process.GetManufacturer() << " has been "
  592.              "advised of the possibility of such damages."
  593.           << PHTML::Bold() << PHTML::Paragraph()
  594.           << process.GetCopyrightText()
  595.           << PHTML::Body();
  596.   SetString(regPage);
  597.   return PConfigPage::LoadText(request);
  598. }
  599. static BOOL FindSpliceBlock(const PRegularExpression & regex,
  600.                             const PString & text,
  601.                             PINDEX & pos,
  602.                             PINDEX & len,
  603.                             PINDEX & start,
  604.                             PINDEX & finish)
  605. {
  606.   if (!text.FindRegEx(regex, pos, len, 0))
  607.     return FALSE;
  608.   PINDEX endpos, endlen;
  609.   static PRegularExpression EndBlock("<?!--#registration[ tn]*end[ tn]*[a-z]*[ tn]*-->?",
  610.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  611.   if (text.FindRegEx(EndBlock, endpos, endlen, pos)) {
  612.     start = pos+len;
  613.     finish = endpos-1;
  614.     len = endpos - pos + endlen;
  615.   }
  616.   return TRUE;
  617. }
  618. void PRegisterPage::OnLoadedText(PHTTPRequest & request, PString & text)
  619. {
  620.   PString block;
  621.   PINDEX pos, len, start = 0, finish = 0;
  622.   PSecureConfig securedConf(process.GetProductKey(), process.GetSecuredKeys());
  623.   PTime expiry = securedConf.GetTime(securedConf.GetExpiryDateKey());
  624.   static PRegularExpression Default("<?!--#registration[ tn]*start[ tn]*Default[ tn]*-->?",
  625.                                     PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  626.   static PRegularExpression Permanent("<?!--#registration[ tn]*start[ tn]*Permanent[ tn]*-->?",
  627.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  628.   static PRegularExpression Temporary("<?!--#registration[ tn]*start[ tn]*Temporary[ tn]*-->?",
  629.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  630.   static PRegularExpression Expired("<?!--#registration[ tn]*start[ tn]*Expired[ tn]*-->?",
  631.                                     PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  632.   static PRegularExpression Invalid("<?!--#registration[ tn]*start[ tn]*Invalid[ tn]*-->?",
  633.                                     PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  634.   static PRegularExpression Pending("name[ tn]*=[ tn]*"" +
  635.                                     securedConf.GetPendingPrefix() +
  636.                                     "[^"]+"",
  637.                                     PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  638.   PServiceHTML::ProcessMacros(request, text,
  639.                               baseURL.AsString(PURL::PathOnly).Mid(1),
  640.                               PServiceHTML::LoadFromFile);
  641.   switch (securedConf.GetValidation()) {
  642.     case PSecureConfig::Defaults :
  643.       while (FindSpliceBlock(Default, text, pos, len, start, finish))
  644.         text.Splice(text(start, finish), pos, len);
  645.       while (FindSpliceBlock(Permanent, text, pos, len, start, finish))
  646.         text.Delete(pos, len);
  647.       while (FindSpliceBlock(Temporary, text, pos, len, start, finish))
  648.         text.Delete(pos, len);
  649.       while (FindSpliceBlock(Expired, text, pos, len, start, finish))
  650.         text.Delete(pos, len);
  651.       while (FindSpliceBlock(Invalid, text, pos, len, start, finish))
  652.         text.Delete(pos, len);
  653.       break;
  654.     case PSecureConfig::Invalid :
  655.     case PSecureConfig::Pending :
  656.       while (FindSpliceBlock(Default, text, pos, len, start, finish))
  657.         text.Delete(pos, len);
  658.       while (FindSpliceBlock(Permanent, text, pos, len, start, finish))
  659.         text.Delete(pos, len);
  660.       while (FindSpliceBlock(Temporary, text, pos, len, start, finish))
  661.         text.Delete(pos, len);
  662.       while (FindSpliceBlock(Expired, text, pos, len, start, finish))
  663.         text.Delete(pos, len);
  664.       while (FindSpliceBlock(Invalid, text, pos, len, start, finish))
  665.         text.Splice(text(start, finish), pos, len);
  666.       break;
  667.     case PSecureConfig::Expired :
  668.       while (FindSpliceBlock(Default, text, pos, len, start, finish))
  669.         text.Delete(pos, len);
  670.       while (FindSpliceBlock(Permanent, text, pos, len, start, finish))
  671.         text.Delete(pos, len);
  672.       while (FindSpliceBlock(Temporary, text, pos, len, start, finish))
  673.         text.Delete(pos, len);
  674.       while (FindSpliceBlock(Expired, text, pos, len, start, finish))
  675.         text.Splice(text(start, finish), pos, len);
  676.       while (FindSpliceBlock(Invalid, text, pos, len, start, finish))
  677.         text.Delete(pos, len);
  678.       break;
  679.     case PSecureConfig::IsValid :
  680.       while (text.FindRegEx(Pending, pos, len)) {
  681.         static PINDEX pendingLength = securedConf.GetPendingPrefix().GetLength();
  682.         text.Delete(text.Find('"', pos)+1, pendingLength);
  683.         start = pos + len - pendingLength;
  684.       }
  685.       if (expiry.GetYear() < 2011) {
  686.         while (FindSpliceBlock(Default, text, pos, len, start, finish))
  687.           text.Delete(pos, len);
  688.         while (FindSpliceBlock(Permanent, text, pos, len, start, finish))
  689.           text.Delete(pos, len);
  690.         while (FindSpliceBlock(Temporary, text, pos, len, start, finish))
  691.           text.Splice(text(start, finish), pos, len);
  692.         while (FindSpliceBlock(Expired, text, pos, len, start, finish))
  693.           text.Delete(pos, len);
  694.         while (FindSpliceBlock(Invalid, text, pos, len, start, finish))
  695.           text.Delete(pos, len);
  696.       }
  697.       else {
  698.         while (FindSpliceBlock(Default, text, pos, len, start, finish))
  699.           text.Delete(pos, len);
  700.         while (FindSpliceBlock(Permanent, text, pos, len, start, finish))
  701.           text.Splice(text(start, finish), pos, len);
  702.         while (FindSpliceBlock(Temporary, text, pos, len, start, finish))
  703.           text.Delete(pos, len);
  704.         while (FindSpliceBlock(Expired, text, pos, len, start, finish))
  705.           text.Delete(pos, len);
  706.         while (FindSpliceBlock(Invalid, text, pos, len, start, finish))
  707.           text.Delete(pos, len);
  708.       }
  709.   }
  710.   static PRegularExpression ExpiryDate("<?!--#registration[ tn]*ExpiryDate[ tn]*-->?",
  711.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  712.   while (text.FindRegEx(ExpiryDate, pos, len, 0))
  713.     text.Splice(expiry.AsString(PTime::LongDate), pos, len);
  714.   PHTTPConfig::OnLoadedText(request, text);
  715.   PServiceHTML::ProcessMacros(request, text, "", PServiceHTML::NoOptions);
  716. }
  717. BOOL PRegisterPage::Post(PHTTPRequest & request,
  718.                          const PStringToString & data,
  719.                          PHTML & reply)
  720. {
  721.   if (fields.GetSize() == 0)
  722.     LoadText(request);
  723.   BOOL retval = PHTTPConfig::Post(request, data, reply);
  724.   if (request.code != PHTTP::OK)
  725.     return FALSE;
  726.   PSecureConfig sconf(process.GetProductKey(), process.GetSecuredKeys());
  727.   switch (sconf.GetValidation()) {
  728.     case PSecureConfig::Defaults :
  729.       sconf.ResetPending();
  730.       break;
  731.     case PSecureConfig::IsValid :
  732.       break;
  733.     case PSecureConfig::Pending :
  734.       sconf.ValidatePending();
  735.       break;
  736.     default :
  737.       sconf.ResetPending();
  738.   }
  739.   RemoveAllFields();
  740.   LoadText(request);
  741.   OnLoadedText(request, reply);
  742.   return retval;
  743. }
  744. ///////////////////////////////////////////////////////////////////
  745. static void DigestSecuredKeys(PHTTPServiceProcess & process,
  746.                               PString & reginfo,
  747.                               PHTML * html)
  748. {
  749.   const PStringArray & securedKeys = process.GetSecuredKeys();
  750.   PSecureConfig sconf(process.GetProductKey(), securedKeys);
  751.   PString prefix;
  752.   if (sconf.GetValidation() != PSecureConfig::IsValid) 
  753.     prefix = sconf.GetPendingPrefix();
  754.   PMessageDigest5 digestor;
  755.   PStringStream info;
  756.   info << '"' << process.GetName() << "" ===";
  757.   PINDEX i;
  758.   for (i = 0; i < securedKeys.GetSize(); i++) {
  759.     PString val = sconf.GetString(prefix + securedKeys[i]).Trim();
  760.     info << " "" << val << '"';
  761.     if (html != NULL)
  762.       *html << PHTML::HiddenField(securedKeys[i], val);
  763.     digestor.Process(val);
  764.   }
  765.   PString digest = digestor.Complete();
  766.   if (html != NULL)
  767.     *html << PHTML::HiddenField("digest", digest);
  768.   info.Replace("===", digest);
  769.   reginfo = info;
  770. }
  771. ///////////////////////////////////////////////////////////////////
  772. PServiceHTML::PServiceHTML(const char * title, const char * help, const char * helpGif)
  773. {
  774.   PHTTPServiceProcess::Current().GetPageHeader(*this, title);
  775.   *this << PHTML::Heading(1) << title;
  776.   
  777.   if (help != NULL)
  778.     *this << "&nbsp;"
  779.           << PHTML::HotLink(help)
  780.           << PHTML::Image(helpGif, "Help", 48, 23, "align=absmiddle")
  781.           << PHTML::HotLink();
  782.   *this << PHTML::Heading(1) << PHTML::Paragraph();
  783. }
  784. PString PServiceHTML::ExtractSignature(PString & out)
  785. {
  786.   return ExtractSignature(*this, out);
  787. }
  788. PString PServiceHTML::ExtractSignature(const PString & html,
  789.                                        PString & out,
  790.                                        const char * keyword)
  791. {
  792.   PString signature;
  793.   out = PString();
  794.   // search for all comment blocks
  795.   PINDEX  lastPos = 0, endPos = 0;
  796.   PINDEX  pos;
  797.   while ((pos    = html.Find("<!--", lastPos)) != P_MAX_INDEX &&
  798.          (endPos = html.Find("-->", pos))      != P_MAX_INDEX) {
  799.     // add in the text before the comment and move the ptr to the end of
  800.     // the comment
  801.     if (pos > lastPos)
  802.       out += html(lastPos, pos-1);
  803.     lastPos = endPos+3;
  804.     // tokenise the text inside the comment
  805.     PStringArray tokens = html(pos+4, endPos-1).Trim().Tokenise(" n", FALSE);
  806.     // if this is a signature, then retreive it
  807.     if (tokens[0] *= keyword) {
  808.       PINDEX len = tokens.GetSize();
  809.       if (tokens[1] != "signature" || len != 3)
  810.         out += html(pos, endPos+2);
  811.       else
  812.         signature = tokens[2];
  813.     }
  814.   }
  815.   out += html(lastPos, P_MAX_INDEX);
  816.   return signature;
  817. }
  818. PString PServiceHTML::CalculateSignature()
  819. {
  820.   return CalculateSignature(*this);
  821. }
  822. PString PServiceHTML::CalculateSignature(const PString & out)
  823. {
  824.   return CalculateSignature(out, PHTTPServiceProcess::Current().GetSignatureKey());
  825. }
  826. PString PServiceHTML::CalculateSignature(const PString & out,
  827.                                          const PTEACypher::Key & sig)
  828. {
  829.   // calculate the MD5 digest of the HTML data
  830.   PMessageDigest5 digestor;
  831.   PINDEX p1 = 0;
  832.   PINDEX p2;
  833.   while ((p2 = out.FindOneOf("rn", p1)) != P_MAX_INDEX) {
  834.     if (p2 > p1)
  835.       digestor.Process(out(p1, p2-1));
  836.     digestor.Process("rn", 2);
  837.     p1 = p2 + 1;
  838.     if (out[p2] == 'r' && out[p1] == 'n') // CR LF pair
  839.       p1++;
  840.   }
  841.   digestor.Process(out(p1, P_MAX_INDEX));
  842.   PMessageDigest5::Code md5;
  843.   digestor.Complete(md5);
  844.   // encode it
  845.   PTEACypher cypher(sig);
  846.   return cypher.Encode(&md5, sizeof(md5));
  847. }
  848. BOOL PServiceHTML::CheckSignature()
  849. {
  850.   return CheckSignature(*this);
  851. }
  852. BOOL PServiceHTML::CheckSignature(const PString & html)
  853. {
  854.   // extract the signature from the file
  855.   PString out;
  856.   PString signature = ExtractSignature(html, out);
  857.   // calculate the signature on the data
  858.   PString checkSignature = CalculateSignature(out);
  859.   // return TRUE or FALSE
  860.   return checkSignature == signature;
  861. }
  862. static BOOL FindBrackets(const PString & args, PINDEX & open, PINDEX & close)
  863. {
  864.   open = args.FindOneOf("[{(", close);
  865.   if (open == P_MAX_INDEX)
  866.     return FALSE;
  867.   switch (args[open]) {
  868.     case '[' :
  869.       close = args.Find(']', open+1);
  870.       break;
  871.     case '{' :
  872.       close = args.Find('}', open+1);
  873.       break;
  874.     case '(' :
  875.       close = args.Find(')', open+1);
  876.       break;
  877.   }
  878.   return close != P_MAX_INDEX;
  879. }
  880. static BOOL ExtractVariables(const PString & args,
  881.                              PString & variable,
  882.                              PString & value)
  883. {
  884.   PINDEX open;
  885.   PINDEX close = 0;
  886.   if (FindBrackets(args, open, close))
  887.     variable = args(open+1, close-1);
  888.   else {
  889.     variable = args.Trim();
  890.     close = P_MAX_INDEX-1;
  891.   }
  892.   if (variable.IsEmpty())
  893.     return FALSE;
  894.   if (FindBrackets(args, open, close))
  895.     value = args(open+1, close-1);
  896.   return TRUE;
  897. }
  898. ///////////////////////////////////////////////////////////////////////////////
  899. #undef new
  900. class PServiceMacro : public PObject
  901. {
  902.   public:
  903.     PServiceMacro(const char * name);
  904.     PServiceMacro(const PCaselessString & name);
  905.     Comparison Compare(const PObject & obj) const;
  906.     virtual PString Translate(PHTTPRequest & request, const PString & args) const;
  907.   protected:
  908.     const char * macroName;
  909.     PServiceMacro * link;
  910.     static PServiceMacro * list;
  911.   friend class PServiceMacros_list;
  912. };
  913. PServiceMacro * PServiceMacro::list;
  914. PServiceMacro::PServiceMacro(const char * name)
  915. {
  916.   macroName = name;
  917.   link = list;
  918.   list = this;
  919. }
  920. PServiceMacro::PServiceMacro(const PCaselessString & name)
  921. {
  922.   macroName = name;
  923. }
  924. PObject::Comparison PServiceMacro::Compare(const PObject & obj) const
  925. {
  926.   PAssert(obj.IsDescendant(PServiceMacro::Class()), PInvalidCast);
  927.   return (Comparison)strcasecmp(macroName, ((const PServiceMacro &)obj).macroName);
  928. }
  929. PString PServiceMacro::Translate(PHTTPRequest &, const PString &) const
  930. {
  931.   return PString();
  932. };
  933. PSORTED_LIST(PServiceMacros_base, PServiceMacro);
  934. class PServiceMacros_list : public PServiceMacros_base
  935. {
  936.   public:
  937.     PServiceMacros_list();
  938. };
  939. PServiceMacros_list::PServiceMacros_list()
  940. {
  941.   DisallowDeleteObjects();
  942.   PServiceMacro * macro = PServiceMacro::list;
  943.   while (macro != NULL) {
  944.     Append(macro);
  945.     macro = macro->link;
  946.   }
  947. }
  948. #define EMPTY
  949. #define CREATE_MACRO(name, request, args) 
  950.   class PServiceMacro_##name : public PServiceMacro { 
  951.     public: 
  952.       PServiceMacro_##name() : PServiceMacro(#name) { } 
  953.       PString Translate(PHTTPRequest & request, const PString & args) const; 
  954.   }; 
  955.   static const PServiceMacro_##name serviceMacro_##name; 
  956.   PString PServiceMacro_##name::Translate(PHTTPRequest & request, const PString & args) const
  957. CREATE_MACRO(Header,request,EMPTY)
  958. {
  959.   PString hdr = PHTTPServiceProcess::Current().GetPageGraphic();
  960.   PServiceHTML::ProcessMacros(request, hdr, "header.html",
  961.                 PServiceHTML::LoadFromFile|PServiceHTML::NoURLOverride);
  962.   return hdr;
  963. }
  964. CREATE_MACRO(Copyright,EMPTY,EMPTY)
  965. {
  966.   return PHTTPServiceProcess::Current().GetCopyrightText();
  967. }
  968. CREATE_MACRO(ProductName,EMPTY,EMPTY)
  969. {
  970.   return PHTTPServiceProcess::Current().GetProductName();
  971. }
  972. CREATE_MACRO(Manufacturer,EMPTY,EMPTY)
  973. {
  974.   return PHTTPServiceProcess::Current().GetManufacturer();
  975. }
  976. CREATE_MACRO(Version,EMPTY,EMPTY)
  977. {
  978.   return PHTTPServiceProcess::Current().GetVersion(TRUE);
  979. }
  980. CREATE_MACRO(BuildDate,EMPTY,args)
  981. {
  982.   const PTime & date = PHTTPServiceProcess::Current().GetCompilationDate();
  983.   if (args.IsEmpty())
  984.     return date.AsString("d MMMM yyyy");
  985.   return date.AsString(args);
  986. }
  987. CREATE_MACRO(OS,EMPTY,EMPTY)
  988. {
  989.   return PHTTPServiceProcess::Current().GetOSClass() &
  990.          PHTTPServiceProcess::Current().GetOSName();
  991. }
  992. CREATE_MACRO(LongDateTime,EMPTY,EMPTY)
  993. {
  994.   return PTime().AsString(PTime::LongDateTime);
  995. }
  996. CREATE_MACRO(LongDate,EMPTY,EMPTY)
  997. {
  998.   return PTime().AsString(PTime::LongDate);
  999. }
  1000. CREATE_MACRO(LongTime,EMPTY,EMPTY)
  1001. {
  1002.   return PTime().AsString(PTime::LongTime);
  1003. }
  1004. CREATE_MACRO(MediumDateTime,EMPTY,EMPTY)
  1005. {
  1006.   return PTime().AsString(PTime::MediumDateTime);
  1007. }
  1008. CREATE_MACRO(MediumDate,EMPTY,EMPTY)
  1009. {
  1010.   return PTime().AsString(PTime::MediumDate);
  1011. }
  1012. CREATE_MACRO(ShortDateTime,EMPTY,EMPTY)
  1013. {
  1014.   return PTime().AsString(PTime::ShortDateTime);
  1015. }
  1016. CREATE_MACRO(ShortDate,EMPTY,EMPTY)
  1017. {
  1018.   return PTime().AsString(PTime::ShortDate);
  1019. }
  1020. CREATE_MACRO(ShortTime,EMPTY,EMPTY)
  1021. {
  1022.   return PTime().AsString(PTime::ShortTime);
  1023. }
  1024. CREATE_MACRO(Time,EMPTY,args)
  1025. {
  1026.   PTime now;
  1027.   if (args.IsEmpty())
  1028.     return now.AsString();
  1029.   return now.AsString(args);
  1030. }
  1031. CREATE_MACRO(LocalHost,request,EMPTY)
  1032. {
  1033.   if (request.localAddr != 0)
  1034.     return PIPSocket::GetHostName(request.localAddr);
  1035.   else
  1036.     return PIPSocket::GetHostName();
  1037. }
  1038. CREATE_MACRO(LocalIP,request,EMPTY)
  1039. {
  1040.   if (request.localAddr != 0)
  1041.     return request.localAddr;
  1042.   else
  1043.     return "127.0.0.1";
  1044. }
  1045. CREATE_MACRO(LocalPort,request,EMPTY)
  1046. {
  1047.   if (request.localPort != 0)
  1048.     return psprintf("%u", request.localPort);
  1049.   else
  1050.     return "80";
  1051. }
  1052. CREATE_MACRO(PeerHost,request,EMPTY)
  1053. {
  1054.   if (request.origin != 0)
  1055.     return PIPSocket::GetHostName(request.origin);
  1056.   else
  1057.     return "N/A";
  1058. }
  1059. CREATE_MACRO(PeerIP,request,EMPTY)
  1060. {
  1061.   if (request.origin != 0)
  1062.     return request.origin;
  1063.   else
  1064.     return "N/A";
  1065. }
  1066. CREATE_MACRO(RegInfo,EMPTY,EMPTY)
  1067. {
  1068.   PString subs;
  1069.   DigestSecuredKeys(PHTTPServiceProcess::Current(), subs, NULL);
  1070.   return subs;
  1071. }
  1072. static PString GetRegInfo(const char * info)
  1073. {
  1074.   PHTTPServiceProcess & process = PHTTPServiceProcess::Current();
  1075.   PSecureConfig sconf(process.GetProductKey(), process.GetSecuredKeys());
  1076.   PString pending = sconf.GetPendingPrefix();
  1077.   return sconf.GetString(info, sconf.GetString(pending+info));
  1078. }
  1079. CREATE_MACRO(RegUser,EMPTY,EMPTY)
  1080. {
  1081.   return GetRegInfo("Name");
  1082. }
  1083. CREATE_MACRO(RegCompany,EMPTY,EMPTY)
  1084. {
  1085.   return GetRegInfo("Company");
  1086. }
  1087. CREATE_MACRO(RegEmail,EMPTY,EMPTY)
  1088. {
  1089.   return GetRegInfo("EMail");
  1090. }
  1091. CREATE_MACRO(Registration,EMPTY,args)
  1092. {
  1093.   PHTTPServiceProcess & process = PHTTPServiceProcess::Current();
  1094.   PSecureConfig sconf(process.GetProductKey(), process.GetSecuredKeys());
  1095.   PString pending = sconf.GetPendingPrefix();
  1096.   PString regNow = "Register Now!";
  1097.   PString viewReg = "View Registration";
  1098.   PString demoCopy = "Unregistered Demonstration Copy";
  1099.   PINDEX open;
  1100.   PINDEX close = 0;
  1101.   if (FindBrackets(args, open, close)) {
  1102.     regNow = args(open+1, close-1);
  1103.     if (FindBrackets(args, open, close)) {
  1104.       viewReg = args(open+1, close-1);
  1105.       if (FindBrackets(args, open, close))
  1106.         demoCopy = args(open+1, close-1);
  1107.     }
  1108.   }
  1109.   PHTML out(PHTML::InBody);
  1110.   out << "<font size=5>"
  1111.       << sconf.GetString("Name", sconf.GetString(pending+"Name", "*** "+demoCopy+" ***"))
  1112.       << PHTML::BreakLine()
  1113.       << "<font size=4>"
  1114.       << sconf.GetString("Company", sconf.GetString(pending+"Company"))
  1115.       << PHTML::BreakLine()
  1116.       << PHTML::BreakLine()
  1117.       << "<font size=3>";
  1118.   if (sconf.GetString("Name").IsEmpty())
  1119.     process.AddUnregisteredText(out);
  1120.   else
  1121.     process.AddRegisteredText(out);
  1122.   out << PHTML::HotLink("/register.html")
  1123.       << (sconf.GetString("Name").IsEmpty() ? regNow : viewReg)
  1124.       << PHTML::HotLink();
  1125.   return out;
  1126. }
  1127. CREATE_MACRO(InputsFromQuery,request,EMPTY)
  1128. {
  1129.   PStringToString vars = request.url.GetQueryVars();
  1130.   PStringStream subs;
  1131.   for (PINDEX i = 0; i < vars.GetSize(); i++)
  1132.     subs << "<INPUT TYPE=hidden NAME="" << vars.GetKeyAt(i)
  1133.          << "" VALUE="" << vars.GetDataAt(i) << "">rn";
  1134.   return subs;
  1135. }
  1136. CREATE_MACRO(Query,request,args)
  1137. {
  1138.   if (args.IsEmpty())
  1139.     return request.url.GetQuery();
  1140.   PString variable, value;
  1141.   if (ExtractVariables(args, variable, value)) {
  1142.     value = request.url.GetQueryVars()(variable, value);
  1143.     if (!value)
  1144.       return value;
  1145.   }
  1146.   return PString();
  1147. }
  1148. CREATE_MACRO(Get,request,args)
  1149. {
  1150.   PString variable, value;
  1151.   if (ExtractVariables(args, variable, value)) {
  1152.     PString section = request.url.GetQueryVars()("section");
  1153.     PINDEX slash = variable.FindLast('\');
  1154.     if (slash != P_MAX_INDEX) {
  1155.       section += variable.Left(slash);
  1156.       variable = variable.Mid(slash+1);
  1157.     }
  1158.     if (!section && !variable) {
  1159.       PConfig config(section);
  1160.       return config.GetString(variable, value);
  1161.     }
  1162.   }
  1163.   return PString();
  1164. }
  1165. CREATE_MACRO(URL,request,EMPTY)
  1166. {
  1167.   return request.url.AsString();
  1168. }
  1169. BOOL PServiceHTML::ProcessMacros(PHTTPRequest & request,
  1170.                                  PString & text,
  1171.                                  const PString & defaultFile,
  1172.                                  unsigned options)
  1173. {
  1174.   PINDEX alreadyLoadedPrefixLength = 0;
  1175.   PString filename = defaultFile;
  1176.   if ((options&LoadFromFile) != 0) {
  1177.     if ((options&NoURLOverride) == 0) {
  1178.       filename = request.url.GetParameters();
  1179.       if (filename.IsEmpty())
  1180.         filename = defaultFile;
  1181.     }
  1182.     if (!filename) {
  1183.       PString alreadyLoaded = "<!--#loadedfrom " + filename + "-->rn";
  1184.       alreadyLoadedPrefixLength = alreadyLoaded.GetLength();
  1185.       if (text.Find(alreadyLoaded) != 0) {
  1186.         PFile file;
  1187.         if (file.Open(filename, PFile::ReadOnly)) {
  1188.           text = alreadyLoaded + file.ReadString(file.GetLength());
  1189.           if ((options&NoSignatureForFile) == 0)
  1190.             options |= NeedSignature;
  1191.         }
  1192.       }
  1193.     }
  1194.   }
  1195.   if ((options&NeedSignature) != 0) {
  1196.     if (!CheckSignature(text.Mid(alreadyLoadedPrefixLength))) {
  1197.       PHTTPServiceProcess & process = PHTTPServiceProcess::Current();
  1198.       PHTML html("Invalid OEM Signature");
  1199.       html << "The HTML file ""
  1200.            << filename
  1201.            << "" contains an invalid signature for ""
  1202.            << process.GetName()
  1203.            << "" by ""
  1204.            << process.GetManufacturer()
  1205.            << '"'
  1206.            << PHTML::Body();
  1207.       text = html;
  1208.       return FALSE;
  1209.     }
  1210.   }
  1211.   PINDEX pos = 0;
  1212.   for (;;) {
  1213.     pos = text.Find("!--#equival", pos);
  1214.     if (pos == P_MAX_INDEX)
  1215.       break;
  1216.     PINDEX end = text.Find("--", pos+3);
  1217.     if (end == P_MAX_INDEX)
  1218.       break;
  1219.     PString include = text(pos+12, end-1).Trim();
  1220.     if (text[pos-1] == '<')
  1221.       pos--;
  1222.     end += 2;
  1223.     if (text[end] == '>')
  1224.       end++;
  1225.     PString subs;
  1226.     if (!PHTTPServiceProcess::Current().SubstituteEquivalSequence(request, include, subs)) {
  1227.       PCaselessString cmd = include.Left(include.Find(' '));
  1228.       static PServiceMacros_list ServiceMacros;
  1229.       PINDEX idx = ServiceMacros.GetValuesIndex(PServiceMacro(cmd));
  1230.       if (idx != P_MAX_INDEX)
  1231.         subs = ServiceMacros[idx].Translate(request, include.Mid(cmd.GetLength()).LeftTrim());
  1232.     }
  1233.     text.Splice(subs, pos, end-pos);
  1234.   }
  1235.   return TRUE;
  1236. }
  1237. ///////////////////////////////////////////////////////////////////
  1238. static void ServiceOnLoadedText(PString & text)
  1239. {
  1240.   PHTTPServiceProcess & process = PHTTPServiceProcess::Current();
  1241.   PString manuf = "<!--Standard_" + process.GetManufacturer() + "_Header-->";
  1242.   if (text.Find(manuf) != P_MAX_INDEX)
  1243.     text.Replace(manuf, process.GetPageGraphic(), TRUE);
  1244.   static const char equiv[] = "<!--Standard_Equivalence_Header-->";
  1245.   if (text.Find(equiv) != P_MAX_INDEX)
  1246.     text.Replace(equiv, process.GetPageGraphic(), TRUE);
  1247.   static const char copy[] = "<!--Standard_Copyright_Header-->";
  1248.   if (text.Find(copy) != P_MAX_INDEX)
  1249.     text.Replace(copy, process.GetCopyrightText(), TRUE);
  1250. }
  1251. PString PServiceHTTPString::LoadText(PHTTPRequest & request)
  1252. {
  1253.   PString text = PHTTPString::LoadText(request);
  1254.   ServiceOnLoadedText(text);
  1255.   PServiceHTML::ProcessMacros(request, text, "", PServiceHTML::LoadFromFile);
  1256.   return text;
  1257. }
  1258. void PServiceHTTPFile::OnLoadedText(PHTTPRequest & request, PString & text)
  1259. {
  1260.   ServiceOnLoadedText(text);
  1261.   PServiceHTML::ProcessMacros(request, text, baseURL.AsString(PURL::PathOnly),
  1262.           needSignature ? PServiceHTML::NeedSignature : PServiceHTML::NoOptions);
  1263. }
  1264. void PServiceHTTPDirectory::OnLoadedText(PHTTPRequest & request, PString & text)
  1265. {
  1266.   ServiceOnLoadedText(text);
  1267.   PServiceHTML::ProcessMacros(request, text, baseURL.AsString(PURL::PathOnly),
  1268.           needSignature ? PServiceHTML::NeedSignature : PServiceHTML::NoOptions);
  1269. }
  1270. ///////////////////////////////////////////////////////////////////