Many and various changes to support new Visual C++ 2003
[pwlib.git] / src / ptclib / httpform.cxx
blob795487d11c0c7a8624e59a60ee73b0fe67c9459c
1 /*
2 * httpform.cxx
4 * Forms using HTTP user interface.
6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
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/
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.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.47 2003/03/24 04:31:03 robertj
28 * Added function to set and get strings from PConfig in correct format for
29 * use with HTTP form array contsructs.
31 * Revision 1.46 2002/11/22 06:20:26 robertj
32 * Added extra space around data entry fields.
33 * Added borders around arrays and composite fields.
34 * Added multi-line data entry for HTTPStringField > 128 characters.
36 * Revision 1.45 2002/11/06 22:47:25 robertj
37 * Fixed header comment (copyright etc)
39 * Revision 1.44 2002/10/10 04:43:44 robertj
40 * VxWorks port, thanks Martijn Roest
42 * Revision 1.43 2002/07/17 08:44:58 robertj
43 * Added links back to page and home page on accepted data html.
44 * Fixed display of validation error text if page not accepted.
46 * Revision 1.42 2001/10/10 08:07:48 robertj
47 * Fixed large memory leak of strings when doing POST to a form.
49 * Revision 1.41 2001/05/16 06:03:14 craigs
50 * Changed to allow access to absolute registry paths from within subforms
52 * Revision 1.40 2001/02/07 04:44:47 robertj
53 * Added ability to use check box to add/delete fields from arrays.
55 * Revision 1.39 2001/01/08 04:13:23 robertj
56 * Fixed bug with skipping every second option in determining the selected
57 * option in a SELECT field. No longer requires a </option> to work.
59 * Revision 1.38 2000/12/20 02:23:39 robertj
60 * Fixed variable array size value (caused extra blank entry ever commit).
62 * Revision 1.37 2000/12/18 12:13:08 robertj
63 * Fixed bug in auto-generated HTML in fixed size arrays, should not have add/delete box.
65 * Revision 1.36 2000/12/18 11:41:01 robertj
66 * Fixed bug in auto-generated HTML in non-array composite fields
68 * Revision 1.35 2000/12/18 07:14:30 robertj
69 * Added ability to have fixed length array fields.
70 * Fixed regular expressions so can have single '-' in field name.
71 * Fixed use of non-array subforprefix based compsite fields.
73 * Revision 1.34 2000/12/12 07:21:35 robertj
74 * Added ability to expand fields based on regex into repeated chunks of HTML.
76 * Revision 1.33 2000/11/02 21:55:28 craigs
77 * Added extra constructor
79 * Revision 1.32 2000/09/05 09:52:24 robertj
80 * Fixed bug in HTTP form updating SELECT fields from registry.
82 * Revision 1.31 2000/06/19 11:35:01 robertj
83 * Fixed bug in setting current value of options in select form fields.
85 * Revision 1.30 1999/02/10 13:19:45 robertj
86 * Fixed PConfig update problem when POSTing to the form. Especiall with arrays.
88 * Revision 1.29 1998/11/30 04:51:57 robertj
89 * New directory structure
91 * Revision 1.28 1998/11/14 11:11:06 robertj
92 * PPC GNU compiler compatibility.
94 * Revision 1.27 1998/10/01 09:05:11 robertj
95 * Fixed bug in nested composite field names, array indexes not being set correctly.
97 * Revision 1.26 1998/09/23 06:22:11 robertj
98 * Added open source copyright license.
100 * Revision 1.25 1998/08/20 05:51:06 robertj
101 * Fixed bug where substitutions did not always occur if near end of macro block.
102 * Improved internationalisation. Allow HTML override of strings in macros.
104 * Revision 1.24 1998/08/09 11:25:51 robertj
105 * GNU C++ warning removal.
107 * Revision 1.23 1998/08/09 10:35:11 robertj
108 * Changed array control so can have language override.
110 * Revision 1.22 1998/07/24 06:56:05 robertj
111 * Fixed case significance problem in HTTP forms.
112 * Improved detection of VALUE= fields with and without quotes.
114 * Revision 1.21 1998/03/20 03:16:43 robertj
115 * Fixed bug in beaing able to reset a check box field.
117 * Revision 1.20 1998/02/03 06:26:09 robertj
118 * Fixed propagation of inital values in arrays subfields.
119 * Fixed problem where hidden fields were being relaced with default values from PHTTPForm.
121 * Revision 1.19 1998/01/26 02:49:17 robertj
122 * GNU support.
124 * Revision 1.18 1998/01/26 01:51:37 robertj
125 * Fixed uninitialised variable.
127 * Revision 1.17 1998/01/26 00:25:25 robertj
128 * Major rewrite of HTTP forms management.
130 * Revision 1.16 1997/12/18 05:06:51 robertj
131 * Added missing braces to kill GNU compiler warning.
133 * Revision 1.15 1997/10/10 10:43:43 robertj
134 * Fixed bug in password encryption, missing string terminator.
136 * Revision 1.14 1997/08/28 12:48:29 robertj
137 * Changed array fields to allow for reordering.
139 * Revision 1.13 1997/08/21 12:44:10 robertj
140 * Fixed bug in HTTP form array size field.
141 * Fixed bug where section list was only replacing first instance of macro.
143 * Revision 1.12 1997/08/09 07:46:52 robertj
144 * Fixed problems with value of SELECT fields in form
146 * Revision 1.11 1997/08/04 10:41:13 robertj
147 * Fixed bug in new section list page for names with special characters in them.
149 * Revision 1.10 1997/07/26 11:38:20 robertj
150 * Support for overridable pages in HTTP service applications.
152 * Revision 1.9 1997/07/14 11:49:51 robertj
153 * Put "Add" and "Keep" on check boxes in array fields.
155 * Revision 1.8 1997/07/08 13:12:29 robertj
156 * Major HTTP form enhancements for lists and arrays of fields.
158 * Revision 1.7 1997/06/08 04:47:27 robertj
159 * Adding new llist based form field.
161 * Revision 1.6 1997/04/12 02:07:26 robertj
162 * Fixed boolean check boxes being more flexible on string values.
164 * Revision 1.5 1997/04/01 06:00:53 robertj
165 * Changed PHTTPConfig so if section empty string, does not write PConfig parameters.
167 * Revision 1.4 1996/10/08 13:10:34 robertj
168 * Fixed bug in boolean (checkbox) html forms, cannot be reset.
170 * Revision 1.3 1996/09/14 13:09:31 robertj
171 * Major upgrade:
172 * rearranged sockets to help support IPX.
173 * added indirect channel class and moved all protocols to descend from it,
174 * separating the protocol from the low level byte transport.
176 * Revision 1.2 1996/08/08 13:34:10 robertj
177 * Removed redundent call.
179 * Revision 1.1 1996/06/28 12:56:20 robertj
180 * Initial revision
184 #ifdef __GNUC__
185 #pragma implementation "httpform.h"
186 #endif
188 #include <ptlib.h>
189 #include <ptclib/httpform.h>
190 #include <ptclib/cypher.h>
193 //////////////////////////////////////////////////////////////////////////////
194 // PHTTPField
196 PHTTPField::PHTTPField(const char * nam, const char * titl, const char * hlp)
197 : baseName(nam), fullName(nam),
198 title(titl != NULL ? titl : nam),
199 help(hlp != NULL ? hlp : "")
201 notInHTML = TRUE;
205 PObject::Comparison PHTTPField::Compare(const PObject & obj) const
207 PAssert(obj.IsDescendant(PHTTPField::Class()), PInvalidCast);
208 return fullName.Compare(((const PHTTPField &)obj).fullName);
212 void PHTTPField::SetName(const PString & newName)
214 fullName = newName;
218 const PHTTPField * PHTTPField::LocateName(const PString & name) const
220 if (fullName == name)
221 return this;
223 return NULL;
227 void PHTTPField::SetHelp(const PString & hotLinkURL,
228 const PString & linkText)
230 help = "<A HREF=\"" + hotLinkURL + "\">" + linkText + "</A>\r\n";
234 void PHTTPField::SetHelp(const PString & hotLinkURL,
235 const PString & imageURL,
236 const PString & imageText)
238 help = "<A HREF=\"" + hotLinkURL + "\"><IMG SRC=\"" +
239 imageURL + "\" ALT=\"" + imageText + "\" ALIGN=absmiddle></A>\r\n";
243 static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
244 const PRegularExpression & endExpr,
245 const PString & text,
246 PINDEX offset,
247 PINDEX & pos,
248 PINDEX & len,
249 PINDEX & start,
250 PINDEX & finish)
252 start = finish = P_MAX_INDEX;
254 if (!text.FindRegEx(startExpr, pos, len, offset))
255 return FALSE;
257 PINDEX endpos, endlen;
258 if (!text.FindRegEx(endExpr, endpos, endlen, pos+len))
259 return TRUE;
261 start = pos + len;
262 finish = endpos - 1;
263 len = endpos - pos + endlen;
264 return TRUE;
268 static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
269 const PString & text,
270 PINDEX offset,
271 PINDEX & pos,
272 PINDEX & len,
273 PINDEX & start,
274 PINDEX & finish)
276 static PRegularExpression EndBlock("<?!--#form[ \t\r\n]+end[ \t\r\n]*-->?",
277 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
278 return FindSpliceBlock(startExpr, EndBlock, text, offset, pos, len, start, finish);
282 static BOOL FindSpliceName(const PCaselessString & text,
283 PINDEX start,
284 PINDEX finish,
285 PINDEX & pos,
286 PINDEX & end)
288 if (text[start+1] != '!') {
289 static PRegularExpression NameExpr("name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"",
290 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
291 if ((pos = text.FindRegEx(NameExpr, start)) == P_MAX_INDEX)
292 return FALSE;
294 if (pos >= finish)
295 return FALSE;
297 pos = text.Find('"', pos) + 1;
298 end = text.Find('"', pos) - 1;
300 else {
301 pos = start + 9; // Skip over the <!--#form
302 while (isspace(text[pos])) // Skip over blanks
303 pos++;
304 while (pos < finish && !isspace(text[pos])) // Skip over keyword
305 pos++;
306 while (isspace(text[pos])) // Skip over more blanks
307 pos++;
309 end = text.Find("--", pos) - 1;
312 return end < finish;
316 static BOOL FindSpliceFieldName(const PString & text,
317 PINDEX offset,
318 PINDEX & pos,
319 PINDEX & len,
320 PString & name)
322 static PRegularExpression FieldName("<?!--#form[ \t\r\n]+[a-z0-9]+[ \t\r\n]+(-?[^-])+-->?"
324 "<[a-z]+[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
325 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
326 if (!text.FindRegEx(FieldName, pos, len, offset))
327 return FALSE;
329 PINDEX nameStart, nameEnd;
330 if (!FindSpliceName(text, pos, pos+len-1, nameStart, nameEnd))
331 return FALSE;
333 name = text(nameStart, nameEnd);
334 pos = nameStart;
335 len = nameEnd - nameStart + 1;
336 return TRUE;
340 static void SpliceAdjust(const PString & str,
341 PString & text,
342 PINDEX pos,
343 PINDEX & len,
344 PINDEX & finish)
346 text.Splice(str, pos, len);
347 PINDEX newLen = str.GetLength();
348 if (finish != P_MAX_INDEX)
349 finish += newLen - len;
350 len = newLen;
354 void PHTTPField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
356 PString name;
357 PINDEX pos, len;
358 while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
359 if (pos > finish)
360 break;
361 if (baseName == name)
362 SpliceAdjust(fullName, text, pos, len, finish);
363 start = pos + len;
368 static BOOL FindInputValue(const PString & text, PINDEX & before, PINDEX & after)
370 static PRegularExpression Value("value[ \t\r\n]*=[ \t\r\n]*(\"[^\"]*\"|[^> \t\r\n]+)",
371 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
372 PINDEX pos = text.FindRegEx(Value);
373 if (pos == P_MAX_INDEX)
374 return FALSE;
376 before = text.Find('"', pos);
377 if (before != P_MAX_INDEX)
378 after = text.Find('"', before+1);
379 else {
380 before = text.Find('=', pos);
381 while (isspace(text[before+1]))
382 before++;
383 after = before + 1;
384 while (text[after] != '\0' && text[after] != '>' && !isspace(text[after]))
385 after++;
387 return TRUE;
391 PString PHTTPField::GetHTMLInput(const PString & input) const
393 PINDEX before, after;
394 if (FindInputValue(input, before, after))
395 return input(0, before) + GetValue(FALSE) + input.Mid(after);
397 return "<input value=\"" + GetValue(FALSE) + "\"" + input.Mid(6);
401 static void AdjustSelectOptions(PString & text, PINDEX begin, PINDEX end,
402 const PString & myValue, PStringList & validValues,
403 PINDEX & finishAdjust)
405 PINDEX start, finish;
406 PINDEX pos = begin;
407 PINDEX len = 0;
408 static PRegularExpression StartOption("<[ \t\r\n]*option[^>]*>",
409 PRegularExpression::IgnoreCase);
410 static PRegularExpression EndOption("<[ \t\r\n]*/?option[^>]*>",
411 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
412 while (FindSpliceBlock(StartOption, EndOption, text, pos+len, pos, len, start, finish) && pos < end) {
413 if (start == P_MAX_INDEX)
414 start = text.Find('>', pos)+1;
415 else {
416 // Check for if option was not closed by </option> but another <option>
417 PINDEX optpos = text.FindRegEx(StartOption, start);
418 if (optpos < pos+len) // Adjust back to before <option> if so.
419 len = optpos-pos;
421 PCaselessString option = text(pos, start-1);
422 PINDEX before, after;
423 if (FindInputValue(option, before, after)) {
424 start = pos + before + 1;
425 finish = pos + after - 1;
427 PINDEX selpos = option.Find("selected");
428 PString thisValue = text(start, finish).Trim();
429 if (thisValue == myValue) {
430 if (selpos == P_MAX_INDEX) {
431 text.Splice(" selected", pos+7, 0);
432 if (finishAdjust != P_MAX_INDEX)
433 finishAdjust += 9;
434 if (end != P_MAX_INDEX)
435 end += 9;
436 len += 9;
439 else {
440 if (validValues.GetSize() > 0) {
441 PINDEX valid;
442 for (valid = 0; valid < validValues.GetSize(); valid++) {
443 if (thisValue == validValues[valid])
444 break;
446 if (valid >= validValues.GetSize()) {
447 text.Delete(pos, len);
448 selpos = P_MAX_INDEX;
449 if (finishAdjust != P_MAX_INDEX)
450 finishAdjust -= len;
451 if (end != P_MAX_INDEX)
452 end -= len;
453 len = 0;
456 if (selpos != P_MAX_INDEX) {
457 selpos += pos;
458 PINDEX sellen = 8;
459 if (text[selpos-1] == ' ') {
460 selpos--;
461 sellen++;
463 text.Delete(selpos, sellen);
464 if (finishAdjust != P_MAX_INDEX)
465 finishAdjust -= sellen;
466 if (end != P_MAX_INDEX)
467 end -= sellen;
468 len -= sellen;
474 PString PHTTPField::GetHTMLSelect(const PString & selection) const
476 PString text = selection;
477 PStringList dummy1;
478 PINDEX dummy2 = P_MAX_INDEX;
479 AdjustSelectOptions(text, 0, P_MAX_INDEX, GetValue(FALSE), dummy1, dummy2);
480 return text;
484 void PHTTPField::GetHTMLHeading(PHTML &) const
489 static int SplitConfigKey(const PString & fullName,
490 PString & section, PString & key)
492 if (fullName.IsEmpty())
493 return 0;
495 PINDEX slash = fullName.FindLast('\\');
496 if (slash == 0 || slash >= fullName.GetLength()-1) {
497 key = fullName;
498 return 1;
501 section = fullName.Left(slash);
502 key = fullName.Mid(slash+1);
503 if (section.IsEmpty() || key.IsEmpty())
504 return 0;
506 return 2;
510 void PHTTPField::LoadFromConfig(PConfig & cfg)
512 PString section, key;
513 switch (SplitConfigKey(fullName, section, key)) {
514 case 1 :
515 SetValue(cfg.GetString(key, GetValue(TRUE)));
516 break;
517 case 2 :
518 SetValue(cfg.GetString(section, key, GetValue(TRUE)));
523 void PHTTPField::SaveToConfig(PConfig & cfg) const
525 PString section, key;
526 switch (SplitConfigKey(fullName, section, key)) {
527 case 1 :
528 cfg.SetString(key, GetValue());
529 break;
530 case 2 :
531 cfg.SetString(section, key, GetValue());
536 BOOL PHTTPField::Validated(const PString &, PStringStream &) const
538 return TRUE;
542 void PHTTPField::GetAllNames(PStringList & list) const
544 list.AppendString(fullName);
548 void PHTTPField::SetAllValues(const PStringToString & data)
550 if (!baseName && data.Contains(fullName))
551 SetValue(data[fullName]);
555 BOOL PHTTPField::ValidateAll(const PStringToString & data, PStringStream & msg) const
557 if (data.Contains(fullName))
558 return Validated(data[fullName], msg);
559 return TRUE;
563 //////////////////////////////////////////////////////////////////////////////
564 // PHTTPCompositeField
566 PHTTPCompositeField::PHTTPCompositeField(const char * nam,
567 const char * titl,
568 const char * hlp)
569 : PHTTPField(nam, titl, hlp)
574 void PHTTPCompositeField::SetName(const PString & newName)
576 if (fullName.IsEmpty() || newName.IsEmpty())
577 return;
579 for (PINDEX i = 0; i < fields.GetSize(); i++) {
580 PHTTPField & field = fields[i];
582 PString firstPartOfName = psprintf(fullName, i+1);
583 PString subFieldName;
584 if (field.GetName().Find(firstPartOfName) == 0)
585 subFieldName = field.GetName().Mid(firstPartOfName.GetLength());
586 else
587 subFieldName = field.GetName();
589 firstPartOfName = psprintf(newName, i+1);
590 if (subFieldName[0] == '\\' || firstPartOfName[firstPartOfName.GetLength()-1] == '\\')
591 field.SetName(firstPartOfName + subFieldName);
592 else
593 field.SetName(firstPartOfName & subFieldName);
596 PHTTPField::SetName(newName);
600 const PHTTPField * PHTTPCompositeField::LocateName(const PString & name) const
602 if (fullName == name)
603 return this;
605 for (PINDEX i = 0; i < fields.GetSize(); i++) {
606 const PHTTPField * field = fields[i].LocateName(name);
607 if (field != NULL)
608 return field;
611 return NULL;
615 PHTTPField * PHTTPCompositeField::NewField() const
617 PHTTPCompositeField * fld = new PHTTPCompositeField(baseName, title, help);
618 for (PINDEX i = 0; i < fields.GetSize(); i++)
619 fld->Append(fields[i].NewField());
620 return fld;
624 void PHTTPCompositeField::GetHTMLTag(PHTML & html) const
626 for (PINDEX i = 0; i < fields.GetSize(); i++) {
627 if (i != 0 && html.Is(PHTML::InTable))
628 html << PHTML::TableData("NOWRAP ALIGN=CENTER");
629 fields[i].GetHTMLTag(html);
634 PString PHTTPCompositeField::GetHTMLInput(const PString & input) const
636 return input;
640 void PHTTPCompositeField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
642 static PRegularExpression FieldName( "!--#form[ \t\r\n]+(-?[^-])+[ \t\r\n]+(-?[^-])+--"
644 "<[a-z]*[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
645 PRegularExpression::IgnoreCase);
647 PString name;
648 PINDEX pos, len;
649 while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
650 if (pos > finish)
651 break;
652 for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
653 if (fields[fld].GetBaseName() *= name) {
654 SpliceAdjust(fields[fld].GetName(), text, pos, len, finish);
655 break;
658 start = pos + len;
663 void PHTTPCompositeField::GetHTMLHeading(PHTML & html) const
665 html << PHTML::TableRow();
666 for (PINDEX i = 0; i < fields.GetSize(); i++)
667 html << PHTML::TableHeader() << fields[i].GetTitle();
671 PString PHTTPCompositeField::GetValue(BOOL dflt) const
673 PStringStream value;
674 for (PINDEX i = 0; i < fields.GetSize(); i++)
675 value << fields[i].GetValue(dflt) << '\n';
676 return value;
680 void PHTTPCompositeField::SetValue(const PString &)
682 PAssertAlways(PLogicError);
686 void PHTTPCompositeField::LoadFromConfig(PConfig & cfg)
688 SetName(fullName);
689 for (PINDEX i = 0; i < GetSize(); i++)
690 fields[i].LoadFromConfig(cfg);
694 void PHTTPCompositeField::SaveToConfig(PConfig & cfg) const
696 for (PINDEX i = 0; i < GetSize(); i++)
697 fields[i].SaveToConfig(cfg);
701 void PHTTPCompositeField::GetAllNames(PStringList & list) const
703 for (PINDEX i = 0; i < GetSize(); i++)
704 fields[i].GetAllNames(list);
708 void PHTTPCompositeField::SetAllValues(const PStringToString & data)
710 for (PINDEX i = 0; i < fields.GetSize(); i++)
711 fields[i].SetAllValues(data);
715 BOOL PHTTPCompositeField::ValidateAll(const PStringToString & data,
716 PStringStream & msg) const
718 for (PINDEX i = 0; i < fields.GetSize(); i++)
719 if (!fields[i].ValidateAll(data, msg))
720 return FALSE;
722 return TRUE;
726 PINDEX PHTTPCompositeField::GetSize() const
728 return fields.GetSize();
732 void PHTTPCompositeField::Append(PHTTPField * fld)
734 fields.Append(fld);
738 //////////////////////////////////////////////////////////////////////////////
739 // PHTTPSubForm
741 PHTTPSubForm::PHTTPSubForm(const PString & subForm,
742 const char * name,
743 const char * title,
744 PINDEX prim,
745 PINDEX sec)
746 : PHTTPCompositeField(name, title, NULL),
747 subFormName(subForm)
749 primary = prim;
750 secondary = sec;
754 PHTTPField * PHTTPSubForm::NewField() const
756 PHTTPCompositeField * fld = new PHTTPSubForm(subFormName, baseName, title, primary, secondary);
757 for (PINDEX i = 0; i < fields.GetSize(); i++)
758 fld->Append(fields[i].NewField());
759 return fld;
763 void PHTTPSubForm::GetHTMLTag(PHTML & html) const
765 PString value = fields[primary].GetValue();
766 if (value.IsEmpty())
767 value = "New";
768 html << PHTML::HotLink(subFormName +
769 "?subformprefix=" + PURL::TranslateString(fullName, PURL::QueryTranslation))
770 << value << PHTML::HotLink();
772 if (secondary != P_MAX_INDEX)
773 html << PHTML::TableData("NOWRAP") << fields[secondary].GetValue();
777 void PHTTPSubForm::GetHTMLHeading(PHTML &) const
782 //////////////////////////////////////////////////////////////////////////////
783 // PHTTPFieldArray
785 PHTTPFieldArray::PHTTPFieldArray(PHTTPField * fld, BOOL ordered, PINDEX fixedSize)
786 : PHTTPCompositeField(fld->GetName(), fld->GetTitle(), fld->GetHelp()),
787 baseField(fld)
789 orderedArray = ordered;
790 canAddElements = fixedSize == 0;
791 SetSize(fixedSize);
795 PHTTPFieldArray::~PHTTPFieldArray()
797 delete baseField;
801 void PHTTPFieldArray::SetSize(PINDEX newSize)
803 while (fields.GetSize() > newSize)
804 fields.RemoveAt(fields.GetSize()-1);
805 while (fields.GetSize() < newSize)
806 AddBlankField();
807 if (canAddElements)
808 AddBlankField();
812 PHTTPField * PHTTPFieldArray::NewField() const
814 return new PHTTPFieldArray(baseField->NewField(), orderedArray);
818 static const char ArrayControlBox[] = " Array Control";
819 static const char ArrayControlKeep[] = "Keep";
820 static const char ArrayControlRemove[] = "Remove";
821 static const char ArrayControlMoveUp[] = "Move Up";
822 static const char ArrayControlMoveDown[] = "Move Down";
823 static const char ArrayControlToTop[] = "To Top";
824 static const char ArrayControlToBottom[] = "To Bottom";
825 static const char ArrayControlIgnore[] = "Ignore";
826 static const char ArrayControlAddTop[] = "Add Top";
827 static const char ArrayControlAddBottom[] = "Add Bottom";
828 static const char ArrayControlAdd[] = "Add";
830 static PStringList GetArrayControlOptions(PINDEX fld, PINDEX size, BOOL orderedArray)
832 PStringList options;
834 if (fld >= size) {
835 options.AppendString(ArrayControlIgnore);
836 if (size == 0 || !orderedArray)
837 options.AppendString(ArrayControlAdd);
838 else {
839 options.AppendString(ArrayControlAddTop);
840 options.AppendString(ArrayControlAddBottom);
843 else {
844 options.AppendString(ArrayControlKeep);
845 options.AppendString(ArrayControlRemove);
846 if (orderedArray) {
847 if (fld > 0)
848 options.AppendString(ArrayControlMoveUp);
849 if (fld < size-1)
850 options.AppendString(ArrayControlMoveDown);
851 if (fld > 0)
852 options.AppendString(ArrayControlToTop);
853 if (fld < size-1)
854 options.AppendString(ArrayControlToBottom);
858 return options;
861 void PHTTPFieldArray::AddArrayControlBox(PHTML & html, PINDEX fld) const
863 PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
864 html << PHTML::Select(fields[fld].GetName() + ArrayControlBox);
865 for (PINDEX i = 0; i < options.GetSize(); i++)
866 html << PHTML::Option(i == 0 ? PHTML::Selected : PHTML::NotSelected) << options[i];
867 html << PHTML::Select();
871 void PHTTPFieldArray::GetHTMLTag(PHTML & html) const
873 html << PHTML::TableStart("border=1 cellspacing=0 cellpadding=8");
874 baseField->GetHTMLHeading(html);
875 for (PINDEX i = 0; i < fields.GetSize(); i++) {
876 html << PHTML::TableRow() << PHTML::TableData("NOWRAP");
877 fields[i].GetHTMLTag(html);
878 html << PHTML::TableData("NOWRAP");
879 if (canAddElements)
880 AddArrayControlBox(html, i);
882 html << PHTML::TableEnd();
886 void PHTTPFieldArray::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
888 PString original = text(start, finish);
889 PINDEX origFinish = finish;
890 PINDEX finalFinish = finish;
892 PINDEX fld = fields.GetSize();
893 while (fld > 0) {
894 fields[--fld].ExpandFieldNames(text, start, finish);
896 PINDEX pos,len;
897 static PRegularExpression RowNum("<?!--#form[ \t\r\n]+rownum[ \t\r\n]*-->?",
898 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
899 while (text.FindRegEx(RowNum, pos, len, start, finish))
900 SpliceAdjust(psprintf("%u", fld+1), text, pos, len, finish);
902 static PRegularExpression SubForm("<?!--#form[ \t\r\n]+subform[ \t\r\n]*-->?",
903 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
904 while (text.FindRegEx(SubForm, pos, len, start, finish)) {
905 PString fmt = fullName;
906 if (fmt.Find("%u") == P_MAX_INDEX)
907 fmt += " %u";
908 SpliceAdjust("subformprefix=" + PURL::TranslateString(psprintf(fmt, fld+1), PURL::QueryTranslation),
909 text, pos, len, finish);
912 static PRegularExpression RowControl("<?!--#form[ \t\r\n]+rowcontrol[ \t\r\n]*-->?",
913 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
914 while (text.FindRegEx(RowControl, pos, len, start, finish)) {
915 PHTML html(PHTML::InForm);
916 if (canAddElements)
917 AddArrayControlBox(html, fld);
918 SpliceAdjust(html, text, pos, len, finish);
921 static PRegularExpression RowCheck("<?!--#form[ \t\r\n]+row(add|delete)[ \t\r\n]*(-?[^-])*-->?",
922 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
923 while (text.FindRegEx(RowCheck, pos, len, start, finish)) {
924 PStringStream checkbox;
925 if (canAddElements) {
926 PINDEX titlepos = text.Find("row", start)+3;
927 BOOL adding = text[titlepos] == 'a';
928 if (( adding && fld >= fields.GetSize()-1) ||
929 (!adding && fld < fields.GetSize()-1)) {
930 titlepos += adding ? 3 : 6;
931 PINDEX dashes = text.Find("--", titlepos);
932 PString title = text(titlepos, dashes-1).Trim();
933 if (title.IsEmpty() && adding)
934 title = "Add";
935 checkbox << title
936 << "<INPUT TYPE=checkbox NAME=\""
937 << fields[fld].GetName()
938 << ArrayControlBox
939 << "\" VALUE="
940 << (adding ? ArrayControlAdd : ArrayControlRemove)
941 << '>';
944 SpliceAdjust(checkbox, text, pos, len, finish);
947 static PRegularExpression SelectRow("<select[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"!--#form[ \t\r\n]+rowselect[ \t\r\n]*--\"[^>]*>",
948 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
949 static PRegularExpression SelEndRegEx("</select[^>]*>",
950 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
951 PINDEX begin, end;
952 while (FindSpliceBlock(SelectRow, SelEndRegEx, text, 0, pos, len, begin, end)) {
953 PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
954 AdjustSelectOptions(text, begin, end, options[0], options, finish);
955 static PRegularExpression RowSelect("!--#form[ \t\r\n]+rowselect[ \t\r\n]*--",
956 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
957 if (text.FindRegEx(RowSelect, pos, len, pos, begin))
958 SpliceAdjust(fields[fld].GetName() + ArrayControlBox, text, pos, len, finish);
961 finalFinish += finish - origFinish;
963 if (fld > 0) {
964 text.Splice(original, start, 0);
965 finish = origFinish;
966 finalFinish += finish - start;
970 finish = finalFinish;
974 static int SplitArraySizeKey(const PString & fullName,
975 PString & section, PString & key)
977 static const char ArraySize[] = "Array Size";
978 PINDEX pos = fullName.Find("%u");
979 if (pos == P_MAX_INDEX)
980 return SplitConfigKey(fullName & ArraySize, section, key);
982 PINDEX endPos = fullName.GetLength() - 1;
983 if (fullName[endPos] == '\\')
984 endPos--;
985 return SplitConfigKey(fullName.Left(pos) & ArraySize & fullName(pos+2, endPos), section, key);
989 void PHTTPFieldArray::LoadFromConfig(PConfig & cfg)
991 if (canAddElements) {
992 PString section, key;
993 switch (SplitArraySizeKey(fullName, section, key)) {
994 case 1 :
995 SetSize(cfg.GetInteger(key, GetSize()));
996 break;
997 case 2 :
998 SetSize(cfg.GetInteger(section, key, GetSize()));
1001 PHTTPCompositeField::LoadFromConfig(cfg);
1005 void PHTTPFieldArray::SaveToConfig(PConfig & cfg) const
1007 if (canAddElements) {
1008 PString section, key;
1009 switch (SplitArraySizeKey(fullName, section, key)) {
1010 case 1 :
1011 cfg.SetInteger(key, GetSize());
1012 break;
1013 case 2 :
1014 cfg.SetInteger(section, key, GetSize());
1017 PHTTPCompositeField::SaveToConfig(cfg);
1021 void PHTTPFieldArray::SetArrayFieldName(PINDEX idx) const
1023 PString fmt = fullName;
1024 if (fmt.Find("%u") == P_MAX_INDEX)
1025 fmt += " %u";
1026 fields[idx].SetName(psprintf(fmt, idx+1));
1030 void PHTTPFieldArray::SetAllValues(const PStringToString & data)
1032 PHTTPFieldList newFields;
1033 newFields.DisallowDeleteObjects();
1034 PINDEX i;
1035 for (i = 0; i < fields.GetSize(); i++)
1036 newFields.Append(fields.GetAt(i));
1038 BOOL lastFieldIsSet = FALSE;
1039 PINDEX size = fields.GetSize();
1040 for (i = 0; i < size; i++) {
1041 PHTTPField * fieldPtr = &fields[i];
1042 PINDEX pos = newFields.GetObjectsIndex(fieldPtr);
1043 fieldPtr->SetAllValues(data);
1045 PString control = data(fieldPtr->GetName() + ArrayControlBox);
1046 if (control == ArrayControlMoveUp) {
1047 if (pos > 0) {
1048 newFields.SetAt(pos, newFields.GetAt(pos-1));
1049 newFields.SetAt(pos-1, fieldPtr);
1052 else if (control == ArrayControlMoveDown) {
1053 if (size > 2 && pos < size-2) {
1054 newFields.SetAt(pos, newFields.GetAt(pos+1));
1055 newFields.SetAt(pos+1, fieldPtr);
1058 else if (control == ArrayControlToTop) {
1059 newFields.RemoveAt(pos);
1060 newFields.InsertAt(0, fieldPtr);
1062 else if (control == ArrayControlToBottom) {
1063 newFields.RemoveAt(pos);
1064 newFields.Append(fieldPtr);
1066 else if (control == ArrayControlAddTop) {
1067 if (i == size-1) {
1068 newFields.RemoveAt(pos);
1069 newFields.InsertAt(0, fieldPtr);
1070 lastFieldIsSet = TRUE;
1073 else if (control == ArrayControlAddBottom || control == ArrayControlAdd) {
1074 if (i == size-1) {
1075 newFields.RemoveAt(pos);
1076 newFields.Append(fieldPtr);
1077 lastFieldIsSet = TRUE;
1080 else if (control == ArrayControlIgnore) {
1081 newFields.RemoveAt(pos);
1082 newFields.Append(fieldPtr);
1084 else if (control == ArrayControlRemove)
1085 newFields.RemoveAt(pos);
1088 fields.DisallowDeleteObjects();
1089 for (i = 0; i < newFields.GetSize(); i++)
1090 fields.Remove(newFields.GetAt(i));
1091 fields.AllowDeleteObjects();
1092 fields.RemoveAll();
1094 for (i = 0; i < newFields.GetSize(); i++) {
1095 fields.Append(newFields.GetAt(i));
1096 SetArrayFieldName(i);
1099 if (lastFieldIsSet && canAddElements)
1100 AddBlankField();
1104 PINDEX PHTTPFieldArray::GetSize() const
1106 PINDEX size = fields.GetSize();
1107 PAssert(size > 0, PLogicError);
1108 if (canAddElements)
1109 size--;
1110 return size;
1114 void PHTTPFieldArray::AddBlankField()
1116 fields.Append(baseField->NewField());
1117 SetArrayFieldName(fields.GetSize()-1);
1121 PStringArray PHTTPFieldArray::GetStrings(PConfig & cfg)
1123 LoadFromConfig(cfg);
1125 PStringArray values(GetSize());
1127 for (PINDEX i = 0; i < GetSize(); i++)
1128 values[i] = fields[i].GetValue(FALSE);
1130 return values;
1134 void PHTTPFieldArray::SetStrings(PConfig & cfg, const PStringArray & values)
1136 SetSize(values.GetSize());
1137 for (PINDEX i = 0; i < values.GetSize(); i++)
1138 fields[i].SetValue(values[i]);
1140 SaveToConfig(cfg);
1144 //////////////////////////////////////////////////////////////////////////////
1145 // PHTTPStringField
1147 PHTTPStringField::PHTTPStringField(const char * name,
1148 PINDEX siz,
1149 const char * initVal,
1150 const char * help)
1151 : PHTTPField(name, NULL, help),
1152 value(initVal != NULL ? initVal : ""),
1153 initialValue(value)
1155 size = siz;
1159 PHTTPStringField::PHTTPStringField(const char * name,
1160 const char * title,
1161 PINDEX siz,
1162 const char * initVal,
1163 const char * help)
1164 : PHTTPField(name, title, help),
1165 value(initVal != NULL ? initVal : ""),
1166 initialValue(value)
1168 size = siz;
1172 PHTTPField * PHTTPStringField::NewField() const
1174 return new PHTTPStringField(baseName, title, size, initialValue, help);
1178 void PHTTPStringField::GetHTMLTag(PHTML & html) const
1180 if (size < 128)
1181 html << PHTML::InputText(fullName, size, value);
1182 else
1183 html << PHTML::TextArea(fullName, (size+79)/80, 80) << value << PHTML::TextArea(fullName);
1187 void PHTTPStringField::SetValue(const PString & newVal)
1189 value = newVal;
1193 PString PHTTPStringField::GetValue(BOOL dflt) const
1195 if (dflt)
1196 return initialValue;
1197 else
1198 return value;
1202 //////////////////////////////////////////////////////////////////////////////
1203 // PHTTPPasswordField
1205 PHTTPPasswordField::PHTTPPasswordField(const char * name,
1206 PINDEX siz,
1207 const char * initVal,
1208 const char * help)
1209 : PHTTPStringField(name, siz, initVal, help)
1214 PHTTPPasswordField::PHTTPPasswordField(const char * name,
1215 const char * title,
1216 PINDEX siz,
1217 const char * initVal,
1218 const char * help)
1219 : PHTTPStringField(name, title, siz, initVal, help)
1224 PHTTPField * PHTTPPasswordField::NewField() const
1226 return new PHTTPPasswordField(baseName, title, size, initialValue, help);
1230 void PHTTPPasswordField::GetHTMLTag(PHTML & html) const
1232 html << PHTML::InputPassword(fullName, size, value);
1236 static const PTEACypher::Key PasswordKey = {
1238 103, 60, 222, 17, 128, 157, 31, 137,
1239 133, 64, 82, 148, 94, 136, 4, 209
1243 void PHTTPPasswordField::SetValue(const PString & newVal)
1245 value = Decrypt(newVal);
1249 PString PHTTPPasswordField::GetValue(BOOL dflt) const
1251 if (dflt)
1252 return initialValue;
1254 PTEACypher crypt(PasswordKey);
1255 return crypt.Encode(value);
1259 PString PHTTPPasswordField::Decrypt(const PString & pword)
1261 PString clear;
1262 PTEACypher crypt(PasswordKey);
1263 return crypt.Decode(pword, clear) ? clear : pword;
1267 //////////////////////////////////////////////////////////////////////////////
1268 // PHTTPIntegerField
1270 PHTTPIntegerField::PHTTPIntegerField(const char * nam,
1271 int lo, int hig,
1272 int initVal,
1273 const char * unit,
1274 const char * help)
1275 : PHTTPField(nam, NULL, help), units(unit != NULL ? unit : "")
1277 low = lo;
1278 high = hig;
1279 value = initialValue = initVal;
1282 PHTTPIntegerField::PHTTPIntegerField(const char * nam,
1283 const char * titl,
1284 int lo, int hig,
1285 int initVal,
1286 const char * unit,
1287 const char * help)
1288 : PHTTPField(nam, titl, help), units(unit != NULL ? unit : "")
1290 low = lo;
1291 high = hig;
1292 value = initialValue = initVal;
1296 PHTTPField * PHTTPIntegerField::NewField() const
1298 return new PHTTPIntegerField(baseName, title, low, high, initialValue, units, help);
1302 void PHTTPIntegerField::GetHTMLTag(PHTML & html) const
1304 html << PHTML::InputRange(fullName, low, high, value) << " " << units;
1308 void PHTTPIntegerField::SetValue(const PString & newVal)
1310 value = newVal.AsInteger();
1314 PString PHTTPIntegerField::GetValue(BOOL dflt) const
1316 return PString(PString::Signed, dflt ? initialValue : value);
1320 void PHTTPIntegerField::LoadFromConfig(PConfig & cfg)
1322 PString section, key;
1323 switch (SplitConfigKey(fullName, section, key)) {
1324 case 1 :
1325 value = cfg.GetInteger(key, initialValue);
1326 break;
1327 case 2 :
1328 value = cfg.GetInteger(section, key, initialValue);
1333 void PHTTPIntegerField::SaveToConfig(PConfig & cfg) const
1335 PString section, key;
1336 switch (SplitConfigKey(fullName, section, key)) {
1337 case 1 :
1338 cfg.SetInteger(key, value);
1339 break;
1340 case 2 :
1341 cfg.SetInteger(section, key, value);
1346 BOOL PHTTPIntegerField::Validated(const PString & newVal, PStringStream & msg) const
1348 int val = newVal.AsInteger();
1349 if (val >= low && val <= high)
1350 return TRUE;
1352 msg << "The field \"" << GetName() << "\" should be between "
1353 << low << " and " << high << ".<BR>";
1354 return FALSE;
1358 //////////////////////////////////////////////////////////////////////////////
1359 // PHTTPBooleanField
1361 PHTTPBooleanField::PHTTPBooleanField(const char * name,
1362 BOOL initVal,
1363 const char * help)
1364 : PHTTPField(name, NULL, help)
1366 value = initialValue = initVal;
1370 PHTTPBooleanField::PHTTPBooleanField(const char * name,
1371 const char * title,
1372 BOOL initVal,
1373 const char * help)
1374 : PHTTPField(name, title, help)
1376 value = initialValue = initVal;
1380 PHTTPField * PHTTPBooleanField::NewField() const
1382 return new PHTTPBooleanField(baseName, title, initialValue, help);
1386 void PHTTPBooleanField::GetHTMLTag(PHTML & html) const
1388 html << PHTML::HiddenField(fullName, "FALSE")
1389 << PHTML::CheckBox(fullName, value ? PHTML::Checked : PHTML::UnChecked);
1393 static void SpliceChecked(PString & text, BOOL value)
1395 PINDEX pos = text.Find("checked");
1396 if (value) {
1397 if (pos == P_MAX_INDEX)
1398 text.Splice(" checked", 6, 0);
1400 else {
1401 if (pos != P_MAX_INDEX) {
1402 PINDEX len = 7;
1403 if (text[pos-1] == ' ') {
1404 pos--;
1405 len++;
1407 text.Delete(pos, len);
1413 PString PHTTPBooleanField::GetHTMLInput(const PString & input) const
1415 static PRegularExpression checkboxRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?checkbox\"?",
1416 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1417 if (input.FindRegEx(checkboxRegEx) != P_MAX_INDEX) {
1418 PCaselessString text;
1419 PINDEX before, after;
1420 if (FindInputValue(input, before, after))
1421 text = input(0, before) + "TRUE" + input.Mid(after);
1422 else
1423 text = "<input value=\"TRUE\"" + input.Mid(6);
1424 SpliceChecked(text, value);
1425 return "<input type=hidden name=\"" + fullName + "\">" + text;
1428 static PRegularExpression radioRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?radio\"?",
1429 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1430 if (input.FindRegEx(radioRegEx) != P_MAX_INDEX) {
1431 PINDEX before, after;
1432 if (FindInputValue(input, before, after)) {
1433 PCaselessString text = input;
1434 PString val = input(before+1, after-1);
1435 SpliceChecked(text, (value && (val *= "TRUE")) || (!value && (val *= "FALSE")));
1436 return text;
1438 return input;
1441 return PHTTPField::GetHTMLInput(input);
1445 void PHTTPBooleanField::SetValue(const PString & val)
1447 value = toupper(val[0]) == 'T' || toupper(val[0]) == 'y' ||
1448 val.AsInteger() != 0 || val.Find("TRUE") != P_MAX_INDEX;
1452 PString PHTTPBooleanField::GetValue(BOOL dflt) const
1454 return ((dflt ? initialValue : value) ? "True" : "False");
1458 void PHTTPBooleanField::LoadFromConfig(PConfig & cfg)
1460 PString section, key;
1461 switch (SplitConfigKey(fullName, section, key)) {
1462 case 1 :
1463 value = cfg.GetBoolean(key, initialValue);
1464 break;
1465 case 2 :
1466 value = cfg.GetBoolean(section, key, initialValue);
1471 void PHTTPBooleanField::SaveToConfig(PConfig & cfg) const
1473 PString section, key;
1474 switch (SplitConfigKey(fullName, section, key)) {
1475 case 1 :
1476 cfg.SetBoolean(key, value);
1477 break;
1478 case 2 :
1479 cfg.SetBoolean(section, key, value);
1484 //////////////////////////////////////////////////////////////////////////////
1485 // PHTTPRadioField
1487 PHTTPRadioField::PHTTPRadioField(const char * name,
1488 const PStringArray & valueArray,
1489 PINDEX initVal,
1490 const char * help)
1491 : PHTTPField(name, NULL, help),
1492 values(valueArray),
1493 titles(valueArray),
1494 value(valueArray[initVal]),
1495 initialValue(value)
1500 PHTTPRadioField::PHTTPRadioField(const char * name,
1501 const PStringArray & valueArray,
1502 const PStringArray & titleArray,
1503 PINDEX initVal,
1504 const char * help)
1505 : PHTTPField(name, NULL, help),
1506 values(valueArray),
1507 titles(titleArray),
1508 value(valueArray[initVal]),
1509 initialValue(value)
1514 PHTTPRadioField::PHTTPRadioField(const char * name,
1515 PINDEX count,
1516 const char * const * valueStrings,
1517 PINDEX initVal,
1518 const char * help)
1519 : PHTTPField(name, NULL, help),
1520 values(count, valueStrings),
1521 titles(count, valueStrings),
1522 value(valueStrings[initVal]),
1523 initialValue(value)
1528 PHTTPRadioField::PHTTPRadioField(const char * name,
1529 PINDEX count,
1530 const char * const * valueStrings,
1531 const char * const * titleStrings,
1532 PINDEX initVal,
1533 const char * help)
1534 : PHTTPField(name, NULL, help),
1535 values(count, valueStrings),
1536 titles(count, titleStrings),
1537 value(valueStrings[initVal]),
1538 initialValue(value)
1543 PHTTPRadioField::PHTTPRadioField(const char * name,
1544 const char * groupTitle,
1545 const PStringArray & valueArray,
1546 PINDEX initVal,
1547 const char * help)
1548 : PHTTPField(name, groupTitle, help),
1549 values(valueArray),
1550 titles(valueArray),
1551 value(valueArray[initVal]),
1552 initialValue(value)
1557 PHTTPRadioField::PHTTPRadioField(const char * name,
1558 const char * groupTitle,
1559 const PStringArray & valueArray,
1560 const PStringArray & titleArray,
1561 PINDEX initVal,
1562 const char * help)
1563 : PHTTPField(name, groupTitle, help),
1564 values(valueArray),
1565 titles(titleArray),
1566 value(valueArray[initVal]),
1567 initialValue(value)
1572 PHTTPRadioField::PHTTPRadioField(const char * name,
1573 const char * groupTitle,
1574 PINDEX count,
1575 const char * const * valueStrings,
1576 PINDEX initVal,
1577 const char * help)
1578 : PHTTPField(name, groupTitle, help),
1579 values(count, valueStrings),
1580 titles(count, valueStrings),
1581 value(valueStrings[initVal]),
1582 initialValue(value)
1587 PHTTPRadioField::PHTTPRadioField(const char * name,
1588 const char * groupTitle,
1589 PINDEX count,
1590 const char * const * valueStrings,
1591 const char * const * titleStrings,
1592 PINDEX initVal,
1593 const char * help)
1594 : PHTTPField(name, groupTitle, help),
1595 values(count, valueStrings),
1596 titles(count, titleStrings),
1597 value(valueStrings[initVal]),
1598 initialValue(value)
1603 PHTTPField * PHTTPRadioField::NewField() const
1605 return new PHTTPRadioField(*this);
1609 void PHTTPRadioField::GetHTMLTag(PHTML & html) const
1611 for (PINDEX i = 0; i < values.GetSize(); i++)
1612 html << PHTML::RadioButton(fullName, values[i],
1613 values[i] == value ? PHTML::Checked : PHTML::UnChecked)
1614 << titles[i]
1615 << PHTML::BreakLine();
1619 PString PHTTPRadioField::GetHTMLInput(const PString & input) const
1621 PString inval;
1622 PINDEX before, after;
1623 if (FindInputValue(input, before, after))
1624 inval = input(before+1, after-1);
1625 else
1626 inval = baseName;
1628 if (inval != value)
1629 return input;
1631 return "<input checked" + input.Mid(6);
1635 PString PHTTPRadioField::GetValue(BOOL dflt) const
1637 if (dflt)
1638 return initialValue;
1639 else
1640 return value;
1644 void PHTTPRadioField::SetValue(const PString & newVal)
1646 value = newVal;
1650 //////////////////////////////////////////////////////////////////////////////
1651 // PHTTPSelectField
1653 PHTTPSelectField::PHTTPSelectField(const char * name,
1654 const PStringArray & valueArray,
1655 PINDEX initVal,
1656 const char * help)
1657 : PHTTPField(name, NULL, help),
1658 values(valueArray)
1660 initialValue = initVal;
1661 if (initVal < values.GetSize())
1662 value = values[initVal];
1666 PHTTPSelectField::PHTTPSelectField(const char * name,
1667 PINDEX count,
1668 const char * const * valueStrings,
1669 PINDEX initVal,
1670 const char * help)
1671 : PHTTPField(name, NULL, help),
1672 values(count, valueStrings)
1674 initialValue = initVal;
1675 if (initVal < count)
1676 value = values[initVal];
1680 PHTTPSelectField::PHTTPSelectField(const char * name,
1681 const char * title,
1682 const PStringArray & valueArray,
1683 PINDEX initVal,
1684 const char * help)
1685 : PHTTPField(name, title, help),
1686 values(valueArray)
1688 initialValue = initVal;
1689 if (initVal < values.GetSize())
1690 value = values[initVal];
1694 PHTTPSelectField::PHTTPSelectField(const char * name,
1695 const char * title,
1696 PINDEX count,
1697 const char * const * valueStrings,
1698 PINDEX initVal,
1699 const char * help)
1700 : PHTTPField(name, title, help),
1701 values(count, valueStrings)
1703 initialValue = initVal;
1704 if (initVal < values.GetSize())
1705 value = values[initVal];
1709 PHTTPField * PHTTPSelectField::NewField() const
1711 return new PHTTPSelectField(baseName, title, values, initialValue, help);
1715 void PHTTPSelectField::GetHTMLTag(PHTML & html) const
1717 html << PHTML::Select(fullName);
1718 for (PINDEX i = 0; i < values.GetSize(); i++)
1719 html << PHTML::Option(values[i] == value ? PHTML::Selected : PHTML::NotSelected)
1720 << values[i];
1721 html << PHTML::Select();
1725 PString PHTTPSelectField::GetValue(BOOL dflt) const
1727 if (dflt)
1728 if (initialValue < values.GetSize())
1729 return values[initialValue];
1730 else
1731 return PString();
1732 else
1733 return value;
1737 void PHTTPSelectField::SetValue(const PString & newVal)
1739 value = newVal;
1744 //////////////////////////////////////////////////////////////////////////////
1745 // PHTTPForm
1747 PHTTPForm::PHTTPForm(const PURL & url)
1748 : PHTTPString(url),
1749 fields("")
1753 PHTTPForm::PHTTPForm(const PURL & url, const PHTTPAuthority & auth)
1754 : PHTTPString(url, auth),
1755 fields("")
1759 PHTTPForm::PHTTPForm(const PURL & url, const PString & html)
1760 : PHTTPString(url, html),
1761 fields("")
1765 PHTTPForm::PHTTPForm(const PURL & url,
1766 const PString & html,
1767 const PHTTPAuthority & auth)
1768 : PHTTPString(url, html, auth),
1769 fields("")
1774 static BOOL FindSpliceAccepted(const PString & text,
1775 PINDEX offset,
1776 PINDEX & pos,
1777 PINDEX & len,
1778 PINDEX & start,
1779 PINDEX & finish)
1781 static PRegularExpression Accepted("<?!--#form[ \t\r\n]+accepted[ \t\r\n]*-->?",
1782 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1783 return FindSpliceBlock(Accepted, text, offset, pos, len, start, finish);
1787 static BOOL FindSpliceErrors(const PString & text,
1788 PINDEX offset,
1789 PINDEX & pos,
1790 PINDEX & len,
1791 PINDEX & start,
1792 PINDEX & finish)
1794 static PRegularExpression Errors("<?!--#form[ \t\r\n]+errors[ \t\r\n]*-->?",
1795 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1796 return FindSpliceBlock(Errors, text, offset, pos, len, start, finish);
1800 static BOOL FindSpliceField(const PRegularExpression & startExpr,
1801 const PRegularExpression & endExpr,
1802 const PString & text,
1803 PINDEX offset,
1804 const PHTTPField & rootField,
1805 PINDEX & pos,
1806 PINDEX & len,
1807 PINDEX & start,
1808 PINDEX & finish,
1809 const PHTTPField * & field)
1811 field = NULL;
1813 if (!FindSpliceBlock(startExpr, endExpr, text, offset, pos, len, start, finish))
1814 return FALSE;
1816 PINDEX endBlock = start != finish ? (start-1) : (pos+len-1);
1817 PINDEX namePos, nameEnd;
1818 if (FindSpliceName(text, pos, endBlock, namePos, nameEnd))
1819 field = rootField.LocateName(text(namePos, nameEnd));
1820 return TRUE;
1824 static const char ListFieldDeleteBox[] = "List Row Delete ";
1826 void PHTTPForm::OnLoadedText(PHTTPRequest & request, PString & text)
1828 PINDEX pos, len, start, finish;
1829 const PHTTPField * field;
1831 // Remove the subsections for POST command
1832 pos = 0;
1833 while (FindSpliceAccepted(text, pos, pos, len, start, finish))
1834 text.Delete(pos, len);
1836 pos = 0;
1837 while (FindSpliceErrors(text, pos, pos, len, start, finish))
1838 text.Delete(pos, len);
1840 // See if are a subform, set root composite field accordingly
1841 PString prefix = request.url.GetQueryVars()("subformprefix");
1842 if (!prefix) {
1843 static PRegularExpression SubFormPrefix("<?!--#form[ \t\r\n]+subformprefix[ \t\r\n]*-->?",
1844 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1845 while (text.FindRegEx(SubFormPrefix, pos, len))
1846 text.Splice("subformprefix=" +
1847 PURL::TranslateString(prefix, PURL::QueryTranslation),
1848 pos, len);
1849 field = fields.LocateName(prefix);
1850 if (field != NULL) {
1851 finish = P_MAX_INDEX;
1852 field->ExpandFieldNames(text, 0, finish);
1856 // Locate <!--#form list name--> macros and expand them
1857 static PRegularExpression ListRegEx("<!--#form[ \t\r\n]+listfields[ \t\r\n]+(-?[^-])+-->",
1858 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1859 static PRegularExpression EndBlock("<?!--#form[ \t\r\n]+end[ \t\r\n]+(-?[^-])+-->?",
1860 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1861 pos = len = 0;
1862 while (FindSpliceBlock(ListRegEx, EndBlock, text, pos+len, pos, len, start, finish)) {
1863 if (start != finish) {
1864 PString repeat = text(start, finish);
1866 PINDEX namePos, nameEnd;
1867 PRegularExpression fieldsRegEx;
1868 if (FindSpliceName(text, pos, start-1, namePos, nameEnd))
1869 fieldsRegEx.Compile(text(namePos, nameEnd), PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1870 else
1871 fieldsRegEx.Compile(".*");
1873 PString insert;
1874 for (PINDEX f = 0; f < fields.GetSize(); f++) {
1875 if (fields[f].GetName().FindRegEx(fieldsRegEx) != P_MAX_INDEX) {
1876 PString iteration = repeat;
1877 PINDEX npos, nlen;
1879 static PRegularExpression FieldNameRegEx("<?!--#form[ \t\r\n]+fieldname[ \t\r\n]*-->?",
1880 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1881 while (iteration.FindRegEx(FieldNameRegEx, npos, nlen))
1882 iteration.Splice(fields[f].GetName(), npos, nlen);
1884 static PRegularExpression RowDeleteRegEx("<?!--#form[ \t\r\n]+rowdelete[ \t\r\n]*-->?",
1885 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1886 while (iteration.FindRegEx(RowDeleteRegEx, npos, nlen)) {
1887 PHTML html(PHTML::InForm);
1888 html << PHTML::CheckBox(ListFieldDeleteBox + fields[f].GetName());
1889 iteration.Splice(html, npos, nlen);
1892 insert += iteration;
1895 text.Splice(insert, pos, len);
1899 // Locate <!--#form array name--> macros and expand them
1900 static PRegularExpression ArrayRegEx("<!--#form[ \t\r\n]+array[ \t\r\n]+(-?[^-])+-->",
1901 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1902 pos = len = 0;
1903 while (FindSpliceField(ArrayRegEx, EndBlock, text, pos+len, fields, pos, len, start, finish, field)) {
1904 if (start != finish && field != NULL)
1905 field->ExpandFieldNames(text, start, finish);
1908 // Have now expanded all field names to be fully qualified
1910 static PRegularExpression HTMLRegEx("<!--#form[ \t\r\n]+html[ \t\r\n]+(-?[^-])+-->",
1911 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1912 while (FindSpliceField(HTMLRegEx, "", text, 0, fields, pos, len, start, finish, field)) {
1913 if (field != NULL) {
1914 PHTML html(PHTML::InForm);
1915 field->GetHTMLTag(html);
1916 text.Splice(html, pos, len);
1920 pos = len = 0;
1921 static PRegularExpression ValueRegEx("<!--#form[ \t\r\n]+value[ \t\r\n]+(-?[^-])+-->",
1922 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1923 while (FindSpliceField(ValueRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
1924 if (field != NULL)
1925 text.Splice(field->GetValue(), pos, len);
1928 pos = len = 0;
1929 static PRegularExpression InputRegEx("<input[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1930 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1931 while (FindSpliceField(InputRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
1932 if (field != NULL) {
1933 static PRegularExpression HiddenRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?hidden\"?",
1934 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1935 PString substr = text.Mid(pos, len);
1936 if (substr.FindRegEx(HiddenRegEx) == P_MAX_INDEX)
1937 text.Splice(field->GetHTMLInput(substr), pos, len);
1941 pos = len = 0;
1942 static PRegularExpression SelectRegEx("<select[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1943 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1944 static PRegularExpression SelEndRegEx("</select[^>]*>",
1945 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1946 while (FindSpliceField(SelectRegEx, SelEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
1947 if (field != NULL)
1948 text.Splice(field->GetHTMLSelect(text(start, finish)), start, finish-start+1);
1951 pos = len = 0;
1952 static PRegularExpression TextRegEx("<textarea[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1953 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1954 static PRegularExpression TextEndRegEx("</textarea[^>]*>", PRegularExpression::IgnoreCase);
1955 while (FindSpliceField(TextRegEx, TextEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
1956 if (field != NULL)
1957 text.Splice(field->GetValue(), start, finish-start+1);
1962 PHTTPField * PHTTPForm::Add(PHTTPField * fld)
1964 PAssertNULL(fld);
1965 PAssert(!fieldNames[fld->GetName()], "Field already on form!");
1966 fieldNames += fld->GetName();
1967 fields.Append(fld);
1968 return fld;
1972 void PHTTPForm::BuildHTML(const char * heading)
1974 PHTML html(heading);
1975 BuildHTML(html);
1979 void PHTTPForm::BuildHTML(const PString & heading)
1981 PHTML html(heading);
1982 BuildHTML(html);
1986 void PHTTPForm::BuildHTML(PHTML & html, BuildOptions option)
1988 if (!html.Is(PHTML::InForm))
1989 html << PHTML::Form("POST");
1991 html << PHTML::TableStart("cellspacing=8");
1992 for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
1993 PHTTPField & field = fields[fld];
1994 if (field.NotYetInHTML()) {
1995 html << PHTML::TableRow()
1996 << PHTML::TableData("align=right")
1997 << field.GetTitle()
1998 << PHTML::TableData("align=left")
1999 << "<!--#form html " << field.GetName() << "-->"
2000 << PHTML::TableData()
2001 << field.GetHelp();
2002 field.SetInHTML();
2005 html << PHTML::TableEnd();
2006 if (option != InsertIntoForm)
2007 html << PHTML::Paragraph()
2008 << ' ' << PHTML::SubmitButton("Accept")
2009 << ' ' << PHTML::ResetButton("Reset")
2010 << PHTML::Form();
2012 if (option == CompleteHTML) {
2013 html << PHTML::Body();
2014 string = html;
2019 BOOL PHTTPForm::Post(PHTTPRequest & request,
2020 const PStringToString & data,
2021 PHTML & msg)
2023 //PString prefix = request.url.GetQueryVars()("subformprefix");
2024 const PHTTPField * field = NULL;
2025 //if (!prefix)
2026 // field = fields.LocateName(prefix);
2027 //if (field == NULL)
2028 field = &fields;
2030 PStringStream errors;
2031 if (field->ValidateAll(data, errors)) {
2032 ((PHTTPField *)field)->SetAllValues(data);
2034 if (msg.IsEmpty()) {
2035 msg << PHTML::Title() << "Accepted New Configuration" << PHTML::Body()
2036 << PHTML::Heading(1) << "Accepted New Configuration" << PHTML::Heading(1)
2037 << PHTML::HotLink(request.url.AsString()) << "Reload page" << PHTML::HotLink()
2038 << "&nbsp;&nbsp;&nbsp;&nbsp;"
2039 << PHTML::HotLink("/") << "Home page" << PHTML::HotLink();
2041 else {
2042 PString block;
2043 PINDEX pos = 0;
2044 PINDEX len, start, finish;
2045 while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
2046 msg.Splice(msg(start, finish), pos, len);
2047 pos = 0;
2048 while (FindSpliceErrors(msg, pos, pos, len, start, finish))
2049 msg.Delete(pos, len);
2052 else {
2053 if (msg.IsEmpty()) {
2054 msg << PHTML::Title() << "Validation Error in Request" << PHTML::Body()
2055 << PHTML::Heading(1) << "Validation Error in Request" << PHTML::Heading(1)
2056 << errors
2057 << PHTML::Paragraph()
2058 << PHTML::HotLink(request.url.AsString()) << "Reload page" << PHTML::HotLink()
2059 << "&nbsp;&nbsp;&nbsp;&nbsp;"
2060 << PHTML::HotLink("/") << "Home page" << PHTML::HotLink();
2062 else {
2063 PINDEX pos = 0;
2064 PINDEX len, start, finish;
2065 while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
2066 msg.Delete(pos, len);
2068 BOOL appendErrors = TRUE;
2069 pos = 0;
2070 while (FindSpliceErrors(msg, pos, pos, len, start, finish)) {
2071 PString block = msg(start, finish);
2072 PINDEX vPos, vLen;
2073 static PRegularExpression Validation("<?!--#form[ \t\r\n]+validation[ \t\r\n]*-->?",
2074 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
2075 if (block.FindRegEx(Validation, vPos, vLen))
2076 block.Splice(errors, vPos, vLen);
2077 else
2078 block += errors;
2079 msg.Splice(block, pos, len);
2080 appendErrors = FALSE;
2083 if (appendErrors)
2084 msg << errors;
2088 return TRUE;
2092 //////////////////////////////////////////////////////////////////////////////
2093 // PHTTPConfig
2095 PHTTPConfig::PHTTPConfig(const PURL & url,
2096 const PString & sect)
2097 : PHTTPForm(url), section(sect)
2099 Construct();
2103 PHTTPConfig::PHTTPConfig(const PURL & url,
2104 const PString & sect,
2105 const PHTTPAuthority & auth)
2106 : PHTTPForm(url, auth), section(sect)
2108 Construct();
2112 PHTTPConfig::PHTTPConfig(const PURL & url,
2113 const PString & html,
2114 const PString & sect)
2115 : PHTTPForm(url, html), section(sect)
2117 Construct();
2121 PHTTPConfig::PHTTPConfig(const PURL & url,
2122 const PString & html,
2123 const PString & sect,
2124 const PHTTPAuthority & auth)
2125 : PHTTPForm(url, html, auth), section(sect)
2127 Construct();
2131 void PHTTPConfig::Construct()
2133 sectionField = NULL;
2134 keyField = NULL;
2135 valField = NULL;
2139 void PHTTPConfig::LoadFromConfig()
2141 PConfig cfg(section);
2142 fields.LoadFromConfig(cfg);
2146 void PHTTPConfig::OnLoadedText(PHTTPRequest & request, PString & text)
2148 if (sectionField == NULL) {
2149 PString sectionName = request.url.GetQueryVars()("section", section);
2150 if (!sectionName) {
2151 section = sectionName;
2152 LoadFromConfig();
2156 PHTTPForm::OnLoadedText(request, text);
2160 BOOL PHTTPConfig::Post(PHTTPRequest & request,
2161 const PStringToString & data,
2162 PHTML & msg)
2164 // Make sure the internal structure is up to date before accepting new data
2165 if (!section)
2166 LoadFromConfig();
2169 PSortedStringList oldValues;
2171 // Remember fields that are here now, so can delete removed array fields
2172 PINDEX fld;
2173 for (fld = 0; fld < fields.GetSize(); fld++) {
2174 PHTTPField & field = fields[fld];
2175 if (&field != keyField && &field != valField && &field != sectionField) {
2176 PStringList names;
2177 field.GetAllNames(names);
2178 oldValues = names;
2182 PHTTPForm::Post(request, data, msg);
2183 if (request.code != PHTTP::RequestOK)
2184 return TRUE;
2186 if (sectionField != NULL)
2187 section = sectionPrefix + sectionField->GetValue() + sectionSuffix;
2189 PString sectionName = request.url.GetQueryVars()("section", section);
2190 if (sectionName.IsEmpty())
2191 return TRUE;
2193 PConfig cfg(sectionName);
2195 for (fld = 0; fld < fields.GetSize(); fld++) {
2196 PHTTPField & field = fields[fld];
2197 if (&field == keyField) {
2198 PString key = field.GetValue();
2199 if (!key)
2200 cfg.SetString(key, valField->GetValue());
2202 else if (&field != valField && &field != sectionField)
2203 field.SaveToConfig(cfg);
2206 // Find out which fields have been removed (arrays elements deleted)
2207 for (fld = 0; fld < fields.GetSize(); fld++) {
2208 PHTTPField & field = fields[fld];
2209 if (&field != keyField && &field != valField && &field != sectionField) {
2210 PStringList names;
2211 field.GetAllNames(names);
2212 for (PINDEX i = 0; i < names.GetSize(); i++) {
2213 PINDEX idx = oldValues.GetStringsIndex(names[i]);
2214 if (idx != P_MAX_INDEX)
2215 oldValues.RemoveAt(idx);
2220 for (fld = 0; fld < oldValues.GetSize(); fld++) {
2221 PString section, key;
2222 switch (SplitConfigKey(oldValues[fld], section, key)) {
2223 case 1 :
2224 cfg.DeleteKey(key);
2225 break;
2226 case 2 :
2227 cfg.DeleteKey(section, key);
2228 if (cfg.GetKeys(section).IsEmpty())
2229 cfg.DeleteSection(section);
2233 section = sectionName;
2234 return TRUE;
2238 PHTTPField * PHTTPConfig::AddSectionField(PHTTPField * sectionFld,
2239 const char * prefix,
2240 const char * suffix)
2242 sectionField = PAssertNULL(sectionFld);
2243 PAssert(!sectionField->IsDescendant(PHTTPCompositeField::Class()), "Section field is composite");
2244 Add(sectionField);
2246 if (prefix != NULL)
2247 sectionPrefix = prefix;
2248 if (suffix != NULL)
2249 sectionSuffix = suffix;
2251 return sectionField;
2255 void PHTTPConfig::AddNewKeyFields(PHTTPField * keyFld,
2256 PHTTPField * valFld)
2258 keyField = PAssertNULL(keyFld);
2259 Add(keyFld);
2260 valField = PAssertNULL(valFld);
2261 Add(valFld);
2265 //////////////////////////////////////////////////////////////////////////////
2266 // PHTTPConfigSectionList
2268 static const char FormListInclude[] = "<!--#form pagelist-->";
2270 PHTTPConfigSectionList::PHTTPConfigSectionList(const PURL & url,
2271 const PHTTPAuthority & auth,
2272 const PString & prefix,
2273 const PString & valueName,
2274 const PURL & editSection,
2275 const PURL & newSection,
2276 const PString & newTitle,
2277 PHTML & heading)
2278 : PHTTPString(url, auth),
2279 sectionPrefix(prefix),
2280 additionalValueName(valueName),
2281 newSectionLink(newSection.AsString(PURL::URIOnly)),
2282 newSectionTitle(newTitle),
2283 editSectionLink(editSection.AsString(PURL::URIOnly) +
2284 "?section=" + PURL::TranslateString(prefix, PURL::QueryTranslation))
2286 if (heading.Is(PHTML::InBody))
2287 heading << FormListInclude << PHTML::Body();
2288 SetString(heading);
2292 void PHTTPConfigSectionList::OnLoadedText(PHTTPRequest &, PString & text)
2294 PConfig cfg;
2295 PStringList nameList = cfg.GetSections();
2297 PINDEX pos = text.Find(FormListInclude);
2298 if (pos != P_MAX_INDEX) {
2299 PINDEX endpos = text.Find(FormListInclude, pos + sizeof(FormListInclude)-1);
2300 if (endpos == P_MAX_INDEX) {
2301 PHTML html(PHTML::InBody);
2302 html << PHTML::Form("POST") << PHTML::TableStart();
2304 PINDEX i;
2305 for (i = 0; i < nameList.GetSize(); i++) {
2306 if (nameList[i].Find(sectionPrefix) == 0) {
2307 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2308 html << PHTML::TableRow()
2309 << PHTML::TableData()
2310 << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
2311 << name
2312 << PHTML::HotLink();
2313 if (!additionalValueName)
2314 html << PHTML::TableData()
2315 << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
2316 << cfg.GetString(nameList[i], additionalValueName, "")
2317 << PHTML::HotLink();
2318 html << PHTML::TableData() << PHTML::SubmitButton("Remove", name);
2322 html << PHTML::TableRow()
2323 << PHTML::TableData()
2324 << PHTML::HotLink(newSectionLink)
2325 << newSectionTitle
2326 << PHTML::HotLink()
2327 << PHTML::TableEnd()
2328 << PHTML::Form();
2330 text.Splice(html, pos, sizeof(FormListInclude)-1);
2332 else {
2333 PString repeat = text(pos + sizeof(FormListInclude)-1, endpos-1);
2334 text.Delete(pos, endpos - pos);
2336 PINDEX i;
2337 for (i = 0; i < nameList.GetSize(); i++) {
2338 if (nameList[i].Find(sectionPrefix) == 0) {
2339 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2340 text.Splice(repeat, pos, 0);
2341 text.Replace("<!--#form hotlink-->",
2342 editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation),
2343 TRUE, pos);
2344 if (!additionalValueName)
2345 text.Replace("<!--#form additional-->",
2346 cfg.GetString(nameList[i], additionalValueName, ""),
2347 TRUE, pos);
2348 text.Replace("<!--#form section-->", name, TRUE, pos);
2349 pos = text.Find(FormListInclude, pos);
2352 text.Delete(text.Find(FormListInclude, pos), sizeof(FormListInclude)-1);
2358 BOOL PHTTPConfigSectionList::Post(PHTTPRequest &,
2359 const PStringToString & data,
2360 PHTML & replyMessage)
2362 PConfig cfg;
2363 PStringList nameList = cfg.GetSections();
2364 PINDEX i;
2365 for (i = 0; i < nameList.GetSize(); i++) {
2366 if (nameList[i].Find(sectionPrefix) == 0) {
2367 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2368 if (data.Contains(name)) {
2369 cfg.DeleteSection(nameList[i]);
2370 replyMessage << name << " removed.";
2375 return TRUE;
2380 // End Of File ///////////////////////////////////////////////////////////////