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

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * httpform.cxx
  3.  *
  4.  * Forms using HTTP 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: httpform.cxx,v $
  30.  * Revision 1.31  2000/06/19 11:35:01  robertj
  31.  * Fixed bug in setting current value of options in select form fields.
  32.  *
  33.  * Revision 1.30  1999/02/10 13:19:45  robertj
  34.  * Fixed PConfig update problem when POSTing to the form. Especiall with arrays.
  35.  *
  36.  * Revision 1.29  1998/11/30 04:51:57  robertj
  37.  * New directory structure
  38.  *
  39.  * Revision 1.28  1998/11/14 11:11:06  robertj
  40.  * PPC GNU compiler compatibility.
  41.  *
  42.  * Revision 1.27  1998/10/01 09:05:11  robertj
  43.  * Fixed bug in nested composite field names, array indexes not being set correctly.
  44.  *
  45.  * Revision 1.26  1998/09/23 06:22:11  robertj
  46.  * Added open source copyright license.
  47.  *
  48.  * Revision 1.25  1998/08/20 05:51:06  robertj
  49.  * Fixed bug where substitutions did not always occur if near end of macro block.
  50.  * Improved internationalisation. Allow HTML override of strings in macros.
  51.  *
  52.  * Revision 1.24  1998/08/09 11:25:51  robertj
  53.  * GNU C++ warning removal.
  54.  *
  55.  * Revision 1.23  1998/08/09 10:35:11  robertj
  56.  * Changed array control so can have language override.
  57.  *
  58.  * Revision 1.22  1998/07/24 06:56:05  robertj
  59.  * Fixed case significance problem in HTTP forms.
  60.  * Improved detection of VALUE= fields with and without quotes.
  61.  *
  62.  * Revision 1.21  1998/03/20 03:16:43  robertj
  63.  * Fixed bug in beaing able to reset a check box field.
  64.  *
  65.  * Revision 1.20  1998/02/03 06:26:09  robertj
  66.  * Fixed propagation of inital values in arrays subfields.
  67.  * Fixed problem where hidden fields were being relaced with default values from PHTTPForm.
  68.  *
  69.  * Revision 1.19  1998/01/26 02:49:17  robertj
  70.  * GNU support.
  71.  *
  72.  * Revision 1.18  1998/01/26 01:51:37  robertj
  73.  * Fixed uninitialised variable.
  74.  *
  75.  * Revision 1.17  1998/01/26 00:25:25  robertj
  76.  * Major rewrite of HTTP forms management.
  77.  *
  78.  * Revision 1.16  1997/12/18 05:06:51  robertj
  79.  * Added missing braces to kill GNU compiler warning.
  80.  *
  81.  * Revision 1.15  1997/10/10 10:43:43  robertj
  82.  * Fixed bug in password encryption, missing string terminator.
  83.  *
  84.  * Revision 1.14  1997/08/28 12:48:29  robertj
  85.  * Changed array fields to allow for reordering.
  86.  *
  87.  * Revision 1.13  1997/08/21 12:44:10  robertj
  88.  * Fixed bug in HTTP form array size field.
  89.  * Fixed bug where section list was only replacing first instance of macro.
  90.  *
  91.  * Revision 1.12  1997/08/09 07:46:52  robertj
  92.  * Fixed problems with value of SELECT fields in form
  93.  *
  94.  * Revision 1.11  1997/08/04 10:41:13  robertj
  95.  * Fixed bug in new section list page for names with special characters in them.
  96.  *
  97.  * Revision 1.10  1997/07/26 11:38:20  robertj
  98.  * Support for overridable pages in HTTP service applications.
  99.  *
  100.  * Revision 1.9  1997/07/14 11:49:51  robertj
  101.  * Put "Add" and "Keep" on check boxes in array fields.
  102.  *
  103.  * Revision 1.8  1997/07/08 13:12:29  robertj
  104.  * Major HTTP form enhancements for lists and arrays of fields.
  105.  *
  106.  * Revision 1.7  1997/06/08 04:47:27  robertj
  107.  * Adding new llist based form field.
  108.  *
  109.  * Revision 1.6  1997/04/12 02:07:26  robertj
  110.  * Fixed boolean check boxes being more flexible on string values.
  111.  *
  112.  * Revision 1.5  1997/04/01 06:00:53  robertj
  113.  * Changed PHTTPConfig so if section empty string, does not write PConfig parameters.
  114.  *
  115.  * Revision 1.4  1996/10/08 13:10:34  robertj
  116.  * Fixed bug in boolean (checkbox) html forms, cannot be reset.
  117.  *
  118.  * Revision 1.3  1996/09/14 13:09:31  robertj
  119.  * Major upgrade:
  120.  *   rearranged sockets to help support IPX.
  121.  *   added indirect channel class and moved all protocols to descend from it,
  122.  *   separating the protocol from the low level byte transport.
  123.  *
  124.  * Revision 1.2  1996/08/08 13:34:10  robertj
  125.  * Removed redundent call.
  126.  *
  127.  * Revision 1.1  1996/06/28 12:56:20  robertj
  128.  * Initial revision
  129.  *
  130.  */
  131. #ifdef __GNUC__
  132. #pragma implementation "httpform.h"
  133. #endif
  134. #include <ptlib.h>
  135. #include <ptclib/httpform.h>
  136. #include <ptclib/cypher.h>
  137. //////////////////////////////////////////////////////////////////////////////
  138. // PHTTPField
  139. PHTTPField::PHTTPField(const char * nam, const char * titl, const char * hlp)
  140.   : baseName(nam), fullName(nam),
  141.     title(titl != NULL ? titl : nam),
  142.     help(hlp != NULL ? hlp : "")
  143. {
  144.   notInHTML = TRUE;
  145. }
  146. PObject::Comparison PHTTPField::Compare(const PObject & obj) const
  147. {
  148.   PAssert(obj.IsDescendant(PHTTPField::Class()), PInvalidCast);
  149.   return fullName.Compare(((const PHTTPField &)obj).fullName);
  150. }
  151. void PHTTPField::SetName(const PString & newName)
  152. {
  153.   fullName = newName;
  154. }
  155. const PHTTPField * PHTTPField::LocateName(const PString & name) const
  156. {
  157.   if (fullName == name)
  158.     return this;
  159.   return NULL;
  160. }
  161. void PHTTPField::SetHelp(const PString & hotLinkURL,
  162.                          const PString & linkText)
  163. {
  164.   help = "<A HREF="" + hotLinkURL + "">" + linkText + "</A>rn";
  165. }
  166. void PHTTPField::SetHelp(const PString & hotLinkURL,
  167.                          const PString & imageURL,
  168.                          const PString & imageText)
  169. {
  170.   help = "<A HREF="" + hotLinkURL + ""><IMG SRC="" +
  171.              imageURL + "" ALT="" + imageText + "" ALIGN=absmiddle></A>rn";
  172. }
  173. static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
  174.                             const PRegularExpression & endExpr,
  175.                             const PString & text,
  176.                             PINDEX offset,
  177.                             PINDEX & pos,
  178.                             PINDEX & len,
  179.                             PINDEX & start,
  180.                             PINDEX & finish)
  181. {
  182.   start = finish = P_MAX_INDEX;
  183.   if (!text.FindRegEx(startExpr, pos, len, offset))
  184.     return FALSE;
  185.   PINDEX endpos, endlen;
  186.   if (!text.FindRegEx(endExpr, endpos, endlen, pos+len))
  187.     return TRUE;
  188.   start = pos + len;
  189.   finish = endpos - 1;
  190.   len = endpos - pos + endlen;
  191.   return TRUE;
  192. }
  193. static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
  194.                             const PString & text,
  195.                             PINDEX offset,
  196.                             PINDEX & pos,
  197.                             PINDEX & len,
  198.                             PINDEX & start,
  199.                             PINDEX & finish)
  200. {
  201.   static PRegularExpression EndBlock("<?!--#form[ trn]+end[ trn]*-->?",
  202.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  203.   return FindSpliceBlock(startExpr, EndBlock, text, offset, pos, len, start, finish);
  204. }
  205. static BOOL FindSpliceName(const PCaselessString & text,
  206.                            PINDEX start,
  207.                            PINDEX finish,
  208.                            PINDEX & pos,
  209.                            PINDEX & end)
  210. {
  211.   if (text[start+1] != '!') {
  212.     static PRegularExpression NameExpr("name[ trn]*=[ trn]*"[^"]*"",
  213.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  214.     if ((pos = text.FindRegEx(NameExpr, start)) == P_MAX_INDEX)
  215.       return FALSE;
  216.     if (pos >= finish)
  217.       return FALSE;
  218.     pos = text.Find('"', pos) + 1;
  219.     end = text.Find('"', pos) - 1;
  220.   }
  221.   else {
  222.     pos = start + 9;            // Skip over the <!--#form
  223.     while (isspace(text[pos]))  // Skip over blanks
  224.       pos++;
  225.     while (pos < finish && !isspace(text[pos])) // Skip over keyword
  226.       pos++;
  227.     while (isspace(text[pos]))  // Skip over more blanks
  228.       pos++;
  229.     
  230.     end = text.Find("--", pos) - 1;
  231.   }
  232.   return end < finish;
  233. }
  234. static BOOL FindSpliceFieldName(const PString & text,
  235.                             PINDEX offset,
  236.                             PINDEX & pos,
  237.                             PINDEX & len,
  238.                             PString & name)
  239. {
  240.   static PRegularExpression FieldName("<?!--#form[ trn]+[a-z0-9]+[ trn]+[^-]+[ trn]*-->?"
  241.                                       "|"
  242.                                       "<[a-z]+[ trn][^>]*name[ trn]*=[ trn]*"[^"]*"[^>]*>",
  243.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  244.   if (!text.FindRegEx(FieldName, pos, len, offset))
  245.     return FALSE;
  246.   PINDEX nameStart, nameEnd;
  247.   if (!FindSpliceName(text, pos, pos+len-1, nameStart, nameEnd))
  248.     return FALSE;
  249.   name = text(nameStart, nameEnd);
  250.   pos = nameStart;
  251.   len = nameEnd - nameStart + 1;
  252.   return TRUE;
  253. }
  254. static void SpliceAdjust(const PString & str,
  255.                          PString & text,
  256.                          PINDEX pos,
  257.                          PINDEX & len,
  258.                          PINDEX & finish)
  259. {
  260.   text.Splice(str, pos, len);
  261.   PINDEX newLen = str.GetLength();
  262.   if (finish != P_MAX_INDEX)
  263.     finish += newLen - len;
  264.   len = newLen;
  265. }
  266. void PHTTPField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
  267. {
  268.   PString name;
  269.   PINDEX pos, len;
  270.   while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
  271.     if (pos > finish)
  272.       break;
  273.     if (baseName == name)
  274.       SpliceAdjust(fullName, text, pos, len, finish);
  275.     start = pos + len;
  276.   }
  277. }
  278. static BOOL FindInputValue(const PString & text, PINDEX & before, PINDEX & after)
  279. {
  280.   static PRegularExpression Value("value[ trn]*=[ trn]*("[^"]*"|[^> trn]+)",
  281.                                   PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  282.   PINDEX pos = text.FindRegEx(Value);
  283.   if (pos == P_MAX_INDEX)
  284.     return FALSE;
  285.   before = text.Find('"', pos);
  286.   if (before != P_MAX_INDEX)
  287.     after = text.Find('"', before+1);
  288.   else {
  289.     before = text.Find('=', pos);
  290.     while (isspace(text[before+1]))
  291.       before++;
  292.     after = before + 1;
  293.     while (text[after] != '' && text[after] != '>' && !isspace(text[after]))
  294.       after++;
  295.   }
  296.   return TRUE;
  297. }
  298. PString PHTTPField::GetHTMLInput(const PString & input) const
  299. {
  300.   PINDEX before, after;
  301.   if (FindInputValue(input, before, after))
  302.     return input(0, before) + GetValue(FALSE) + input.Mid(after);
  303.   return "<input value="" + GetValue(FALSE) + """ + input.Mid(6);
  304. }
  305. static void AdjustSelectOptions(PString & text, PINDEX begin, PINDEX end,
  306.                                 const PString & myValue, PStringList & validValues,
  307.                                 PINDEX & finishAdjust)
  308. {
  309.   PINDEX start, finish;
  310.   PINDEX pos = begin;
  311.   PINDEX len = 0;
  312.   static PRegularExpression StartOption("<[ trn]*option[^>]*>",
  313.                                         PRegularExpression::IgnoreCase);
  314.   static PRegularExpression EndOption("<[ trn]*/?option[^>]*>",
  315.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  316.   while (FindSpliceBlock(StartOption, EndOption, text, pos+len, pos, len, start, finish) && pos < end) {
  317.     PCaselessString option = text(pos, start-1);
  318.     PINDEX before, after;
  319.     if (FindInputValue(option, before, after)) {
  320.       start = pos + before + 1;
  321.       finish = pos + after - 1;
  322.     }
  323.     PINDEX selpos = option.Find("selected");
  324.     PString thisValue = text(start, finish);
  325.     if (thisValue == myValue) {
  326.       if (selpos == P_MAX_INDEX) {
  327.         text.Splice(" selected", pos+7, 0);
  328.         if (finishAdjust != P_MAX_INDEX)
  329.           finishAdjust += 9;
  330.         if (end != P_MAX_INDEX)
  331.           end += 9;
  332.         len += 9;
  333.       }
  334.     }
  335.     else {
  336.       if (validValues.GetSize() > 0) {
  337.         PINDEX valid;
  338.         for (valid = 0; valid < validValues.GetSize(); valid++) {
  339.           if (thisValue == validValues[valid])
  340.             break;
  341.         }
  342.         if (valid >= validValues.GetSize()) {
  343.           text.Delete(pos, len);
  344.           selpos = P_MAX_INDEX;
  345.           if (finishAdjust != P_MAX_INDEX)
  346.             finishAdjust -= len;
  347.           if (end != P_MAX_INDEX)
  348.             end -= len;
  349.           len = 0;
  350.         }
  351.       }
  352.       if (selpos != P_MAX_INDEX) {
  353.         selpos += pos;
  354.         PINDEX sellen = 8;
  355.         if (text[selpos-1] == ' ') {
  356.           selpos--;
  357.           sellen++;
  358.         }
  359.         text.Delete(selpos, sellen);
  360.         if (finishAdjust != P_MAX_INDEX)
  361.           finishAdjust -= sellen;
  362.         if (end != P_MAX_INDEX)
  363.           end -= sellen;
  364.         len -= sellen;
  365.       }
  366.     }
  367.   }
  368. }
  369. PString PHTTPField::GetHTMLSelect(const PString & selection) const
  370. {
  371.   PString text = selection;
  372.   PStringList dummy1;
  373.   PINDEX dummy2 = P_MAX_INDEX;
  374.   AdjustSelectOptions(text, 0, P_MAX_INDEX, GetValue(FALSE), dummy1, dummy2);
  375.   return text;
  376. }
  377. void PHTTPField::GetHTMLHeading(PHTML &) const
  378. {
  379. }
  380. static int SplitConfigKey(const PString & fullName,
  381.                           PString & section, PString & key)
  382. {
  383.   if (fullName.IsEmpty())
  384.     return 0;
  385.   PINDEX slash = fullName.FindLast('\');
  386.   if (slash == 0 || slash >= fullName.GetLength()-1) {
  387.     key = fullName;
  388.     return 1;
  389.   }
  390.   section = fullName.Left(slash);
  391.   key = fullName.Mid(slash+1);
  392.   if (section.IsEmpty() || key.IsEmpty())
  393.     return 0;
  394.   return 2;
  395. }
  396. void PHTTPField::LoadFromConfig(PConfig & cfg)
  397. {
  398.   PString section, key;
  399.   switch (SplitConfigKey(fullName, section, key)) {
  400.     case 1 :
  401.       SetValue(cfg.GetString(key, GetValue(TRUE)));
  402.       break;
  403.     case 2 :
  404.       SetValue(cfg.GetString(section, key, GetValue(TRUE)));
  405.   }
  406. }
  407. void PHTTPField::SaveToConfig(PConfig & cfg) const
  408. {
  409.   PString section, key;
  410.   switch (SplitConfigKey(fullName, section, key)) {
  411.     case 1 :
  412.       cfg.SetString(key, GetValue());
  413.       break;
  414.     case 2 :
  415.       cfg.SetString(section, key, GetValue());
  416.   }
  417. }
  418. BOOL PHTTPField::Validated(const PString &, PStringStream &) const
  419. {
  420.   return TRUE;
  421. }
  422. PStringList PHTTPField::GetAllNames() const
  423. {
  424.   PStringList list;
  425.   list.DisallowDeleteObjects();
  426.   list.AppendString(fullName);
  427.   return list;
  428. }
  429. void PHTTPField::SetAllValues(const PStringToString & data)
  430. {
  431.   if (!baseName && data.Contains(fullName))
  432.     SetValue(data[fullName]);
  433. }
  434. BOOL PHTTPField::ValidateAll(const PStringToString & data, PStringStream & msg) const
  435. {
  436.   if (data.Contains(fullName))
  437.     return Validated(data[fullName], msg);
  438.   return TRUE;
  439. }
  440. //////////////////////////////////////////////////////////////////////////////
  441. // PHTTPCompositeField
  442. PHTTPCompositeField::PHTTPCompositeField(const char * nam,
  443.                                          const char * titl,
  444.                                          const char * hlp)
  445.   : PHTTPField(nam, titl, hlp)
  446. {
  447. }
  448. void PHTTPCompositeField::SetName(const PString & newName)
  449. {
  450.   for (PINDEX i = 0; i < fields.GetSize(); i++) {
  451.     PHTTPField & field = fields[i];
  452.     PString firstPartOfName = psprintf(fullName, i+1);
  453.     PString subFieldName;
  454.     if (field.GetName().Find(firstPartOfName) == 0)
  455.       subFieldName = field.GetName().Mid(firstPartOfName.GetLength());
  456.     else
  457.       subFieldName = field.GetName();
  458.     firstPartOfName = psprintf(newName, i+1);
  459.     if (subFieldName[0] == '\' || firstPartOfName[firstPartOfName.GetLength()-1] == '\')
  460.       field.SetName(firstPartOfName + subFieldName);
  461.     else
  462.       field.SetName(firstPartOfName & subFieldName);
  463.   }
  464.   PHTTPField::SetName(newName);
  465. }
  466. const PHTTPField * PHTTPCompositeField::LocateName(const PString & name) const
  467. {
  468.   if (fullName == name)
  469.     return this;
  470.   for (PINDEX i = 0; i < fields.GetSize(); i++) {
  471.     const PHTTPField * field = fields[i].LocateName(name);
  472.     if (field != NULL)
  473.       return field;
  474.   }
  475.   return NULL;
  476. }
  477. PHTTPField * PHTTPCompositeField::NewField() const
  478. {
  479.   PHTTPCompositeField * fld = new PHTTPCompositeField(baseName, title, help);
  480.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  481.     fld->Append(fields[i].NewField());
  482.   return fld;
  483. }
  484. void PHTTPCompositeField::GetHTMLTag(PHTML & html) const
  485. {
  486.   for (PINDEX i = 0; i < fields.GetSize(); i++) {
  487.     if (i != 0)
  488.       html << PHTML::TableData("NOWRAP");
  489.     fields[i].GetHTMLTag(html);
  490.   }
  491. }
  492. PString PHTTPCompositeField::GetHTMLInput(const PString & input) const
  493. {
  494.   return input;
  495. }
  496. void PHTTPCompositeField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
  497. {
  498.   static PRegularExpression FieldName( "!--#form[ trn]+[^-]*[ trn]+[^-]*[ trn]*)?--"
  499.                                        "|"
  500.                                        "<[a-z]*[ trn][^>]*name[ trn]*=[ trn]*"[^"]*"[^>]*>",
  501.                                        PRegularExpression::IgnoreCase);
  502.   PString name;
  503.   PINDEX pos, len;
  504.   while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
  505.     if (pos > finish)
  506.       break;
  507.     for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
  508.       if (fields[fld].GetBaseName() == name) {
  509.         SpliceAdjust(fields[fld].GetName(), text, pos, len, finish);
  510.         break;
  511.       }
  512.     }
  513.     start = pos + len;
  514.   }
  515. }
  516. void PHTTPCompositeField::GetHTMLHeading(PHTML & html) const
  517. {
  518.   html << PHTML::TableRow();
  519.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  520.     html << PHTML::TableData() << fields[i].GetTitle();
  521. }
  522. PString PHTTPCompositeField::GetValue(BOOL dflt) const
  523. {
  524.   PStringStream value;
  525.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  526.     value << fields[i].GetValue(dflt) << 'n';
  527.   return value;
  528. }
  529. void PHTTPCompositeField::SetValue(const PString &)
  530. {
  531.   PAssertAlways(PLogicError);
  532. }
  533. void PHTTPCompositeField::LoadFromConfig(PConfig & cfg)
  534. {
  535.   for (PINDEX i = 0; i < GetSize(); i++)
  536.     fields[i].LoadFromConfig(cfg);
  537. }
  538. void PHTTPCompositeField::SaveToConfig(PConfig & cfg) const
  539. {
  540.   for (PINDEX i = 0; i < GetSize(); i++)
  541.     fields[i].SaveToConfig(cfg);
  542. }
  543. PStringList PHTTPCompositeField::GetAllNames() const
  544. {
  545.   PStringList list;
  546.   list.DisallowDeleteObjects();
  547.   for (PINDEX i = 0; i < GetSize(); i++) {
  548.     PStringList sublist = fields[i].GetAllNames();
  549.     for (PINDEX j = 0; j < sublist.GetSize(); j++)
  550.       list.AppendString(sublist[j]);
  551.   }
  552.   return list;
  553. }
  554. void PHTTPCompositeField::SetAllValues(const PStringToString & data)
  555. {
  556.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  557.     fields[i].SetAllValues(data);
  558. }
  559. BOOL PHTTPCompositeField::ValidateAll(const PStringToString & data,
  560.                                       PStringStream & msg) const
  561. {
  562.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  563.     if (!fields[i].ValidateAll(data, msg))
  564.       return FALSE;
  565.   return TRUE;
  566. }
  567. PINDEX PHTTPCompositeField::GetSize() const
  568. {
  569.   return fields.GetSize();
  570. }
  571. void PHTTPCompositeField::Append(PHTTPField * fld)
  572. {
  573.   fields.Append(fld);
  574. }
  575. //////////////////////////////////////////////////////////////////////////////
  576. // PHTTPSubForm
  577. PHTTPSubForm::PHTTPSubForm(const PString & subForm,
  578.                            const char * name,
  579.                            const char * title,
  580.                            PINDEX prim,
  581.                            PINDEX sec)
  582.   : PHTTPCompositeField(name, title, NULL),
  583.     subFormName(subForm)
  584. {
  585.   primary = prim;
  586.   secondary = sec;
  587. }
  588. PHTTPField * PHTTPSubForm::NewField() const
  589. {
  590.   PHTTPCompositeField * fld = new PHTTPSubForm(subFormName, baseName, title, primary, secondary);
  591.   for (PINDEX i = 0; i < fields.GetSize(); i++)
  592.     fld->Append(fields[i].NewField());
  593.   return fld;
  594. }
  595. void PHTTPSubForm::GetHTMLTag(PHTML & html) const
  596. {
  597.   PString value = fields[primary].GetValue();
  598.   if (value.IsEmpty())
  599.     value = "New";
  600.   html << PHTML::HotLink(subFormName +
  601.             "?subformprefix=" + PURL::TranslateString(fullName, PURL::QueryTranslation))
  602.        << value << PHTML::HotLink();
  603.   if (secondary != P_MAX_INDEX)
  604.     html << PHTML::TableData("NOWRAP") << fields[secondary].GetValue();
  605. }
  606. void PHTTPSubForm::GetHTMLHeading(PHTML &) const
  607. {
  608. }
  609. //////////////////////////////////////////////////////////////////////////////
  610. // PHTTPFieldArray
  611. PHTTPFieldArray::PHTTPFieldArray(PHTTPField * fld, BOOL ordered)
  612.   : PHTTPCompositeField(fld->GetName(), fld->GetTitle(), fld->GetHelp()),
  613.     baseField(fld)
  614. {
  615.   orderedArray = ordered;
  616.   AddBlankField();
  617. }
  618. PHTTPFieldArray::~PHTTPFieldArray()
  619. {
  620.   delete baseField;
  621. }
  622. void PHTTPFieldArray::SetSize(PINDEX newSize)
  623. {
  624.   while (fields.GetSize() > newSize)
  625.     fields.RemoveAt(fields.GetSize()-1);
  626.   while (fields.GetSize() <= newSize)
  627.     AddBlankField();
  628. }
  629. PHTTPField * PHTTPFieldArray::NewField() const
  630. {
  631.   return new PHTTPFieldArray(baseField->NewField(), orderedArray);
  632. }
  633. static const char ArrayControlBox[] = " Array Control";
  634. static const char ArrayControlKeep[] = "Keep";
  635. static const char ArrayControlRemove[] = "Remove";
  636. static const char ArrayControlMoveUp[] = "Move Up";
  637. static const char ArrayControlMoveDown[] = "Move Down";
  638. static const char ArrayControlToTop[] = "To Top";
  639. static const char ArrayControlToBottom[] = "To Bottom";
  640. static const char ArrayControlIgnore[] = "Ignore";
  641. static const char ArrayControlAddTop[] = "Add Top";
  642. static const char ArrayControlAddBottom[] = "Add Bottom";
  643. static const char ArrayControlAdd[] = "Add";
  644. static PStringList GetArrayControlOptions(PINDEX fld, PINDEX size, BOOL orderedArray)
  645. {
  646.   PStringList options;
  647.   if (fld >= size) {
  648.     options.AppendString(ArrayControlIgnore);
  649.     if (size == 0 || !orderedArray)
  650.       options.AppendString(ArrayControlAdd);
  651.     else {
  652.       options.AppendString(ArrayControlAddTop);
  653.       options.AppendString(ArrayControlAddBottom);
  654.     }
  655.   }
  656.   else {
  657.     options.AppendString(ArrayControlKeep);
  658.     options.AppendString(ArrayControlRemove);
  659.     if (orderedArray) {
  660.       if (fld > 0)
  661.         options.AppendString(ArrayControlMoveUp);
  662.       if (fld < size-1)
  663.         options.AppendString(ArrayControlMoveDown);
  664.       if (fld > 0)
  665.         options.AppendString(ArrayControlToTop);
  666.       if (fld < size-1)
  667.         options.AppendString(ArrayControlToBottom);
  668.     }
  669.   }
  670.   return options;
  671. }
  672. void PHTTPFieldArray::AddArrayControlBox(PHTML & html, PINDEX fld) const
  673. {
  674.   PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
  675.   html << PHTML::Select(fields[fld].GetName() + ArrayControlBox);
  676.   for (PINDEX i = 0; i < options.GetSize(); i++)
  677.     html << PHTML::Option(i == 0 ? PHTML::Selected : PHTML::NotSelected) << options[i];
  678.   html << PHTML::Select();
  679. }
  680. void PHTTPFieldArray::GetHTMLTag(PHTML & html) const
  681. {
  682.   html << PHTML::TableStart();
  683.   baseField->GetHTMLHeading(html);
  684.   for (PINDEX i = 0; i < fields.GetSize(); i++) {
  685.     html << PHTML::TableRow() << PHTML::TableData("NOWRAP");
  686.     fields[i].GetHTMLTag(html);
  687.     html << PHTML::TableData("NOWRAP");
  688.     AddArrayControlBox(html, i);
  689.   }
  690.   html << PHTML::TableEnd();
  691. }
  692. void PHTTPFieldArray::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
  693. {
  694.   PString original = text(start, finish);
  695.   PINDEX origFinish = finish;
  696.   PINDEX finalFinish = finish;
  697.   PINDEX fld = fields.GetSize();
  698.   while (fld > 0) {
  699.     fields[--fld].ExpandFieldNames(text, start, finish);
  700.     PINDEX pos,len;
  701.     static PRegularExpression RowNum("<?!--#form[ trn]+rownum[ trn]*-->?",
  702.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  703.     while (text.FindRegEx(RowNum, pos, len, start, finish))
  704.       SpliceAdjust(psprintf("%u", fld+1), text, pos, len, finish);
  705.     static PRegularExpression SubForm("<?!--#form[ trn]+subform[ trn]*-->?",
  706.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  707.     while (text.FindRegEx(SubForm, pos, len, start, finish)) {
  708.       PString fmt = fullName;
  709.       if (fmt.Find("%u") == P_MAX_INDEX)
  710.         fmt += " %u";
  711.       SpliceAdjust("subformprefix=" + PURL::TranslateString(psprintf(fmt, fld+1), PURL::QueryTranslation),
  712.                    text, pos, len, finish);
  713.     }
  714.     static PRegularExpression RowControl("<?!--#form[ trn]+rowcontrol[ trn]*-->?",
  715.                                          PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  716.     while (text.FindRegEx(RowControl, pos, len, start, finish)) {
  717.       PHTML html(PHTML::InForm);
  718.       AddArrayControlBox(html, fld);
  719.       SpliceAdjust(html, text, pos, len, finish);
  720.     }
  721.     static PRegularExpression SelectRow("<select[ trn][^>]*name[ trn]*=[ trn]*"!--#form[ trn]+rowselect[ trn]*--"[^>]*>",
  722.                                         PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  723.     static PRegularExpression SelEndRegEx("</select[^>]*>",
  724.                                           PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  725.     PINDEX begin, end;
  726.     while (FindSpliceBlock(SelectRow, SelEndRegEx, text, 0, pos, len, begin, end)) {
  727.       PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
  728.       AdjustSelectOptions(text, begin, end, options[0], options, finish);
  729.       static PRegularExpression RowSelect("!--#form[ trn]+rowselect[ trn]*--",
  730.                                           PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  731.       if (text.FindRegEx(RowSelect, pos, len, pos, begin))
  732.         SpliceAdjust(fields[fld].GetName() + ArrayControlBox, text, pos, len, finish);
  733.     }
  734.     finalFinish += finish - origFinish;
  735.     if (fld > 0) {
  736.       text.Splice(original, start, 0);
  737.       finish = origFinish;
  738.       finalFinish += finish - start;
  739.     }
  740.   }
  741.   finish = finalFinish;
  742. }
  743. static int SplitArraySizeKey(const PString & fullName,
  744.                              PString & section, PString & key)
  745. {
  746.   static const char ArraySize[] = "Array Size";
  747.   PINDEX pos = fullName.Find("%u");
  748.   if (pos == P_MAX_INDEX)
  749.     return SplitConfigKey(fullName & ArraySize, section, key);
  750.   PINDEX endPos = fullName.GetLength() - 1;
  751.   if (fullName[endPos] == '\')
  752.     endPos--;
  753.   return SplitConfigKey(fullName.Left(pos) & ArraySize & fullName(pos+2, endPos), section, key);
  754. }
  755. void PHTTPFieldArray::LoadFromConfig(PConfig & cfg)
  756. {
  757.   PString section, key;
  758.   switch (SplitArraySizeKey(fullName, section, key)) {
  759.     case 1 :
  760.       SetSize(cfg.GetInteger(key, GetSize()));
  761.       break;
  762.     case 2 :
  763.       SetSize(cfg.GetInteger(section, key, GetSize()));
  764.   }
  765.   PHTTPCompositeField::LoadFromConfig(cfg);
  766. }
  767. void PHTTPFieldArray::SaveToConfig(PConfig & cfg) const
  768. {
  769.   PString section, key;
  770.   switch (SplitArraySizeKey(fullName, section, key)) {
  771.     case 1 :
  772.       cfg.SetInteger(key, GetSize());
  773.       break;
  774.     case 2 :
  775.       cfg.SetInteger(section, key, GetSize());
  776.   }
  777.   PHTTPCompositeField::SaveToConfig(cfg);
  778. }
  779. void PHTTPFieldArray::SetArrayFieldName(PINDEX idx) const
  780. {
  781.   PString fmt = fullName;
  782.   if (fmt.Find("%u") == P_MAX_INDEX)
  783.     fmt += " %u";
  784.   fields[idx].SetName(psprintf(fmt, idx+1));
  785. }
  786. void PHTTPFieldArray::SetAllValues(const PStringToString & data)
  787. {
  788.   PHTTPFieldList newFields;
  789.   newFields.DisallowDeleteObjects();
  790.   PINDEX i;
  791.   for (i = 0; i < fields.GetSize(); i++)
  792.     newFields.Append(fields.GetAt(i));
  793.   BOOL lastFieldIsSet = FALSE;
  794.   PINDEX size = fields.GetSize();
  795.   for (i = 0; i < size; i++) {
  796.     PHTTPField * fieldPtr = &fields[i];
  797.     PINDEX pos = newFields.GetObjectsIndex(fieldPtr);
  798.     fieldPtr->SetAllValues(data);
  799.     PString control = data(fieldPtr->GetName() + ArrayControlBox);
  800.     if (control == ArrayControlMoveUp) {
  801.       if (pos > 0) {
  802.         newFields.SetAt(pos, newFields.GetAt(pos-1));
  803.         newFields.SetAt(pos-1, fieldPtr);
  804.       }
  805.     }
  806.     else if (control == ArrayControlMoveDown) {
  807.       if (size > 2 && pos < size-2) {
  808.         newFields.SetAt(pos, newFields.GetAt(pos+1));
  809.         newFields.SetAt(pos+1, fieldPtr);
  810.       }
  811.     }
  812.     else if (control == ArrayControlToTop) {
  813.       newFields.RemoveAt(pos);
  814.       newFields.InsertAt(0, fieldPtr);
  815.     }
  816.     else if (control == ArrayControlToBottom) {
  817.       newFields.RemoveAt(pos);
  818.       newFields.Append(fieldPtr);
  819.     }
  820.     else if (control == ArrayControlAddTop) {
  821.       if (i == size-1) {
  822.         newFields.RemoveAt(pos);
  823.         newFields.InsertAt(0, fieldPtr);
  824.         lastFieldIsSet = TRUE;
  825.       }
  826.     }
  827.     else if (control == ArrayControlAddBottom || control == ArrayControlAdd) {
  828.       if (i == size-1) {
  829.         newFields.RemoveAt(pos);
  830.         newFields.Append(fieldPtr);
  831.         lastFieldIsSet = TRUE;
  832.       }
  833.     }
  834.     else if (control == ArrayControlIgnore) {
  835.       newFields.RemoveAt(pos);
  836.       newFields.Append(fieldPtr);
  837.     }
  838.     else if (control == ArrayControlRemove)
  839.       newFields.RemoveAt(pos);
  840.   }
  841.   fields.DisallowDeleteObjects();
  842.   for (i = 0; i < newFields.GetSize(); i++)
  843.     fields.Remove(newFields.GetAt(i));
  844.   fields.AllowDeleteObjects();
  845.   fields.RemoveAll();
  846.   for (i = 0; i < newFields.GetSize(); i++) {
  847.     fields.Append(newFields.GetAt(i));
  848.     SetArrayFieldName(i);
  849.   }
  850.   if (lastFieldIsSet)
  851.     AddBlankField();
  852. }
  853. PINDEX PHTTPFieldArray::GetSize() const
  854. {
  855.   PAssert(fields.GetSize() > 0, PLogicError);
  856.   return fields.GetSize()-1;
  857. }
  858. void PHTTPFieldArray::AddBlankField()
  859. {
  860.   fields.Append(baseField->NewField());
  861.   SetArrayFieldName(fields.GetSize()-1);
  862. }
  863. //////////////////////////////////////////////////////////////////////////////
  864. // PHTTPStringField
  865. PHTTPStringField::PHTTPStringField(const char * name,
  866.                                    PINDEX siz,
  867.                                    const char * initVal,
  868.                                    const char * help)
  869.   : PHTTPField(name, NULL, help),
  870.     value(initVal != NULL ? initVal : ""),
  871.     initialValue(value)
  872. {
  873.   size = siz;
  874. }
  875. PHTTPStringField::PHTTPStringField(const char * name,
  876.                                    const char * title,
  877.                                    PINDEX siz,
  878.                                    const char * initVal,
  879.                                    const char * help)
  880.   : PHTTPField(name, title, help),
  881.     value(initVal != NULL ? initVal : ""),
  882.     initialValue(value)
  883. {
  884.   size = siz;
  885. }
  886. PHTTPField * PHTTPStringField::NewField() const
  887. {
  888.   return new PHTTPStringField(baseName, title, size, initialValue, help);
  889. }
  890. void PHTTPStringField::GetHTMLTag(PHTML & html) const
  891. {
  892.   html << PHTML::InputText(fullName, size, value);
  893. }
  894. void PHTTPStringField::SetValue(const PString & newVal)
  895. {
  896.   value = newVal;
  897. }
  898. PString PHTTPStringField::GetValue(BOOL dflt) const
  899. {
  900.   if (dflt)
  901.     return initialValue;
  902.   else
  903.     return value;
  904. }
  905. //////////////////////////////////////////////////////////////////////////////
  906. // PHTTPPasswordField
  907. PHTTPPasswordField::PHTTPPasswordField(const char * name,
  908.                                        PINDEX siz,
  909.                                        const char * initVal,
  910.                                        const char * help)
  911.   : PHTTPStringField(name, siz, initVal, help)
  912. {
  913. }
  914. PHTTPPasswordField::PHTTPPasswordField(const char * name,
  915.                                        const char * title,
  916.                                        PINDEX siz,
  917.                                        const char * initVal,
  918.                                        const char * help)
  919.   : PHTTPStringField(name, title, siz, initVal, help)
  920. {
  921. }
  922. PHTTPField * PHTTPPasswordField::NewField() const
  923. {
  924.   return new PHTTPPasswordField(baseName, title, size, initialValue, help);
  925. }
  926. void PHTTPPasswordField::GetHTMLTag(PHTML & html) const
  927. {
  928.   html << PHTML::InputPassword(fullName, size, value);
  929. }
  930. static const PTEACypher::Key PasswordKey = {
  931.   {
  932.     103,  60, 222,  17, 128, 157,  31, 137,
  933.     133,  64,  82, 148,  94, 136,   4, 209
  934.   }
  935. };
  936. void PHTTPPasswordField::SetValue(const PString & newVal)
  937. {
  938.   value = Decrypt(newVal);
  939. }
  940. PString PHTTPPasswordField::GetValue(BOOL dflt) const
  941. {
  942.   if (dflt)
  943.     return initialValue;
  944.   PTEACypher crypt(PasswordKey);
  945.   return crypt.Encode(value);
  946. }
  947. PString PHTTPPasswordField::Decrypt(const PString & pword)
  948. {
  949.   PString clear;
  950.   PTEACypher crypt(PasswordKey);
  951.   return crypt.Decode(pword, clear) ? clear : pword;
  952. }
  953. //////////////////////////////////////////////////////////////////////////////
  954. // PHTTPIntegerField
  955. PHTTPIntegerField::PHTTPIntegerField(const char * nam,
  956.                                      int lo, int hig,
  957.                                      int initVal,
  958.                                      const char * unit,
  959.                                      const char * help)
  960.   : PHTTPField(nam, NULL, help), units(unit != NULL ? unit : "")
  961. {
  962.   low = lo;
  963.   high = hig;
  964.   value = initialValue = initVal;
  965. }
  966. PHTTPIntegerField::PHTTPIntegerField(const char * nam,
  967.                                      const char * titl,
  968.                                      int lo, int hig,
  969.                                      int initVal,
  970.                                      const char * unit,
  971.                                      const char * help)
  972.   : PHTTPField(nam, titl, help), units(unit != NULL ? unit : "")
  973. {
  974.   low = lo;
  975.   high = hig;
  976.   value = initialValue = initVal;
  977. }
  978. PHTTPField * PHTTPIntegerField::NewField() const
  979. {
  980.   return new PHTTPIntegerField(baseName, title, low, high, initialValue, units, help);
  981. }
  982. void PHTTPIntegerField::GetHTMLTag(PHTML & html) const
  983. {
  984.   html << PHTML::InputRange(fullName, low, high, value) << "  " << units;
  985. }
  986. void PHTTPIntegerField::SetValue(const PString & newVal)
  987. {
  988.   value = newVal.AsInteger();
  989. }
  990. PString PHTTPIntegerField::GetValue(BOOL dflt) const
  991. {
  992.   return PString(PString::Signed, dflt ? initialValue : value);
  993. }
  994. void PHTTPIntegerField::LoadFromConfig(PConfig & cfg)
  995. {
  996.   PString section, key;
  997.   switch (SplitConfigKey(fullName, section, key)) {
  998.     case 1 :
  999.       value = cfg.GetInteger(key, initialValue);
  1000.       break;
  1001.     case 2 :
  1002.       value = cfg.GetInteger(section, key, initialValue);
  1003.   }
  1004. }
  1005. void PHTTPIntegerField::SaveToConfig(PConfig & cfg) const
  1006. {
  1007.   PString section, key;
  1008.   switch (SplitConfigKey(fullName, section, key)) {
  1009.     case 1 :
  1010.       cfg.SetInteger(key, value);
  1011.       break;
  1012.     case 2 :
  1013.       cfg.SetInteger(section, key, value);
  1014.   }
  1015. }
  1016. BOOL PHTTPIntegerField::Validated(const PString & newVal, PStringStream & msg) const
  1017. {
  1018.   int val = newVal.AsInteger();
  1019.   if (val >= low && val <= high)
  1020.     return TRUE;
  1021.   msg << "The field "" << GetName() << "" should be between "
  1022.       << low << " and " << high << ".<BR>";
  1023.   return FALSE;
  1024. }
  1025. //////////////////////////////////////////////////////////////////////////////
  1026. // PHTTPBooleanField
  1027. PHTTPBooleanField::PHTTPBooleanField(const char * name,
  1028.                                      BOOL initVal,
  1029.                                    const char * help)
  1030.   : PHTTPField(name, NULL, help)
  1031. {
  1032.   value = initialValue = initVal;
  1033. }
  1034. PHTTPBooleanField::PHTTPBooleanField(const char * name,
  1035.                                      const char * title,
  1036.                                      BOOL initVal,
  1037.                                      const char * help)
  1038.   : PHTTPField(name, title, help)
  1039. {
  1040.   value = initialValue = initVal;
  1041. }
  1042. PHTTPField * PHTTPBooleanField::NewField() const
  1043. {
  1044.   return new PHTTPBooleanField(baseName, title, initialValue, help);
  1045. }
  1046. void PHTTPBooleanField::GetHTMLTag(PHTML & html) const
  1047. {
  1048.   html << PHTML::HiddenField(fullName, "FALSE")
  1049.        << PHTML::CheckBox(fullName, value ? PHTML::Checked : PHTML::UnChecked);
  1050. }
  1051. static void SpliceChecked(PString & text, BOOL value)
  1052. {
  1053.   PINDEX pos = text.Find("checked");
  1054.   if (value) {
  1055.     if (pos == P_MAX_INDEX)
  1056.       text.Splice(" checked", 6, 0);
  1057.   }
  1058.   else {
  1059.     if (pos != P_MAX_INDEX) {
  1060.       PINDEX len = 7;
  1061.       if (text[pos-1] == ' ') {
  1062.         pos--;
  1063.         len++;
  1064.       }
  1065.       text.Delete(pos, len);
  1066.     }
  1067.   }
  1068. }
  1069. PString PHTTPBooleanField::GetHTMLInput(const PString & input) const
  1070. {
  1071.   static PRegularExpression checkboxRegEx("type[ trn]*=[ trn]*"?checkbox"?",
  1072.                                           PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1073.   if (input.FindRegEx(checkboxRegEx) != P_MAX_INDEX) {
  1074.     PCaselessString text;
  1075.     PINDEX before, after;
  1076.     if (FindInputValue(input, before, after)) 
  1077.       text = input(0, before) + "TRUE" + input.Mid(after);
  1078.     else
  1079.       text = "<input value="TRUE"" + input.Mid(6);
  1080.     SpliceChecked(text, value);
  1081.     return "<input type=hidden name="" + fullName + "">" + text;
  1082.   }
  1083.   static PRegularExpression radioRegEx("type[ trn]*=[ trn]*"?radio"?",
  1084.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1085.   if (input.FindRegEx(radioRegEx) != P_MAX_INDEX) {
  1086.     PINDEX before, after;
  1087.     if (FindInputValue(input, before, after)) {
  1088.       PCaselessString text = input;
  1089.       PString val = input(before+1, after-1);
  1090.       SpliceChecked(text, (value && (val *= "TRUE")) || (!value && (val *= "FALSE")));
  1091.       return text;
  1092.     }
  1093.     return input;
  1094.   }
  1095.   return PHTTPField::GetHTMLInput(input);
  1096. }
  1097. void PHTTPBooleanField::SetValue(const PString & val)
  1098. {
  1099.   value = toupper(val[0]) == 'T' || toupper(val[0]) == 'y' ||
  1100.           val.AsInteger() != 0 || val.Find("TRUE") != P_MAX_INDEX;
  1101. }
  1102. PString PHTTPBooleanField::GetValue(BOOL dflt) const
  1103. {
  1104.   return ((dflt ? initialValue : value) ? "True" : "False");
  1105. }
  1106. void PHTTPBooleanField::LoadFromConfig(PConfig & cfg)
  1107. {
  1108.   PString section, key;
  1109.   switch (SplitConfigKey(fullName, section, key)) {
  1110.     case 1 :
  1111.       value = cfg.GetBoolean(key, initialValue);
  1112.       break;
  1113.     case 2 :
  1114.       value = cfg.GetBoolean(section, key, initialValue);
  1115.   }
  1116. }
  1117. void PHTTPBooleanField::SaveToConfig(PConfig & cfg) const
  1118. {
  1119.   PString section, key;
  1120.   switch (SplitConfigKey(fullName, section, key)) {
  1121.     case 1 :
  1122.       cfg.SetBoolean(key, value);
  1123.       break;
  1124.     case 2 :
  1125.       cfg.SetBoolean(section, key, value);
  1126.   }
  1127. }
  1128. //////////////////////////////////////////////////////////////////////////////
  1129. // PHTTPRadioField
  1130. PHTTPRadioField::PHTTPRadioField(const char * name,
  1131.                                  const PStringArray & valueArray,
  1132.                                  PINDEX initVal,
  1133.                                  const char * help)
  1134.   : PHTTPField(name, NULL, help),
  1135.     values(valueArray),
  1136.     titles(valueArray),
  1137.     value(valueArray[initVal]),
  1138.     initialValue(value)
  1139. {
  1140. }
  1141. PHTTPRadioField::PHTTPRadioField(const char * name,
  1142.                                  const PStringArray & valueArray,
  1143.                                  const PStringArray & titleArray,
  1144.                                  PINDEX initVal,
  1145.                                  const char * help)
  1146.   : PHTTPField(name, NULL, help),
  1147.     values(valueArray),
  1148.     titles(titleArray),
  1149.     value(valueArray[initVal]),
  1150.     initialValue(value)
  1151. {
  1152. }
  1153. PHTTPRadioField::PHTTPRadioField(const char * name,
  1154.                                  PINDEX count,
  1155.                                  const char * const * valueStrings,
  1156.                                  PINDEX initVal,
  1157.                                  const char * help)
  1158.   : PHTTPField(name, NULL, help),
  1159.     values(count, valueStrings),
  1160.     titles(count, valueStrings),
  1161.     value(valueStrings[initVal]),
  1162.     initialValue(value)
  1163. {
  1164. }
  1165. PHTTPRadioField::PHTTPRadioField(const char * name,
  1166.                                  PINDEX count,
  1167.                                  const char * const * valueStrings,
  1168.                                  const char * const * titleStrings,
  1169.                                  PINDEX initVal,
  1170.                                  const char * help)
  1171.   : PHTTPField(name, NULL, help),
  1172.     values(count, valueStrings),
  1173.     titles(count, titleStrings),
  1174.     value(valueStrings[initVal]),
  1175.     initialValue(value)
  1176. {
  1177. }
  1178. PHTTPRadioField::PHTTPRadioField(const char * name,
  1179.                                  const char * groupTitle,
  1180.                                  const PStringArray & valueArray,
  1181.                                  PINDEX initVal,
  1182.                                  const char * help)
  1183.   : PHTTPField(name, groupTitle, help),
  1184.     values(valueArray),
  1185.     titles(valueArray),
  1186.     value(valueArray[initVal]),
  1187.     initialValue(value)
  1188. {
  1189. }
  1190. PHTTPRadioField::PHTTPRadioField(const char * name,
  1191.                                  const char * groupTitle,
  1192.                                  const PStringArray & valueArray,
  1193.                                  const PStringArray & titleArray,
  1194.                                  PINDEX initVal,
  1195.                                  const char * help)
  1196.   : PHTTPField(name, groupTitle, help),
  1197.     values(valueArray),
  1198.     titles(titleArray),
  1199.     value(valueArray[initVal]),
  1200.     initialValue(value)
  1201. {
  1202. }
  1203. PHTTPRadioField::PHTTPRadioField(const char * name,
  1204.                                  const char * groupTitle,
  1205.                                  PINDEX count,
  1206.                                  const char * const * valueStrings,
  1207.                                  PINDEX initVal,
  1208.                                  const char * help)
  1209.   : PHTTPField(name, groupTitle, help),
  1210.     values(count, valueStrings),
  1211.     titles(count, valueStrings),
  1212.     value(valueStrings[initVal]),
  1213.     initialValue(value)
  1214. {
  1215. }
  1216. PHTTPRadioField::PHTTPRadioField(const char * name,
  1217.                                  const char * groupTitle,
  1218.                                  PINDEX count,
  1219.                                  const char * const * valueStrings,
  1220.                                  const char * const * titleStrings,
  1221.                                  PINDEX initVal,
  1222.                                  const char * help)
  1223.   : PHTTPField(name, groupTitle, help),
  1224.     values(count, valueStrings),
  1225.     titles(count, titleStrings),
  1226.     value(valueStrings[initVal]),
  1227.     initialValue(value)
  1228. {
  1229. }
  1230. PHTTPField * PHTTPRadioField::NewField() const
  1231. {
  1232.   return new PHTTPRadioField(*this);
  1233. }
  1234. void PHTTPRadioField::GetHTMLTag(PHTML & html) const
  1235. {
  1236.   for (PINDEX i = 0; i < values.GetSize(); i++)
  1237.     html << PHTML::RadioButton(fullName, values[i],
  1238.                         values[i] == value ? PHTML::Checked : PHTML::UnChecked)
  1239.          << titles[i]
  1240.          << PHTML::BreakLine();
  1241. }
  1242. PString PHTTPRadioField::GetHTMLInput(const PString & input) const
  1243. {
  1244.   PString inval;
  1245.   PINDEX before, after;
  1246.   if (FindInputValue(input, before, after))
  1247.     inval = input(before+1, after-1);
  1248.   else
  1249.     inval = baseName;
  1250.   if (inval != value)
  1251.     return input;
  1252.   return "<input checked" + input.Mid(6);
  1253. }
  1254. PString PHTTPRadioField::GetValue(BOOL dflt) const
  1255. {
  1256.   if (dflt)
  1257.     return initialValue;
  1258.   else
  1259.     return value;
  1260. }
  1261. void PHTTPRadioField::SetValue(const PString & newVal)
  1262. {
  1263.   value = newVal;
  1264. }
  1265. //////////////////////////////////////////////////////////////////////////////
  1266. // PHTTPSelectField
  1267. PHTTPSelectField::PHTTPSelectField(const char * name,
  1268.                                    const PStringArray & valueArray,
  1269.                                    PINDEX initVal,
  1270.                                    const char * help)
  1271.   : PHTTPField(name, NULL, help),
  1272.     values(valueArray)
  1273. {
  1274.   initialValue = initVal;
  1275.   if (initVal < values.GetSize())
  1276.     value = values[initVal];
  1277. }
  1278. PHTTPSelectField::PHTTPSelectField(const char * name,
  1279.                                    PINDEX count,
  1280.                                    const char * const * valueStrings,
  1281.                                    PINDEX initVal,
  1282.                                    const char * help)
  1283.   : PHTTPField(name, NULL, help),
  1284.     values(count, valueStrings)
  1285. {
  1286.   initialValue = initVal;
  1287.   if (initVal < count)
  1288.     value = values[initVal];
  1289. }
  1290. PHTTPSelectField::PHTTPSelectField(const char * name,
  1291.                                    const char * title,
  1292.                                    const PStringArray & valueArray,
  1293.                                    PINDEX initVal,
  1294.                                    const char * help)
  1295.   : PHTTPField(name, title, help),
  1296.     values(valueArray)
  1297. {
  1298.   initialValue = initVal;
  1299.   if (initVal < values.GetSize())
  1300.     value = values[initVal];
  1301. }
  1302. PHTTPSelectField::PHTTPSelectField(const char * name,
  1303.                                    const char * title,
  1304.                                    PINDEX count,
  1305.                                    const char * const * valueStrings,
  1306.                                    PINDEX initVal,
  1307.                                    const char * help)
  1308.   : PHTTPField(name, title, help),
  1309.     values(count, valueStrings)
  1310. {
  1311.   initialValue = initVal;
  1312.   if (initVal < values.GetSize())
  1313.     value = values[initVal];
  1314. }
  1315. PHTTPField * PHTTPSelectField::NewField() const
  1316. {
  1317.   return new PHTTPSelectField(baseName, title, values, initialValue, help);
  1318. }
  1319. void PHTTPSelectField::GetHTMLTag(PHTML & html) const
  1320. {
  1321.   html << PHTML::Select(fullName);
  1322.   for (PINDEX i = 0; i < values.GetSize(); i++)
  1323.     html << PHTML::Option(values[i] == value ? PHTML::Selected : PHTML::NotSelected)
  1324.          << values[i];
  1325.   html << PHTML::Select();
  1326. }
  1327. PString PHTTPSelectField::GetValue(BOOL dflt) const
  1328. {
  1329.   if (dflt)
  1330.     if (initialValue < values.GetSize())
  1331.       return values[initialValue];
  1332.     else
  1333.       return PString();
  1334.   else
  1335.     return value;
  1336. }
  1337. void PHTTPSelectField::SetValue(const PString & newVal)
  1338. {
  1339.   value = newVal;
  1340. }
  1341. //////////////////////////////////////////////////////////////////////////////
  1342. // PHTTPForm
  1343. PHTTPForm::PHTTPForm(const PURL & url)
  1344.   : PHTTPString(url),
  1345.     fields("")
  1346. {
  1347. }
  1348. PHTTPForm::PHTTPForm(const PURL & url, const PHTTPAuthority & auth)
  1349.   : PHTTPString(url, auth),
  1350.     fields("")
  1351. {
  1352. }
  1353. PHTTPForm::PHTTPForm(const PURL & url, const PString & html)
  1354.   : PHTTPString(url, html),
  1355.     fields("")
  1356. {
  1357. }
  1358. PHTTPForm::PHTTPForm(const PURL & url,
  1359.                      const PString & html,
  1360.                      const PHTTPAuthority & auth)
  1361.   : PHTTPString(url, html, auth),
  1362.     fields("")
  1363. {
  1364. }
  1365. static BOOL FindSpliceAccepted(const PString & text,
  1366.                               PINDEX offset,
  1367.                               PINDEX & pos,
  1368.                               PINDEX & len,
  1369.                               PINDEX & start,
  1370.                               PINDEX & finish)
  1371. {
  1372.   static PRegularExpression Accepted("<?!--#form[ trn]+accepted[ trn]*-->?",
  1373.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1374.   return FindSpliceBlock(Accepted, text, offset, pos, len, start, finish);
  1375. }
  1376. static BOOL FindSpliceErrors(const PString & text,
  1377.                             PINDEX offset,
  1378.                             PINDEX & pos,
  1379.                             PINDEX & len,
  1380.                             PINDEX & start,
  1381.                             PINDEX & finish)
  1382. {
  1383.   static PRegularExpression Errors("<?!--#form[ trn]+errors[ trn]*-->?",
  1384.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1385.   return FindSpliceBlock(Errors, text, offset, pos, len, start, finish);
  1386. }
  1387. static BOOL FindSpliceField(const PRegularExpression & startExpr,
  1388.                             const PRegularExpression & endExpr,
  1389.                             const PString & text,
  1390.                             PINDEX offset,
  1391.                             const PHTTPField & rootField,
  1392.                             PINDEX & pos,
  1393.                             PINDEX & len,
  1394.                             PINDEX & start,
  1395.                             PINDEX & finish,
  1396.                             const PHTTPField * & field)
  1397. {
  1398.   field = NULL;
  1399.   if (!FindSpliceBlock(startExpr, endExpr, text, offset, pos, len, start, finish))
  1400.     return FALSE;
  1401.   PINDEX endBlock = start != finish ? (start-1) : (pos+len-1);
  1402.   PINDEX namePos, nameEnd;
  1403.   if (FindSpliceName(text, pos, endBlock, namePos, nameEnd))
  1404.     field = rootField.LocateName(text(namePos, nameEnd));
  1405.   return TRUE;
  1406. }
  1407. void PHTTPForm::OnLoadedText(PHTTPRequest & request, PString & text)
  1408. {
  1409.   PINDEX pos, len, start, finish;
  1410.   const PHTTPField * field;
  1411.   // Remove the subsections for POST command
  1412.   pos = 0;
  1413.   while (FindSpliceAccepted(text, pos, pos, len, start, finish))
  1414.     text.Delete(pos, len);
  1415.   pos = 0;
  1416.   while (FindSpliceErrors(text, pos, pos, len, start, finish))
  1417.     text.Delete(pos, len);
  1418.   // See if are a subform, set root composite field accordingly
  1419.   PString prefix = request.url.GetQueryVars()("subformprefix");
  1420.   if (!prefix) {
  1421.     static PRegularExpression SubFormPrefix("<?!--#form[ trn]+subformprefix[ trn]*-->?",
  1422.                                             PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1423.     while (text.FindRegEx(SubFormPrefix, pos, len))
  1424.       text.Splice("subformprefix=" +
  1425.                   PURL::TranslateString(prefix, PURL::QueryTranslation),
  1426.                   pos, len);
  1427.     field = fields.LocateName(prefix);
  1428.     if (field != NULL) {
  1429.       finish = P_MAX_INDEX;
  1430.       field->ExpandFieldNames(text, 0, finish);
  1431.     }
  1432.   }
  1433.   // Locate <!--#form array name--> macros and expand them
  1434.   static PRegularExpression ArrayRegEx("<!--#form[ trn]+array[ trn]+[^-]+-->",
  1435.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1436.   static PRegularExpression EndBlock("<?!--#form[ trn]+end[ trn]+[^-]+-->?",
  1437.                                      PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1438.   pos = len = 0;
  1439.   while (FindSpliceField(ArrayRegEx, EndBlock, text, pos+len, fields, pos, len, start, finish, field)) {
  1440.     if (start != finish && field != NULL)
  1441.       field->ExpandFieldNames(text, start, finish);
  1442.   }
  1443.   // Have now expanded all field names to be fully qualified
  1444.   static PRegularExpression HTMLRegEx("<!--#form[ trn]+html[ trn]+[^-]+-->",
  1445.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1446.   while (FindSpliceField(HTMLRegEx, "", text, 0, fields, pos, len, start, finish, field)) {
  1447.     if (field != NULL) {
  1448.       PHTML html(PHTML::InForm);
  1449.       field->GetHTMLTag(html);
  1450.       text.Splice(html, pos, len);
  1451.     }
  1452.   }
  1453.   pos = len = 0;
  1454.   static PRegularExpression ValueRegEx("<!--#form[ trn]+value[ trn]+[^-]+-->",
  1455.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1456.   while (FindSpliceField(ValueRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
  1457.     if (field != NULL)
  1458.       text.Splice(field->GetValue(), pos, len);
  1459.   }
  1460.   pos = len = 0;
  1461.   static PRegularExpression InputRegEx("<input[ trn][^>]*name[ trn]*=[ trn]*"[^"]*"[^>]*>",
  1462.                                        PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1463.   while (FindSpliceField(InputRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
  1464.     if (field != NULL) {
  1465.       static PRegularExpression HiddenRegEx("type[ trn]*=[ trn]*"?hidden"?",
  1466.                                             PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1467.       PString substr = text.Mid(pos, len);
  1468.       if (substr.FindRegEx(HiddenRegEx) == P_MAX_INDEX)
  1469.         text.Splice(field->GetHTMLInput(substr), pos, len);
  1470.     }
  1471.   }
  1472.   pos = len = 0;
  1473.   static PRegularExpression SelectRegEx("<select[ trn][^>]*name[ trn]*=[ trn]*"[^"]*"[^>]*>",
  1474.                                         PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1475.   static PRegularExpression SelEndRegEx("</select[^>]*>",
  1476.                                         PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1477.   while (FindSpliceField(SelectRegEx, SelEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
  1478.     if (field != NULL)
  1479.       text.Splice(field->GetHTMLSelect(text(start, finish)), start, finish-start+1);
  1480.   }
  1481.   pos = len = 0;
  1482.   static PRegularExpression TextRegEx("<textarea[ trn][^>]*name[ trn]*=[ trn]*"[^"]*"[^>]*>",
  1483.                                       PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1484.   static PRegularExpression TextEndRegEx("</textarea[^>]*>", PRegularExpression::IgnoreCase);
  1485.   while (FindSpliceField(TextRegEx, TextEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
  1486.     if (field != NULL)
  1487.       text.Splice(field->GetValue(), start, finish-start+1);
  1488.   }
  1489. }
  1490. PHTTPField * PHTTPForm::Add(PHTTPField * fld)
  1491. {
  1492.   PAssertNULL(fld);
  1493.   PAssert(!fieldNames[fld->GetName()], "Field already on form!");
  1494.   fieldNames += fld->GetName();
  1495.   fields.Append(fld);
  1496.   return fld;
  1497. }
  1498. void PHTTPForm::BuildHTML(const char * heading)
  1499. {
  1500.   PHTML html(heading);
  1501.   BuildHTML(html);
  1502. }
  1503. void PHTTPForm::BuildHTML(const PString & heading)
  1504. {
  1505.   PHTML html(heading);
  1506.   BuildHTML(html);
  1507. }
  1508. void PHTTPForm::BuildHTML(PHTML & html, BuildOptions option)
  1509. {
  1510.   if (!html.Is(PHTML::InForm))
  1511.     html << PHTML::Form("POST");
  1512.   html << PHTML::TableStart();
  1513.   for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
  1514.     PHTTPField & field = fields[fld];
  1515.     if (field.NotYetInHTML()) {
  1516.       html << PHTML::TableRow()
  1517.            << PHTML::TableData("align=right")
  1518.            << field.GetTitle()
  1519.            << PHTML::TableData("align=left")
  1520.            << "<!--#form html " << field.GetName() << "-->"
  1521.            << PHTML::TableData()
  1522.            << field.GetHelp();
  1523.       field.SetInHTML();
  1524.     }
  1525.   }
  1526.   html << PHTML::TableEnd();
  1527.   if (option != InsertIntoForm)
  1528.     html << PHTML::Paragraph()
  1529.          << ' ' << PHTML::SubmitButton("Accept")
  1530.          << ' ' << PHTML::ResetButton("Reset")
  1531.          << PHTML::Form();
  1532.   if (option == CompleteHTML) {
  1533.     html << PHTML::Body();
  1534.     string = html;
  1535.   }
  1536. }
  1537. BOOL PHTTPForm::Post(PHTTPRequest & request,
  1538.                      const PStringToString & data,
  1539.                      PHTML & msg)
  1540. {
  1541.   PString prefix = request.url.GetQueryVars()("subformprefix");
  1542.   const PHTTPField * field = NULL;
  1543.   if (!prefix)
  1544.     field = fields.LocateName(prefix);
  1545.   if (field == NULL)
  1546.     field = &fields;
  1547.   PStringStream errors;
  1548.   if (field->ValidateAll(data, errors)) {
  1549.     ((PHTTPField *)field)->SetAllValues(data);
  1550.     if (msg.IsEmpty())
  1551.       msg = "Accepted New Configuration";
  1552.     else {
  1553.       PString block;
  1554.       PINDEX pos = 0;
  1555.       PINDEX len, start, finish;
  1556.       while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
  1557.         msg.Splice(msg(start, finish), pos, len);
  1558.       pos = 0;
  1559.       while (FindSpliceErrors(msg, pos, pos, len, start, finish))
  1560.         msg.Delete(pos, len);
  1561.     }
  1562.   }
  1563.   else {
  1564.     request.code = PHTTP::BadRequest;
  1565.     if (msg.IsEmpty()) {
  1566.       msg = "Validation Error in Request";
  1567.       msg << errors;
  1568.     }
  1569.     else {
  1570.       PINDEX pos = 0;
  1571.       PINDEX len, start, finish;
  1572.       while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
  1573.         msg.Delete(pos, len);
  1574.       BOOL appendErrors = TRUE;
  1575.       pos = 0;
  1576.       while (FindSpliceErrors(msg, pos, pos, len, start, finish)) {
  1577.         PString block = msg(start, finish);
  1578.         PINDEX vPos, vLen;
  1579.         static PRegularExpression Validation("<?!--#form[ trn]+validation[ trn]*-->?",
  1580.                                              PRegularExpression::Extended|PRegularExpression::IgnoreCase);
  1581.         if (block.FindRegEx(Validation, vPos, vLen))
  1582.           block.Splice(errors, vPos, vLen);
  1583.         else
  1584.           block += errors;
  1585.         msg.Splice(block, pos, len);
  1586.         appendErrors = FALSE;
  1587.       }
  1588.       if (appendErrors)
  1589.         msg << errors;
  1590.     }
  1591.   }
  1592.   return TRUE;
  1593. }
  1594. //////////////////////////////////////////////////////////////////////////////
  1595. // PHTTPConfig
  1596. PHTTPConfig::PHTTPConfig(const PURL & url,
  1597.                          const PString & sect)
  1598.   : PHTTPForm(url), section(sect)
  1599. {
  1600.   Construct();
  1601. }
  1602. PHTTPConfig::PHTTPConfig(const PURL & url,
  1603.                          const PString & sect,
  1604.                          const PHTTPAuthority & auth)
  1605.   : PHTTPForm(url, auth), section(sect)
  1606. {
  1607.   Construct();
  1608. }
  1609. PHTTPConfig::PHTTPConfig(const PURL & url,
  1610.                          const PString & html,
  1611.                          const PString & sect)
  1612.   : PHTTPForm(url, html), section(sect)
  1613. {
  1614.   Construct();
  1615. }
  1616. PHTTPConfig::PHTTPConfig(const PURL & url,
  1617.                          const PString & html,
  1618.                          const PString & sect,
  1619.                          const PHTTPAuthority & auth)
  1620.   : PHTTPForm(url, html, auth), section(sect)
  1621. {
  1622.   Construct();
  1623. }
  1624. void PHTTPConfig::Construct()
  1625. {
  1626.   sectionField = NULL;
  1627.   keyField = NULL;
  1628.   valField = NULL;
  1629. }
  1630. void PHTTPConfig::LoadFromConfig()
  1631. {
  1632.   PConfig cfg(section);
  1633.   fields.LoadFromConfig(cfg);
  1634. }
  1635. void PHTTPConfig::OnLoadedText(PHTTPRequest & request, PString & text)
  1636. {
  1637.   if (sectionField == NULL) {
  1638.     PString sectionName = request.url.GetQueryVars()("section", section);
  1639.     if (!sectionName) {
  1640.       section = sectionName;
  1641.       LoadFromConfig();
  1642.     }
  1643.   }
  1644.   PHTTPForm::OnLoadedText(request, text);
  1645. }
  1646. BOOL PHTTPConfig::Post(PHTTPRequest & request,
  1647.                        const PStringToString & data,
  1648.                        PHTML & msg)
  1649. {
  1650.   // Make sure the internal structure is up to date before accepting new data
  1651.   if (!section)
  1652.     LoadFromConfig();
  1653.   PSortedStringList oldValues;
  1654.   // Remember fields that are here now, so can delete removed array fields
  1655.   PINDEX fld;
  1656.   for (fld = 0; fld < fields.GetSize(); fld++) {
  1657.     PHTTPField & field = fields[fld];
  1658.     if (&field != keyField && &field != valField && &field != sectionField) {
  1659.       PStringList names = field.GetAllNames();
  1660.       for (PINDEX i = 0; i < names.GetSize(); i++)
  1661.         oldValues.AppendString(names[i]);
  1662.     }
  1663.   }
  1664.   PHTTPForm::Post(request, data, msg);
  1665.   if (request.code != PHTTP::OK)
  1666.     return TRUE;
  1667.   if (sectionField != NULL)
  1668.     section = sectionPrefix + sectionField->GetValue() + sectionSuffix;
  1669.   PString sectionName = request.url.GetQueryVars()("section", section);
  1670.   if (sectionName.IsEmpty())
  1671.     return TRUE;
  1672.   PConfig cfg(sectionName);
  1673.   for (fld = 0; fld < fields.GetSize(); fld++) {
  1674.     PHTTPField & field = fields[fld];
  1675.     if (&field == keyField) {
  1676.       PString key = field.GetValue();
  1677.       if (!key)
  1678.         cfg.SetString(key, valField->GetValue());
  1679.     }
  1680.     else if (&field != valField && &field != sectionField)
  1681.       field.SaveToConfig(cfg);
  1682.   }
  1683.   // Find out which fields have been removed (arrays elements deleted)
  1684.   for (fld = 0; fld < fields.GetSize(); fld++) {
  1685.     PHTTPField & field = fields[fld];
  1686.     if (&field != keyField && &field != valField && &field != sectionField) {
  1687.       PStringList names = field.GetAllNames();
  1688.       for (PINDEX i = 0; i < names.GetSize(); i++) {
  1689.         PINDEX idx = oldValues.GetStringsIndex(names[i]);
  1690.         if (idx != P_MAX_INDEX)
  1691.           oldValues.RemoveAt(idx);
  1692.       }
  1693.     }
  1694.   }
  1695.   for (fld = 0; fld < oldValues.GetSize(); fld++) {
  1696.     PString section, key;
  1697.     switch (SplitConfigKey(oldValues[fld], section, key)) {
  1698.       case 1 :
  1699.         cfg.DeleteKey(key);
  1700.         break;
  1701.       case 2 :
  1702.         cfg.DeleteKey(section, key);
  1703.         if (cfg.GetKeys(section).IsEmpty())
  1704.           cfg.DeleteSection(section);
  1705.     }
  1706.   }
  1707.   section = sectionName;
  1708.   return TRUE;
  1709. }
  1710. PHTTPField * PHTTPConfig::AddSectionField(PHTTPField * sectionFld,
  1711.                                           const char * prefix,
  1712.                                           const char * suffix)
  1713. {
  1714.   sectionField = PAssertNULL(sectionFld);
  1715.   PAssert(!sectionField->IsDescendant(PHTTPCompositeField::Class()), "Section field is composite");
  1716.   Add(sectionField);
  1717.   if (prefix != NULL)
  1718.     sectionPrefix = prefix;
  1719.   if (suffix != NULL)
  1720.     sectionSuffix = suffix;
  1721.   return sectionField;
  1722. }
  1723. void PHTTPConfig::AddNewKeyFields(PHTTPField * keyFld,
  1724.                                   PHTTPField * valFld)
  1725. {
  1726.   keyField = PAssertNULL(keyFld);
  1727.   Add(keyFld);
  1728.   valField = PAssertNULL(valFld);
  1729.   Add(valFld);
  1730. }
  1731. //////////////////////////////////////////////////////////////////////////////
  1732. // PHTTPConfigSectionList
  1733. static const char FormListInclude[] = "<!--#form pagelist-->";
  1734. PHTTPConfigSectionList::PHTTPConfigSectionList(const PURL & url,
  1735.                                                const PHTTPAuthority & auth,
  1736.                                                const PString & prefix,
  1737.                                                const PString & valueName,
  1738.                                                const PURL & editSection,
  1739.                                                const PURL & newSection,
  1740.                                                const PString & newTitle,
  1741.                                                PHTML & heading)
  1742.   : PHTTPString(url, auth),
  1743.     sectionPrefix(prefix),
  1744.     additionalValueName(valueName),
  1745.     newSectionLink(newSection.AsString(PURL::URIOnly)),
  1746.     newSectionTitle(newTitle),
  1747.     editSectionLink(editSection.AsString(PURL::URIOnly) +
  1748.                       "?section=" + PURL::TranslateString(prefix, PURL::QueryTranslation))
  1749. {
  1750.   if (heading.Is(PHTML::InBody))
  1751.     heading << FormListInclude << PHTML::Body();
  1752.   SetString(heading);
  1753. }
  1754. void PHTTPConfigSectionList::OnLoadedText(PHTTPRequest &, PString & text)
  1755. {
  1756.   PConfig cfg;
  1757.   PStringList nameList = cfg.GetSections();
  1758.   PINDEX pos = text.Find(FormListInclude);
  1759.   if (pos != P_MAX_INDEX) {
  1760.     PINDEX endpos = text.Find(FormListInclude, pos + sizeof(FormListInclude)-1);
  1761.     if (endpos == P_MAX_INDEX) {
  1762.       PHTML html(PHTML::InBody);
  1763.       html << PHTML::Form("POST") << PHTML::TableStart();
  1764.       PINDEX i;
  1765.       for (i = 0; i < nameList.GetSize(); i++) {
  1766.         if (nameList[i].Find(sectionPrefix) == 0) {
  1767.           PString name = nameList[i].Mid(sectionPrefix.GetLength());
  1768.           html << PHTML::TableRow()
  1769.                << PHTML::TableData()
  1770.                << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
  1771.                << name
  1772.                << PHTML::HotLink();
  1773.           if (!additionalValueName)
  1774.             html << PHTML::TableData()
  1775.                  << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
  1776.                  << cfg.GetString(nameList[i], additionalValueName, "")
  1777.                  << PHTML::HotLink();
  1778.           html << PHTML::TableData() << PHTML::SubmitButton("Remove", name);
  1779.         }
  1780.       }
  1781.       html << PHTML::TableRow()
  1782.            << PHTML::TableData()
  1783.            << PHTML::HotLink(newSectionLink)
  1784.            << newSectionTitle
  1785.            << PHTML::HotLink()
  1786.            << PHTML::TableEnd()
  1787.            << PHTML::Form();
  1788.       text.Splice(html, pos, sizeof(FormListInclude)-1);
  1789.     }
  1790.     else {
  1791.       PString repeat = text(pos + sizeof(FormListInclude)-1, endpos-1);
  1792.       text.Delete(pos, endpos - pos);
  1793.       PINDEX i;
  1794.       for (i = 0; i < nameList.GetSize(); i++) {
  1795.         if (nameList[i].Find(sectionPrefix) == 0) {
  1796.           PString name = nameList[i].Mid(sectionPrefix.GetLength());
  1797.           text.Splice(repeat, pos, 0);
  1798.           text.Replace("<!--#form hotlink-->",
  1799.                        editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation),
  1800.                        TRUE, pos);
  1801.           if (!additionalValueName)
  1802.             text.Replace("<!--#form additional-->",
  1803.                          cfg.GetString(nameList[i], additionalValueName, ""),
  1804.                          TRUE, pos);
  1805.           text.Replace("<!--#form section-->", name, TRUE, pos);
  1806.           pos = text.Find(FormListInclude, pos);
  1807.         }
  1808.       }
  1809.       text.Delete(text.Find(FormListInclude, pos), sizeof(FormListInclude)-1);
  1810.     }
  1811.   }
  1812. }
  1813. BOOL PHTTPConfigSectionList::Post(PHTTPRequest &,
  1814.                                   const PStringToString & data,
  1815.                                   PHTML & replyMessage)
  1816. {
  1817.   PConfig cfg;
  1818.   PStringList nameList = cfg.GetSections();
  1819.   PINDEX i; 
  1820.   for (i = 0; i < nameList.GetSize(); i++) {
  1821.     if (nameList[i].Find(sectionPrefix) == 0) {
  1822.       PString name = nameList[i].Mid(sectionPrefix.GetLength());
  1823.       if (data.Contains(name)) {
  1824.         cfg.DeleteSection(nameList[i]);
  1825.         replyMessage << name << " removed.";
  1826.       }
  1827.     }
  1828.   }
  1829.   return TRUE;
  1830. }
  1831. // End Of File ///////////////////////////////////////////////////////////////