Fixed incorrect usage of result (now object rather than scalar), thanks Michal Zygmun...
[pwlib.git] / src / ptclib / httpform.cxx
blobfc88250975f7c31a2c8cbeaf22b0b644ff72607f
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.49 2004/04/24 06:27:56 rjongbloed
28 * Fixed GCC 3.4.0 warnings about PAssertNULL and improved recoverability on
29 * NULL pointer usage in various bits of code.
31 * Revision 1.48 2004/04/03 08:22:20 csoutheren
32 * Remove pseudo-RTTI and replaced with real RTTI
34 * Revision 1.47 2003/03/24 04:31:03 robertj
35 * Added function to set and get strings from PConfig in correct format for
36 * use with HTTP form array contsructs.
38 * Revision 1.46 2002/11/22 06:20:26 robertj
39 * Added extra space around data entry fields.
40 * Added borders around arrays and composite fields.
41 * Added multi-line data entry for HTTPStringField > 128 characters.
43 * Revision 1.45 2002/11/06 22:47:25 robertj
44 * Fixed header comment (copyright etc)
46 * Revision 1.44 2002/10/10 04:43:44 robertj
47 * VxWorks port, thanks Martijn Roest
49 * Revision 1.43 2002/07/17 08:44:58 robertj
50 * Added links back to page and home page on accepted data html.
51 * Fixed display of validation error text if page not accepted.
53 * Revision 1.42 2001/10/10 08:07:48 robertj
54 * Fixed large memory leak of strings when doing POST to a form.
56 * Revision 1.41 2001/05/16 06:03:14 craigs
57 * Changed to allow access to absolute registry paths from within subforms
59 * Revision 1.40 2001/02/07 04:44:47 robertj
60 * Added ability to use check box to add/delete fields from arrays.
62 * Revision 1.39 2001/01/08 04:13:23 robertj
63 * Fixed bug with skipping every second option in determining the selected
64 * option in a SELECT field. No longer requires a </option> to work.
66 * Revision 1.38 2000/12/20 02:23:39 robertj
67 * Fixed variable array size value (caused extra blank entry ever commit).
69 * Revision 1.37 2000/12/18 12:13:08 robertj
70 * Fixed bug in auto-generated HTML in fixed size arrays, should not have add/delete box.
72 * Revision 1.36 2000/12/18 11:41:01 robertj
73 * Fixed bug in auto-generated HTML in non-array composite fields
75 * Revision 1.35 2000/12/18 07:14:30 robertj
76 * Added ability to have fixed length array fields.
77 * Fixed regular expressions so can have single '-' in field name.
78 * Fixed use of non-array subforprefix based compsite fields.
80 * Revision 1.34 2000/12/12 07:21:35 robertj
81 * Added ability to expand fields based on regex into repeated chunks of HTML.
83 * Revision 1.33 2000/11/02 21:55:28 craigs
84 * Added extra constructor
86 * Revision 1.32 2000/09/05 09:52:24 robertj
87 * Fixed bug in HTTP form updating SELECT fields from registry.
89 * Revision 1.31 2000/06/19 11:35:01 robertj
90 * Fixed bug in setting current value of options in select form fields.
92 * Revision 1.30 1999/02/10 13:19:45 robertj
93 * Fixed PConfig update problem when POSTing to the form. Especiall with arrays.
95 * Revision 1.29 1998/11/30 04:51:57 robertj
96 * New directory structure
98 * Revision 1.28 1998/11/14 11:11:06 robertj
99 * PPC GNU compiler compatibility.
101 * Revision 1.27 1998/10/01 09:05:11 robertj
102 * Fixed bug in nested composite field names, array indexes not being set correctly.
104 * Revision 1.26 1998/09/23 06:22:11 robertj
105 * Added open source copyright license.
107 * Revision 1.25 1998/08/20 05:51:06 robertj
108 * Fixed bug where substitutions did not always occur if near end of macro block.
109 * Improved internationalisation. Allow HTML override of strings in macros.
111 * Revision 1.24 1998/08/09 11:25:51 robertj
112 * GNU C++ warning removal.
114 * Revision 1.23 1998/08/09 10:35:11 robertj
115 * Changed array control so can have language override.
117 * Revision 1.22 1998/07/24 06:56:05 robertj
118 * Fixed case significance problem in HTTP forms.
119 * Improved detection of VALUE= fields with and without quotes.
121 * Revision 1.21 1998/03/20 03:16:43 robertj
122 * Fixed bug in beaing able to reset a check box field.
124 * Revision 1.20 1998/02/03 06:26:09 robertj
125 * Fixed propagation of inital values in arrays subfields.
126 * Fixed problem where hidden fields were being relaced with default values from PHTTPForm.
128 * Revision 1.19 1998/01/26 02:49:17 robertj
129 * GNU support.
131 * Revision 1.18 1998/01/26 01:51:37 robertj
132 * Fixed uninitialised variable.
134 * Revision 1.17 1998/01/26 00:25:25 robertj
135 * Major rewrite of HTTP forms management.
137 * Revision 1.16 1997/12/18 05:06:51 robertj
138 * Added missing braces to kill GNU compiler warning.
140 * Revision 1.15 1997/10/10 10:43:43 robertj
141 * Fixed bug in password encryption, missing string terminator.
143 * Revision 1.14 1997/08/28 12:48:29 robertj
144 * Changed array fields to allow for reordering.
146 * Revision 1.13 1997/08/21 12:44:10 robertj
147 * Fixed bug in HTTP form array size field.
148 * Fixed bug where section list was only replacing first instance of macro.
150 * Revision 1.12 1997/08/09 07:46:52 robertj
151 * Fixed problems with value of SELECT fields in form
153 * Revision 1.11 1997/08/04 10:41:13 robertj
154 * Fixed bug in new section list page for names with special characters in them.
156 * Revision 1.10 1997/07/26 11:38:20 robertj
157 * Support for overridable pages in HTTP service applications.
159 * Revision 1.9 1997/07/14 11:49:51 robertj
160 * Put "Add" and "Keep" on check boxes in array fields.
162 * Revision 1.8 1997/07/08 13:12:29 robertj
163 * Major HTTP form enhancements for lists and arrays of fields.
165 * Revision 1.7 1997/06/08 04:47:27 robertj
166 * Adding new llist based form field.
168 * Revision 1.6 1997/04/12 02:07:26 robertj
169 * Fixed boolean check boxes being more flexible on string values.
171 * Revision 1.5 1997/04/01 06:00:53 robertj
172 * Changed PHTTPConfig so if section empty string, does not write PConfig parameters.
174 * Revision 1.4 1996/10/08 13:10:34 robertj
175 * Fixed bug in boolean (checkbox) html forms, cannot be reset.
177 * Revision 1.3 1996/09/14 13:09:31 robertj
178 * Major upgrade:
179 * rearranged sockets to help support IPX.
180 * added indirect channel class and moved all protocols to descend from it,
181 * separating the protocol from the low level byte transport.
183 * Revision 1.2 1996/08/08 13:34:10 robertj
184 * Removed redundent call.
186 * Revision 1.1 1996/06/28 12:56:20 robertj
187 * Initial revision
191 #ifdef __GNUC__
192 #pragma implementation "httpform.h"
193 #endif
195 #include <ptlib.h>
196 #include <ptclib/httpform.h>
197 #include <ptclib/cypher.h>
200 //////////////////////////////////////////////////////////////////////////////
201 // PHTTPField
203 PHTTPField::PHTTPField(const char * nam, const char * titl, const char * hlp)
204 : baseName(nam), fullName(nam),
205 title(titl != NULL ? titl : nam),
206 help(hlp != NULL ? hlp : "")
208 notInHTML = TRUE;
212 PObject::Comparison PHTTPField::Compare(const PObject & obj) const
214 PAssert(PIsDescendant(&obj, PHTTPField), PInvalidCast);
215 return fullName.Compare(((const PHTTPField &)obj).fullName);
219 void PHTTPField::SetName(const PString & newName)
221 fullName = newName;
225 const PHTTPField * PHTTPField::LocateName(const PString & name) const
227 if (fullName == name)
228 return this;
230 return NULL;
234 void PHTTPField::SetHelp(const PString & hotLinkURL,
235 const PString & linkText)
237 help = "<A HREF=\"" + hotLinkURL + "\">" + linkText + "</A>\r\n";
241 void PHTTPField::SetHelp(const PString & hotLinkURL,
242 const PString & imageURL,
243 const PString & imageText)
245 help = "<A HREF=\"" + hotLinkURL + "\"><IMG SRC=\"" +
246 imageURL + "\" ALT=\"" + imageText + "\" ALIGN=absmiddle></A>\r\n";
250 static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
251 const PRegularExpression & endExpr,
252 const PString & text,
253 PINDEX offset,
254 PINDEX & pos,
255 PINDEX & len,
256 PINDEX & start,
257 PINDEX & finish)
259 start = finish = P_MAX_INDEX;
261 if (!text.FindRegEx(startExpr, pos, len, offset))
262 return FALSE;
264 PINDEX endpos, endlen;
265 if (!text.FindRegEx(endExpr, endpos, endlen, pos+len))
266 return TRUE;
268 start = pos + len;
269 finish = endpos - 1;
270 len = endpos - pos + endlen;
271 return TRUE;
275 static BOOL FindSpliceBlock(const PRegularExpression & startExpr,
276 const PString & text,
277 PINDEX offset,
278 PINDEX & pos,
279 PINDEX & len,
280 PINDEX & start,
281 PINDEX & finish)
283 static PRegularExpression EndBlock("<?!--#form[ \t\r\n]+end[ \t\r\n]*-->?",
284 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
285 return FindSpliceBlock(startExpr, EndBlock, text, offset, pos, len, start, finish);
289 static BOOL FindSpliceName(const PCaselessString & text,
290 PINDEX start,
291 PINDEX finish,
292 PINDEX & pos,
293 PINDEX & end)
295 if (text[start+1] != '!') {
296 static PRegularExpression NameExpr("name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"",
297 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
298 if ((pos = text.FindRegEx(NameExpr, start)) == P_MAX_INDEX)
299 return FALSE;
301 if (pos >= finish)
302 return FALSE;
304 pos = text.Find('"', pos) + 1;
305 end = text.Find('"', pos) - 1;
307 else {
308 pos = start + 9; // Skip over the <!--#form
309 while (isspace(text[pos])) // Skip over blanks
310 pos++;
311 while (pos < finish && !isspace(text[pos])) // Skip over keyword
312 pos++;
313 while (isspace(text[pos])) // Skip over more blanks
314 pos++;
316 end = text.Find("--", pos) - 1;
319 return end < finish;
323 static BOOL FindSpliceFieldName(const PString & text,
324 PINDEX offset,
325 PINDEX & pos,
326 PINDEX & len,
327 PString & name)
329 static PRegularExpression FieldName("<?!--#form[ \t\r\n]+[a-z0-9]+[ \t\r\n]+(-?[^-])+-->?"
331 "<[a-z]+[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
332 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
333 if (!text.FindRegEx(FieldName, pos, len, offset))
334 return FALSE;
336 PINDEX nameStart, nameEnd;
337 if (!FindSpliceName(text, pos, pos+len-1, nameStart, nameEnd))
338 return FALSE;
340 name = text(nameStart, nameEnd);
341 pos = nameStart;
342 len = nameEnd - nameStart + 1;
343 return TRUE;
347 static void SpliceAdjust(const PString & str,
348 PString & text,
349 PINDEX pos,
350 PINDEX & len,
351 PINDEX & finish)
353 text.Splice(str, pos, len);
354 PINDEX newLen = str.GetLength();
355 if (finish != P_MAX_INDEX)
356 finish += newLen - len;
357 len = newLen;
361 void PHTTPField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
363 PString name;
364 PINDEX pos, len;
365 while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
366 if (pos > finish)
367 break;
368 if (baseName == name)
369 SpliceAdjust(fullName, text, pos, len, finish);
370 start = pos + len;
375 static BOOL FindInputValue(const PString & text, PINDEX & before, PINDEX & after)
377 static PRegularExpression Value("value[ \t\r\n]*=[ \t\r\n]*(\"[^\"]*\"|[^> \t\r\n]+)",
378 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
379 PINDEX pos = text.FindRegEx(Value);
380 if (pos == P_MAX_INDEX)
381 return FALSE;
383 before = text.Find('"', pos);
384 if (before != P_MAX_INDEX)
385 after = text.Find('"', before+1);
386 else {
387 before = text.Find('=', pos);
388 while (isspace(text[before+1]))
389 before++;
390 after = before + 1;
391 while (text[after] != '\0' && text[after] != '>' && !isspace(text[after]))
392 after++;
394 return TRUE;
398 PString PHTTPField::GetHTMLInput(const PString & input) const
400 PINDEX before, after;
401 if (FindInputValue(input, before, after))
402 return input(0, before) + GetValue(FALSE) + input.Mid(after);
404 return "<input value=\"" + GetValue(FALSE) + "\"" + input.Mid(6);
408 static void AdjustSelectOptions(PString & text, PINDEX begin, PINDEX end,
409 const PString & myValue, PStringList & validValues,
410 PINDEX & finishAdjust)
412 PINDEX start, finish;
413 PINDEX pos = begin;
414 PINDEX len = 0;
415 static PRegularExpression StartOption("<[ \t\r\n]*option[^>]*>",
416 PRegularExpression::IgnoreCase);
417 static PRegularExpression EndOption("<[ \t\r\n]*/?option[^>]*>",
418 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
419 while (FindSpliceBlock(StartOption, EndOption, text, pos+len, pos, len, start, finish) && pos < end) {
420 if (start == P_MAX_INDEX)
421 start = text.Find('>', pos)+1;
422 else {
423 // Check for if option was not closed by </option> but another <option>
424 PINDEX optpos = text.FindRegEx(StartOption, start);
425 if (optpos < pos+len) // Adjust back to before <option> if so.
426 len = optpos-pos;
428 PCaselessString option = text(pos, start-1);
429 PINDEX before, after;
430 if (FindInputValue(option, before, after)) {
431 start = pos + before + 1;
432 finish = pos + after - 1;
434 PINDEX selpos = option.Find("selected");
435 PString thisValue = text(start, finish).Trim();
436 if (thisValue == myValue) {
437 if (selpos == P_MAX_INDEX) {
438 text.Splice(" selected", pos+7, 0);
439 if (finishAdjust != P_MAX_INDEX)
440 finishAdjust += 9;
441 if (end != P_MAX_INDEX)
442 end += 9;
443 len += 9;
446 else {
447 if (validValues.GetSize() > 0) {
448 PINDEX valid;
449 for (valid = 0; valid < validValues.GetSize(); valid++) {
450 if (thisValue == validValues[valid])
451 break;
453 if (valid >= validValues.GetSize()) {
454 text.Delete(pos, len);
455 selpos = P_MAX_INDEX;
456 if (finishAdjust != P_MAX_INDEX)
457 finishAdjust -= len;
458 if (end != P_MAX_INDEX)
459 end -= len;
460 len = 0;
463 if (selpos != P_MAX_INDEX) {
464 selpos += pos;
465 PINDEX sellen = 8;
466 if (text[selpos-1] == ' ') {
467 selpos--;
468 sellen++;
470 text.Delete(selpos, sellen);
471 if (finishAdjust != P_MAX_INDEX)
472 finishAdjust -= sellen;
473 if (end != P_MAX_INDEX)
474 end -= sellen;
475 len -= sellen;
481 PString PHTTPField::GetHTMLSelect(const PString & selection) const
483 PString text = selection;
484 PStringList dummy1;
485 PINDEX dummy2 = P_MAX_INDEX;
486 AdjustSelectOptions(text, 0, P_MAX_INDEX, GetValue(FALSE), dummy1, dummy2);
487 return text;
491 void PHTTPField::GetHTMLHeading(PHTML &) const
496 static int SplitConfigKey(const PString & fullName,
497 PString & section, PString & key)
499 if (fullName.IsEmpty())
500 return 0;
502 PINDEX slash = fullName.FindLast('\\');
503 if (slash == 0 || slash >= fullName.GetLength()-1) {
504 key = fullName;
505 return 1;
508 section = fullName.Left(slash);
509 key = fullName.Mid(slash+1);
510 if (section.IsEmpty() || key.IsEmpty())
511 return 0;
513 return 2;
517 void PHTTPField::LoadFromConfig(PConfig & cfg)
519 PString section, key;
520 switch (SplitConfigKey(fullName, section, key)) {
521 case 1 :
522 SetValue(cfg.GetString(key, GetValue(TRUE)));
523 break;
524 case 2 :
525 SetValue(cfg.GetString(section, key, GetValue(TRUE)));
530 void PHTTPField::SaveToConfig(PConfig & cfg) const
532 PString section, key;
533 switch (SplitConfigKey(fullName, section, key)) {
534 case 1 :
535 cfg.SetString(key, GetValue());
536 break;
537 case 2 :
538 cfg.SetString(section, key, GetValue());
543 BOOL PHTTPField::Validated(const PString &, PStringStream &) const
545 return TRUE;
549 void PHTTPField::GetAllNames(PStringList & list) const
551 list.AppendString(fullName);
555 void PHTTPField::SetAllValues(const PStringToString & data)
557 if (!baseName && data.Contains(fullName))
558 SetValue(data[fullName]);
562 BOOL PHTTPField::ValidateAll(const PStringToString & data, PStringStream & msg) const
564 if (data.Contains(fullName))
565 return Validated(data[fullName], msg);
566 return TRUE;
570 //////////////////////////////////////////////////////////////////////////////
571 // PHTTPCompositeField
573 PHTTPCompositeField::PHTTPCompositeField(const char * nam,
574 const char * titl,
575 const char * hlp)
576 : PHTTPField(nam, titl, hlp)
581 void PHTTPCompositeField::SetName(const PString & newName)
583 if (fullName.IsEmpty() || newName.IsEmpty())
584 return;
586 for (PINDEX i = 0; i < fields.GetSize(); i++) {
587 PHTTPField & field = fields[i];
589 PString firstPartOfName = psprintf(fullName, i+1);
590 PString subFieldName;
591 if (field.GetName().Find(firstPartOfName) == 0)
592 subFieldName = field.GetName().Mid(firstPartOfName.GetLength());
593 else
594 subFieldName = field.GetName();
596 firstPartOfName = psprintf(newName, i+1);
597 if (subFieldName[0] == '\\' || firstPartOfName[firstPartOfName.GetLength()-1] == '\\')
598 field.SetName(firstPartOfName + subFieldName);
599 else
600 field.SetName(firstPartOfName & subFieldName);
603 PHTTPField::SetName(newName);
607 const PHTTPField * PHTTPCompositeField::LocateName(const PString & name) const
609 if (fullName == name)
610 return this;
612 for (PINDEX i = 0; i < fields.GetSize(); i++) {
613 const PHTTPField * field = fields[i].LocateName(name);
614 if (field != NULL)
615 return field;
618 return NULL;
622 PHTTPField * PHTTPCompositeField::NewField() const
624 PHTTPCompositeField * fld = new PHTTPCompositeField(baseName, title, help);
625 for (PINDEX i = 0; i < fields.GetSize(); i++)
626 fld->Append(fields[i].NewField());
627 return fld;
631 void PHTTPCompositeField::GetHTMLTag(PHTML & html) const
633 for (PINDEX i = 0; i < fields.GetSize(); i++) {
634 if (i != 0 && html.Is(PHTML::InTable))
635 html << PHTML::TableData("NOWRAP ALIGN=CENTER");
636 fields[i].GetHTMLTag(html);
641 PString PHTTPCompositeField::GetHTMLInput(const PString & input) const
643 return input;
647 void PHTTPCompositeField::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
649 static PRegularExpression FieldName( "!--#form[ \t\r\n]+(-?[^-])+[ \t\r\n]+(-?[^-])+--"
651 "<[a-z]*[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
652 PRegularExpression::IgnoreCase);
654 PString name;
655 PINDEX pos, len;
656 while (start < finish && FindSpliceFieldName(text, start, pos, len, name)) {
657 if (pos > finish)
658 break;
659 for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
660 if (fields[fld].GetBaseName() *= name) {
661 SpliceAdjust(fields[fld].GetName(), text, pos, len, finish);
662 break;
665 start = pos + len;
670 void PHTTPCompositeField::GetHTMLHeading(PHTML & html) const
672 html << PHTML::TableRow();
673 for (PINDEX i = 0; i < fields.GetSize(); i++)
674 html << PHTML::TableHeader() << fields[i].GetTitle();
678 PString PHTTPCompositeField::GetValue(BOOL dflt) const
680 PStringStream value;
681 for (PINDEX i = 0; i < fields.GetSize(); i++)
682 value << fields[i].GetValue(dflt) << '\n';
683 return value;
687 void PHTTPCompositeField::SetValue(const PString &)
689 PAssertAlways(PLogicError);
693 void PHTTPCompositeField::LoadFromConfig(PConfig & cfg)
695 SetName(fullName);
696 for (PINDEX i = 0; i < GetSize(); i++)
697 fields[i].LoadFromConfig(cfg);
701 void PHTTPCompositeField::SaveToConfig(PConfig & cfg) const
703 for (PINDEX i = 0; i < GetSize(); i++)
704 fields[i].SaveToConfig(cfg);
708 void PHTTPCompositeField::GetAllNames(PStringList & list) const
710 for (PINDEX i = 0; i < GetSize(); i++)
711 fields[i].GetAllNames(list);
715 void PHTTPCompositeField::SetAllValues(const PStringToString & data)
717 for (PINDEX i = 0; i < fields.GetSize(); i++)
718 fields[i].SetAllValues(data);
722 BOOL PHTTPCompositeField::ValidateAll(const PStringToString & data,
723 PStringStream & msg) const
725 for (PINDEX i = 0; i < fields.GetSize(); i++)
726 if (!fields[i].ValidateAll(data, msg))
727 return FALSE;
729 return TRUE;
733 PINDEX PHTTPCompositeField::GetSize() const
735 return fields.GetSize();
739 void PHTTPCompositeField::Append(PHTTPField * fld)
741 fields.Append(fld);
745 //////////////////////////////////////////////////////////////////////////////
746 // PHTTPSubForm
748 PHTTPSubForm::PHTTPSubForm(const PString & subForm,
749 const char * name,
750 const char * title,
751 PINDEX prim,
752 PINDEX sec)
753 : PHTTPCompositeField(name, title, NULL),
754 subFormName(subForm)
756 primary = prim;
757 secondary = sec;
761 PHTTPField * PHTTPSubForm::NewField() const
763 PHTTPCompositeField * fld = new PHTTPSubForm(subFormName, baseName, title, primary, secondary);
764 for (PINDEX i = 0; i < fields.GetSize(); i++)
765 fld->Append(fields[i].NewField());
766 return fld;
770 void PHTTPSubForm::GetHTMLTag(PHTML & html) const
772 PString value = fields[primary].GetValue();
773 if (value.IsEmpty())
774 value = "New";
775 html << PHTML::HotLink(subFormName +
776 "?subformprefix=" + PURL::TranslateString(fullName, PURL::QueryTranslation))
777 << value << PHTML::HotLink();
779 if (secondary != P_MAX_INDEX)
780 html << PHTML::TableData("NOWRAP") << fields[secondary].GetValue();
784 void PHTTPSubForm::GetHTMLHeading(PHTML &) const
789 //////////////////////////////////////////////////////////////////////////////
790 // PHTTPFieldArray
792 PHTTPFieldArray::PHTTPFieldArray(PHTTPField * fld, BOOL ordered, PINDEX fixedSize)
793 : PHTTPCompositeField(fld->GetName(), fld->GetTitle(), fld->GetHelp()),
794 baseField(fld)
796 orderedArray = ordered;
797 canAddElements = fixedSize == 0;
798 SetSize(fixedSize);
802 PHTTPFieldArray::~PHTTPFieldArray()
804 delete baseField;
808 void PHTTPFieldArray::SetSize(PINDEX newSize)
810 while (fields.GetSize() > newSize)
811 fields.RemoveAt(fields.GetSize()-1);
812 while (fields.GetSize() < newSize)
813 AddBlankField();
814 if (canAddElements)
815 AddBlankField();
819 PHTTPField * PHTTPFieldArray::NewField() const
821 return new PHTTPFieldArray(baseField->NewField(), orderedArray);
825 static const char ArrayControlBox[] = " Array Control";
826 static const char ArrayControlKeep[] = "Keep";
827 static const char ArrayControlRemove[] = "Remove";
828 static const char ArrayControlMoveUp[] = "Move Up";
829 static const char ArrayControlMoveDown[] = "Move Down";
830 static const char ArrayControlToTop[] = "To Top";
831 static const char ArrayControlToBottom[] = "To Bottom";
832 static const char ArrayControlIgnore[] = "Ignore";
833 static const char ArrayControlAddTop[] = "Add Top";
834 static const char ArrayControlAddBottom[] = "Add Bottom";
835 static const char ArrayControlAdd[] = "Add";
837 static PStringList GetArrayControlOptions(PINDEX fld, PINDEX size, BOOL orderedArray)
839 PStringList options;
841 if (fld >= size) {
842 options.AppendString(ArrayControlIgnore);
843 if (size == 0 || !orderedArray)
844 options.AppendString(ArrayControlAdd);
845 else {
846 options.AppendString(ArrayControlAddTop);
847 options.AppendString(ArrayControlAddBottom);
850 else {
851 options.AppendString(ArrayControlKeep);
852 options.AppendString(ArrayControlRemove);
853 if (orderedArray) {
854 if (fld > 0)
855 options.AppendString(ArrayControlMoveUp);
856 if (fld < size-1)
857 options.AppendString(ArrayControlMoveDown);
858 if (fld > 0)
859 options.AppendString(ArrayControlToTop);
860 if (fld < size-1)
861 options.AppendString(ArrayControlToBottom);
865 return options;
868 void PHTTPFieldArray::AddArrayControlBox(PHTML & html, PINDEX fld) const
870 PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
871 html << PHTML::Select(fields[fld].GetName() + ArrayControlBox);
872 for (PINDEX i = 0; i < options.GetSize(); i++)
873 html << PHTML::Option(i == 0 ? PHTML::Selected : PHTML::NotSelected) << options[i];
874 html << PHTML::Select();
878 void PHTTPFieldArray::GetHTMLTag(PHTML & html) const
880 html << PHTML::TableStart("border=1 cellspacing=0 cellpadding=8");
881 baseField->GetHTMLHeading(html);
882 for (PINDEX i = 0; i < fields.GetSize(); i++) {
883 html << PHTML::TableRow() << PHTML::TableData("NOWRAP");
884 fields[i].GetHTMLTag(html);
885 html << PHTML::TableData("NOWRAP");
886 if (canAddElements)
887 AddArrayControlBox(html, i);
889 html << PHTML::TableEnd();
893 void PHTTPFieldArray::ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const
895 PString original = text(start, finish);
896 PINDEX origFinish = finish;
897 PINDEX finalFinish = finish;
899 PINDEX fld = fields.GetSize();
900 while (fld > 0) {
901 fields[--fld].ExpandFieldNames(text, start, finish);
903 PINDEX pos,len;
904 static PRegularExpression RowNum("<?!--#form[ \t\r\n]+rownum[ \t\r\n]*-->?",
905 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
906 while (text.FindRegEx(RowNum, pos, len, start, finish))
907 SpliceAdjust(psprintf("%u", fld+1), text, pos, len, finish);
909 static PRegularExpression SubForm("<?!--#form[ \t\r\n]+subform[ \t\r\n]*-->?",
910 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
911 while (text.FindRegEx(SubForm, pos, len, start, finish)) {
912 PString fmt = fullName;
913 if (fmt.Find("%u") == P_MAX_INDEX)
914 fmt += " %u";
915 SpliceAdjust("subformprefix=" + PURL::TranslateString(psprintf(fmt, fld+1), PURL::QueryTranslation),
916 text, pos, len, finish);
919 static PRegularExpression RowControl("<?!--#form[ \t\r\n]+rowcontrol[ \t\r\n]*-->?",
920 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
921 while (text.FindRegEx(RowControl, pos, len, start, finish)) {
922 PHTML html(PHTML::InForm);
923 if (canAddElements)
924 AddArrayControlBox(html, fld);
925 SpliceAdjust(html, text, pos, len, finish);
928 static PRegularExpression RowCheck("<?!--#form[ \t\r\n]+row(add|delete)[ \t\r\n]*(-?[^-])*-->?",
929 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
930 while (text.FindRegEx(RowCheck, pos, len, start, finish)) {
931 PStringStream checkbox;
932 if (canAddElements) {
933 PINDEX titlepos = text.Find("row", start)+3;
934 BOOL adding = text[titlepos] == 'a';
935 if (( adding && fld >= fields.GetSize()-1) ||
936 (!adding && fld < fields.GetSize()-1)) {
937 titlepos += adding ? 3 : 6;
938 PINDEX dashes = text.Find("--", titlepos);
939 PString title = text(titlepos, dashes-1).Trim();
940 if (title.IsEmpty() && adding)
941 title = "Add";
942 checkbox << title
943 << "<INPUT TYPE=checkbox NAME=\""
944 << fields[fld].GetName()
945 << ArrayControlBox
946 << "\" VALUE="
947 << (adding ? ArrayControlAdd : ArrayControlRemove)
948 << '>';
951 SpliceAdjust(checkbox, text, pos, len, finish);
954 static PRegularExpression SelectRow("<select[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"!--#form[ \t\r\n]+rowselect[ \t\r\n]*--\"[^>]*>",
955 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
956 static PRegularExpression SelEndRegEx("</select[^>]*>",
957 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
958 PINDEX begin, end;
959 while (FindSpliceBlock(SelectRow, SelEndRegEx, text, 0, pos, len, begin, end)) {
960 PStringList options = GetArrayControlOptions(fld, fields.GetSize()-1, orderedArray);
961 AdjustSelectOptions(text, begin, end, options[0], options, finish);
962 static PRegularExpression RowSelect("!--#form[ \t\r\n]+rowselect[ \t\r\n]*--",
963 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
964 if (text.FindRegEx(RowSelect, pos, len, pos, begin))
965 SpliceAdjust(fields[fld].GetName() + ArrayControlBox, text, pos, len, finish);
968 finalFinish += finish - origFinish;
970 if (fld > 0) {
971 text.Splice(original, start, 0);
972 finish = origFinish;
973 finalFinish += finish - start;
977 finish = finalFinish;
981 static int SplitArraySizeKey(const PString & fullName,
982 PString & section, PString & key)
984 static const char ArraySize[] = "Array Size";
985 PINDEX pos = fullName.Find("%u");
986 if (pos == P_MAX_INDEX)
987 return SplitConfigKey(fullName & ArraySize, section, key);
989 PINDEX endPos = fullName.GetLength() - 1;
990 if (fullName[endPos] == '\\')
991 endPos--;
992 return SplitConfigKey(fullName.Left(pos) & ArraySize & fullName(pos+2, endPos), section, key);
996 void PHTTPFieldArray::LoadFromConfig(PConfig & cfg)
998 if (canAddElements) {
999 PString section, key;
1000 switch (SplitArraySizeKey(fullName, section, key)) {
1001 case 1 :
1002 SetSize(cfg.GetInteger(key, GetSize()));
1003 break;
1004 case 2 :
1005 SetSize(cfg.GetInteger(section, key, GetSize()));
1008 PHTTPCompositeField::LoadFromConfig(cfg);
1012 void PHTTPFieldArray::SaveToConfig(PConfig & cfg) const
1014 if (canAddElements) {
1015 PString section, key;
1016 switch (SplitArraySizeKey(fullName, section, key)) {
1017 case 1 :
1018 cfg.SetInteger(key, GetSize());
1019 break;
1020 case 2 :
1021 cfg.SetInteger(section, key, GetSize());
1024 PHTTPCompositeField::SaveToConfig(cfg);
1028 void PHTTPFieldArray::SetArrayFieldName(PINDEX idx) const
1030 PString fmt = fullName;
1031 if (fmt.Find("%u") == P_MAX_INDEX)
1032 fmt += " %u";
1033 fields[idx].SetName(psprintf(fmt, idx+1));
1037 void PHTTPFieldArray::SetAllValues(const PStringToString & data)
1039 PHTTPFieldList newFields;
1040 newFields.DisallowDeleteObjects();
1041 PINDEX i;
1042 for (i = 0; i < fields.GetSize(); i++)
1043 newFields.Append(fields.GetAt(i));
1045 BOOL lastFieldIsSet = FALSE;
1046 PINDEX size = fields.GetSize();
1047 for (i = 0; i < size; i++) {
1048 PHTTPField * fieldPtr = &fields[i];
1049 PINDEX pos = newFields.GetObjectsIndex(fieldPtr);
1050 fieldPtr->SetAllValues(data);
1052 PString control = data(fieldPtr->GetName() + ArrayControlBox);
1053 if (control == ArrayControlMoveUp) {
1054 if (pos > 0) {
1055 newFields.SetAt(pos, newFields.GetAt(pos-1));
1056 newFields.SetAt(pos-1, fieldPtr);
1059 else if (control == ArrayControlMoveDown) {
1060 if (size > 2 && pos < size-2) {
1061 newFields.SetAt(pos, newFields.GetAt(pos+1));
1062 newFields.SetAt(pos+1, fieldPtr);
1065 else if (control == ArrayControlToTop) {
1066 newFields.RemoveAt(pos);
1067 newFields.InsertAt(0, fieldPtr);
1069 else if (control == ArrayControlToBottom) {
1070 newFields.RemoveAt(pos);
1071 newFields.Append(fieldPtr);
1073 else if (control == ArrayControlAddTop) {
1074 if (i == size-1) {
1075 newFields.RemoveAt(pos);
1076 newFields.InsertAt(0, fieldPtr);
1077 lastFieldIsSet = TRUE;
1080 else if (control == ArrayControlAddBottom || control == ArrayControlAdd) {
1081 if (i == size-1) {
1082 newFields.RemoveAt(pos);
1083 newFields.Append(fieldPtr);
1084 lastFieldIsSet = TRUE;
1087 else if (control == ArrayControlIgnore) {
1088 newFields.RemoveAt(pos);
1089 newFields.Append(fieldPtr);
1091 else if (control == ArrayControlRemove)
1092 newFields.RemoveAt(pos);
1095 fields.DisallowDeleteObjects();
1096 for (i = 0; i < newFields.GetSize(); i++)
1097 fields.Remove(newFields.GetAt(i));
1098 fields.AllowDeleteObjects();
1099 fields.RemoveAll();
1101 for (i = 0; i < newFields.GetSize(); i++) {
1102 fields.Append(newFields.GetAt(i));
1103 SetArrayFieldName(i);
1106 if (lastFieldIsSet && canAddElements)
1107 AddBlankField();
1111 PINDEX PHTTPFieldArray::GetSize() const
1113 PINDEX size = fields.GetSize();
1114 PAssert(size > 0, PLogicError);
1115 if (canAddElements)
1116 size--;
1117 return size;
1121 void PHTTPFieldArray::AddBlankField()
1123 fields.Append(baseField->NewField());
1124 SetArrayFieldName(fields.GetSize()-1);
1128 PStringArray PHTTPFieldArray::GetStrings(PConfig & cfg)
1130 LoadFromConfig(cfg);
1132 PStringArray values(GetSize());
1134 for (PINDEX i = 0; i < GetSize(); i++)
1135 values[i] = fields[i].GetValue(FALSE);
1137 return values;
1141 void PHTTPFieldArray::SetStrings(PConfig & cfg, const PStringArray & values)
1143 SetSize(values.GetSize());
1144 for (PINDEX i = 0; i < values.GetSize(); i++)
1145 fields[i].SetValue(values[i]);
1147 SaveToConfig(cfg);
1151 //////////////////////////////////////////////////////////////////////////////
1152 // PHTTPStringField
1154 PHTTPStringField::PHTTPStringField(const char * name,
1155 PINDEX siz,
1156 const char * initVal,
1157 const char * help)
1158 : PHTTPField(name, NULL, help),
1159 value(initVal != NULL ? initVal : ""),
1160 initialValue(value)
1162 size = siz;
1166 PHTTPStringField::PHTTPStringField(const char * name,
1167 const char * title,
1168 PINDEX siz,
1169 const char * initVal,
1170 const char * help)
1171 : PHTTPField(name, title, help),
1172 value(initVal != NULL ? initVal : ""),
1173 initialValue(value)
1175 size = siz;
1179 PHTTPField * PHTTPStringField::NewField() const
1181 return new PHTTPStringField(baseName, title, size, initialValue, help);
1185 void PHTTPStringField::GetHTMLTag(PHTML & html) const
1187 if (size < 128)
1188 html << PHTML::InputText(fullName, size, value);
1189 else
1190 html << PHTML::TextArea(fullName, (size+79)/80, 80) << value << PHTML::TextArea(fullName);
1194 void PHTTPStringField::SetValue(const PString & newVal)
1196 value = newVal;
1200 PString PHTTPStringField::GetValue(BOOL dflt) const
1202 if (dflt)
1203 return initialValue;
1204 else
1205 return value;
1209 //////////////////////////////////////////////////////////////////////////////
1210 // PHTTPPasswordField
1212 PHTTPPasswordField::PHTTPPasswordField(const char * name,
1213 PINDEX siz,
1214 const char * initVal,
1215 const char * help)
1216 : PHTTPStringField(name, siz, initVal, help)
1221 PHTTPPasswordField::PHTTPPasswordField(const char * name,
1222 const char * title,
1223 PINDEX siz,
1224 const char * initVal,
1225 const char * help)
1226 : PHTTPStringField(name, title, siz, initVal, help)
1231 PHTTPField * PHTTPPasswordField::NewField() const
1233 return new PHTTPPasswordField(baseName, title, size, initialValue, help);
1237 void PHTTPPasswordField::GetHTMLTag(PHTML & html) const
1239 html << PHTML::InputPassword(fullName, size, value);
1243 static const PTEACypher::Key PasswordKey = {
1245 103, 60, 222, 17, 128, 157, 31, 137,
1246 133, 64, 82, 148, 94, 136, 4, 209
1250 void PHTTPPasswordField::SetValue(const PString & newVal)
1252 value = Decrypt(newVal);
1256 PString PHTTPPasswordField::GetValue(BOOL dflt) const
1258 if (dflt)
1259 return initialValue;
1261 PTEACypher crypt(PasswordKey);
1262 return crypt.Encode(value);
1266 PString PHTTPPasswordField::Decrypt(const PString & pword)
1268 PString clear;
1269 PTEACypher crypt(PasswordKey);
1270 return crypt.Decode(pword, clear) ? clear : pword;
1274 //////////////////////////////////////////////////////////////////////////////
1275 // PHTTPIntegerField
1277 PHTTPIntegerField::PHTTPIntegerField(const char * nam,
1278 int lo, int hig,
1279 int initVal,
1280 const char * unit,
1281 const char * help)
1282 : PHTTPField(nam, NULL, help), units(unit != NULL ? unit : "")
1284 low = lo;
1285 high = hig;
1286 value = initialValue = initVal;
1289 PHTTPIntegerField::PHTTPIntegerField(const char * nam,
1290 const char * titl,
1291 int lo, int hig,
1292 int initVal,
1293 const char * unit,
1294 const char * help)
1295 : PHTTPField(nam, titl, help), units(unit != NULL ? unit : "")
1297 low = lo;
1298 high = hig;
1299 value = initialValue = initVal;
1303 PHTTPField * PHTTPIntegerField::NewField() const
1305 return new PHTTPIntegerField(baseName, title, low, high, initialValue, units, help);
1309 void PHTTPIntegerField::GetHTMLTag(PHTML & html) const
1311 html << PHTML::InputRange(fullName, low, high, value) << " " << units;
1315 void PHTTPIntegerField::SetValue(const PString & newVal)
1317 value = newVal.AsInteger();
1321 PString PHTTPIntegerField::GetValue(BOOL dflt) const
1323 return PString(PString::Signed, dflt ? initialValue : value);
1327 void PHTTPIntegerField::LoadFromConfig(PConfig & cfg)
1329 PString section, key;
1330 switch (SplitConfigKey(fullName, section, key)) {
1331 case 1 :
1332 value = cfg.GetInteger(key, initialValue);
1333 break;
1334 case 2 :
1335 value = cfg.GetInteger(section, key, initialValue);
1340 void PHTTPIntegerField::SaveToConfig(PConfig & cfg) const
1342 PString section, key;
1343 switch (SplitConfigKey(fullName, section, key)) {
1344 case 1 :
1345 cfg.SetInteger(key, value);
1346 break;
1347 case 2 :
1348 cfg.SetInteger(section, key, value);
1353 BOOL PHTTPIntegerField::Validated(const PString & newVal, PStringStream & msg) const
1355 int val = newVal.AsInteger();
1356 if (val >= low && val <= high)
1357 return TRUE;
1359 msg << "The field \"" << GetName() << "\" should be between "
1360 << low << " and " << high << ".<BR>";
1361 return FALSE;
1365 //////////////////////////////////////////////////////////////////////////////
1366 // PHTTPBooleanField
1368 PHTTPBooleanField::PHTTPBooleanField(const char * name,
1369 BOOL initVal,
1370 const char * help)
1371 : PHTTPField(name, NULL, help)
1373 value = initialValue = initVal;
1377 PHTTPBooleanField::PHTTPBooleanField(const char * name,
1378 const char * title,
1379 BOOL initVal,
1380 const char * help)
1381 : PHTTPField(name, title, help)
1383 value = initialValue = initVal;
1387 PHTTPField * PHTTPBooleanField::NewField() const
1389 return new PHTTPBooleanField(baseName, title, initialValue, help);
1393 void PHTTPBooleanField::GetHTMLTag(PHTML & html) const
1395 html << PHTML::HiddenField(fullName, "FALSE")
1396 << PHTML::CheckBox(fullName, value ? PHTML::Checked : PHTML::UnChecked);
1400 static void SpliceChecked(PString & text, BOOL value)
1402 PINDEX pos = text.Find("checked");
1403 if (value) {
1404 if (pos == P_MAX_INDEX)
1405 text.Splice(" checked", 6, 0);
1407 else {
1408 if (pos != P_MAX_INDEX) {
1409 PINDEX len = 7;
1410 if (text[pos-1] == ' ') {
1411 pos--;
1412 len++;
1414 text.Delete(pos, len);
1420 PString PHTTPBooleanField::GetHTMLInput(const PString & input) const
1422 static PRegularExpression checkboxRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?checkbox\"?",
1423 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1424 if (input.FindRegEx(checkboxRegEx) != P_MAX_INDEX) {
1425 PCaselessString text;
1426 PINDEX before, after;
1427 if (FindInputValue(input, before, after))
1428 text = input(0, before) + "TRUE" + input.Mid(after);
1429 else
1430 text = "<input value=\"TRUE\"" + input.Mid(6);
1431 SpliceChecked(text, value);
1432 return "<input type=hidden name=\"" + fullName + "\">" + text;
1435 static PRegularExpression radioRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?radio\"?",
1436 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1437 if (input.FindRegEx(radioRegEx) != P_MAX_INDEX) {
1438 PINDEX before, after;
1439 if (FindInputValue(input, before, after)) {
1440 PCaselessString text = input;
1441 PString val = input(before+1, after-1);
1442 SpliceChecked(text, (value && (val *= "TRUE")) || (!value && (val *= "FALSE")));
1443 return text;
1445 return input;
1448 return PHTTPField::GetHTMLInput(input);
1452 void PHTTPBooleanField::SetValue(const PString & val)
1454 value = toupper(val[0]) == 'T' || toupper(val[0]) == 'y' ||
1455 val.AsInteger() != 0 || val.Find("TRUE") != P_MAX_INDEX;
1459 PString PHTTPBooleanField::GetValue(BOOL dflt) const
1461 return ((dflt ? initialValue : value) ? "True" : "False");
1465 void PHTTPBooleanField::LoadFromConfig(PConfig & cfg)
1467 PString section, key;
1468 switch (SplitConfigKey(fullName, section, key)) {
1469 case 1 :
1470 value = cfg.GetBoolean(key, initialValue);
1471 break;
1472 case 2 :
1473 value = cfg.GetBoolean(section, key, initialValue);
1478 void PHTTPBooleanField::SaveToConfig(PConfig & cfg) const
1480 PString section, key;
1481 switch (SplitConfigKey(fullName, section, key)) {
1482 case 1 :
1483 cfg.SetBoolean(key, value);
1484 break;
1485 case 2 :
1486 cfg.SetBoolean(section, key, value);
1491 //////////////////////////////////////////////////////////////////////////////
1492 // PHTTPRadioField
1494 PHTTPRadioField::PHTTPRadioField(const char * name,
1495 const PStringArray & valueArray,
1496 PINDEX initVal,
1497 const char * help)
1498 : PHTTPField(name, NULL, help),
1499 values(valueArray),
1500 titles(valueArray),
1501 value(valueArray[initVal]),
1502 initialValue(value)
1507 PHTTPRadioField::PHTTPRadioField(const char * name,
1508 const PStringArray & valueArray,
1509 const PStringArray & titleArray,
1510 PINDEX initVal,
1511 const char * help)
1512 : PHTTPField(name, NULL, help),
1513 values(valueArray),
1514 titles(titleArray),
1515 value(valueArray[initVal]),
1516 initialValue(value)
1521 PHTTPRadioField::PHTTPRadioField(const char * name,
1522 PINDEX count,
1523 const char * const * valueStrings,
1524 PINDEX initVal,
1525 const char * help)
1526 : PHTTPField(name, NULL, help),
1527 values(count, valueStrings),
1528 titles(count, valueStrings),
1529 value(valueStrings[initVal]),
1530 initialValue(value)
1535 PHTTPRadioField::PHTTPRadioField(const char * name,
1536 PINDEX count,
1537 const char * const * valueStrings,
1538 const char * const * titleStrings,
1539 PINDEX initVal,
1540 const char * help)
1541 : PHTTPField(name, NULL, help),
1542 values(count, valueStrings),
1543 titles(count, titleStrings),
1544 value(valueStrings[initVal]),
1545 initialValue(value)
1550 PHTTPRadioField::PHTTPRadioField(const char * name,
1551 const char * groupTitle,
1552 const PStringArray & valueArray,
1553 PINDEX initVal,
1554 const char * help)
1555 : PHTTPField(name, groupTitle, help),
1556 values(valueArray),
1557 titles(valueArray),
1558 value(valueArray[initVal]),
1559 initialValue(value)
1564 PHTTPRadioField::PHTTPRadioField(const char * name,
1565 const char * groupTitle,
1566 const PStringArray & valueArray,
1567 const PStringArray & titleArray,
1568 PINDEX initVal,
1569 const char * help)
1570 : PHTTPField(name, groupTitle, help),
1571 values(valueArray),
1572 titles(titleArray),
1573 value(valueArray[initVal]),
1574 initialValue(value)
1579 PHTTPRadioField::PHTTPRadioField(const char * name,
1580 const char * groupTitle,
1581 PINDEX count,
1582 const char * const * valueStrings,
1583 PINDEX initVal,
1584 const char * help)
1585 : PHTTPField(name, groupTitle, help),
1586 values(count, valueStrings),
1587 titles(count, valueStrings),
1588 value(valueStrings[initVal]),
1589 initialValue(value)
1594 PHTTPRadioField::PHTTPRadioField(const char * name,
1595 const char * groupTitle,
1596 PINDEX count,
1597 const char * const * valueStrings,
1598 const char * const * titleStrings,
1599 PINDEX initVal,
1600 const char * help)
1601 : PHTTPField(name, groupTitle, help),
1602 values(count, valueStrings),
1603 titles(count, titleStrings),
1604 value(valueStrings[initVal]),
1605 initialValue(value)
1610 PHTTPField * PHTTPRadioField::NewField() const
1612 return new PHTTPRadioField(*this);
1616 void PHTTPRadioField::GetHTMLTag(PHTML & html) const
1618 for (PINDEX i = 0; i < values.GetSize(); i++)
1619 html << PHTML::RadioButton(fullName, values[i],
1620 values[i] == value ? PHTML::Checked : PHTML::UnChecked)
1621 << titles[i]
1622 << PHTML::BreakLine();
1626 PString PHTTPRadioField::GetHTMLInput(const PString & input) const
1628 PString inval;
1629 PINDEX before, after;
1630 if (FindInputValue(input, before, after))
1631 inval = input(before+1, after-1);
1632 else
1633 inval = baseName;
1635 if (inval != value)
1636 return input;
1638 return "<input checked" + input.Mid(6);
1642 PString PHTTPRadioField::GetValue(BOOL dflt) const
1644 if (dflt)
1645 return initialValue;
1646 else
1647 return value;
1651 void PHTTPRadioField::SetValue(const PString & newVal)
1653 value = newVal;
1657 //////////////////////////////////////////////////////////////////////////////
1658 // PHTTPSelectField
1660 PHTTPSelectField::PHTTPSelectField(const char * name,
1661 const PStringArray & valueArray,
1662 PINDEX initVal,
1663 const char * help)
1664 : PHTTPField(name, NULL, help),
1665 values(valueArray)
1667 initialValue = initVal;
1668 if (initVal < values.GetSize())
1669 value = values[initVal];
1673 PHTTPSelectField::PHTTPSelectField(const char * name,
1674 PINDEX count,
1675 const char * const * valueStrings,
1676 PINDEX initVal,
1677 const char * help)
1678 : PHTTPField(name, NULL, help),
1679 values(count, valueStrings)
1681 initialValue = initVal;
1682 if (initVal < count)
1683 value = values[initVal];
1687 PHTTPSelectField::PHTTPSelectField(const char * name,
1688 const char * title,
1689 const PStringArray & valueArray,
1690 PINDEX initVal,
1691 const char * help)
1692 : PHTTPField(name, title, help),
1693 values(valueArray)
1695 initialValue = initVal;
1696 if (initVal < values.GetSize())
1697 value = values[initVal];
1701 PHTTPSelectField::PHTTPSelectField(const char * name,
1702 const char * title,
1703 PINDEX count,
1704 const char * const * valueStrings,
1705 PINDEX initVal,
1706 const char * help)
1707 : PHTTPField(name, title, help),
1708 values(count, valueStrings)
1710 initialValue = initVal;
1711 if (initVal < values.GetSize())
1712 value = values[initVal];
1716 PHTTPField * PHTTPSelectField::NewField() const
1718 return new PHTTPSelectField(baseName, title, values, initialValue, help);
1722 void PHTTPSelectField::GetHTMLTag(PHTML & html) const
1724 html << PHTML::Select(fullName);
1725 for (PINDEX i = 0; i < values.GetSize(); i++)
1726 html << PHTML::Option(values[i] == value ? PHTML::Selected : PHTML::NotSelected)
1727 << values[i];
1728 html << PHTML::Select();
1732 PString PHTTPSelectField::GetValue(BOOL dflt) const
1734 if (dflt)
1735 if (initialValue < values.GetSize())
1736 return values[initialValue];
1737 else
1738 return PString();
1739 else
1740 return value;
1744 void PHTTPSelectField::SetValue(const PString & newVal)
1746 value = newVal;
1751 //////////////////////////////////////////////////////////////////////////////
1752 // PHTTPForm
1754 PHTTPForm::PHTTPForm(const PURL & url)
1755 : PHTTPString(url),
1756 fields("")
1760 PHTTPForm::PHTTPForm(const PURL & url, const PHTTPAuthority & auth)
1761 : PHTTPString(url, auth),
1762 fields("")
1766 PHTTPForm::PHTTPForm(const PURL & url, const PString & html)
1767 : PHTTPString(url, html),
1768 fields("")
1772 PHTTPForm::PHTTPForm(const PURL & url,
1773 const PString & html,
1774 const PHTTPAuthority & auth)
1775 : PHTTPString(url, html, auth),
1776 fields("")
1781 static BOOL FindSpliceAccepted(const PString & text,
1782 PINDEX offset,
1783 PINDEX & pos,
1784 PINDEX & len,
1785 PINDEX & start,
1786 PINDEX & finish)
1788 static PRegularExpression Accepted("<?!--#form[ \t\r\n]+accepted[ \t\r\n]*-->?",
1789 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1790 return FindSpliceBlock(Accepted, text, offset, pos, len, start, finish);
1794 static BOOL FindSpliceErrors(const PString & text,
1795 PINDEX offset,
1796 PINDEX & pos,
1797 PINDEX & len,
1798 PINDEX & start,
1799 PINDEX & finish)
1801 static PRegularExpression Errors("<?!--#form[ \t\r\n]+errors[ \t\r\n]*-->?",
1802 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1803 return FindSpliceBlock(Errors, text, offset, pos, len, start, finish);
1807 static BOOL FindSpliceField(const PRegularExpression & startExpr,
1808 const PRegularExpression & endExpr,
1809 const PString & text,
1810 PINDEX offset,
1811 const PHTTPField & rootField,
1812 PINDEX & pos,
1813 PINDEX & len,
1814 PINDEX & start,
1815 PINDEX & finish,
1816 const PHTTPField * & field)
1818 field = NULL;
1820 if (!FindSpliceBlock(startExpr, endExpr, text, offset, pos, len, start, finish))
1821 return FALSE;
1823 PINDEX endBlock = start != finish ? (start-1) : (pos+len-1);
1824 PINDEX namePos, nameEnd;
1825 if (FindSpliceName(text, pos, endBlock, namePos, nameEnd))
1826 field = rootField.LocateName(text(namePos, nameEnd));
1827 return TRUE;
1831 static const char ListFieldDeleteBox[] = "List Row Delete ";
1833 void PHTTPForm::OnLoadedText(PHTTPRequest & request, PString & text)
1835 PINDEX pos, len, start, finish;
1836 const PHTTPField * field;
1838 // Remove the subsections for POST command
1839 pos = 0;
1840 while (FindSpliceAccepted(text, pos, pos, len, start, finish))
1841 text.Delete(pos, len);
1843 pos = 0;
1844 while (FindSpliceErrors(text, pos, pos, len, start, finish))
1845 text.Delete(pos, len);
1847 // See if are a subform, set root composite field accordingly
1848 PString prefix = request.url.GetQueryVars()("subformprefix");
1849 if (!prefix) {
1850 static PRegularExpression SubFormPrefix("<?!--#form[ \t\r\n]+subformprefix[ \t\r\n]*-->?",
1851 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1852 while (text.FindRegEx(SubFormPrefix, pos, len))
1853 text.Splice("subformprefix=" +
1854 PURL::TranslateString(prefix, PURL::QueryTranslation),
1855 pos, len);
1856 field = fields.LocateName(prefix);
1857 if (field != NULL) {
1858 finish = P_MAX_INDEX;
1859 field->ExpandFieldNames(text, 0, finish);
1863 // Locate <!--#form list name--> macros and expand them
1864 static PRegularExpression ListRegEx("<!--#form[ \t\r\n]+listfields[ \t\r\n]+(-?[^-])+-->",
1865 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1866 static PRegularExpression EndBlock("<?!--#form[ \t\r\n]+end[ \t\r\n]+(-?[^-])+-->?",
1867 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1868 pos = len = 0;
1869 while (FindSpliceBlock(ListRegEx, EndBlock, text, pos+len, pos, len, start, finish)) {
1870 if (start != finish) {
1871 PString repeat = text(start, finish);
1873 PINDEX namePos, nameEnd;
1874 PRegularExpression fieldsRegEx;
1875 if (FindSpliceName(text, pos, start-1, namePos, nameEnd))
1876 fieldsRegEx.Compile(text(namePos, nameEnd), PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1877 else
1878 fieldsRegEx.Compile(".*");
1880 PString insert;
1881 for (PINDEX f = 0; f < fields.GetSize(); f++) {
1882 if (fields[f].GetName().FindRegEx(fieldsRegEx) != P_MAX_INDEX) {
1883 PString iteration = repeat;
1884 PINDEX npos, nlen;
1886 static PRegularExpression FieldNameRegEx("<?!--#form[ \t\r\n]+fieldname[ \t\r\n]*-->?",
1887 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1888 while (iteration.FindRegEx(FieldNameRegEx, npos, nlen))
1889 iteration.Splice(fields[f].GetName(), npos, nlen);
1891 static PRegularExpression RowDeleteRegEx("<?!--#form[ \t\r\n]+rowdelete[ \t\r\n]*-->?",
1892 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1893 while (iteration.FindRegEx(RowDeleteRegEx, npos, nlen)) {
1894 PHTML html(PHTML::InForm);
1895 html << PHTML::CheckBox(ListFieldDeleteBox + fields[f].GetName());
1896 iteration.Splice(html, npos, nlen);
1899 insert += iteration;
1902 text.Splice(insert, pos, len);
1906 // Locate <!--#form array name--> macros and expand them
1907 static PRegularExpression ArrayRegEx("<!--#form[ \t\r\n]+array[ \t\r\n]+(-?[^-])+-->",
1908 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1909 pos = len = 0;
1910 while (FindSpliceField(ArrayRegEx, EndBlock, text, pos+len, fields, pos, len, start, finish, field)) {
1911 if (start != finish && field != NULL)
1912 field->ExpandFieldNames(text, start, finish);
1915 // Have now expanded all field names to be fully qualified
1917 static PRegularExpression HTMLRegEx("<!--#form[ \t\r\n]+html[ \t\r\n]+(-?[^-])+-->",
1918 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1919 while (FindSpliceField(HTMLRegEx, "", text, 0, fields, pos, len, start, finish, field)) {
1920 if (field != NULL) {
1921 PHTML html(PHTML::InForm);
1922 field->GetHTMLTag(html);
1923 text.Splice(html, pos, len);
1927 pos = len = 0;
1928 static PRegularExpression ValueRegEx("<!--#form[ \t\r\n]+value[ \t\r\n]+(-?[^-])+-->",
1929 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1930 while (FindSpliceField(ValueRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
1931 if (field != NULL)
1932 text.Splice(field->GetValue(), pos, len);
1935 pos = len = 0;
1936 static PRegularExpression InputRegEx("<input[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1937 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1938 while (FindSpliceField(InputRegEx, "", text, pos+len, fields, pos, len, start, finish, field)) {
1939 if (field != NULL) {
1940 static PRegularExpression HiddenRegEx("type[ \t\r\n]*=[ \t\r\n]*\"?hidden\"?",
1941 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1942 PString substr = text.Mid(pos, len);
1943 if (substr.FindRegEx(HiddenRegEx) == P_MAX_INDEX)
1944 text.Splice(field->GetHTMLInput(substr), pos, len);
1948 pos = len = 0;
1949 static PRegularExpression SelectRegEx("<select[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1950 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1951 static PRegularExpression SelEndRegEx("</select[^>]*>",
1952 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1953 while (FindSpliceField(SelectRegEx, SelEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
1954 if (field != NULL)
1955 text.Splice(field->GetHTMLSelect(text(start, finish)), start, finish-start+1);
1958 pos = len = 0;
1959 static PRegularExpression TextRegEx("<textarea[ \t\r\n][^>]*name[ \t\r\n]*=[ \t\r\n]*\"[^\"]*\"[^>]*>",
1960 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
1961 static PRegularExpression TextEndRegEx("</textarea[^>]*>", PRegularExpression::IgnoreCase);
1962 while (FindSpliceField(TextRegEx, TextEndRegEx, text, pos+len, fields, pos, len, start, finish, field)) {
1963 if (field != NULL)
1964 text.Splice(field->GetValue(), start, finish-start+1);
1969 PHTTPField * PHTTPForm::Add(PHTTPField * fld)
1971 if (PAssertNULL(fld) == NULL)
1972 return NULL;
1974 PAssert(!fieldNames[fld->GetName()], "Field already on form!");
1975 fieldNames += fld->GetName();
1976 fields.Append(fld);
1977 return fld;
1981 void PHTTPForm::BuildHTML(const char * heading)
1983 PHTML html(heading);
1984 BuildHTML(html);
1988 void PHTTPForm::BuildHTML(const PString & heading)
1990 PHTML html(heading);
1991 BuildHTML(html);
1995 void PHTTPForm::BuildHTML(PHTML & html, BuildOptions option)
1997 if (!html.Is(PHTML::InForm))
1998 html << PHTML::Form("POST");
2000 html << PHTML::TableStart("cellspacing=8");
2001 for (PINDEX fld = 0; fld < fields.GetSize(); fld++) {
2002 PHTTPField & field = fields[fld];
2003 if (field.NotYetInHTML()) {
2004 html << PHTML::TableRow()
2005 << PHTML::TableData("align=right")
2006 << field.GetTitle()
2007 << PHTML::TableData("align=left")
2008 << "<!--#form html " << field.GetName() << "-->"
2009 << PHTML::TableData()
2010 << field.GetHelp();
2011 field.SetInHTML();
2014 html << PHTML::TableEnd();
2015 if (option != InsertIntoForm)
2016 html << PHTML::Paragraph()
2017 << ' ' << PHTML::SubmitButton("Accept")
2018 << ' ' << PHTML::ResetButton("Reset")
2019 << PHTML::Form();
2021 if (option == CompleteHTML) {
2022 html << PHTML::Body();
2023 string = html;
2028 BOOL PHTTPForm::Post(PHTTPRequest & request,
2029 const PStringToString & data,
2030 PHTML & msg)
2032 //PString prefix = request.url.GetQueryVars()("subformprefix");
2033 const PHTTPField * field = NULL;
2034 //if (!prefix)
2035 // field = fields.LocateName(prefix);
2036 //if (field == NULL)
2037 field = &fields;
2039 PStringStream errors;
2040 if (field->ValidateAll(data, errors)) {
2041 ((PHTTPField *)field)->SetAllValues(data);
2043 if (msg.IsEmpty()) {
2044 msg << PHTML::Title() << "Accepted New Configuration" << PHTML::Body()
2045 << PHTML::Heading(1) << "Accepted New Configuration" << PHTML::Heading(1)
2046 << PHTML::HotLink(request.url.AsString()) << "Reload page" << PHTML::HotLink()
2047 << "&nbsp;&nbsp;&nbsp;&nbsp;"
2048 << PHTML::HotLink("/") << "Home page" << PHTML::HotLink();
2050 else {
2051 PString block;
2052 PINDEX pos = 0;
2053 PINDEX len, start, finish;
2054 while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
2055 msg.Splice(msg(start, finish), pos, len);
2056 pos = 0;
2057 while (FindSpliceErrors(msg, pos, pos, len, start, finish))
2058 msg.Delete(pos, len);
2061 else {
2062 if (msg.IsEmpty()) {
2063 msg << PHTML::Title() << "Validation Error in Request" << PHTML::Body()
2064 << PHTML::Heading(1) << "Validation Error in Request" << PHTML::Heading(1)
2065 << errors
2066 << PHTML::Paragraph()
2067 << PHTML::HotLink(request.url.AsString()) << "Reload page" << PHTML::HotLink()
2068 << "&nbsp;&nbsp;&nbsp;&nbsp;"
2069 << PHTML::HotLink("/") << "Home page" << PHTML::HotLink();
2071 else {
2072 PINDEX pos = 0;
2073 PINDEX len, start, finish;
2074 while (FindSpliceAccepted(msg, pos, pos, len, start, finish))
2075 msg.Delete(pos, len);
2077 BOOL appendErrors = TRUE;
2078 pos = 0;
2079 while (FindSpliceErrors(msg, pos, pos, len, start, finish)) {
2080 PString block = msg(start, finish);
2081 PINDEX vPos, vLen;
2082 static PRegularExpression Validation("<?!--#form[ \t\r\n]+validation[ \t\r\n]*-->?",
2083 PRegularExpression::Extended|PRegularExpression::IgnoreCase);
2084 if (block.FindRegEx(Validation, vPos, vLen))
2085 block.Splice(errors, vPos, vLen);
2086 else
2087 block += errors;
2088 msg.Splice(block, pos, len);
2089 appendErrors = FALSE;
2092 if (appendErrors)
2093 msg << errors;
2097 return TRUE;
2101 //////////////////////////////////////////////////////////////////////////////
2102 // PHTTPConfig
2104 PHTTPConfig::PHTTPConfig(const PURL & url,
2105 const PString & sect)
2106 : PHTTPForm(url), section(sect)
2108 Construct();
2112 PHTTPConfig::PHTTPConfig(const PURL & url,
2113 const PString & sect,
2114 const PHTTPAuthority & auth)
2115 : PHTTPForm(url, auth), section(sect)
2117 Construct();
2121 PHTTPConfig::PHTTPConfig(const PURL & url,
2122 const PString & html,
2123 const PString & sect)
2124 : PHTTPForm(url, html), section(sect)
2126 Construct();
2130 PHTTPConfig::PHTTPConfig(const PURL & url,
2131 const PString & html,
2132 const PString & sect,
2133 const PHTTPAuthority & auth)
2134 : PHTTPForm(url, html, auth), section(sect)
2136 Construct();
2140 void PHTTPConfig::Construct()
2142 sectionField = NULL;
2143 keyField = NULL;
2144 valField = NULL;
2148 void PHTTPConfig::LoadFromConfig()
2150 PConfig cfg(section);
2151 fields.LoadFromConfig(cfg);
2155 void PHTTPConfig::OnLoadedText(PHTTPRequest & request, PString & text)
2157 if (sectionField == NULL) {
2158 PString sectionName = request.url.GetQueryVars()("section", section);
2159 if (!sectionName) {
2160 section = sectionName;
2161 LoadFromConfig();
2165 PHTTPForm::OnLoadedText(request, text);
2169 BOOL PHTTPConfig::Post(PHTTPRequest & request,
2170 const PStringToString & data,
2171 PHTML & msg)
2173 // Make sure the internal structure is up to date before accepting new data
2174 if (!section)
2175 LoadFromConfig();
2178 PSortedStringList oldValues;
2180 // Remember fields that are here now, so can delete removed array fields
2181 PINDEX fld;
2182 for (fld = 0; fld < fields.GetSize(); fld++) {
2183 PHTTPField & field = fields[fld];
2184 if (&field != keyField && &field != valField && &field != sectionField) {
2185 PStringList names;
2186 field.GetAllNames(names);
2187 oldValues = names;
2191 PHTTPForm::Post(request, data, msg);
2192 if (request.code != PHTTP::RequestOK)
2193 return TRUE;
2195 if (sectionField != NULL)
2196 section = sectionPrefix + sectionField->GetValue() + sectionSuffix;
2198 PString sectionName = request.url.GetQueryVars()("section", section);
2199 if (sectionName.IsEmpty())
2200 return TRUE;
2202 PConfig cfg(sectionName);
2204 for (fld = 0; fld < fields.GetSize(); fld++) {
2205 PHTTPField & field = fields[fld];
2206 if (&field == keyField) {
2207 PString key = field.GetValue();
2208 if (!key)
2209 cfg.SetString(key, valField->GetValue());
2211 else if (&field != valField && &field != sectionField)
2212 field.SaveToConfig(cfg);
2215 // Find out which fields have been removed (arrays elements deleted)
2216 for (fld = 0; fld < fields.GetSize(); fld++) {
2217 PHTTPField & field = fields[fld];
2218 if (&field != keyField && &field != valField && &field != sectionField) {
2219 PStringList names;
2220 field.GetAllNames(names);
2221 for (PINDEX i = 0; i < names.GetSize(); i++) {
2222 PINDEX idx = oldValues.GetStringsIndex(names[i]);
2223 if (idx != P_MAX_INDEX)
2224 oldValues.RemoveAt(idx);
2229 for (fld = 0; fld < oldValues.GetSize(); fld++) {
2230 PString section, key;
2231 switch (SplitConfigKey(oldValues[fld], section, key)) {
2232 case 1 :
2233 cfg.DeleteKey(key);
2234 break;
2235 case 2 :
2236 cfg.DeleteKey(section, key);
2237 if (cfg.GetKeys(section).IsEmpty())
2238 cfg.DeleteSection(section);
2242 section = sectionName;
2243 return TRUE;
2247 PHTTPField * PHTTPConfig::AddSectionField(PHTTPField * sectionFld,
2248 const char * prefix,
2249 const char * suffix)
2251 sectionField = PAssertNULL(sectionFld);
2252 PAssert(!PIsDescendant(sectionField, PHTTPCompositeField), "Section field is composite");
2253 Add(sectionField);
2255 if (prefix != NULL)
2256 sectionPrefix = prefix;
2257 if (suffix != NULL)
2258 sectionSuffix = suffix;
2260 return sectionField;
2264 void PHTTPConfig::AddNewKeyFields(PHTTPField * keyFld,
2265 PHTTPField * valFld)
2267 keyField = PAssertNULL(keyFld);
2268 Add(keyFld);
2269 valField = PAssertNULL(valFld);
2270 Add(valFld);
2274 //////////////////////////////////////////////////////////////////////////////
2275 // PHTTPConfigSectionList
2277 static const char FormListInclude[] = "<!--#form pagelist-->";
2279 PHTTPConfigSectionList::PHTTPConfigSectionList(const PURL & url,
2280 const PHTTPAuthority & auth,
2281 const PString & prefix,
2282 const PString & valueName,
2283 const PURL & editSection,
2284 const PURL & newSection,
2285 const PString & newTitle,
2286 PHTML & heading)
2287 : PHTTPString(url, auth),
2288 sectionPrefix(prefix),
2289 additionalValueName(valueName),
2290 newSectionLink(newSection.AsString(PURL::URIOnly)),
2291 newSectionTitle(newTitle),
2292 editSectionLink(editSection.AsString(PURL::URIOnly) +
2293 "?section=" + PURL::TranslateString(prefix, PURL::QueryTranslation))
2295 if (heading.Is(PHTML::InBody))
2296 heading << FormListInclude << PHTML::Body();
2297 SetString(heading);
2301 void PHTTPConfigSectionList::OnLoadedText(PHTTPRequest &, PString & text)
2303 PConfig cfg;
2304 PStringList nameList = cfg.GetSections();
2306 PINDEX pos = text.Find(FormListInclude);
2307 if (pos != P_MAX_INDEX) {
2308 PINDEX endpos = text.Find(FormListInclude, pos + sizeof(FormListInclude)-1);
2309 if (endpos == P_MAX_INDEX) {
2310 PHTML html(PHTML::InBody);
2311 html << PHTML::Form("POST") << PHTML::TableStart();
2313 PINDEX i;
2314 for (i = 0; i < nameList.GetSize(); i++) {
2315 if (nameList[i].Find(sectionPrefix) == 0) {
2316 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2317 html << PHTML::TableRow()
2318 << PHTML::TableData()
2319 << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
2320 << name
2321 << PHTML::HotLink();
2322 if (!additionalValueName)
2323 html << PHTML::TableData()
2324 << PHTML::HotLink(editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation))
2325 << cfg.GetString(nameList[i], additionalValueName, "")
2326 << PHTML::HotLink();
2327 html << PHTML::TableData() << PHTML::SubmitButton("Remove", name);
2331 html << PHTML::TableRow()
2332 << PHTML::TableData()
2333 << PHTML::HotLink(newSectionLink)
2334 << newSectionTitle
2335 << PHTML::HotLink()
2336 << PHTML::TableEnd()
2337 << PHTML::Form();
2339 text.Splice(html, pos, sizeof(FormListInclude)-1);
2341 else {
2342 PString repeat = text(pos + sizeof(FormListInclude)-1, endpos-1);
2343 text.Delete(pos, endpos - pos);
2345 PINDEX i;
2346 for (i = 0; i < nameList.GetSize(); i++) {
2347 if (nameList[i].Find(sectionPrefix) == 0) {
2348 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2349 text.Splice(repeat, pos, 0);
2350 text.Replace("<!--#form hotlink-->",
2351 editSectionLink + PURL::TranslateString(name, PURL::QueryTranslation),
2352 TRUE, pos);
2353 if (!additionalValueName)
2354 text.Replace("<!--#form additional-->",
2355 cfg.GetString(nameList[i], additionalValueName, ""),
2356 TRUE, pos);
2357 text.Replace("<!--#form section-->", name, TRUE, pos);
2358 pos = text.Find(FormListInclude, pos);
2361 text.Delete(text.Find(FormListInclude, pos), sizeof(FormListInclude)-1);
2367 BOOL PHTTPConfigSectionList::Post(PHTTPRequest &,
2368 const PStringToString & data,
2369 PHTML & replyMessage)
2371 PConfig cfg;
2372 PStringList nameList = cfg.GetSections();
2373 PINDEX i;
2374 for (i = 0; i < nameList.GetSize(); i++) {
2375 if (nameList[i].Find(sectionPrefix) == 0) {
2376 PString name = nameList[i].Mid(sectionPrefix.GetLength());
2377 if (data.Contains(name)) {
2378 cfg.DeleteSection(nameList[i]);
2379 replyMessage << name << " removed.";
2384 return TRUE;
2389 // End Of File ///////////////////////////////////////////////////////////////