home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / layform.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  100.8 KB  |  4,229 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "xp.h"
  21. #include "net.h"
  22. #include "shist.h"
  23. #include "pa_parse.h"
  24. #include "layout.h"
  25. #include "java.h"
  26. #include "laylayer.h"
  27. #include "libevent.h"
  28. #include "libimg.h"             /* Image Library public API. */
  29. #include "libi18n.h"        /* For the character code set conversions */
  30. #include "intl_csi.h"
  31.  
  32. #include "secnav.h"        /* For SECNAV_GenKeyFromChoice and SECNAV_GetKeyChoiceList protos */
  33.  
  34. #ifdef PROFILE
  35. #pragma profile on
  36. #endif
  37.  
  38. #ifndef XP_TRACE
  39. # define XP_TRACE(X) fprintf X
  40. #endif
  41.  
  42. #ifdef TEST_16BIT
  43. #define XP_WIN16
  44. #endif /* TEST_16BIT */
  45.  
  46. #ifdef XP_WIN16
  47. #define SIZE_LIMIT              32000
  48. #endif /* XP_WIN16 */
  49.  
  50.  
  51. #define    DEF_ISINDEX_PROMPT "This is a searchable index. Enter search keywords: "
  52. #define    ISINDEX_TAG_TEXT    "name=isindex>"
  53. #define    DEF_FILE_ELE_VALUE    "Choose File"
  54. #define    DEF_RESET_BUTTON_NAME    "reset"
  55. #define    DEF_RESET_BUTTON_TEXT    "Reset"
  56. #define    DEF_SUBMIT_BUTTON_NAME    "submit"
  57. #define    DEF_SUBMIT_BUTTON_TEXT    "Submit Query"
  58. #define    DEF_BUTTON_TEXT        "  "
  59. #define    DEF_TOGGLE_VALUE    "on"
  60. #define    DEF_TEXT_ELE_SIZE    20
  61. #define    DEF_TEXTAREA_ELE_ROWS    1
  62. #define    DEF_TEXTAREA_ELE_COLS    20
  63. #define    DEF_SELECT_ELE_SIZE    1
  64.  
  65. #define    MAX_BUTTON_WIDTH    1000
  66. #define    MAX_BUTTON_HEIGHT    1000
  67.  
  68. static PA_Block lo_dup_block(PA_Block);        /* forward declaration */
  69.  
  70. /* VERY IMPORTANT
  71.  *
  72.  * the form_list linked list is in REVERSE
  73.  * order.  Therefore if there is more than
  74.  * one form on a page the different forms
  75.  * are in the list in the REVERSE order
  76.  * that they appear on the page.
  77.  */
  78. PRIVATE LO_FormElementStruct *
  79. lo_return_next_form_element(MWContext *context,
  80.                             LO_FormElementStruct *current_element,
  81.                             XP_Bool reverse_order)
  82. {
  83.     int32 doc_id;
  84.     int i;
  85.     lo_TopState *top_state;
  86.     lo_DocState *state;
  87.     lo_FormData *form_list;
  88.     lo_FormData *prev_form_list=NULL;
  89.     LO_Element **ele_list;
  90.     LO_FormElementStruct *form_ele;
  91.  
  92.     /*
  93.      * Get the unique document ID, and retreive this
  94.      * documents layout state.
  95.      */
  96.     doc_id = XP_DOCID(context);
  97.     top_state = lo_FetchTopState(doc_id);
  98.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  99.     {
  100.         return(NULL);
  101.     }
  102.     state = top_state->doc_state;
  103.  
  104.     /* 
  105.      * XXX BUGBUG This and the corresponding routines, only deal
  106.      * with forms in the main document and not forms in layers.
  107.      */
  108.     /*
  109.      * Extract the list of all forms in this doc.
  110.      */
  111.     form_list = top_state->doc_lists.form_list;
  112.     
  113.     while(form_list)
  114.       {
  115.         PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  116.  
  117.         for (i=0; i<form_list->form_ele_cnt; i++)
  118.           {
  119.     
  120.             form_ele = (LO_FormElementStruct *)ele_list[i];
  121.  
  122.             if(NULL == current_element && FALSE == reverse_order)
  123.               {
  124.                 /* since the passed in element was NULL
  125.                  * or we set the current element below
  126.                  * since we wanted the next element
  127.                  * return the first element we encounter.
  128.                  */
  129.                 PA_UNLOCK(form_list->form_elements);
  130.                 return(form_ele);
  131.  
  132.               }
  133.             else if(form_ele == current_element)
  134.                 {
  135.                 if(reverse_order)
  136.                   {
  137.                     if(i > 0)
  138.                       {
  139.                         PA_UNLOCK(form_list->form_elements);
  140.                         return((LO_FormElementStruct *)ele_list[i-1]);
  141.                       }
  142.                     else if(NULL == form_list->next)
  143.                       {
  144.                         PA_UNLOCK(form_list->form_elements);
  145.                         return NULL;  /* first element in whole list*/
  146.                       }
  147.                     else
  148.                       {
  149.                         /* if there is a next form_list
  150.                          * then return the last element
  151.                          * of the next form_list
  152.                          */
  153.                         PA_UNLOCK(form_list->form_elements);
  154.  
  155.                         form_list = form_list->next;
  156.                         if(form_list->form_ele_cnt == 0)
  157.                             return NULL;
  158.  
  159.                         PA_LOCK(ele_list, 
  160.                                 LO_Element **, 
  161.                                 form_list->form_elements);
  162.                         form_ele = (LO_FormElementStruct *)
  163.                                     ele_list[form_list->form_ele_cnt-1];
  164.  
  165.                         PA_UNLOCK(form_list->form_elements);
  166.  
  167.                         return(form_ele);
  168.                       }
  169.                   }
  170.                 else
  171.                   {
  172.                     if(i+1<form_list->form_ele_cnt)
  173.                       {
  174.                         PA_UNLOCK(form_list->form_elements);
  175.                         return((LO_FormElementStruct *)ele_list[i+1]);
  176.                       }
  177.                     else if(NULL == prev_form_list)
  178.                       {
  179.                         PA_UNLOCK(form_list->form_elements);
  180.                         return NULL;  /* last element in whole list*/
  181.                       }
  182.                     else
  183.                       {
  184.                         /* choose the first element of the
  185.                          * previous form list 
  186.                          */
  187.                         PA_UNLOCK(form_list->form_elements);
  188.  
  189.                         if(prev_form_list->form_ele_cnt == 0)
  190.                             return NULL;
  191.  
  192.                         PA_LOCK(ele_list,
  193.                                 LO_Element **,
  194.                                 prev_form_list->form_elements);
  195.  
  196.                         form_ele = (LO_FormElementStruct *)
  197.                                     ele_list[0];
  198.  
  199.                         PA_UNLOCK(prev_form_list->form_elements);
  200.  
  201.                         return(form_ele);
  202.  
  203.                       }
  204.                   }
  205.                 }
  206.           }
  207.  
  208.         PA_UNLOCK(form_list->form_elements);
  209.  
  210.         if(NULL == current_element && TRUE == reverse_order)
  211.           {
  212.             /* since the passed in element was NULL
  213.              * return the last element we encountered.
  214.              */
  215.             return(form_ele);
  216.           }
  217.  
  218.         prev_form_list = form_list;
  219.         form_list = form_list->next;
  220.       }
  221.  
  222.     if(current_element == NULL)
  223.         return NULL;
  224.  
  225.     /* the element was not found in the list
  226.      * something must be wrong, lets assert!
  227.      */
  228.     XP_ASSERT(0);
  229.  
  230.     return NULL;
  231. }
  232.  
  233.  
  234. /* return the next form element in layouts list of form elements
  235.  *
  236.  * If NULL is passed in, this function returns the first element.
  237.  *
  238.  * If the last element is passed in, this function returns NULL
  239.  *
  240.  * If a garbage pointer is passed in, this function returns NULL
  241.  */
  242. PUBLIC LO_FormElementStruct *
  243. LO_ReturnNextFormElement(MWContext *context,
  244.                          LO_FormElementStruct *current_element)
  245. {
  246.     return(lo_return_next_form_element(context,   
  247.                                         current_element,
  248.                                         FALSE));
  249.  
  250. }
  251.  
  252. /* return the previous form element in layouts list of form elements
  253.  *
  254.  * If NULL is passed in, this function returns the last element.
  255.  *
  256.  * If the first element is passed in, this function returns NULL
  257.  *
  258.  * If a garbage pointer is passed in, this function returns NULL
  259.  */
  260. PUBLIC LO_FormElementStruct *
  261. LO_ReturnPrevFormElement(MWContext *context,
  262.                          LO_FormElementStruct *current_element)
  263. {
  264.  
  265.     return(lo_return_next_form_element(context, 
  266.                                         current_element,
  267.                                         TRUE));
  268. }
  269.  
  270. /* #ifndef NO_TAB_NAVIGATION */
  271. /*
  272.  for Form element type FORM_TYPE_RADIO and FORM_TYPE_CHECKBOX,
  273.  if the element has focus, the Text elment following it needs to
  274.  draw the Tab Focus(dotted box).
  275. */
  276. Bool
  277. LO_isFormElementNeedTextTabFocus( LO_FormElementStruct *pElement )
  278. {
  279.     if( pElement == NULL || pElement->type != LO_FORM_ELE )
  280.         return(FALSE);
  281.  
  282.     /*
  283.      * Under bizarre cases, this may be an invalid form element
  284.      * with no form data.
  285.      */
  286.     if (pElement->element_data == NULL)
  287.         return(FALSE);
  288.     
  289.     if( pElement->element_data->type == FORM_TYPE_RADIO
  290.         || pElement->element_data->type == FORM_TYPE_CHECKBOX )
  291.         return(TRUE);
  292.  
  293.     return(FALSE);
  294.  
  295. }
  296.  
  297. /* Function LO_isTabableFormElement() is copied from
  298.  PUBLIC LO_FormElementStruct * LO_ReturnNextFormElementInTabGroup(MWContext *context,     
  299. */
  300. Bool 
  301. LO_isTabableFormElement( LO_FormElementStruct * next_ele )  
  302. {
  303.     /*
  304.      * Under bizarre cases, this may be an invalid form element
  305.      * with no form data.
  306.      */
  307.     if (next_ele->element_data == NULL)
  308.         return(FALSE);
  309.  
  310.     if (next_ele->element_data->type == FORM_TYPE_TEXT
  311.         || next_ele->element_data->type == FORM_TYPE_SUBMIT
  312.         || next_ele->element_data->type == FORM_TYPE_RESET
  313.         || next_ele->element_data->type == FORM_TYPE_PASSWORD
  314.         || next_ele->element_data->type == FORM_TYPE_BUTTON
  315.         || next_ele->element_data->type == FORM_TYPE_RADIO
  316.         || next_ele->element_data->type == FORM_TYPE_CHECKBOX
  317.         || next_ele->element_data->type == FORM_TYPE_SELECT_ONE
  318.         || next_ele->element_data->type == FORM_TYPE_SELECT_MULT
  319.         || next_ele->element_data->type == FORM_TYPE_TEXTAREA
  320.         || next_ele->element_data->type == FORM_TYPE_FILE)
  321.     {
  322.         return(TRUE);
  323.     }
  324.     else 
  325.         return( FALSE );
  326. }
  327. /* NO_TAB_NAVIGATION */
  328.  
  329. /* NO_TAB_NAVIGATION, 
  330.     LO_ReturnNextFormElementInTabGroup() is used to tab through form elements.
  331.     Since the winfe now has TAB_NAVIGATION, it is not used any more.
  332.     If mac and Unix don't use it either, it can be removed.
  333. */
  334.  
  335. /* return the next tabable form element struct
  336.  *
  337.  * Current tabable elements are:
  338.  *  
  339.  *  FORM_TYPE_TEXT
  340.  *    FORM_TYPE_SUBMIT
  341.  *    FORM_TYPE_RESET
  342.  *    FORM_TYPE_PASSWORD
  343.  *    FORM_TYPE_BUTTON
  344.  *    FORM_TYPE_FILE
  345.  *  FORM_TYPE_RADIO
  346.  *  FORM_TYPE_CHECKBOX
  347.  *  FORM_TYPE_SELECT_ONE
  348.  *  FORM_TYPE_SELECT_MULT
  349.  *  FORM_TYPE_TEXTAREA
  350.  *
  351.  * If the last element is passed in the first element is returned.
  352.  * If garbage is passed in the first element is returned.
  353.  */
  354. PUBLIC LO_FormElementStruct *
  355. LO_ReturnNextFormElementInTabGroup(MWContext *context,     
  356.                                    LO_FormElementStruct *current_element,
  357.                                    XP_Bool go_backwards)
  358. {
  359.     LO_FormElementStruct *next_ele;
  360.  
  361.     /*
  362.      * Under bizarre cases, this may be an invalid form element
  363.      * with no form data.
  364.      */
  365.     if (current_element->element_data == NULL)
  366.         return(NULL);
  367.  
  368.     while((next_ele = lo_return_next_form_element(context, current_element, go_backwards)) != NULL)
  369.       {
  370.  
  371.         if (next_ele->element_data->type == FORM_TYPE_TEXT
  372.             || next_ele->element_data->type == FORM_TYPE_SUBMIT
  373.             || next_ele->element_data->type == FORM_TYPE_RESET
  374.             || next_ele->element_data->type == FORM_TYPE_PASSWORD
  375.             || next_ele->element_data->type == FORM_TYPE_BUTTON
  376.             || next_ele->element_data->type == FORM_TYPE_RADIO
  377.             || next_ele->element_data->type == FORM_TYPE_CHECKBOX
  378.             || next_ele->element_data->type == FORM_TYPE_SELECT_ONE
  379.             || next_ele->element_data->type == FORM_TYPE_SELECT_MULT
  380.             || next_ele->element_data->type == FORM_TYPE_TEXTAREA
  381.             || next_ele->element_data->type == FORM_TYPE_FILE)
  382.           {
  383.  
  384.             return(next_ele);
  385.           }
  386.         else
  387.           {
  388.             current_element = next_ele;
  389.           }
  390.       }
  391.  
  392.     /* return the first element */    
  393.     return(lo_return_next_form_element(context, NULL, go_backwards));
  394. }
  395.  
  396. void
  397. lo_BeginForm(MWContext *context, lo_DocState *state, PA_Tag *tag)
  398. {
  399.     lo_FormData *form;
  400.     PA_Block buff;
  401.     char *str;
  402.     lo_DocLists *doc_lists;
  403.  
  404.     form = XP_NEW(lo_FormData);
  405.     if (form == NULL)
  406.     {
  407.         state->top_state->out_of_memory = TRUE;
  408.         return;
  409.     }
  410.  
  411.     doc_lists = lo_GetCurrentDocLists(state);
  412.  
  413.     state->top_state->in_form = TRUE;
  414.     doc_lists->current_form_num++;
  415.  
  416.     form->id = doc_lists->current_form_num;
  417.     form->form_ele_cnt = 0;
  418.     form->form_ele_size = 0;
  419.     form->form_elements = NULL;
  420.     form->next = NULL;
  421. #ifdef MOCHA
  422.     form->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  423.     form->mocha_object = NULL;
  424. #endif
  425.  
  426.     buff = lo_FetchParamValue(context, tag, PARAM_ACTION);
  427.     if (buff != NULL)
  428.     {
  429.         char *url;
  430.  
  431.         PA_LOCK(str, char *, buff);
  432.         url = NET_MakeAbsoluteURL(state->top_state->base_url, str);
  433.         PA_UNLOCK(buff);
  434.         PA_FREE(buff);
  435.         if (url == NULL)
  436.         {
  437.             buff = NULL;
  438.         }
  439.         else
  440.         {
  441.             buff = PA_ALLOC(XP_STRLEN(url) + 1);
  442.             if (buff != NULL)
  443.             {
  444.                 PA_LOCK(str, char *, buff);
  445.                 XP_STRCPY(str, url);
  446.                 PA_UNLOCK(buff);
  447.             }
  448.             else
  449.             {
  450.                 state->top_state->out_of_memory = TRUE;
  451.             }
  452.             XP_FREE(url);
  453.         }
  454.     }
  455.     else if (state->top_state->base_url != NULL)
  456.     {
  457.         buff = PA_ALLOC(XP_STRLEN(state->top_state->base_url) + 1);
  458.         if (buff != NULL)
  459.         {
  460.             PA_LOCK(str, char *, buff);
  461.             XP_STRCPY(str, state->top_state->base_url);
  462.             PA_UNLOCK(buff);
  463.         }
  464.         else
  465.         {
  466.             state->top_state->out_of_memory = TRUE;
  467.         }
  468.     }
  469.     form->action = buff;
  470.  
  471.     form->encoding = lo_FetchParamValue(context, tag, PARAM_ENCODING);
  472.  
  473.     buff = lo_FetchParamValue(context, tag, PARAM_TARGET);
  474.     if (buff != NULL)
  475.     {
  476.         int32 len;
  477.         char *target;
  478.  
  479.         PA_LOCK(target, char *, buff);
  480.         len = lo_StripTextWhitespace(target, XP_STRLEN(target));
  481.         if ((*target == '\0')||
  482.             (lo_IsValidTarget(target) == FALSE))
  483.         {
  484.             PA_UNLOCK(buff);
  485.             PA_FREE(buff);
  486.             buff = NULL;
  487.         }
  488.         else
  489.         {
  490.             PA_UNLOCK(buff);
  491.         }
  492.     }
  493.     /*
  494.      * If there was no target use the default one.
  495.      * (default provided by BASE tag)
  496.      */
  497.     if ((buff == NULL)&&(state->top_state->base_target != NULL))
  498.     {
  499.         buff = PA_ALLOC(XP_STRLEN(state->top_state->base_target) + 1);
  500.         if (buff != NULL)
  501.         {
  502.             char *targ;
  503.  
  504.             PA_LOCK(targ, char *, buff);
  505.             XP_STRCPY(targ, state->top_state->base_target);
  506.             PA_UNLOCK(buff);
  507.         }
  508.         else
  509.         {
  510.             state->top_state->out_of_memory = TRUE;
  511.         }
  512.     }
  513.     form->window_target = buff;
  514.  
  515.     form->method = FORM_METHOD_GET;
  516.     buff = lo_FetchParamValue(context, tag, PARAM_METHOD);
  517.     if (buff != NULL)
  518.     {
  519.         PA_LOCK(str, char *, buff);
  520.         if (pa_TagEqual("post", str))
  521.         {
  522.             form->method = FORM_METHOD_POST;
  523.         }
  524.         PA_UNLOCK(buff);
  525.         PA_FREE(buff);
  526.     }
  527.  
  528.     form->next = doc_lists->form_list;
  529.     doc_lists->form_list = form;
  530.  
  531. #ifdef MOCHA
  532.     if (!state->in_relayout)
  533.     {
  534.         lo_BeginReflectForm(context, state, tag, form);
  535.     }
  536. #endif
  537. }
  538.  
  539.  
  540. void
  541. lo_EndForm(MWContext *context, lo_DocState *state)
  542. {
  543.     intn i, form_id;
  544.     lo_FormData *form_list;
  545.     LO_Element **ele_list;
  546.     LO_FormElementStruct *single_text_ele;
  547.     lo_DocLists *doc_lists;
  548.  
  549.     state->top_state->in_form = FALSE;
  550.  
  551.     doc_lists = lo_GetCurrentDocLists(state);
  552.     form_id = doc_lists->current_form_num;
  553.     form_list = doc_lists->form_list;
  554.     while (form_list != NULL)
  555.     {
  556.         if (form_list->id == form_id)
  557.         {
  558.             break;
  559.         }
  560.         form_list = form_list->next;
  561.     }
  562.     if (form_list == NULL)
  563.     {
  564.         return;
  565.     }
  566.  
  567.     single_text_ele = NULL;
  568.     PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  569.     for (i=0; i<form_list->form_ele_cnt; i++)
  570.     {
  571.         LO_FormElementStruct *form_ele;
  572.  
  573.         form_ele = (LO_FormElementStruct *)ele_list[i];
  574.         if (form_ele->element_data == NULL)
  575.         {
  576.             continue;
  577.         }
  578.  
  579.         if ((form_ele->element_data->type == FORM_TYPE_TEXT)||
  580.             (form_ele->element_data->type == FORM_TYPE_PASSWORD))
  581.         {
  582.             if (single_text_ele != NULL)
  583.             {
  584.                 single_text_ele = NULL;
  585.                 break;
  586.             }
  587.             else
  588.             {
  589.                 single_text_ele = form_ele;
  590.             }
  591.         }
  592.     }
  593.     PA_UNLOCK(form_list->form_elements);
  594.  
  595.     if (single_text_ele != NULL)
  596.     {
  597.         FE_FormTextIsSubmit(context, single_text_ele);
  598.     }
  599.  
  600. #ifdef MOCHA
  601.     if (!state->in_relayout)
  602.     {
  603.         lo_EndReflectForm(context, form_list);
  604.     }
  605. #endif
  606. }
  607.  
  608.  
  609. int32
  610. lo_ResolveInputType(char *type_str)
  611. {
  612.     if (type_str == NULL)
  613.     {
  614.         return(FORM_TYPE_TEXT);
  615.     }
  616.  
  617.     if (pa_TagEqual(S_FORM_TYPE_TEXT, type_str))
  618.     {
  619.         return(FORM_TYPE_TEXT);
  620.     }
  621.     else if (pa_TagEqual(S_FORM_TYPE_RADIO, type_str))
  622.     {
  623.         return(FORM_TYPE_RADIO);
  624.     }
  625.     else if (pa_TagEqual(S_FORM_TYPE_CHECKBOX, type_str))
  626.     {
  627.         return(FORM_TYPE_CHECKBOX);
  628.     }
  629.     else if (pa_TagEqual(S_FORM_TYPE_HIDDEN, type_str))
  630.     {
  631.         return(FORM_TYPE_HIDDEN);
  632.     }
  633.     else if (pa_TagEqual(S_FORM_TYPE_SUBMIT, type_str))
  634.     {
  635.         return(FORM_TYPE_SUBMIT);
  636.     }
  637.     else if (pa_TagEqual(S_FORM_TYPE_RESET, type_str))
  638.     {
  639.         return(FORM_TYPE_RESET);
  640.     }
  641.     else if (pa_TagEqual(S_FORM_TYPE_PASSWORD, type_str))
  642.     {
  643.         return(FORM_TYPE_PASSWORD);
  644.     }
  645.     else if (pa_TagEqual(S_FORM_TYPE_BUTTON, type_str))
  646.     {
  647.         return(FORM_TYPE_BUTTON);
  648.     }
  649.     else if (pa_TagEqual(S_FORM_TYPE_FILE, type_str))
  650.     {
  651.         return(FORM_TYPE_FILE);
  652.     }
  653.     else if (pa_TagEqual(S_FORM_TYPE_IMAGE, type_str))
  654.     {
  655.         return(FORM_TYPE_IMAGE);
  656.     }
  657.     else if (pa_TagEqual(S_FORM_TYPE_OBJECT, type_str))
  658.     {
  659.         return(FORM_TYPE_OBJECT);
  660.     }
  661.     else if (pa_TagEqual(S_FORM_TYPE_JOT, type_str))
  662.     {
  663.         return(FORM_TYPE_JOT);
  664.     }
  665.     else if (pa_TagEqual(S_FORM_TYPE_READONLY, type_str))
  666.     {
  667.         return(FORM_TYPE_READONLY);
  668.     }
  669.     else
  670.     {
  671.         return(FORM_TYPE_TEXT);
  672.     }
  673. }
  674.  
  675.  
  676. static void
  677. lo_recolor_form_element_bg(lo_DocState *state, LO_FormElementStruct *form_ele,
  678.     LO_Color *bg_color)
  679. {
  680.     LO_TextAttr *old_attr;
  681.     LO_TextAttr *attr;
  682.     LO_TextAttr tmp_attr;
  683.  
  684.     attr = NULL;
  685.     old_attr = form_ele->text_attr;
  686.     if (old_attr != NULL)
  687.     {
  688.         lo_CopyTextAttr(old_attr, &tmp_attr);
  689.         
  690.         /* don't recolor the background if it was
  691.          * explicitly set to another color 
  692.          */
  693.         if(tmp_attr.no_background == TRUE)
  694.         {
  695.             tmp_attr.bg.red = bg_color->red;
  696.             tmp_attr.bg.green = bg_color->green;
  697.             tmp_attr.bg.blue = bg_color->blue;
  698.         }
  699.  
  700.         /* removed by Lou 4-3-97.  Allow text to
  701.          * overlap correctly in tables
  702.           */
  703.         /* tmp_attr.no_background = FALSE; */
  704.  
  705.         attr = lo_FetchTextAttr(state, &tmp_attr);
  706.     }
  707.     form_ele->text_attr = attr;
  708. }
  709.  
  710.  
  711. static LO_FormElementStruct *
  712. new_form_element(MWContext *context, lo_DocState *state, int32 type)
  713. {
  714.     LO_FormElementStruct *form_element;
  715.     lo_DocLists *doc_lists;
  716. #ifdef XP_WIN
  717.     XP_Bool attr_change;
  718.     LO_TextAttr tmp_attr;
  719. #endif
  720.  
  721.     doc_lists = lo_GetCurrentDocLists(state);
  722.     
  723.     form_element = (LO_FormElementStruct *)lo_NewElement(context, state, LO_FORM_ELE, NULL, 0);
  724.     if (form_element == NULL)
  725.     {
  726.         return(NULL);
  727.     }
  728.  
  729.     form_element->type = LO_FORM_ELE;
  730.     form_element->ele_id = NEXT_ELEMENT;
  731.     form_element->x = state->x;
  732.     form_element->y = state->y;
  733.     form_element->x_offset = 0;
  734.     form_element->y_offset = 0;
  735.     form_element->border_vert_space = 0;
  736.     form_element->border_horiz_space = 0;
  737.     form_element->width = 0;
  738.     form_element->height = 0;
  739.  
  740.     form_element->next = NULL;
  741.     form_element->prev = NULL;
  742.  
  743.     form_element->form_id = doc_lists->current_form_num;
  744.     form_element->layer_id = lo_CurrentLayerId(state);
  745.     form_element->element_data = NULL;
  746.     form_element->element_index = 0;
  747. #ifdef MOCHA
  748.     form_element->mocha_object = NULL;
  749.     form_element->event_handler_present = FALSE;
  750. #endif
  751.  
  752.     if (state->font_stack == NULL)
  753.     {
  754.         form_element->text_attr = NULL;
  755.     }
  756.     else
  757.     {
  758.         form_element->text_attr = state->font_stack->text_attr;
  759.         /*
  760.          * Possibly inherit the background color attribute
  761.          * of a parent table cell.
  762.          */
  763.         if (state->is_a_subdoc == SUBDOC_CELL)
  764.         {
  765.             lo_DocState *up_state;
  766.  
  767.             /*
  768.              * Find the parent subdoc's state.
  769.              */
  770.             up_state = state->top_state->doc_state;
  771.             while ((up_state->sub_state != NULL)&&
  772.                 (up_state->sub_state != state))
  773.             {
  774.                 up_state = up_state->sub_state;
  775.             }
  776.             if ((up_state->sub_state != NULL)&&
  777.                 (up_state->current_ele != NULL)&&
  778.                 (up_state->current_ele->type == LO_SUBDOC)&&
  779.                 (up_state->current_ele->lo_subdoc.backdrop.bg_color != NULL))
  780.             {
  781.                 lo_recolor_form_element_bg(state, form_element,
  782.                     up_state->current_ele->lo_subdoc.backdrop.bg_color);
  783.             }
  784.         }
  785.     }
  786. #ifdef XP_WIN
  787.     attr_change = FALSE;
  788.     attr_change = FE_CheckFormTextAttributes(context,
  789.             form_element->text_attr, &tmp_attr, type);
  790.     if (attr_change != FALSE)
  791.     {
  792.         form_element->text_attr = lo_FetchTextAttr(state, &tmp_attr);
  793.     }
  794. #endif
  795.  
  796.     form_element->ele_attrmask = 0;
  797.  
  798.     form_element->sel_start = -1;
  799.     form_element->sel_end = -1;
  800.  
  801.     return(form_element);
  802. }
  803.  
  804.  
  805. /*
  806.  * If this document already has a list of form
  807.  * data elements, return a pointer to the next form element data
  808.  * structure.  Otherwise allocate a new data element structure, and
  809.  * put the pointer to it in the document's list of
  810.  * form data elements before returning it.
  811.  */
  812. static LO_FormElementData *
  813. lo_next_element_data(lo_DocState *state, int32 type)
  814. {
  815.     lo_SavedFormListData *all_ele;
  816.     int32 index;
  817.     LO_FormElementData **data_list;
  818.     LO_FormElementData *data_ele;
  819.  
  820.     all_ele = state->top_state->savedData.FormList;
  821.     index = all_ele->data_index++;
  822.  
  823.     /*
  824.      * This only happens if we didn't have a pre-saved
  825.      * data list, so we grow this one and create a new element.
  826.      */
  827.     if (all_ele->data_index > all_ele->data_count)
  828.     {
  829.         PA_Block old_data_list; /* really a (LO_FormElementData **) */
  830.  
  831. #ifdef XP_WIN16
  832.         if ((all_ele->data_index * sizeof(LO_FormElementData *)) >
  833.             SIZE_LIMIT)
  834.         {
  835.             all_ele->data_index--;
  836.             return(NULL);
  837.         }
  838. #endif /* XP_WIN16 */
  839.         all_ele->data_count = all_ele->data_index;
  840.         old_data_list = NULL;
  841.         if (all_ele->data_count == 1)
  842.         {
  843.             all_ele->data_list = PA_ALLOC(all_ele->data_count
  844.                 * sizeof(LO_FormElementData *));
  845.         }
  846.         else
  847.         {
  848.             old_data_list = all_ele->data_list;
  849.             all_ele->data_list = PA_REALLOC(
  850.                 all_ele->data_list, (all_ele->data_count *
  851.                 sizeof(LO_FormElementData *)));
  852.         }
  853.         if (all_ele->data_list == NULL)
  854.         {
  855.             all_ele->data_list = old_data_list;
  856.             all_ele->data_index--;
  857.             all_ele->data_count--;
  858.             state->top_state->out_of_memory = TRUE;
  859.             return(NULL);
  860.         }
  861.  
  862.         PA_LOCK(data_list, LO_FormElementData **,
  863.             all_ele->data_list);
  864.         data_list[index] = XP_NEW_ZAP(LO_FormElementData);
  865.         if (data_list[index] != NULL)
  866.         {
  867.             data_list[index]->type = FORM_TYPE_NONE;
  868.         }
  869.         else
  870.         {
  871.             state->top_state->out_of_memory = TRUE;
  872.         }
  873.         PA_UNLOCK(all_ele->data_list);
  874.     }
  875.  
  876.     PA_LOCK(data_list, LO_FormElementData **, all_ele->data_list);
  877.     data_ele = data_list[index];
  878.  
  879.     /*
  880.      * If the type is changing, someone may be attacking us via server push
  881.      * or JavaScript document.write and history.go(0), substituting a file
  882.      * upload input for a text input from the previous version of the doc
  883.      * that has its value field set to "/etc/passwd".
  884.      */
  885.     if ((data_ele->type != FORM_TYPE_NONE) && (data_ele->type != type))
  886.     {
  887.         lo_FreeFormElementData(data_ele);
  888.         XP_BZERO(data_ele, sizeof(*data_ele));
  889.         data_ele->type = FORM_TYPE_NONE;
  890.     }
  891.     
  892.     PA_UNLOCK(all_ele->data_list);
  893.     /*
  894.      * If we are reusing an old structure, clean it of old memory
  895.      */
  896.     lo_CleanFormElementData(data_ele);
  897.  
  898.     return(data_ele);
  899. }
  900.  
  901.  
  902. static LO_FormElementStruct *
  903. lo_form_input_text(MWContext *context, lo_DocState *state,
  904.     PA_Tag *tag, int32 type)
  905. {
  906.     LO_FormElementStruct *form_element;
  907.     lo_FormElementTextData *form_data;
  908.     PA_Block buff;
  909. #if defined(XP_MAC)&&defined(MOCHA)
  910.     PA_Block keydown, keypress, keyup;
  911. #endif /* defined(XP_MAC)&&defined(MOCHA) */
  912.     char *str;
  913.     char *tptr;
  914.     int16 charset;
  915.  
  916.     form_element = new_form_element(context, state, type);
  917.     if (form_element == NULL)
  918.     {
  919.         return(NULL);
  920.     }
  921.  
  922.     form_element->element_data = lo_next_element_data(state, type);
  923.     if (form_element->element_data == NULL)
  924.     {
  925.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  926.         return(NULL);
  927.     }
  928.     form_element->element_index =
  929.         state->top_state->savedData.FormList->data_index - 1;
  930.     form_data = (lo_FormElementTextData *)form_element->element_data;
  931.  
  932.     /*
  933.      * IF our starting type is NONE, this is a new element,
  934.      * an we need to initialize the locations that will later
  935.      * hold persistent data.
  936.      */
  937.     if (form_data->type == FORM_TYPE_NONE)
  938.     {
  939.         form_data->FE_Data = NULL;
  940.         form_data->current_text = NULL;
  941.     }
  942.  
  943.     form_data->encoding = INPUT_TYPE_ENCODING_NORMAL; /* default */
  944.  
  945.     form_data->type = type;
  946.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  947.     buff = lo_FetchParamValue(context, tag, PARAM_VALUE);
  948.     PA_LOCK(tptr, char *, buff);
  949.     /*
  950.      * strip newlines from single line text
  951.      * default values.
  952.      */
  953.     if ((tptr != NULL)&&(type != FORM_TYPE_PASSWORD))
  954.     {
  955.         int32 len;
  956.  
  957.         len = XP_STRLEN(tptr);
  958.         len = lo_StripTextNewlines(tptr, len);
  959.     }
  960.     charset = form_element->text_attr->charset;
  961.     tptr = FE_TranslateISOText(context, charset, tptr);
  962.     PA_UNLOCK(buff);
  963.     form_data->default_text = buff;
  964.  
  965. #ifdef OLD_FILE_UPLOAD
  966.     if ((form_data->default_text == NULL)&&(type == FORM_TYPE_FILE))
  967.     {
  968.         form_data->default_text = PA_ALLOC(
  969.                 (XP_STRLEN(DEF_FILE_ELE_VALUE) + 1)
  970.                 * sizeof(char));
  971.         if (form_data->default_text != NULL)
  972.         {
  973.             PA_LOCK(tptr, char *, form_data->default_text);
  974.             XP_STRCPY(tptr, DEF_FILE_ELE_VALUE);
  975.             PA_UNLOCK(form_data->default_text);
  976.         }
  977.     }
  978. #else
  979.     /*
  980.      * File upload forms cannot default to a filename
  981.      */
  982.     if ((form_data->default_text != NULL)&&(type == FORM_TYPE_FILE))
  983.     {
  984.         PA_FREE(form_data->default_text);
  985.         form_data->default_text = NULL;
  986.     }
  987. #endif /* OLD_FILE_UPLOAD */
  988.  
  989.     form_data->readonly = FALSE;
  990.     if (type != FORM_TYPE_FILE)
  991.       {
  992.         buff = lo_FetchParamValue(context, tag, PARAM_READONLY);
  993.         if (buff != NULL)
  994.           {
  995.             PA_FREE(buff);
  996.             form_data->readonly = TRUE;
  997.           }
  998.       }
  999.  
  1000.     form_data->size = DEF_TEXT_ELE_SIZE;
  1001.     buff = lo_FetchParamValue(context, tag, PARAM_SIZE);
  1002.     if (buff != NULL)
  1003.     {
  1004.         PA_LOCK(str, char *, buff);
  1005.         form_data->size = XP_ATOI(str);
  1006.         PA_UNLOCK(buff);
  1007.         PA_FREE(buff);
  1008.         if (form_data->size < 1)
  1009.         {
  1010.             form_data->size = 1;
  1011.         }
  1012.     }
  1013. #ifdef OLD_FILE_UPLOAD
  1014.     else if ((type == FORM_TYPE_FILE)&&(form_data->default_text != NULL))
  1015.     {
  1016.         int32 len;
  1017.  
  1018.         PA_LOCK(tptr, char *, form_data->default_text);
  1019.         len = XP_STRLEN(tptr);
  1020.         PA_UNLOCK(form_data->default_text);
  1021.         if (len > 0)
  1022.         {
  1023.             form_data->size = len;
  1024.         }
  1025.     }
  1026. #endif /* OLD_FILE_UPLOAD */
  1027.  
  1028.     buff = lo_FetchParamValue(context, tag, PARAM_ENCODING);
  1029.     if (buff != NULL)
  1030.     {
  1031.         PA_LOCK(str, char *, buff);
  1032.         if(!XP_STRCASECMP(str, "MACBINARY"))
  1033.             form_data->encoding = INPUT_TYPE_ENCODING_MACBIN;
  1034.         PA_UNLOCK(buff);
  1035.         PA_FREE(buff);
  1036.     }
  1037.  
  1038.     form_data->max_size = -1;
  1039.     buff = lo_FetchParamValue(context, tag, PARAM_MAXLENGTH);
  1040.     if (buff != NULL)
  1041.     {
  1042.         PA_LOCK(str, char *, buff);
  1043.         form_data->max_size = XP_ATOI(str);
  1044.         PA_UNLOCK(buff);
  1045.         PA_FREE(buff);
  1046.     }
  1047.     
  1048. #if defined(XP_MAC)&&defined(MOCHA)
  1049.     keydown = lo_FetchParamValue(context, tag, PARAM_ONKEYDOWN);
  1050.     keypress = lo_FetchParamValue(context, tag, PARAM_ONKEYPRESS);
  1051.     keyup = lo_FetchParamValue(context, tag, PARAM_ONKEYUP);
  1052.  
  1053.     /* Text fields need this info which needs to be carried across table cell relayouts.
  1054.        Only the mac FE checks the event_handler_present bit. */
  1055.     if (keydown || keypress || keyup)
  1056.     form_element->event_handler_present = TRUE;
  1057.     
  1058.     if (keydown)
  1059.         PA_FREE(keydown);
  1060.     if (keypress)
  1061.         PA_FREE(keypress);
  1062.     if (keyup)
  1063.         PA_FREE(keyup);        
  1064. #endif /* defined(XP_MAC)&&defined(MOCHA) */
  1065.  
  1066.     return(form_element);
  1067. }
  1068.  
  1069.  
  1070. static LO_FormElementStruct *
  1071. lo_form_textarea(MWContext *context, lo_DocState *state,
  1072.     PA_Tag *tag, int32 type)
  1073. {
  1074.     LO_FormElementStruct *form_element;
  1075.     lo_FormElementTextareaData *form_data;
  1076.     PA_Block buff;
  1077. #if defined(XP_MAC)&&defined(MOCHA)
  1078.     PA_Block keydown, keypress, keyup;
  1079. #endif /* defined(XP_MAC)&&defined(MOCHA) */
  1080.     char *str;
  1081.  
  1082.     form_element = new_form_element(context, state, type);
  1083.     if (form_element == NULL)
  1084.     {
  1085.         return(NULL);
  1086.     }
  1087.  
  1088.     form_element->element_data = lo_next_element_data(state, type);
  1089.     if (form_element->element_data == NULL)
  1090.     {
  1091.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1092.         return(NULL);
  1093.     }
  1094.     form_element->element_index =
  1095.         state->top_state->savedData.FormList->data_index - 1;
  1096.     form_data = (lo_FormElementTextareaData *)form_element->element_data;
  1097.  
  1098.     /*
  1099.      * IF our starting type is NONE, this is a new element,
  1100.      * an we need to initialize the locations that will later
  1101.      * hold persistent data.
  1102.      */
  1103.     if (form_data->type == FORM_TYPE_NONE)
  1104.     {
  1105.         form_data->FE_Data = NULL;
  1106.         form_data->current_text = NULL;
  1107.     }
  1108.  
  1109.     form_data->type = type;
  1110.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1111.     form_data->default_text = NULL;
  1112.  
  1113.     form_data->rows = DEF_TEXTAREA_ELE_ROWS;
  1114.     buff = lo_FetchParamValue(context, tag, PARAM_ROWS);
  1115.     if (buff != NULL)
  1116.     {
  1117.         PA_LOCK(str, char *, buff);
  1118.         form_data->rows = XP_ATOI(str);
  1119.         PA_UNLOCK(buff);
  1120.         PA_FREE(buff);
  1121.         if (form_data->rows < 1)
  1122.         {
  1123.             form_data->rows = 1;
  1124.         }
  1125.     }
  1126.  
  1127.     form_data->cols = DEF_TEXTAREA_ELE_COLS;
  1128.     buff = lo_FetchParamValue(context, tag, PARAM_COLS);
  1129.     if (buff != NULL)
  1130.     {
  1131.         PA_LOCK(str, char *, buff);
  1132.         form_data->cols = XP_ATOI(str);
  1133.         PA_UNLOCK(buff);
  1134.         PA_FREE(buff);
  1135.         if (form_data->cols < 1)
  1136.         {
  1137.             form_data->cols = 1;
  1138.         }
  1139.     }
  1140.  
  1141.     form_data->disabled = FALSE;
  1142.     buff = lo_FetchParamValue(context, tag, PARAM_DISABLED);
  1143.     if (buff != NULL)
  1144.     {
  1145.         PA_FREE(buff);
  1146.         form_data->disabled = TRUE;
  1147.     }
  1148.  
  1149.     form_data->readonly = FALSE;
  1150.     buff = lo_FetchParamValue(context, tag, PARAM_READONLY);
  1151.     if (buff != NULL)
  1152.     {
  1153.         PA_FREE(buff);
  1154.         form_data->readonly = TRUE;
  1155.     }
  1156.  
  1157.     form_data->auto_wrap = TEXTAREA_WRAP_OFF;
  1158.     buff = lo_FetchParamValue(context, tag, PARAM_WRAP);
  1159.     if (buff != NULL)
  1160.     {
  1161.         PA_LOCK(str, char *, buff);
  1162.         if (pa_TagEqual("off", str))
  1163.         {
  1164.             form_data->auto_wrap = TEXTAREA_WRAP_OFF;
  1165.         }
  1166.         else if (pa_TagEqual("hard", str))
  1167.         {
  1168.             form_data->auto_wrap = TEXTAREA_WRAP_HARD;
  1169.         }
  1170.         else if (pa_TagEqual("soft", str))
  1171.         {
  1172.             form_data->auto_wrap = TEXTAREA_WRAP_SOFT;
  1173.         }
  1174.         /*
  1175.          * Make <TEXTAREA WRAP>
  1176.          * default to WRAP=SOFT
  1177.          */
  1178.         else
  1179.         {
  1180.             form_data->auto_wrap = TEXTAREA_WRAP_SOFT;
  1181.         }
  1182.         PA_UNLOCK(buff);
  1183.         PA_FREE(buff);
  1184.     }
  1185.  
  1186. #if defined(XP_MAC)&&defined(MOCHA)
  1187.     keydown = lo_FetchParamValue(context, tag, PARAM_ONKEYDOWN);
  1188.     keypress = lo_FetchParamValue(context, tag, PARAM_ONKEYPRESS);
  1189.     keyup = lo_FetchParamValue(context, tag, PARAM_ONKEYUP);
  1190.  
  1191.     /* Text fields need this info which needs to be carried across table cell relayouts.
  1192.        Only the mac FE checks the event_handler_present bit. */
  1193.     if (keydown || keypress || keyup)
  1194.     form_element->event_handler_present = TRUE;
  1195.     
  1196.     if (keydown)
  1197.         PA_FREE(keydown);
  1198.     if (keypress)
  1199.         PA_FREE(keypress);
  1200.     if (keyup)
  1201.         PA_FREE(keyup);        
  1202. #endif /* defined(XP_MAC)&&defined(MOCHA) */
  1203.  
  1204.     return(form_element);
  1205. }
  1206.  
  1207.  
  1208. static LO_FormElementStruct *
  1209. lo_form_input_minimal(MWContext *context, lo_DocState *state,
  1210.     PA_Tag *tag, int32 type)
  1211. {
  1212.     LO_FormElementStruct *form_element;
  1213.     lo_FormElementMinimalData *form_data;
  1214.  
  1215.     form_element = new_form_element(context, state, type);
  1216.     if (form_element == NULL)
  1217.     {
  1218.         return(NULL);
  1219.     }
  1220.  
  1221.     form_element->element_data = lo_next_element_data(state, type);
  1222.     if (form_element->element_data == NULL)
  1223.     {
  1224.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1225.         return(NULL);
  1226.     }
  1227.     form_element->element_index =
  1228.         state->top_state->savedData.FormList->data_index - 1;
  1229.     form_data = (lo_FormElementMinimalData *)form_element->element_data;
  1230.  
  1231.     /*
  1232.      * IF our starting type is NONE, this is a new element,
  1233.      * an we need to initialize the locations that will later
  1234.      * hold persistent data.
  1235.      */
  1236.     if (form_data->type == FORM_TYPE_NONE)
  1237.     {
  1238.         form_data->FE_Data = NULL;
  1239.     }
  1240.  
  1241.     form_data->type = type;
  1242.  
  1243.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1244. #ifdef NICE_BUT_NOT_NCSA_COMPAT
  1245.     if (form_data->name == NULL)
  1246.     {
  1247.         if (form_data->type == FORM_TYPE_SUBMIT)
  1248.         {
  1249.             form_data->name = XP_ALLOC_BLOCK(XP_STRLEN(
  1250.                 DEF_SUBMIT_BUTTON_NAME) + 1);
  1251.             if (form_data->name != NULL)
  1252.             {
  1253.                 char *name;
  1254.  
  1255.                 XP_LOCK_BLOCK(name, char *, form_data->name);
  1256.                 XP_STRCPY(name, DEF_SUBMIT_BUTTON_NAME);
  1257.                 XP_UNLOCK_BLOCK(form_data->name);
  1258.             }
  1259.         }
  1260.         else if (form_data->type == FORM_TYPE_RESET)
  1261.         {
  1262.             form_data->name = XP_ALLOC_BLOCK(XP_STRLEN(
  1263.                 DEF_RESET_BUTTON_NAME) + 1);
  1264.             if (form_data->name != NULL)
  1265.             {
  1266.                 char *name;
  1267.  
  1268.                 XP_LOCK_BLOCK(name, char *, form_data->name);
  1269.                 XP_STRCPY(name, DEF_RESET_BUTTON_NAME);
  1270.                 XP_UNLOCK_BLOCK(form_data->name);
  1271.             }
  1272.         }
  1273.     }
  1274. #endif /* NICE_BUT_NOT_NCSA_COMPAT */
  1275.  
  1276.     form_data->value = lo_FetchParamValue(context, tag, PARAM_VALUE);
  1277.     if (form_data->value == NULL)
  1278.     {
  1279.         if (form_data->type == FORM_TYPE_SUBMIT)
  1280.         {
  1281.             form_data->value = PA_ALLOC(
  1282.                 XP_STRLEN(DEF_SUBMIT_BUTTON_TEXT) + 1);
  1283.             if (form_data->value != NULL)
  1284.             {
  1285.                 char *value;
  1286.  
  1287.                 PA_LOCK(value, char *, form_data->value);
  1288.                 XP_STRCPY(value, DEF_SUBMIT_BUTTON_TEXT);
  1289.                 PA_UNLOCK(form_data->value);
  1290.             }
  1291.             else
  1292.             {
  1293.                 state->top_state->out_of_memory = TRUE;
  1294.             }
  1295.         }
  1296.         else if (form_data->type == FORM_TYPE_RESET)
  1297.         {
  1298.             form_data->value = PA_ALLOC(
  1299.                 XP_STRLEN(DEF_RESET_BUTTON_TEXT) + 1);
  1300.             if (form_data->value != NULL)
  1301.             {
  1302.                 char *value;
  1303.  
  1304.                 PA_LOCK(value, char *, form_data->value);
  1305.                 XP_STRCPY(value, DEF_RESET_BUTTON_TEXT);
  1306.                 PA_UNLOCK(form_data->value);
  1307.             }
  1308.             else
  1309.             {
  1310.                 state->top_state->out_of_memory = TRUE;
  1311.             }
  1312.         }
  1313.         else
  1314.         {
  1315.             form_data->value = PA_ALLOC(
  1316.                 XP_STRLEN(DEF_BUTTON_TEXT) + 1);
  1317.             if (form_data->value != NULL)
  1318.             {
  1319.                 char *value;
  1320.  
  1321.                 PA_LOCK(value, char *, form_data->value);
  1322.                 XP_STRCPY(value, DEF_BUTTON_TEXT);
  1323.                 PA_UNLOCK(form_data->value);
  1324.             }
  1325.             else
  1326.             {
  1327.                 state->top_state->out_of_memory = TRUE;
  1328.             }
  1329.         }
  1330.     }
  1331.     else if ((type == FORM_TYPE_SUBMIT)||(type == FORM_TYPE_RESET))
  1332.     {
  1333.         int32 len;
  1334.         char *value;
  1335.  
  1336.         /*
  1337.          * strip newlines from single line button names
  1338.          */
  1339.         PA_LOCK(value, char *, form_data->value);
  1340.         len = XP_STRLEN(value);
  1341.         len = lo_StripTextNewlines(value, len);
  1342.         PA_UNLOCK(form_data->value);
  1343.     }
  1344.  
  1345.     /*
  1346.      * Buttons can set a preferred minimum width and height
  1347.      * in pixels that may be larger that what is needed
  1348.      * to display button text.
  1349.      */
  1350.     if ((type == FORM_TYPE_SUBMIT)||(type == FORM_TYPE_RESET)||
  1351.         (type == FORM_TYPE_BUTTON))
  1352.     {
  1353.         PA_Block buff;
  1354.         char *str;
  1355.         int32 val;
  1356.  
  1357.         buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1358.         if (buff != NULL)
  1359.         {
  1360.             PA_LOCK(str, char *, buff);
  1361.             val = XP_ATOI(str);
  1362.             if (val < 0)
  1363.             {
  1364.                 val = 0;
  1365.             }
  1366.             if (val > MAX_BUTTON_WIDTH)
  1367.             {
  1368.                 val = MAX_BUTTON_WIDTH;
  1369.             }
  1370.             PA_UNLOCK(buff);
  1371.             PA_FREE(buff);
  1372.             form_element->width = val;
  1373.         }
  1374.  
  1375.         buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1376.         if (buff != NULL)
  1377.         {
  1378.             PA_LOCK(str, char *, buff);
  1379.             val = XP_ATOI(str);
  1380.             if (val < 0)
  1381.             {
  1382.                 val = 0;
  1383.             }
  1384.             if (val > MAX_BUTTON_HEIGHT)
  1385.             {
  1386.                 val = MAX_BUTTON_HEIGHT;
  1387.             }
  1388.             PA_UNLOCK(buff);
  1389.             PA_FREE(buff);
  1390.             form_element->height = val;
  1391.         }
  1392.     }
  1393.  
  1394. #ifdef NEED_ISO_BACK_TRANSLATE
  1395.     if ((type != FORM_TYPE_HIDDEN)&&(type != FORM_TYPE_KEYGEN))
  1396.     {
  1397.         char *tptr;
  1398.         int16 charset;
  1399.  
  1400.         PA_LOCK(tptr, char *, form_data->value);
  1401.         charset = form_element->text_attr->charset;
  1402.         tptr = FE_TranslateISOText(context, charset, tptr);
  1403.         PA_UNLOCK(form_data->value);
  1404.     }
  1405. #endif
  1406.  
  1407.     return(form_element);
  1408. }
  1409.  
  1410.  
  1411. static LO_FormElementStruct *
  1412. lo_form_input_toggle(MWContext *context, lo_DocState *state,
  1413.     PA_Tag *tag, int32 type)
  1414. {
  1415.     LO_FormElementStruct *form_element;
  1416.     lo_FormElementToggleData *form_data;
  1417.     PA_Block buff;
  1418.  
  1419.     form_element = new_form_element(context, state, type);
  1420.     if (form_element == NULL)
  1421.     {
  1422.         return(NULL);
  1423.     }
  1424.  
  1425.     form_element->element_data = lo_next_element_data(state, type);
  1426.     if (form_element->element_data == NULL)
  1427.     {
  1428.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1429.         return(NULL);
  1430.     }
  1431.     form_element->element_index =
  1432.         state->top_state->savedData.FormList->data_index - 1;
  1433.     form_data = (lo_FormElementToggleData *)form_element->element_data;
  1434.  
  1435.     form_data->default_toggle = FALSE;
  1436.     buff = lo_FetchParamValue(context, tag, PARAM_CHECKED);
  1437.     if (buff != NULL)
  1438.     {
  1439.         form_data->default_toggle = TRUE;
  1440.         PA_FREE(buff);
  1441.     }
  1442.  
  1443.     /*
  1444.      * IF our starting type is NONE, this is a new element,
  1445.      * an we need to initialize the locations that will later
  1446.      * hold persistent data.
  1447.      */
  1448.     if (form_data->type == FORM_TYPE_NONE)
  1449.     {
  1450.         form_data->FE_Data = NULL;
  1451.         form_data->toggled = form_data->default_toggle;
  1452.     }
  1453.  
  1454.     form_data->type = type;
  1455.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1456.  
  1457.     form_data->value = lo_FetchParamValue(context, tag, PARAM_VALUE);
  1458.     if (form_data->value == NULL)
  1459.     {
  1460.         form_data->value = PA_ALLOC(
  1461.             XP_STRLEN(DEF_TOGGLE_VALUE) + 1);
  1462.         if (form_data->value != NULL)
  1463.         {
  1464.             char *value;
  1465.  
  1466.             PA_LOCK(value, char *, form_data->value);
  1467.             XP_STRCPY(value, DEF_TOGGLE_VALUE);
  1468.             PA_UNLOCK(form_data->value);
  1469.         }
  1470.         else
  1471.         {
  1472.             state->top_state->out_of_memory = TRUE;
  1473.         }
  1474.     }
  1475.  
  1476.     return(form_element);
  1477. }
  1478.  
  1479.  
  1480. static LO_FormElementStruct *
  1481. lo_form_input_object(MWContext *context, lo_DocState *state,
  1482.     PA_Tag *tag, int32 type)
  1483. {
  1484. #ifdef JAVA
  1485.     LO_FormElementStruct *form_element;
  1486.     lo_FormElementObjectData *form_data;
  1487.  
  1488.     form_element = new_form_element(context, state, type);
  1489.     if (form_element == NULL)
  1490.     {
  1491.         return(NULL);
  1492.     }
  1493.  
  1494.     form_element->element_data = lo_next_element_data(state, type);
  1495.     if (form_element->element_data == NULL)
  1496.     {
  1497.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1498.         return(NULL);
  1499.     }
  1500.     form_element->element_index =
  1501.         state->top_state->savedData.FormList->data_index - 1;
  1502.     form_data = (lo_FormElementObjectData *)form_element->element_data;
  1503.  
  1504.     /*
  1505.      * IF our starting type is NONE, this is a new element,
  1506.      * an we need to initialize the locations that will later
  1507.      * hold persistent data.
  1508.      */
  1509.     if (form_data->type == FORM_TYPE_NONE)
  1510.     {
  1511.         form_data->FE_Data = NULL;
  1512.     }
  1513.  
  1514.     form_data->type = type;
  1515.  
  1516.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1517.     if (form_data->name == NULL)
  1518.     {
  1519.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1520.         return(NULL);
  1521.     }
  1522.  
  1523.     /*
  1524.      * Find the layout element for the object tag, and set form_data->object
  1525.      * to point to it.
  1526.      */
  1527.     {
  1528.     LO_JavaAppStruct *java_obj = lo_GetCurrentDocLists(state)->applet_list;
  1529.     while (java_obj)
  1530.     {
  1531.         if (java_obj->selector_type == LO_JAVA_SELECTOR_OBJECT_JAVABEAN)
  1532.         {
  1533.             char *name, *obj_name;
  1534.  
  1535.             PA_LOCK(name, char *, form_data->name);
  1536.             PA_LOCK(obj_name, char *, java_obj->attr_name);
  1537.  
  1538.             if (XP_STRCMP(name, obj_name) == 0)
  1539.             {
  1540.                 form_data->object = java_obj;
  1541.                 break;
  1542.             }
  1543.  
  1544.             PA_UNLOCK(form_data->name);
  1545.             PA_UNLOCK(java_obj->attr_name);
  1546.         }
  1547.  
  1548.         java_obj = java_obj->nextApplet;
  1549.     }
  1550.  
  1551.     if (java_obj == NULL)
  1552.     {
  1553.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1554.         return(NULL);
  1555.     }
  1556.     }
  1557.  
  1558.     return(form_element);
  1559. #else
  1560.     return NULL;
  1561. #endif
  1562.  
  1563. }
  1564.  
  1565.  
  1566. static LO_FormElementStruct *
  1567. lo_form_select(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1568. {
  1569.     LO_FormElementStruct *form_element;
  1570.     lo_FormElementSelectData *form_data;
  1571.     PA_Block buff;
  1572.     char *str;
  1573.     XP_Bool multiple;
  1574.     int32 size;
  1575.     int32 type;
  1576.  
  1577.     /*
  1578.      * We have to determine type early so we can pass it to
  1579.      * new_form_element(), so fetch and check the MULTIPLE and SIZE parameters
  1580.      * right away.
  1581.      */
  1582.     multiple = FALSE;
  1583.     buff = lo_FetchParamValue(context, tag, PARAM_MULTIPLE);
  1584.     if (buff != NULL)
  1585.     {
  1586.         multiple = TRUE;
  1587.         PA_FREE(buff);
  1588.     }
  1589.  
  1590.     size = 0;
  1591.     buff = lo_FetchParamValue(context, tag, PARAM_SIZE);
  1592.     if (buff != NULL)
  1593.     {
  1594.         PA_LOCK(str, char *, buff);
  1595.         size = XP_ATOI(str);
  1596.         PA_UNLOCK(buff);
  1597.         PA_FREE(buff);
  1598.         if (size < 1)
  1599.         {
  1600.             size = 1;
  1601.         }
  1602.     }
  1603.  
  1604.     if ((multiple != FALSE)||(size > 1))
  1605.     {
  1606.         type = FORM_TYPE_SELECT_MULT;
  1607.     }
  1608.     else
  1609.     {
  1610.         type = FORM_TYPE_SELECT_ONE;
  1611.     }
  1612.  
  1613.     form_element = new_form_element(context, state, type);
  1614.     if (form_element == NULL)
  1615.     {
  1616.         return(NULL);
  1617.     }
  1618.  
  1619.     form_element->element_data = lo_next_element_data(state, type);
  1620.     if (form_element->element_data == NULL)
  1621.     {
  1622.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1623.         return(NULL);
  1624.     }
  1625.     form_element->element_index =
  1626.         state->top_state->savedData.FormList->data_index - 1;
  1627.     form_data = (lo_FormElementSelectData *)form_element->element_data;
  1628.  
  1629.     /*
  1630.      * IF our starting type is NONE, this is a new element,
  1631.      * an we need to initialize the locations that will later
  1632.      * hold persistent data.
  1633.      */
  1634.     if (form_data->type == FORM_TYPE_NONE)
  1635.     {
  1636.         form_data->FE_Data = NULL;
  1637.         form_data->multiple = FALSE;
  1638.         form_data->options_valid = FALSE;
  1639.         form_data->option_cnt = 0;
  1640.         form_data->options = NULL;
  1641.     }
  1642.  
  1643.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1644.  
  1645.     form_data->multiple = multiple;
  1646.     form_data->size = size;
  1647.     form_data->type = type;
  1648.  
  1649.     /*
  1650.      * Selects can set a preferred minimum width
  1651.      * in pixels that may be larger that what is needed
  1652.      * to display option text.
  1653.      */
  1654.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1655.     if (buff != NULL)
  1656.     {
  1657.         int32 val;
  1658.  
  1659.         PA_LOCK(str, char *, buff);
  1660.         val = XP_ATOI(str);
  1661.         if (val < 0)
  1662.         {
  1663.             val = 0;
  1664.         }
  1665.         if (val > MAX_BUTTON_WIDTH)
  1666.         {
  1667.             val = MAX_BUTTON_WIDTH;
  1668.         }
  1669.         PA_UNLOCK(buff);
  1670.         PA_FREE(buff);
  1671.         form_element->width = val;
  1672.     }
  1673.  
  1674.     /*
  1675.      * Single selects can also set a preferred minimum height
  1676.      * in pixels that may be larger that what is needed
  1677.      * to display button text.  Multi selects must be the height
  1678.      * of the number of items in the list.
  1679.      */
  1680.     if (form_data->type == FORM_TYPE_SELECT_ONE)
  1681.     {
  1682.         int32 val;
  1683.  
  1684.         buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1685.         if (buff != NULL)
  1686.         {
  1687.             PA_LOCK(str, char *, buff);
  1688.             val = XP_ATOI(str);
  1689.             if (val < 0)
  1690.             {
  1691.                 val = 0;
  1692.             }
  1693.             if (val > MAX_BUTTON_HEIGHT)
  1694.             {
  1695.                 val = MAX_BUTTON_HEIGHT;
  1696.             }
  1697.             PA_UNLOCK(buff);
  1698.             PA_FREE(buff);
  1699.             form_element->height = val;
  1700.         }
  1701.     }
  1702.  
  1703.  
  1704.  
  1705.     /*
  1706.      * Make a copy of the tag so that we can correctly reflect this
  1707.      *   element into javascript.  Reflection can't happen until this
  1708.      *   element gets sent to lo_add_form_element() but by then the
  1709.      *   original tag is gone.
  1710.      */
  1711.     if (form_element != NULL && form_element->element_data != NULL)
  1712.     {
  1713.         form_data = (lo_FormElementSelectData *)
  1714.             form_element->element_data;
  1715.  
  1716.         if (form_data->saved_tag == NULL)
  1717.                 form_data->saved_tag = PA_CloneMDLTag(tag);
  1718.     }
  1719.  
  1720. #ifdef MOCHA
  1721.     /* needs to be moved */
  1722.     lo_ReflectFormElement(context, state, tag, form_element);
  1723. #endif
  1724.  
  1725.     return(form_element);
  1726. }
  1727.  
  1728.  
  1729. static LO_FormElementStruct *
  1730. lo_form_keygen(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1731. {
  1732.     LO_FormElementStruct *form_element;
  1733.     lo_FormElementKeygenData *form_data;
  1734.  
  1735.     form_element = new_form_element(context, state, FORM_TYPE_KEYGEN);
  1736.     if (form_element == NULL)
  1737.     {
  1738.         return(NULL);
  1739.     }
  1740.  
  1741.     form_element->element_data = lo_next_element_data(state, FORM_TYPE_KEYGEN);
  1742.     if (form_element->element_data == NULL)
  1743.     {
  1744.         lo_FreeElement(context, (LO_Element *)form_element, FALSE);
  1745.         return(NULL);
  1746.     }
  1747.     form_element->element_index =
  1748.         state->top_state->savedData.FormList->data_index - 1;
  1749.     form_data = (lo_FormElementKeygenData *)form_element->element_data;
  1750.  
  1751.     /*
  1752.      * IF our starting type is NONE, this is a new element,
  1753.      * and we need to initialize the locations that will later
  1754.      * hold persistent data.
  1755.      */
  1756.     if (form_data->type == FORM_TYPE_NONE)
  1757.     {
  1758.         form_data->value_str = NULL;
  1759.     }
  1760.  
  1761.     form_data->type = FORM_TYPE_KEYGEN;
  1762.     form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME);
  1763.     form_data->challenge = lo_FetchParamValue(context, tag, PARAM_CHALLENGE);
  1764.     form_data->pqg = lo_FetchParamValue(context, tag, PARAM_PQG);
  1765.     form_data->key_type = lo_FetchParamValue(context, tag, PARAM_KEYTYPE);
  1766.     form_data->dialog_done = PR_FALSE;
  1767.  
  1768.     return(form_element);
  1769. }
  1770.  
  1771.  
  1772. static Bool
  1773. lo_add_element_to_form_list(MWContext *context, lo_DocState *state,
  1774.     LO_FormElementStruct *form_element)
  1775. {
  1776.     lo_FormData *form_list;
  1777.     LO_Element **ele_array;
  1778.     PA_Block old_form_elements; /* really a (LO_Element **) */
  1779.     lo_DocLists *doc_lists;
  1780.  
  1781.     doc_lists = lo_GetCurrentDocLists(state);
  1782.     form_list = doc_lists->form_list;
  1783.     if (form_list == NULL)
  1784.     {
  1785.         return(FALSE);
  1786.     }
  1787.  
  1788.     form_list->form_ele_cnt++;
  1789. #ifdef XP_WIN16
  1790.     if ((form_list->form_ele_cnt * sizeof(LO_Element *)) > SIZE_LIMIT)
  1791.     {
  1792.         form_list->form_ele_cnt--;
  1793.         return(FALSE);
  1794.     }
  1795. #endif /* XP_WIN16 */
  1796.     old_form_elements = NULL;
  1797.     if (form_list->form_ele_cnt > form_list->form_ele_size)
  1798.     {
  1799.         if (form_list->form_ele_size == 0)
  1800.         {
  1801.             form_list->form_elements = PA_ALLOC(
  1802.                 form_list->form_ele_cnt * sizeof(LO_Element *));
  1803.         }
  1804.         else
  1805.         {
  1806.             old_form_elements = form_list->form_elements;
  1807.             form_list->form_elements = PA_REALLOC(
  1808.                 form_list->form_elements,
  1809.                 (form_list->form_ele_cnt *
  1810.                 sizeof(LO_Element *)));
  1811.         }
  1812. #ifdef MOCHA
  1813.         if (form_list->form_elements != NULL)
  1814.         {
  1815.             int32 i;
  1816.  
  1817.             PA_LOCK(ele_array, LO_Element **,
  1818.                 form_list->form_elements);
  1819.             for (i = form_list->form_ele_size;
  1820.                  i < form_list->form_ele_cnt;
  1821.                  i++)
  1822.             {
  1823.                 ele_array[i] = NULL;
  1824.             }
  1825.             PA_UNLOCK(form_list->form_elements);
  1826.         }
  1827. #endif
  1828.         form_list->form_ele_size = form_list->form_ele_cnt;
  1829.     }
  1830.     if (form_list->form_elements == NULL)
  1831.     {
  1832.         form_list->form_elements = old_form_elements;
  1833.         form_list->form_ele_cnt--;
  1834.         state->top_state->out_of_memory = TRUE;
  1835.         return(FALSE);
  1836.     }
  1837.     PA_LOCK(ele_array, LO_Element **, form_list->form_elements);
  1838. #ifdef MOCHA
  1839.     {
  1840.         LO_FormElementStruct *old_form_ele;
  1841.  
  1842.         old_form_ele = (LO_FormElementStruct *)
  1843.             ele_array[form_list->form_ele_cnt - 1];
  1844.         if ((old_form_ele != NULL) &&
  1845.             (form_element->mocha_object == NULL))
  1846.         {
  1847.             form_element->mocha_object = old_form_ele->mocha_object;
  1848.         }
  1849.     }
  1850. #endif
  1851.     ele_array[form_list->form_ele_cnt - 1] = (LO_Element *)form_element;
  1852.     PA_UNLOCK(form_list->form_elements);
  1853.     return(TRUE);
  1854. }
  1855.  
  1856.  
  1857. void
  1858. lo_LayoutInflowFormElement(MWContext *context,
  1859.                            lo_DocState *state,
  1860.                            LO_FormElementStruct *form_element,
  1861.                            int32 *baseline_inc,
  1862.                            Bool inRelayout)
  1863. {
  1864.     Bool line_break;
  1865.  
  1866.     form_element->ele_id = NEXT_ELEMENT;
  1867.     form_element->x = state->x;
  1868.     form_element->y = state->y;
  1869.     form_element->y_offset = 0;
  1870.     form_element->x_offset = 0;
  1871.     
  1872.     /*
  1873.      * Bad HTML can make thing like linebreaks occur between 
  1874.      * SELECT start and end.  Catch that here and clean up.
  1875.      * Need to reset element ID too to maintain ever increasing order.
  1876.      */
  1877.     if ((form_element->x != state->x)||(form_element->y != state->y))
  1878.     {
  1879.         form_element->ele_id = NEXT_ELEMENT;
  1880.         form_element->x = state->x;
  1881.         form_element->y = state->y;
  1882.     }
  1883.     form_element->baseline = 0;
  1884.     FE_GetFormElementInfo(context, form_element);
  1885.  
  1886.     if ((state->x + form_element->width) > state->right_margin)
  1887.     {
  1888.         line_break = TRUE;
  1889.     }
  1890.     else
  1891.     {
  1892.         line_break = FALSE;
  1893.     }
  1894.  
  1895.     /*
  1896.      * if we are at the beginning of the line.  There is
  1897.      * no point in breaking, we are just too wide.
  1898.      * Also don't break in unwrapped preformatted text.
  1899.      * Also can't break inside a NOBR section.
  1900.      */
  1901.     if ((state->at_begin_line != FALSE)||
  1902.         (state->preformatted == PRE_TEXT_YES)||
  1903.         (state->breakable == FALSE))
  1904.     {
  1905.         line_break = FALSE;
  1906.     }
  1907.  
  1908.     /*
  1909.      * Break on the form element if we have
  1910.      * a break.  If this happens we need to reset the
  1911.      * element id to maintain an ever increasing order.
  1912.      */
  1913.     if (line_break != FALSE)
  1914.     {
  1915.         state->top_state->element_id = form_element->ele_id;
  1916.  
  1917.         if (!inRelayout)
  1918.         {
  1919.             lo_SoftLineBreak(context, state, TRUE);
  1920.         }
  1921.         else 
  1922.         {
  1923.             lo_rl_AddSoftBreakAndFlushLine(context, state);
  1924.         }
  1925.  
  1926.         form_element->ele_id = NEXT_ELEMENT;
  1927.         form_element->x = state->x;
  1928.         form_element->y = state->y;
  1929.     }
  1930.  
  1931.     /*
  1932.      * The baseline of the form element just added to the line may be
  1933.      * less than or greater than the baseline of the rest of the line.
  1934.      * If the baseline is less, this is easy, we just increase
  1935.      * y_offest to move the text down so the baselines
  1936.      * line up.  For greater baselines, we can't move the element up to
  1937.      * line up the baselines because we will overlay the previous line,
  1938.      * so we have to move all the previous elements in this line down.
  1939.      *
  1940.      * If the baseline is zero, we are the first element on the line,
  1941.      * and we get to set the baseline.
  1942.      */
  1943.     *baseline_inc = 0;
  1944.     if (state->baseline == 0)
  1945.     {
  1946.         state->baseline = (intn) form_element->baseline;
  1947.         state->line_height = (intn) form_element->height;
  1948.     }
  1949.     else if (form_element->baseline < state->baseline)
  1950.     {
  1951.         form_element->y_offset = state->baseline -
  1952.             form_element->baseline;
  1953.     }
  1954.     else
  1955.     {
  1956.         *baseline_inc = form_element->baseline - state->baseline;
  1957.     }
  1958. }
  1959.  
  1960. void
  1961. lo_UpdateStateAfterFormElement(MWContext *context, lo_DocState *state,
  1962.                                LO_FormElementStruct *form_element,
  1963.                                int32 baseline_inc)
  1964. {
  1965.   state->baseline += (intn) baseline_inc;
  1966.   state->line_height += (intn) baseline_inc;
  1967.   
  1968.   if ((form_element->y_offset + form_element->height) >
  1969.       state->line_height)
  1970.     {
  1971.       state->line_height = form_element->y_offset +
  1972.         form_element->height;
  1973.     }
  1974.   
  1975.   state->x = state->x + form_element->x_offset + form_element->width;
  1976.   state->linefeed_state = 0;
  1977.   state->at_begin_line = FALSE;
  1978.   state->cur_ele_type = LO_FORM_ELE;
  1979.   state->trailing_space = FALSE;
  1980. }
  1981.  
  1982. static void
  1983. lo_add_form_element(MWContext *context, lo_DocState *state,
  1984.     LO_FormElementStruct *form_element)
  1985. {
  1986.     int32 baseline_inc;
  1987.  
  1988.     if (XP_FAIL_ASSERT(context))
  1989.         return;
  1990.     
  1991.     if (lo_add_element_to_form_list(context, state, form_element) == FALSE)
  1992.     {
  1993.         return;
  1994.     }
  1995.  
  1996.     lo_LayoutInflowFormElement(context, state, form_element, &baseline_inc, FALSE);
  1997.  
  1998.     lo_AppendToLineList(context, state,
  1999.         (LO_Element *)form_element, baseline_inc);
  2000.  
  2001.     lo_UpdateStateAfterFormElement(context, state, form_element, baseline_inc);
  2002.  
  2003.     form_element->layer =
  2004.       lo_CreateEmbeddedObjectLayer(context, state,
  2005.                        (LO_Element*)form_element);
  2006. }
  2007.  
  2008.  
  2009. /*
  2010.  * Function to reallocate the lo_FormElementOptionData array pointed at by
  2011.  * lo_FormElementSelectData's options member to include space for the number
  2012.  * of options given by form_data->options_cnt.
  2013.  *
  2014.  * This function is exported to libmocha/lm_input.c.
  2015.  */
  2016. XP_Bool
  2017. LO_ResizeSelectOptions(lo_FormElementSelectData *form_data)
  2018. {
  2019.     PA_Block old_options; /* really a (lo_FormElementOptionData *) */
  2020.  
  2021.     if (form_data->option_cnt == 0)
  2022.     {
  2023.         if (form_data->options != NULL)
  2024.         {
  2025.             PA_FREE(form_data->options);
  2026.             form_data->options = NULL;
  2027.         }
  2028.         return TRUE;
  2029.     }
  2030. #ifdef XP_WIN16
  2031.     if ((form_data->option_cnt * sizeof(lo_FormElementOptionData)) >
  2032.         SIZE_LIMIT)
  2033.     {
  2034.         return FALSE;
  2035.     }
  2036. #endif /* XP_WIN16 */
  2037.     old_options = form_data->options;
  2038.     if (old_options == NULL)
  2039.     {
  2040.         form_data->options = PA_ALLOC(form_data->option_cnt
  2041.             * sizeof(lo_FormElementOptionData));
  2042.     }
  2043.     else
  2044.     {
  2045.         form_data->options = PA_REALLOC(
  2046.             form_data->options, (form_data->option_cnt *
  2047.             sizeof(lo_FormElementOptionData)));
  2048.     }
  2049.     if (form_data->options == NULL)
  2050.     {
  2051.         form_data->options = old_options;
  2052.         return FALSE;
  2053.     }
  2054.  
  2055.     return TRUE;
  2056. }
  2057.  
  2058.  
  2059. void
  2060. lo_BeginOptionTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2061. {
  2062.     LO_FormElementStruct *form_element;
  2063.     lo_FormElementSelectData *form_data;
  2064.     lo_FormElementOptionData *options;
  2065.     lo_FormElementOptionData *optr;
  2066.     PA_Block buff;
  2067.  
  2068.     form_element = (LO_FormElementStruct *)state->current_ele;
  2069.     if ((form_element == NULL)||(form_element->element_data == NULL))
  2070.     {
  2071.         return;
  2072.     }
  2073.  
  2074.     form_data = (lo_FormElementSelectData *)form_element->element_data;
  2075.     if (form_data->options_valid != FALSE)
  2076.     {
  2077.         return;
  2078.     }
  2079.  
  2080.     form_data->option_cnt++;
  2081.     if (!LO_ResizeSelectOptions(form_data))
  2082.     {
  2083.         state->top_state->out_of_memory = TRUE;
  2084.         form_data->option_cnt--;
  2085.         return;
  2086.     }
  2087.  
  2088.     PA_LOCK(options, lo_FormElementOptionData *,
  2089.         form_data->options);
  2090.     optr = &(options[form_data->option_cnt - 1]);
  2091.     optr->text_value = NULL;
  2092.     optr->selected = FALSE;
  2093.  
  2094.     optr->value = lo_FetchParamValue(context, tag, PARAM_VALUE);
  2095.  
  2096.     optr->def_selected = FALSE;
  2097.     buff = lo_FetchParamValue(context, tag, PARAM_SELECTED);
  2098.     if (buff != NULL)
  2099.     {
  2100.         optr->def_selected = TRUE;
  2101.         PA_FREE(buff);
  2102.     }
  2103.  
  2104.     PA_UNLOCK(form_data->options);
  2105. }
  2106.  
  2107.  
  2108. void
  2109. lo_EndOptionTag(MWContext *context, lo_DocState *state, PA_Block buff)
  2110. {
  2111.     LO_FormElementStruct *form_element;
  2112.     lo_FormElementSelectData *form_data;
  2113.     lo_FormElementOptionData *options;
  2114.     lo_FormElementOptionData *optr;
  2115. #ifdef NEED_ISO_BACK_TRANSLATE
  2116.     char *tptr;
  2117.     int16 charset;
  2118. #endif
  2119.  
  2120.     form_element = (LO_FormElementStruct *)state->current_ele;
  2121.     if ((form_element == NULL)||(form_element->element_data == NULL))
  2122.     {
  2123.         return;
  2124.     }
  2125.  
  2126.     form_data = (lo_FormElementSelectData *)form_element->element_data;
  2127.     if (form_data->options_valid != FALSE)
  2128.     {
  2129.         PA_FREE(buff);
  2130.         return;
  2131.     }
  2132.  
  2133.     PA_LOCK(options, lo_FormElementOptionData *, form_data->options);
  2134.     optr = &(options[form_data->option_cnt - 1]);
  2135.  
  2136. #ifdef NEED_ISO_BACK_TRANSLATE
  2137.     PA_LOCK(tptr, char *, buff);
  2138.     charset = form_element->text_attr->charset;
  2139.     tptr = FE_TranslateISOText(context, charset, tptr);
  2140.     PA_UNLOCK(buff);
  2141. #endif
  2142.     optr->text_value = buff;
  2143.  
  2144.     PA_UNLOCK(form_data->options);
  2145. }
  2146.  
  2147.  
  2148. void
  2149. lo_BeginSelectTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2150. {
  2151.     LO_FormElementStruct *form_element;
  2152.  
  2153.     form_element = lo_form_select(context, state, tag);
  2154.  
  2155.     /*
  2156.      * Make a copy of the tag so that we can correctly reflect this
  2157.      *   element into javascript.  Reflection can't happen until this
  2158.      *   element gets sent to lo_add_form_element() but by then the
  2159.      *   original tag is gone.
  2160.      */
  2161.     if (form_element != NULL && form_element->element_data != NULL)
  2162.     {
  2163.         lo_FormElementSelectData *form_data;
  2164.         form_data = (lo_FormElementSelectData *)
  2165.             form_element->element_data;
  2166.         
  2167.         if (form_data->saved_tag == NULL)
  2168.             form_data->saved_tag = PA_CloneMDLTag(tag);
  2169.     }
  2170.  
  2171.     state->current_ele = (LO_Element *)form_element;
  2172.     state->cur_ele_type = LO_FORM_ELE;
  2173. }
  2174.  
  2175.  
  2176. void
  2177. lo_EndSelectTag(MWContext *context, lo_DocState *state)
  2178. {
  2179.     LO_FormElementStruct *form_element;
  2180.     lo_FormElementSelectData *form_data;
  2181.     lo_FormElementOptionData *options;
  2182.  
  2183.     form_element = (LO_FormElementStruct *)state->current_ele;
  2184.     if (form_element != NULL)
  2185.     {
  2186.         form_data = (lo_FormElementSelectData *)
  2187.                 form_element->element_data;
  2188.         /*
  2189.          * If we have element data for a select one
  2190.          * selection menu, sanify the data in case the user
  2191.          * specified more or less than 1 item to start
  2192.          * selected.
  2193.          */
  2194.         if ((form_data != NULL)&&
  2195.             (form_data->type == FORM_TYPE_SELECT_ONE))
  2196.         {
  2197.             Bool sel_set;
  2198.             int32 i;
  2199.  
  2200.             if (form_data->option_cnt > 0)
  2201.             {
  2202.                 PA_LOCK(options,
  2203.                     lo_FormElementOptionData *,
  2204.                     form_data->options);
  2205.                 sel_set = FALSE;
  2206.                 for (i=0; i < form_data->option_cnt; i++)
  2207.                 {
  2208.                     if (options[i].def_selected != FALSE)
  2209.                     {
  2210.                         if (sel_set != FALSE)
  2211.                         {
  2212.                             options[i].def_selected
  2213.                                  = FALSE;
  2214.                         }
  2215.                         else
  2216.                         {
  2217.                             sel_set = TRUE;
  2218.                         }
  2219.                     }
  2220.                 }
  2221.                 if (sel_set == FALSE)
  2222.                 {
  2223.                     options[0].def_selected = TRUE;
  2224.                 }
  2225.                 PA_UNLOCK(form_data->options);
  2226.             }
  2227.         }
  2228.  
  2229.         if (form_data != NULL)
  2230.         {
  2231.  
  2232.             if ((form_data->size < 1)&&
  2233.                 (form_data->type == FORM_TYPE_SELECT_MULT))
  2234.             {
  2235.                 form_data->size = form_data->option_cnt;
  2236.                 if (form_data->size < 1)
  2237.                 {
  2238.                     form_data->size = 1;
  2239.                 }
  2240.             }
  2241.             else if (form_data->size < 1)
  2242.             {
  2243.                 form_data->size = DEF_SELECT_ELE_SIZE;
  2244.             }
  2245.  
  2246.             form_data->options_valid = TRUE;
  2247.         }
  2248.  
  2249.         lo_add_form_element(context, state, form_element);
  2250.  
  2251.         /*
  2252.          * Now that we have added the element to the form list we
  2253.          *   can reflect it now.  
  2254.          */
  2255.         if (form_data != NULL)
  2256.         {
  2257.             lo_ReflectFormElement(context, state, 
  2258.                           form_data->saved_tag, 
  2259.                           form_element);
  2260.             PA_FreeTag(form_data->saved_tag);
  2261.             form_data->saved_tag = NULL;
  2262.         }
  2263.     
  2264.     }
  2265.     state->current_ele = NULL;
  2266. }
  2267.  
  2268.  
  2269. void
  2270. lo_BeginTextareaTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2271. {
  2272.     LO_FormElementStruct *form_element;
  2273.     LO_TextAttr tmp_attr;
  2274.     LO_TextAttr *old_attr;
  2275.     LO_TextAttr *attr;
  2276.  
  2277.     old_attr = state->font_stack->text_attr;
  2278.     lo_CopyTextAttr(old_attr, &tmp_attr);
  2279.     tmp_attr.fontmask |= LO_FONT_FIXED;
  2280.     attr = lo_FetchTextAttr(state, &tmp_attr);
  2281.  
  2282.     lo_PushFont(state, tag->type, attr);
  2283.  
  2284.     form_element = lo_form_textarea(context, state, tag,
  2285.         FORM_TYPE_TEXTAREA);
  2286.  
  2287.     /*
  2288.      * Make a copy of the tag so that we can correctly reflect this
  2289.      *   element into javascript.  Reflection can't happen until this
  2290.      *   element gets sent to lo_add_form_element() but by then the
  2291.      *   original tag is gone.
  2292.      */
  2293.     if (form_element != NULL && form_element->element_data != NULL)
  2294.     {
  2295.         lo_FormElementTextareaData *form_data;
  2296.         form_data = (lo_FormElementTextareaData *)
  2297.             form_element->element_data;
  2298.         
  2299.         if (form_data->saved_tag == NULL)
  2300.             form_data->saved_tag = PA_CloneMDLTag(tag);
  2301.     }
  2302.  
  2303.     attr = lo_PopFont(state, tag->type);
  2304.  
  2305.     state->current_ele = (LO_Element *)form_element;
  2306.         state->cur_ele_type = LO_FORM_ELE;
  2307. }
  2308.  
  2309.  
  2310. void
  2311. lo_EndTextareaTag(MWContext *context, lo_DocState *state, PA_Block buff)
  2312. {
  2313.     LO_FormElementStruct *form_element;
  2314.     char *tptr;
  2315.  
  2316.     form_element = (LO_FormElementStruct *)state->current_ele;
  2317.     if (form_element != NULL)
  2318.     {
  2319.         lo_FormElementTextareaData *form_data;
  2320.  
  2321.         form_data = (lo_FormElementTextareaData *)
  2322.             form_element->element_data;
  2323.         if (form_data != NULL)
  2324.         {
  2325.             int16 charset;
  2326.  
  2327.             PA_LOCK(tptr, char *, buff);
  2328.             charset = form_element->text_attr->charset;
  2329.             tptr = FE_TranslateISOText(context, charset, tptr);
  2330.             PA_UNLOCK(buff);
  2331.             form_data->default_text = buff;
  2332.         }
  2333.         lo_add_form_element(context, state, form_element);
  2334.  
  2335.         /*
  2336.          * Now that we have added the element to the form list we
  2337.          *   can reflect it now.
  2338.          */
  2339.         if (form_data != NULL)
  2340.         {
  2341.             lo_ReflectFormElement(context, state, 
  2342.                           form_data->saved_tag, 
  2343.                           form_element);
  2344.             PA_FreeTag(form_data->saved_tag);
  2345.             form_data->saved_tag = NULL;
  2346.         }
  2347.     }
  2348.     state->current_ele = NULL;
  2349. }
  2350.  
  2351.  
  2352. void
  2353. lo_ProcessInputTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2354. {
  2355.     LO_FormElementStruct *form_element;
  2356.     PA_Block buff;
  2357.     char *str;
  2358.     int32 type;
  2359.     Bool disabled;
  2360.  
  2361.     type = FORM_TYPE_TEXT;
  2362.     buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
  2363.     if (buff != NULL)
  2364.     {
  2365.         PA_LOCK(str, char *, buff);
  2366.         type = lo_ResolveInputType(str);
  2367.         PA_UNLOCK(buff);
  2368.         PA_FREE(buff);
  2369.     }
  2370.  
  2371.     disabled = FALSE;
  2372.     buff = lo_FetchParamValue(context, tag, PARAM_DISABLED);
  2373.     if (buff != NULL)
  2374.     {
  2375.         PA_FREE(buff);
  2376.         disabled = TRUE;
  2377.     }
  2378.  
  2379.     switch (type)
  2380.     {
  2381.         case FORM_TYPE_IMAGE:
  2382.             lo_FormatImage(context, state, tag);
  2383.             /*
  2384.              * Now check to see if this INPUT image was
  2385.              * prefetched earlier as a fake image.  If so
  2386.              * we can free up that fake image now.
  2387.              */
  2388.             if (tag->lo_data != NULL)
  2389.             {
  2390.                 LO_ImageStruct *image = tag->lo_data;
  2391.  
  2392.                 if (image->image_req)
  2393.                     IL_DestroyImage(image->image_req);
  2394.                 lo_FreeElement(context,    (LO_Element *)image, TRUE);
  2395.                 tag->lo_data = NULL;
  2396.             }
  2397.             return;
  2398.             break;
  2399.         case FORM_TYPE_TEXT:
  2400.         case FORM_TYPE_PASSWORD:
  2401.         case FORM_TYPE_FILE:
  2402.             {
  2403.                 LO_TextAttr tmp_attr;
  2404.                 LO_TextAttr *old_attr;
  2405.                 LO_TextAttr *attr;
  2406.  
  2407.                 old_attr = state->font_stack->text_attr;
  2408.                 lo_CopyTextAttr(old_attr, &tmp_attr);
  2409.                 tmp_attr.fontmask |= LO_FONT_FIXED;
  2410.                 attr = lo_FetchTextAttr(state, &tmp_attr);
  2411.  
  2412.                 lo_PushFont(state, tag->type, attr);
  2413.  
  2414.                 form_element = lo_form_input_text(context,
  2415.                     state, tag, type);
  2416.  
  2417.                 attr = lo_PopFont(state, tag->type);
  2418.             }
  2419.             break;
  2420.         case FORM_TYPE_SUBMIT:
  2421.         case FORM_TYPE_RESET:
  2422.         case FORM_TYPE_BUTTON:
  2423.         case FORM_TYPE_HIDDEN:
  2424.         case FORM_TYPE_READONLY:
  2425.             form_element = lo_form_input_minimal(context, state,
  2426.                 tag, type);
  2427.             break;
  2428.         case FORM_TYPE_RADIO:
  2429.         case FORM_TYPE_CHECKBOX:
  2430.             form_element = lo_form_input_toggle(context, state,
  2431.                 tag, type);
  2432.             break;
  2433.         case FORM_TYPE_OBJECT:
  2434.             form_element = lo_form_input_object(context, state,
  2435.                 tag, type);
  2436.             break;
  2437.         case FORM_TYPE_JOT:
  2438.         default:
  2439.             form_element = NULL;
  2440.             break;
  2441.     }
  2442.  
  2443.     if (form_element == NULL)
  2444.     {
  2445.         return;
  2446.     }
  2447.  
  2448.     if (type == FORM_TYPE_HIDDEN)
  2449.     {
  2450.         Bool status;
  2451.  
  2452.         status = lo_add_element_to_form_list(context, state,
  2453.             form_element);
  2454.     }
  2455.     else
  2456.     {
  2457.         if (type != FORM_TYPE_OBJECT) /* can't disable objects? */
  2458.           {
  2459.             form_element->element_data->ele_minimal.disabled = disabled;
  2460.           }
  2461.  
  2462.         lo_add_form_element(context, state, form_element);
  2463.     }
  2464.  
  2465. #ifdef MOCHA
  2466.     lo_ReflectFormElement(context, state, tag, form_element);
  2467. #endif
  2468. }
  2469.  
  2470.  
  2471. static PA_Block
  2472. lo_dup_block(PA_Block block)
  2473. {
  2474.     PA_Block new_block;
  2475.     char *str;
  2476.     char *str2;
  2477.  
  2478.     if (block != NULL)
  2479.     {
  2480.         PA_LOCK(str, char *, block);
  2481.         new_block = PA_ALLOC(XP_STRLEN(str) + 1);
  2482.         if (new_block != NULL)
  2483.         {
  2484.             PA_LOCK(str2, char *, new_block);
  2485.             XP_STRCPY(str2, str);
  2486.             PA_UNLOCK(new_block);
  2487.         }
  2488.         PA_UNLOCK(block);
  2489.     }
  2490.     else
  2491.     {
  2492.         new_block = NULL;
  2493.     }
  2494.  
  2495.     return(new_block);
  2496. }
  2497.  
  2498.  
  2499. /*
  2500.  * Returns true if the submit should be aborted (likely to be restarted
  2501.  * later), false otherwise.
  2502.  */
  2503. static PRBool
  2504. lo_get_form_element_data(MWContext *context,
  2505.         LO_FormElementStruct *submit_element, LO_Element *element,
  2506.         PA_Block *name_array, PA_Block *value_array, 
  2507.         uint8 *type_array, uint8 *encoding_array, int32 *array_cnt)
  2508. {
  2509.     LO_FormElementStruct *form_element;
  2510.     PA_Block name;
  2511.     PA_Block value;
  2512.     uint8 type;
  2513.     uint8 encoding;
  2514.  
  2515.     name = NULL;
  2516.     value = NULL;
  2517.     type = FORM_TYPE_NONE;
  2518.     encoding = INPUT_TYPE_ENCODING_NORMAL;
  2519.  
  2520.     if ((element == NULL)||(element->type != LO_FORM_ELE))
  2521.     {
  2522.         return PR_FALSE;
  2523.     }
  2524.  
  2525.     form_element = (LO_FormElementStruct *)element;
  2526.     if (form_element->element_data == NULL)
  2527.     {
  2528.         return PR_FALSE;
  2529.     }
  2530.  
  2531. #ifdef XP_WIN16
  2532.     if ((*array_cnt * sizeof(XP_Block)) >= SIZE_LIMIT)
  2533.     {
  2534.         return PR_FALSE;
  2535.     }
  2536. #endif /* XP_WIN16 */
  2537.  
  2538.     if ((form_element->element_data->type != FORM_TYPE_HIDDEN)&&
  2539.         (form_element->element_data->type != FORM_TYPE_KEYGEN)&&
  2540.         (form_element->element_data->type != FORM_TYPE_SUBMIT)&&
  2541.         (form_element->element_data->type != FORM_TYPE_RESET)&&
  2542.         (form_element->element_data->type != FORM_TYPE_READONLY)&&
  2543.         (form_element->element_data->type != FORM_TYPE_BUTTON) &&
  2544.         (form_element->element_data->type != FORM_TYPE_OBJECT))
  2545.     {
  2546.         FE_GetFormElementValue(context, form_element, FALSE);
  2547.     }
  2548.  
  2549.     switch (form_element->element_data->type)
  2550.     {
  2551.         case FORM_TYPE_TEXT:
  2552.         case FORM_TYPE_PASSWORD:
  2553.         case FORM_TYPE_FILE:
  2554.             {
  2555.             lo_FormElementTextData *form_data;
  2556.  
  2557.             form_data = (lo_FormElementTextData *)
  2558.                 form_element->element_data;
  2559.  
  2560. #if DISABLED_READONLY_SUPPORT
  2561.             if (form_data->disabled == TRUE)
  2562.               /* if a form element is disabled, it's name/value pair isn't sent
  2563.                  to the server. */
  2564.               break;
  2565. #endif
  2566.  
  2567.             if (form_data->name != NULL)
  2568.             {
  2569.                 name = lo_dup_block(form_data->name);
  2570.                 value = lo_dup_block(form_data->current_text);
  2571.                 type = (uint8)form_data->type;
  2572.                 encoding = (uint8)form_data->encoding;
  2573.             }
  2574.             }
  2575.             break;
  2576.         case FORM_TYPE_TEXTAREA:
  2577.             {
  2578.             lo_FormElementTextareaData *form_data;
  2579.  
  2580.             form_data = (lo_FormElementTextareaData *)
  2581.                 form_element->element_data;
  2582.  
  2583. #if DISABLED_READONLY_SUPPORT
  2584.             if (form_data->disabled == TRUE)
  2585.               /* if a form element is disabled, it's name/value pair isn't sent
  2586.                  to the server. */
  2587.               break;
  2588. #endif
  2589.  
  2590.             if (form_data->name != NULL)
  2591.             {
  2592.                 name = lo_dup_block(form_data->name);
  2593.                 value = lo_FEToNetLinebreaks(
  2594.                         form_data->current_text);
  2595.                 type = (uint8)form_data->type;
  2596.             }
  2597.             }
  2598.             break;
  2599.         /*
  2600.          * Only submit the name/value for the submit button
  2601.          * pressed.
  2602.          */
  2603.         case FORM_TYPE_SUBMIT:
  2604.         case FORM_TYPE_RESET:
  2605.         case FORM_TYPE_BUTTON:
  2606.             if (form_element == submit_element)
  2607.             {
  2608.             lo_FormElementMinimalData *form_data;
  2609.             form_data = (lo_FormElementMinimalData *)
  2610.                 form_element->element_data;
  2611.  
  2612. #if DISABLED_READONLY_SUPPORT
  2613.             if (form_data->disabled == TRUE)
  2614.               /* if a form element is disabled, it's name/value pair isn't sent
  2615.                  to the server. */
  2616.               break;
  2617. #endif
  2618.  
  2619.             if (form_data->name != NULL)
  2620.             {
  2621.                 name = lo_dup_block(form_data->name);
  2622.                 value = lo_dup_block(form_data->value);
  2623.                 type = (uint8)form_data->type;
  2624.             }
  2625.             }
  2626.             break;
  2627.         case FORM_TYPE_HIDDEN:
  2628.         case FORM_TYPE_READONLY:
  2629.             {
  2630.             lo_FormElementMinimalData *form_data;
  2631.             form_data = (lo_FormElementMinimalData *)
  2632.                 form_element->element_data;
  2633.  
  2634. #if DISABLED_READONLY_SUPPORT
  2635.             if (form_data->disabled == TRUE)
  2636.               /* if a form element is disabled, it's name/value pair isn't sent
  2637.                  to the server. */
  2638.               break;
  2639. #endif
  2640.  
  2641.             if (form_data->name != NULL)
  2642.             {
  2643.                 name = lo_dup_block(form_data->name);
  2644.                 value = lo_dup_block(form_data->value);
  2645.                 type = (uint8)form_data->type;
  2646.             }
  2647.             }
  2648.             break;
  2649.         case FORM_TYPE_RADIO:
  2650.         case FORM_TYPE_CHECKBOX:
  2651.             {
  2652.             lo_FormElementToggleData *form_data;
  2653.             form_data = (lo_FormElementToggleData *)
  2654.                 form_element->element_data;
  2655.  
  2656. #if DISABLED_READONLY_SUPPORT
  2657.             if (form_data->disabled == TRUE)
  2658.               /* if a form element is disabled, it's name/value pair isn't sent
  2659.                  to the server. */
  2660.               break;
  2661. #endif
  2662.  
  2663.             if ((form_data->toggled != FALSE)&&
  2664.                 (form_data->name != NULL))
  2665.             {
  2666.                 name = lo_dup_block(form_data->name);
  2667.                 value = lo_dup_block(form_data->value);
  2668.                 type = (uint8)form_data->type;
  2669.             }
  2670.             }
  2671.             break;
  2672.         case FORM_TYPE_SELECT_ONE:
  2673.         case FORM_TYPE_SELECT_MULT:
  2674.             {
  2675.             int i;
  2676.             lo_FormElementSelectData *form_data;
  2677.             lo_FormElementOptionData *options;
  2678.             form_data = (lo_FormElementSelectData *)
  2679.                 form_element->element_data;
  2680.  
  2681. #if DISABLED_READONLY_SUPPORT
  2682.             if (form_data->disabled == TRUE)
  2683.               /* if a form element is disabled, it's name/value pair isn't sent
  2684.                  to the server. */
  2685.               break;
  2686. #endif
  2687.  
  2688.             if ((form_data->name != NULL)&&
  2689.                 (form_data->option_cnt > 0))
  2690.             {
  2691.                 PA_LOCK(options, lo_FormElementOptionData *,
  2692.                 form_data->options);
  2693.                 for (i=0; i < form_data->option_cnt; i++)
  2694.                 {
  2695.                 if (options[i].selected == FALSE)
  2696.                 {
  2697.                     continue;
  2698.                 }
  2699.                 name = lo_dup_block(form_data->name);
  2700.                 if (options[i].value == NULL)
  2701.                 {
  2702.                     value = lo_dup_block(options[i].text_value);
  2703.                 }
  2704.                 else
  2705.                 {
  2706.                     value = lo_dup_block(options[i].value);
  2707.                 }
  2708.                 type = (uint8)form_data->type;
  2709.                 if (form_element->element_data->type ==
  2710.                     FORM_TYPE_SELECT_ONE)
  2711.                 {
  2712.                     break;
  2713.                 }
  2714.                 name_array[*array_cnt] = name;
  2715.                 value_array[*array_cnt] = value;
  2716.                 encoding_array[*array_cnt] = encoding;
  2717.                 type_array[*array_cnt] = type;
  2718.                 *array_cnt = *array_cnt + 1;
  2719. #ifdef XP_WIN16
  2720.                 if ((*array_cnt * sizeof(XP_Block)) >=
  2721.                     SIZE_LIMIT)
  2722.                 {
  2723.                     PA_UNLOCK(form_data->options);
  2724.                     return;
  2725.                 }
  2726. #endif /* XP_WIN16 */
  2727.                 }
  2728.                 PA_UNLOCK(form_data->options);
  2729.                 if (form_element->element_data->type ==
  2730.                 FORM_TYPE_SELECT_MULT)
  2731.                 {
  2732.                 return PR_FALSE;
  2733.                 }
  2734.             }
  2735.             }
  2736.             break;
  2737.         case FORM_TYPE_KEYGEN:
  2738.             {
  2739.             lo_FormElementKeygenData *form_data;
  2740.             char *cstr;    /* challenge */
  2741.             char *nstr;    /* name */
  2742.             char *tstr;    /* temp */
  2743.             char *vstr;    /* value */
  2744.             char *kstr; /* key type */
  2745.             char *pstr; /* pqg */
  2746.  
  2747.             /*
  2748.              * A KEYGEN element means that the previous
  2749.              * name/value pair should be diverted to
  2750.              * key-generation.
  2751.              */
  2752.  
  2753.             form_data = (lo_FormElementKeygenData *)
  2754.                 form_element->element_data;
  2755.             if (form_data->name == NULL)
  2756.             {
  2757.                 break;
  2758.             }
  2759.  
  2760.             /*
  2761.              * Check that our name matches the previous name;
  2762.              * this is just a sanity check.
  2763.              */
  2764.             if (*array_cnt < 1)
  2765.             {
  2766.                 /* no previous element at all */
  2767.                 break;
  2768.             }
  2769.             PA_LOCK(tstr, char *, form_data->name);
  2770.             PA_LOCK(nstr, char *, name_array[*array_cnt - 1]);
  2771.             if (XP_STRCMP(nstr, tstr) == 0)
  2772.             {
  2773.                 value = value_array[*array_cnt - 1];
  2774.             }
  2775.             PA_UNLOCK(name_array[*array_cnt - 1]);
  2776.             PA_UNLOCK(form_data->name);
  2777.  
  2778.             if (value == NULL)
  2779.             {
  2780.                 /* name did not match; punt */
  2781.                 break;
  2782.             }
  2783.  
  2784.             if (form_data->dialog_done == PR_FALSE)
  2785.             {
  2786.                 PRBool wait;
  2787.  
  2788.                 /*
  2789.                  * If value_str is not null, then we have an
  2790.                  * old string there which we should free
  2791.                  * before replacing.
  2792.                  * XXX This does not seem like quite the
  2793.                  * right location for this, but neither
  2794.                  * does any place else I can think of.
  2795.                  */
  2796.                 if (form_data->value_str != NULL)
  2797.                 {
  2798.                     XP_FREE(form_data->value_str);
  2799.                     form_data->value_str = NULL;
  2800.                 }
  2801.  
  2802.                 /*
  2803.                  * The value of the previous element is
  2804.                  * the key-size string.
  2805.                  */
  2806.                 PA_LOCK(vstr, char *, value);
  2807.                 PA_LOCK(cstr, char *, form_data->challenge);
  2808.                 PA_LOCK(kstr, char *, form_data->key_type);
  2809.                 PA_LOCK(pstr, char *, form_data->pqg);
  2810.                 wait = SECNAV_GenKeyFromChoice(context,
  2811.                         (LO_Element *)submit_element,
  2812.                         vstr, cstr, kstr, pstr,
  2813.                         &form_data->value_str,
  2814.                         &form_data->dialog_done);
  2815.                 PA_UNLOCK(form_data->pqg);
  2816.                 PA_UNLOCK(form_data->key_type);
  2817.                 PA_UNLOCK(form_data->challenge);
  2818.                 PA_UNLOCK(value);
  2819.  
  2820.                 /*
  2821.                  * We may have put up a dialog and be waiting
  2822.                  * now for the user to interact with it; if so,
  2823.                  * just return and the dialog code will call
  2824.                  * back later to really do the submit.
  2825.                  */
  2826.                 if (wait != PR_FALSE)
  2827.                 {
  2828.                     return PR_TRUE;
  2829.                 }
  2830.             }
  2831.  
  2832.             /*
  2833.              * "erase" the previous entry, hanging onto the
  2834.              * name which is already a good duplicate to use
  2835.              */
  2836.             name = name_array[*array_cnt - 1];
  2837.             PA_FREE(value);
  2838.             value = NULL;
  2839.             *array_cnt = *array_cnt - 1;
  2840.  
  2841.             if (form_data->value_str == NULL)
  2842.             {
  2843.                 /* something went wrong */
  2844.                 break;
  2845.             }
  2846.  
  2847.             /*
  2848.              * The real value, finally...
  2849.              */
  2850.             value = PA_ALLOC(XP_STRLEN(form_data->value_str) + 1);
  2851.             if (value != NULL)
  2852.             {
  2853.                 PA_LOCK(vstr, char *, value);
  2854.                 XP_STRCPY(vstr, form_data->value_str);
  2855.                 PA_UNLOCK(value);
  2856.             }
  2857.             type = (uint8)form_data->type;
  2858.             }
  2859.             break;
  2860. #ifdef JAVA
  2861.         case FORM_TYPE_OBJECT:
  2862.             {
  2863.             lo_FormElementObjectData *form_data;
  2864.             form_data = (lo_FormElementObjectData *)
  2865.                 form_element->element_data;
  2866.             if (form_data->name != NULL)
  2867.             {
  2868.                 char *object_value;
  2869.                 char *vstr;
  2870.  
  2871.                 name = lo_dup_block(form_data->name);
  2872.  
  2873.                 object_value = LJ_Applet_GetText(form_data->object->session_data);
  2874.                 value = PA_ALLOC(XP_STRLEN(object_value) + 1);
  2875.                 if (value != NULL)
  2876.                 {
  2877.                     PA_LOCK(vstr, char *, value);
  2878.                     XP_STRCPY(vstr, object_value);
  2879.                     PA_UNLOCK(value);
  2880.                 }
  2881.                 XP_FREE(object_value);
  2882.  
  2883.                 type = (uint8)form_data->type;
  2884.             }
  2885.             }
  2886.             break;
  2887. #endif /* JAVA */
  2888.         case FORM_TYPE_JOT:
  2889.         default:
  2890.             break;
  2891.     }
  2892.  
  2893.     if (name != NULL)
  2894.     {
  2895.         name_array[*array_cnt] = name;
  2896.         value_array[*array_cnt] = value;
  2897.         type_array[*array_cnt] = type;
  2898.         encoding_array[*array_cnt] = encoding;
  2899.         *array_cnt = *array_cnt + 1;
  2900.     }
  2901.  
  2902.     return PR_FALSE;
  2903. }
  2904.  
  2905. static LO_FormSubmitData *
  2906. lo_GatherSubmitData(MWContext *context, lo_DocState *state,
  2907.         lo_FormData *form_list, LO_FormElementStruct *submit_element)
  2908. {
  2909.     intn i;
  2910.     LO_FormSubmitData *submit_data;
  2911.     PA_Block *name_array, *value_array;
  2912.     uint8 *type_array;
  2913.     uint8 *encoding_array;
  2914.     int32 array_size;
  2915.     LO_Element **ele_list;
  2916.     PRBool is_a_image;
  2917.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  2918.  
  2919.     is_a_image = (submit_element->type == LO_IMAGE) ? PR_TRUE : PR_FALSE;
  2920.  
  2921.     submit_data = XP_NEW_ZAP(LO_FormSubmitData);
  2922.     if (submit_data == NULL)
  2923.     {
  2924.         return(NULL);
  2925.     }
  2926.  
  2927.     if (form_list->action != NULL)
  2928.     {
  2929.         submit_data->action = lo_dup_block(form_list->action);
  2930.         if (submit_data->action == NULL)
  2931.         {
  2932.             LO_FreeSubmitData(submit_data);
  2933.             return(NULL);
  2934.         }
  2935.     }
  2936.     if (form_list->encoding != NULL)
  2937.     {
  2938.         submit_data->encoding = lo_dup_block(form_list->encoding);
  2939.         if (submit_data->encoding == NULL)
  2940.         {
  2941.             LO_FreeSubmitData(submit_data);
  2942.             return(NULL);
  2943.         }
  2944.     }
  2945.     if (form_list->window_target != NULL)
  2946.     {
  2947.         submit_data->window_target = lo_dup_block(form_list->window_target);
  2948.         if (submit_data->window_target == NULL)
  2949.         {
  2950.             LO_FreeSubmitData(submit_data);
  2951.             return(NULL);
  2952.         }
  2953.     }
  2954.     submit_data->method = form_list->method;
  2955.  
  2956.     array_size = form_list->form_ele_cnt;
  2957.     if (is_a_image)
  2958.     {
  2959.         array_size += 2;
  2960.     }
  2961.  
  2962.     if (array_size <= 0)
  2963.     {
  2964.         return(submit_data);
  2965.     }
  2966.  
  2967.     /*
  2968.      * Look through all the form elements for a select element of
  2969.      * type multiple, since that can have more than 1 name/value
  2970.      * pair per element.
  2971.      */
  2972.     PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  2973.     for (i=0; i<form_list->form_ele_cnt; i++)
  2974.     {
  2975.         LO_FormElementStruct *form_element;
  2976.         int32 ele_type;
  2977.  
  2978.         form_element = (LO_FormElementStruct *)ele_list[i];
  2979.         if ((form_element != NULL)&&
  2980.             (form_element->element_data != NULL))
  2981.         {
  2982.             ele_type = form_element->element_data->type;
  2983.             if (ele_type != FORM_TYPE_SELECT_MULT)
  2984.             {
  2985.                 continue;
  2986.             }
  2987.         }
  2988.         else
  2989.         {
  2990.             continue;
  2991.         }
  2992.  
  2993.         array_size += form_element->element_data->ele_select.option_cnt;
  2994.     }
  2995.     PA_UNLOCK(form_list->form_elements);
  2996.  
  2997. #ifdef XP_WIN16
  2998.     if ((array_size * sizeof(XP_Block)) > SIZE_LIMIT)
  2999.     {
  3000.         array_size = SIZE_LIMIT / sizeof(XP_Block);
  3001.     }
  3002. #endif /* XP_WIN16 */
  3003.  
  3004.     submit_data->name_array = PA_ALLOC(array_size * sizeof(PA_Block));
  3005.     submit_data->value_array = PA_ALLOC(array_size * sizeof(PA_Block));
  3006.     submit_data->type_array = PA_ALLOC(array_size * sizeof(uint8));
  3007.     submit_data->encoding_array = PA_ALLOC(array_size * sizeof(uint8));
  3008.  
  3009.     if ((submit_data->name_array == NULL)
  3010.         || (submit_data->value_array == NULL)
  3011.             || (submit_data->type_array == NULL)
  3012.                 || (submit_data->encoding_array == NULL))
  3013.     {
  3014.         return(submit_data);
  3015.     }
  3016.  
  3017.     PA_LOCK(name_array, PA_Block *, submit_data->name_array);
  3018.     PA_LOCK(value_array, PA_Block *, submit_data->value_array);
  3019.     PA_LOCK(type_array, uint8 *, submit_data->type_array);
  3020.     PA_LOCK(encoding_array, uint8 *, submit_data->encoding_array);
  3021.     PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  3022.     for (i=0; i<form_list->form_ele_cnt; i++)
  3023.     {
  3024.         PRBool wait;
  3025.  
  3026.         wait = lo_get_form_element_data(context,
  3027.                 submit_element, ele_list[i],
  3028.                 name_array, value_array, type_array, encoding_array,
  3029.                 &submit_data->value_cnt);
  3030.         if (wait != PR_FALSE)
  3031.         {
  3032.             /*
  3033.              * We now go to let the user interact with
  3034.              * the dialogs.  We will be back later!
  3035.              */
  3036.             LO_FreeSubmitData(submit_data);
  3037.             return(NULL);
  3038.         }
  3039.     }
  3040.  
  3041.     /* After all the form data is gathered, we need to convert from
  3042.      * the "native" front-end character code set to the one used
  3043.      * in the HTML form.  Convert each name/value pair.
  3044.      */
  3045.     {
  3046.     CCCDataObject    object;
  3047.     unsigned char    *s1, *s2;
  3048.     int16    doc_csid;
  3049.  
  3050.     object = INTL_CreateCharCodeConverter();
  3051.     if (object == NULL)
  3052.     {
  3053.         PA_UNLOCK(form_list->form_elements);
  3054.         PA_UNLOCK(submit_data->type_array);
  3055.         PA_UNLOCK(submit_data->value_array);
  3056.         PA_UNLOCK(submit_data->name_array);
  3057.         PA_UNLOCK(submit_data->encoding_array);
  3058.         return(submit_data);
  3059.     }
  3060.  
  3061.     doc_csid = INTL_GetCSIDocCSID(c);
  3062.     if (doc_csid == CS_DEFAULT)
  3063.         doc_csid = INTL_DefaultDocCharSetID(context);
  3064.     doc_csid &= (~CS_AUTO);
  3065.  
  3066.     if (INTL_GetCharCodeConverter(INTL_GetCSIWinCSID(c), doc_csid, object)) {
  3067.         for (i = 0; i < submit_data->value_cnt; i++) {
  3068.             s1 = (unsigned char *)name_array[i];
  3069.             s2 = INTL_CallCharCodeConverter(object, s1,
  3070.                 XP_STRLEN((char *)s1));
  3071.             if (s1 != s2) {        /* didn't convert in-place */
  3072.                 PA_FREE((PA_Block)s1);
  3073.                 name_array[i] = lo_dup_block((PA_Block)s2);
  3074.                 PA_FREE((PA_Block)s2);
  3075.             }
  3076.             if (value_array[i] != NULL)
  3077.             {
  3078.                 s1 = (unsigned char *)value_array[i];
  3079.                 s2 = INTL_CallCharCodeConverter(object, s1,
  3080.                     XP_STRLEN((char *)s1));
  3081.                 if (s1 != s2) {    /* didn't convert in-place */
  3082.                     PA_FREE((PA_Block)s1);
  3083.                     value_array[i] =
  3084.                         lo_dup_block((PA_Block)s2);
  3085.                     PA_FREE((PA_Block)s2);
  3086.                 }
  3087.             }
  3088.         }
  3089.     }
  3090.  
  3091.     INTL_DestroyCharCodeConverter(object);
  3092.     }
  3093.  
  3094.     PA_UNLOCK(form_list->form_elements);
  3095.     PA_UNLOCK(submit_data->type_array);
  3096.     PA_UNLOCK(submit_data->value_array);
  3097.     PA_UNLOCK(submit_data->name_array);
  3098.  
  3099.     if (is_a_image)
  3100.     {
  3101.         LO_ImageStruct *image;
  3102.         PA_Block buff;
  3103.         PA_Block name_buff;
  3104.         char val_str[20];
  3105.         char *str;
  3106.         char *name;
  3107.         intn name_len;
  3108.  
  3109.         name_buff = NULL; /* Make gcc and Jamie happy */
  3110.         image = (LO_ImageStruct *)submit_element;
  3111.         PA_LOCK(name_array, PA_Block *, submit_data->name_array);
  3112.         PA_LOCK(value_array, PA_Block *,submit_data->value_array);
  3113.         if (image->alt != NULL)
  3114.         {
  3115.             PA_LOCK(name, char *, image->alt);
  3116.         }
  3117.         else
  3118.         {
  3119.             name_buff = PA_ALLOC(1);
  3120.             if (name_buff == NULL)
  3121.             {
  3122.                 PA_UNLOCK(submit_data->value_array);
  3123.                 PA_UNLOCK(submit_data->name_array);
  3124.                 return(submit_data);
  3125.             }
  3126.             PA_LOCK(name, char *, name_buff);
  3127.             name[0] = '\0';
  3128.         }
  3129.         name_len = XP_STRLEN(name);
  3130.  
  3131.         buff = PA_ALLOC(name_len + 3);
  3132.         if (buff == NULL)
  3133.         {
  3134.             PA_UNLOCK(submit_data->value_array);
  3135.             PA_UNLOCK(submit_data->name_array);
  3136.             return(submit_data);
  3137.         }
  3138.         PA_LOCK(str, char *, buff);
  3139.         if (name_len > 0)
  3140.         {
  3141.             XP_STRCPY(str, name);
  3142.             XP_STRCAT(str, ".x");
  3143.         }
  3144.         else
  3145.         {
  3146.             XP_STRCPY(str, "x");
  3147.         }
  3148.         PA_UNLOCK(buff);
  3149.         name_array[submit_data->value_cnt] = buff;
  3150.  
  3151.         XP_SPRINTF(val_str, "%d", image->image_attr->submit_x);
  3152.         buff = PA_ALLOC(XP_STRLEN(val_str) + 1);
  3153.         if (buff == NULL)
  3154.         {
  3155.             PA_UNLOCK(submit_data->value_array);
  3156.             PA_UNLOCK(submit_data->name_array);
  3157.             return(submit_data);
  3158.         }
  3159.         PA_LOCK(str, char *, buff);
  3160.         XP_STRCPY(str, val_str);
  3161.         PA_UNLOCK(buff);
  3162.         value_array[submit_data->value_cnt] = buff;
  3163.  
  3164.         submit_data->value_cnt++;
  3165.  
  3166.         buff = PA_ALLOC(name_len + 3);
  3167.         if (buff == NULL)
  3168.         {
  3169.             PA_UNLOCK(submit_data->value_array);
  3170.             PA_UNLOCK(submit_data->name_array);
  3171.             return(submit_data);
  3172.         }
  3173.         PA_LOCK(str, char *, buff);
  3174.         if (name_len > 0)
  3175.         {
  3176.             XP_STRCPY(str, name);
  3177.             XP_STRCAT(str, ".y");
  3178.         }
  3179.         else
  3180.         {
  3181.             XP_STRCPY(str, "y");
  3182.         }
  3183.         PA_UNLOCK(buff);
  3184.         name_array[submit_data->value_cnt] = buff;
  3185.  
  3186.         XP_SPRINTF(val_str, "%d", image->image_attr->submit_y);
  3187.         buff = PA_ALLOC(XP_STRLEN(val_str) + 1);
  3188.         if (buff == NULL)
  3189.         {
  3190.             PA_UNLOCK(submit_data->value_array);
  3191.             PA_UNLOCK(submit_data->name_array);
  3192.             return(submit_data);
  3193.         }
  3194.         PA_LOCK(str, char *, buff);
  3195.         XP_STRCPY(str, val_str);
  3196.         PA_UNLOCK(buff);
  3197.         value_array[submit_data->value_cnt] = buff;
  3198.  
  3199.         submit_data->value_cnt++;
  3200.  
  3201.         if (image->alt != NULL)
  3202.         {
  3203.             PA_UNLOCK(image->alt);
  3204.         }
  3205.         else
  3206.         {
  3207.             PA_UNLOCK(name_buff);
  3208.             PA_FREE(name_buff);
  3209.         }
  3210.     }
  3211.  
  3212.     return(submit_data);
  3213. }
  3214.  
  3215.  
  3216. LO_FormSubmitData *
  3217. LO_SubmitForm(MWContext *context, LO_FormElementStruct *form_element)
  3218. {
  3219.     intn form_id;
  3220.     int32 doc_id;
  3221.     lo_TopState *top_state;
  3222.     lo_DocState *state;
  3223.     LO_FormSubmitData *submit_data;
  3224.     lo_FormData *form_list;
  3225.     lo_DocLists *doc_lists;
  3226.  
  3227.     /*
  3228.      * Get the unique document ID, and retrieve this
  3229.      * documents layout state.
  3230.      */
  3231.     doc_id = XP_DOCID(context);
  3232.     top_state = lo_FetchTopState(doc_id);
  3233.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3234.     {
  3235.         return(NULL);
  3236.     }
  3237.     state = top_state->doc_state;
  3238.  
  3239.     if (form_element->type == LO_IMAGE)
  3240.     {
  3241.         LO_ImageStruct *image;
  3242.  
  3243.         image = (LO_ImageStruct *)form_element;
  3244.         form_id = image->image_attr->form_id;
  3245.     }
  3246.     else
  3247.     {
  3248.         form_id = form_element->form_id;
  3249.     }
  3250.  
  3251.     doc_lists = lo_GetDocListsById(state, form_element->layer_id);
  3252.     form_list = doc_lists->form_list;
  3253.     while (form_list != NULL)
  3254.     {
  3255.         if (form_list->id == form_id)
  3256.         {
  3257.             break;
  3258.         }
  3259.         form_list = form_list->next;
  3260.     }
  3261.     if (form_list == NULL)
  3262.     {
  3263.         return(NULL);
  3264.     }
  3265.  
  3266.     submit_data = lo_GatherSubmitData(context, state, form_list,
  3267.                     form_element);
  3268.     if (submit_data == NULL)
  3269.     {
  3270.         return(NULL);
  3271.     }
  3272.  
  3273.     return(submit_data);
  3274. }
  3275.  
  3276.  
  3277. LO_FormSubmitData *
  3278. LO_SubmitImageForm(MWContext *context, LO_ImageStruct *image,
  3279.                 int32 x, int32 y)
  3280. {
  3281.     image->image_attr->submit_x = (intn)x;
  3282.     image->image_attr->submit_y = (intn)y;
  3283.  
  3284.     return LO_SubmitForm(context, (LO_FormElementStruct *)image);
  3285. }
  3286.  
  3287.  
  3288. static void
  3289. lo_save_form_element_data(MWContext *context, LO_Element *element,
  3290.     Bool discard_element)
  3291. {
  3292.     LO_FormElementStruct *form_element;
  3293.  
  3294.     if ((element == NULL)||(element->type != LO_FORM_ELE))
  3295.     {
  3296.         return;
  3297.     }
  3298.  
  3299.     form_element = (LO_FormElementStruct *)element;
  3300.     if (form_element->element_data == NULL)
  3301.     {
  3302.         return;
  3303.     }
  3304.  
  3305.     if ((form_element->element_data->type != FORM_TYPE_HIDDEN)&&
  3306.         (form_element->element_data->type != FORM_TYPE_KEYGEN))
  3307.     {
  3308.         FE_GetFormElementValue(context, form_element, discard_element);
  3309.     }
  3310. }
  3311.  
  3312. void
  3313. lo_SaveFormElementStateInFormList(MWContext *context, lo_FormData *form_list,
  3314.                                   Bool discard_element)
  3315. {
  3316.     intn i;
  3317.     LO_Element **ele_list;
  3318.  
  3319.     while (form_list != NULL)
  3320.     {
  3321.         PA_LOCK(ele_list, LO_Element **,
  3322.             form_list->form_elements);
  3323.         for (i=0; i<form_list->form_ele_cnt; i++)
  3324.         {
  3325.             lo_save_form_element_data(context, ele_list[i],
  3326.                 discard_element);
  3327.         }
  3328.         PA_UNLOCK(form_list->form_elements);
  3329.         form_list = form_list->next;
  3330.     }
  3331. }
  3332.  
  3333.  
  3334. void
  3335. lo_SaveFormElementState(MWContext *context, lo_DocState *state,
  3336.     Bool discard_element)
  3337. {
  3338.     int i;
  3339.     lo_FormData *form_list;
  3340.  
  3341.     for (i = 0; i <= state->top_state->max_layer_num; i++) {
  3342.         lo_LayerDocState *layer_state = state->top_state->layers[i];
  3343.         if (!layer_state)
  3344.             continue;
  3345.         form_list = layer_state->doc_lists->form_list;
  3346.         lo_SaveFormElementStateInFormList(context, 
  3347.                                           form_list, 
  3348.                                           discard_element);
  3349.     }
  3350.     state->top_state->savedData.FormList->valid = TRUE;
  3351. }
  3352.  
  3353.  
  3354. #ifdef XP_MAC
  3355. PRIVATE
  3356. #endif
  3357. void
  3358. lo_RedoHistoryForms(MWContext *context)
  3359. {
  3360.     XP_List *list_ptr;
  3361.     History_entry *entry;
  3362.  
  3363.     list_ptr = SHIST_GetList(context);
  3364.     while ((entry = (History_entry *)XP_ListNextObject(list_ptr))!=0)
  3365.     {
  3366.         if (entry->savedData.FormList != NULL)
  3367.         {
  3368.             int32 i;
  3369.             lo_SavedFormListData *fptr;
  3370.             LO_FormElementData **data_list;
  3371.  
  3372.             fptr = (lo_SavedFormListData *) entry->savedData.FormList;
  3373.             PA_LOCK(data_list, LO_FormElementData **, fptr->data_list);
  3374.             if (data_list != NULL)
  3375.             {
  3376.                 for (i=0; i < (fptr->data_count); i++)
  3377.                 {
  3378.                 if (data_list[i] != NULL)
  3379.                 {
  3380.                     FE_FreeFormElement(context,
  3381.                         (LO_FormElementData *)data_list[i]);
  3382.                 }
  3383.                 }
  3384.             }
  3385.             PA_UNLOCK(fptr->data_list);
  3386.         }
  3387.     }
  3388. }
  3389.  
  3390.  
  3391. #ifdef XP_MAC
  3392. PRIVATE
  3393. #endif
  3394. void
  3395. lo_redo_form_elements_in_form_list(MWContext *context, lo_FormData *form_list)
  3396. {
  3397.     intn i;
  3398.     LO_Element **ele_list;
  3399.  
  3400.     while (form_list != NULL)
  3401.     {
  3402.         LO_FormElementStruct *form_ele;
  3403.  
  3404.         PA_LOCK(ele_list, LO_Element **,
  3405.             form_list->form_elements);
  3406.         for (i=0; i<form_list->form_ele_cnt; i++)
  3407.         {
  3408.             form_ele = (LO_FormElementStruct *)(ele_list[i]);
  3409.             if (form_ele != NULL)
  3410.             {
  3411.                 if (form_ele->element_data != NULL)
  3412.                 {
  3413. #ifdef OLD_WAY
  3414.                     FE_FreeFormElement(context,
  3415.                         form_ele->element_data);
  3416. #else
  3417.                     FE_GetFormElementValue(context,
  3418.                         form_ele, TRUE);
  3419. #endif
  3420.                 }
  3421.                 FE_GetFormElementInfo(context, form_ele);
  3422.             }
  3423.         }
  3424.         PA_UNLOCK(form_list->form_elements);
  3425.         form_list = form_list->next;
  3426.     }
  3427. }
  3428.  
  3429. void
  3430. LO_RedoFormElements(MWContext *context)
  3431. {
  3432.     int32 doc_id, i;
  3433.     lo_TopState *top_state;
  3434.     lo_DocState *state;
  3435.     lo_FormData *form_list;
  3436.  
  3437. #ifdef OLD_WAY
  3438.     lo_RedoHistoryForms(context);
  3439. #endif
  3440.  
  3441.     /*
  3442.      * Get the unique document ID, and retreive this
  3443.      * documents layout state.
  3444.      */
  3445.     doc_id = XP_DOCID(context);
  3446.     top_state = lo_FetchTopState(doc_id);
  3447.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3448.     {
  3449.         return;
  3450.     }
  3451.     state = top_state->doc_state;
  3452.  
  3453.     for (i = 0; i <= state->top_state->max_layer_num; i++) {
  3454.         lo_LayerDocState *layer_state = state->top_state->layers[i];
  3455.         if (!layer_state)
  3456.             continue;
  3457.         form_list = layer_state->doc_lists->form_list;
  3458.         lo_redo_form_elements_in_form_list(context, form_list);
  3459.     }
  3460. }
  3461.  
  3462. #ifdef XP_MAC
  3463. PRIVATE
  3464. #endif
  3465. void
  3466. form_reset_closure(MWContext * context, LO_Element * ele, int32 event, 
  3467.            void *obj, ETEventStatus status)
  3468. {
  3469.     intn i;
  3470.     LO_Element **ele_list;
  3471.     lo_FormData *form_list = (lo_FormData *) obj;
  3472.  
  3473.         if (status != EVENT_OK)
  3474.         return;
  3475.  
  3476.     PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  3477.     for (i=0; i<form_list->form_ele_cnt; i++)
  3478.     {
  3479.         LO_FormElementStruct *form_ele;
  3480.  
  3481.         form_ele = (LO_FormElementStruct *)ele_list[i];
  3482.         if (form_ele->element_data == NULL)
  3483.         {
  3484.             continue;
  3485.         }
  3486.  
  3487.         if ((form_ele->element_data->type != FORM_TYPE_HIDDEN)&&
  3488.             (form_ele->element_data->type != FORM_TYPE_KEYGEN)&&
  3489.             (form_ele->element_data->type != FORM_TYPE_SUBMIT)&&
  3490.             (form_ele->element_data->type != FORM_TYPE_RESET)&&
  3491.             (form_ele->element_data->type != FORM_TYPE_READONLY)&&
  3492.             (form_ele->element_data->type != FORM_TYPE_BUTTON))
  3493.         {
  3494.             FE_ResetFormElement(context, form_ele);
  3495.         }
  3496.     }
  3497.     PA_UNLOCK(form_list->form_elements);
  3498. }
  3499.  
  3500. void
  3501. LO_ResetForm(MWContext *context, LO_FormElementStruct *form_element)
  3502. {
  3503.     intn form_id;
  3504.     int32 doc_id;
  3505.     lo_TopState *top_state;
  3506.     lo_DocState *state;
  3507.     lo_FormData *form_list;
  3508.     JSEvent *event;
  3509.     lo_DocLists *doc_lists;
  3510.  
  3511.     /*
  3512.      * Get the unique document ID, and retreive this
  3513.      * documents layout state.
  3514.      */
  3515.     doc_id = XP_DOCID(context);
  3516.     top_state = lo_FetchTopState(doc_id);
  3517.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3518.     {
  3519.         return;
  3520.     }
  3521.     state = top_state->doc_state;
  3522.  
  3523.     form_id = form_element->form_id;
  3524.     
  3525.     doc_lists = lo_GetDocListsById(state, form_element->layer_id);
  3526.     form_list = doc_lists->form_list;
  3527.     while (form_list != NULL)
  3528.     {
  3529.         if (form_list->id == form_id)
  3530.         {
  3531.             break;
  3532.         }
  3533.         form_list = form_list->next;
  3534.     }
  3535.     if (form_list == NULL)
  3536.     {
  3537.         return;
  3538.     }
  3539.  
  3540.     if (form_list->form_ele_cnt <= 0)
  3541.     {
  3542.         return;
  3543.     }
  3544.  
  3545.     /* all further processing will be done by our closure */
  3546.     event = XP_NEW_ZAP(JSEvent);
  3547.     event->type = EVENT_RESET;
  3548.     event->layer_id = form_element->layer_id;
  3549.  
  3550.     ET_SendEvent(context, (LO_Element *) form_element, event, 
  3551.              form_reset_closure, form_list);
  3552.  
  3553. }
  3554.  
  3555.  
  3556.  
  3557. LO_FormElementStruct *
  3558. LO_FormRadioSet(MWContext *context, LO_FormElementStruct *form_element)
  3559. {
  3560.     intn i, form_id;
  3561.     int32 doc_id;
  3562.     lo_TopState *top_state;
  3563.     lo_DocState *state;
  3564.     lo_FormData *form_list;
  3565.     LO_Element **ele_list;
  3566.     lo_FormElementToggleData *form_data1;
  3567.     char *name1;
  3568.     char *name2;
  3569.     LO_FormElementStruct *prev_ele;
  3570.     lo_DocLists *doc_lists;
  3571.  
  3572.     /*
  3573.      * Get the unique document ID, and retrieve this
  3574.      * documents layout state.
  3575.      */
  3576.     doc_id = XP_DOCID(context);
  3577.     top_state = lo_FetchTopState(doc_id);
  3578.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3579.     {
  3580.         return NULL;
  3581.     }
  3582.     state = top_state->doc_state;
  3583.  
  3584.     if (form_element->element_data == NULL)
  3585.     {
  3586.         return NULL;
  3587.     }
  3588.  
  3589.     if (form_element->element_data->type != FORM_TYPE_RADIO)
  3590.     {
  3591.         return NULL;
  3592.     }
  3593.  
  3594.     form_data1 = (lo_FormElementToggleData *)form_element->element_data;
  3595.     if (form_data1->name == NULL)
  3596.     {
  3597.         return NULL;
  3598.     }
  3599.     form_data1->toggled = TRUE;
  3600.     prev_ele = form_element;
  3601.  
  3602.     form_id = form_element->form_id;
  3603.  
  3604.     doc_lists = lo_GetDocListsById(state, form_element->layer_id);
  3605.     form_list = doc_lists->form_list;
  3606.     while (form_list != NULL)
  3607.     {
  3608.         if (form_list->id == form_id)
  3609.         {
  3610.             break;
  3611.         }
  3612.         form_list = form_list->next;
  3613.     }
  3614.     if (form_list == NULL)
  3615.     {
  3616.         return prev_ele;
  3617.     }
  3618.  
  3619.     PA_LOCK(name1, char *, form_data1->name);
  3620.     PA_LOCK(ele_list, LO_Element **, form_list->form_elements);
  3621.     for (i=0; i<form_list->form_ele_cnt; i++)
  3622.     {
  3623.         LO_FormElementStruct *form_ele;
  3624.         lo_FormElementToggleData *form_data2;
  3625.  
  3626.         form_ele = (LO_FormElementStruct *)ele_list[i];
  3627.         if (form_ele->element_data == NULL)
  3628.         {
  3629.             continue;
  3630.         }
  3631.  
  3632.         if (form_ele->element_data->type != FORM_TYPE_RADIO)
  3633.         {
  3634.             continue;
  3635.         }
  3636.  
  3637.         if (form_ele == form_element)
  3638.         {
  3639.             continue;
  3640.         }
  3641.  
  3642.         form_data2 = (lo_FormElementToggleData *)form_ele->element_data;
  3643.  
  3644.         if (form_data2->name == NULL)
  3645.         {
  3646.             continue;
  3647.         }
  3648.  
  3649.         PA_LOCK(name2, char *, form_data2->name);
  3650.         if (XP_STRCMP(name1, name2) != 0)
  3651.         {
  3652.             PA_UNLOCK(form_data2->name);
  3653.             continue;
  3654.         }
  3655.         PA_UNLOCK(form_data2->name);
  3656.  
  3657.         if (form_data2->toggled != FALSE)
  3658.         {
  3659.             prev_ele = form_ele;
  3660.         }
  3661.         form_data2->toggled = FALSE;
  3662.         FE_SetFormElementToggle(context, form_ele, FALSE);
  3663.     }
  3664.     PA_UNLOCK(form_list->form_elements);
  3665.     PA_UNLOCK(form_data1->name);
  3666.  
  3667.     return prev_ele;
  3668. }
  3669.  
  3670.  
  3671. void
  3672. lo_ProcessIsIndexTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  3673. {
  3674.     PA_Tag tmp_tag;
  3675.     PA_Block buff;
  3676.     char *str;
  3677.  
  3678.     lo_SetSoftLineBreakState(context, state, FALSE, 1);
  3679.     /* passing tag to form gets ACTION */
  3680.     lo_BeginForm(context, state, tag);
  3681.     /* passing NULL tag to hrule gives default */
  3682.     lo_HorizontalRule(context, state, NULL);
  3683.     lo_SoftLineBreak(context, state, FALSE);
  3684.  
  3685.     buff = lo_FetchParamValue(context, tag, PARAM_PROMPT);
  3686.     if (buff != NULL)
  3687.     {
  3688.         PA_LOCK(str, char *, buff);
  3689.     }
  3690.     else
  3691.     {
  3692.         buff = PA_ALLOC(XP_STRLEN(DEF_ISINDEX_PROMPT) + 1);
  3693.         if (buff == NULL)
  3694.         {
  3695.             state->top_state->out_of_memory = TRUE;
  3696.             return;
  3697.         }
  3698.         PA_LOCK(str, char *, buff);
  3699.         XP_STRCPY(str, DEF_ISINDEX_PROMPT);
  3700.     }
  3701.  
  3702.     state->cur_ele_type = LO_NONE;
  3703.     lo_FreshText(state);
  3704.     state->cur_ele_type = LO_TEXT;
  3705.     if (state->preformatted != PRE_TEXT_NO)
  3706.     {
  3707.         lo_PreformatedText(context, state, str);
  3708.     }
  3709.     else
  3710.     {
  3711.         lo_FormatText(context, state, str);
  3712.     }
  3713.     PA_UNLOCK(buff);
  3714.     PA_FREE(buff);
  3715.     lo_FlushLineBuffer(context, state);
  3716.  
  3717.     buff = PA_ALLOC(XP_STRLEN(ISINDEX_TAG_TEXT) + 1);
  3718.     if (buff == NULL)
  3719.     {
  3720.         state->top_state->out_of_memory = TRUE;
  3721.         return;
  3722.     }
  3723.     PA_LOCK(str, char *, buff);
  3724.     XP_STRCPY(str, ISINDEX_TAG_TEXT);
  3725.     PA_UNLOCK(buff);
  3726.  
  3727.     tmp_tag.type = P_INPUT;
  3728.     tmp_tag.is_end = FALSE;
  3729.     tmp_tag.newline_count = tag->newline_count;
  3730.     tmp_tag.data = buff;
  3731.     tmp_tag.data_len = XP_STRLEN(ISINDEX_TAG_TEXT);
  3732.     tmp_tag.true_len = 0;
  3733.     tmp_tag.lo_data = NULL;
  3734.     tmp_tag.next = NULL;
  3735.     lo_ProcessInputTag(context, state, &tmp_tag);
  3736.     PA_FREE(buff);
  3737.  
  3738.     lo_SetSoftLineBreakState(context, state, FALSE, 1);
  3739.     /* passing NULL tag to hrule gives default */
  3740.     lo_HorizontalRule(context, state, NULL);
  3741.     lo_SoftLineBreak(context, state, FALSE);
  3742.     lo_EndForm(context, state);
  3743. }
  3744.  
  3745.  
  3746. void
  3747. lo_ProcessKeygenTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  3748. {
  3749.     LO_FormElementStruct *fe;
  3750.     lo_FormElementKeygenData *keygen_data;
  3751.     lo_FormElementSelectData *select_data;
  3752.     PA_Tag ttag;
  3753.     PA_Block buff;
  3754.     char **keylist;
  3755.     Bool status;
  3756.     intn len;
  3757.     char *str;
  3758.     char *kstr;
  3759.     char *pstr;
  3760.  
  3761.     /*
  3762.      * To produce what we want, we first create a SELECT element
  3763.      * that allows the user to select the key size, then we
  3764.      * add a dummy/hidden element which is a marker that the
  3765.      * *previous* element is the key information.  At the time
  3766.      * of the submit, this will cause the option data to get
  3767.      * figured out first, and then the KEYGEN element is our
  3768.      * cue to take that an pass it to the security library for
  3769.      * processing.
  3770.      */
  3771.  
  3772.     /*
  3773.      * A fake/empty tag for use during the creation of the selection
  3774.      * choices.
  3775.      */
  3776.     ttag.is_end = FALSE;
  3777.     ttag.newline_count = tag->newline_count;
  3778.     ttag.data = NULL;
  3779.     ttag.data_len = 0;
  3780.     ttag.true_len = 0;
  3781.     ttag.lo_data = NULL;
  3782.     ttag.next = NULL;
  3783.  
  3784.     /*
  3785.      * Create a SELECT element whose options are the available key sizes.
  3786.      * This will get displayed so the user can choose the key size, but
  3787.      * it will get turned into a key generation on submit.
  3788.      */
  3789.     ttag.type = P_SELECT;
  3790.     lo_BeginSelectTag(context, state, &ttag);
  3791.  
  3792.     /*
  3793.      * Hang onto the select element so we can copy the KEYGEN
  3794.      * element name into it (see below).
  3795.      */
  3796.     fe = (LO_FormElementStruct *)state->current_ele;
  3797.     select_data = (lo_FormElementSelectData *)fe->element_data;
  3798.  
  3799.     /*
  3800.      * XXX Get any necessary attributes out of "tag" for limiting or
  3801.      * advising the SEC function list of choices.  (Or just pass the
  3802.      * "tag" to SECNAV_GetKeyChoiceList?)  We could also use the
  3803.      * attributes to describe whether the choices should be listed
  3804.      * as select/options or as radio buttons or if there is only one
  3805.      * choice then we don't show anything at all, etc.
  3806.      */
  3807.     kstr = (char *)lo_FetchParamValue(context, tag, PARAM_KEYTYPE);
  3808.     pstr = (char *)lo_FetchParamValue(context, tag, PARAM_PQG);
  3809.     keylist = SECNAV_GetKeyChoiceList(kstr, pstr);
  3810.  
  3811.     ttag.type = P_OPTION;
  3812.     while (*keylist != NULL)
  3813.     {
  3814.         str = *keylist;
  3815.         len = XP_STRLEN(str);
  3816.         buff = PA_ALLOC(len + 1);
  3817.         if (buff != NULL)
  3818.         {
  3819.             char *tptr;
  3820.  
  3821.             PA_LOCK(tptr, char *, buff);
  3822.             XP_BCOPY(str, tptr, len);
  3823.             tptr[len] = '\0';
  3824.             PA_UNLOCK(buff);
  3825.         }
  3826.         lo_BeginOptionTag(context, state, &ttag);
  3827.         lo_EndOptionTag(context, state, buff);
  3828.  
  3829.         keylist++;
  3830.     }
  3831.  
  3832.     lo_EndSelectTag(context, state);
  3833.  
  3834.     /*
  3835.      * Now create and add an INPUT element of type KEYGEN.
  3836.      * This is actually a hidden element which is a marker that the
  3837.      * previous element is the key information selection field.
  3838.      */
  3839.     fe = lo_form_keygen(context, state, tag);
  3840.     if (fe != NULL)
  3841.     {
  3842.         status = lo_add_element_to_form_list(context, state, fe);
  3843.         if (status == FALSE)
  3844.             return;
  3845.     }
  3846.  
  3847.     keygen_data = (lo_FormElementKeygenData *)fe->element_data;
  3848.     select_data->name = lo_dup_block(keygen_data->name);
  3849. }
  3850.  
  3851.  
  3852. void
  3853. LO_SaveFormData(MWContext *context)
  3854. {
  3855.     int32 doc_id;
  3856.     lo_TopState *top_state;
  3857.     lo_DocState *state;
  3858.  
  3859.     /*
  3860.      * Get the unique document ID, and retrieve this
  3861.      * documents layout state.
  3862.      */
  3863.     doc_id = XP_DOCID(context);
  3864.     top_state = lo_FetchTopState(doc_id);
  3865.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3866.     {
  3867.         return;
  3868.     }
  3869.     state = top_state->doc_state;
  3870.  
  3871.     lo_SaveFormElementState(context, state, FALSE);
  3872. }
  3873.  
  3874. #define PA_ALLOC_FAILED(copy,old) (((copy) == NULL)&&((old) != NULL))
  3875.  
  3876. /*
  3877.  * Form element select data options is an array of lo_FormElementOptionData
  3878.  * structures. Makes a deep copy of the array
  3879.  */
  3880. static PA_Block
  3881. lo_copy_select_options(int32 option_cnt, PA_Block options)
  3882. {
  3883.     int i;
  3884.     PA_Block new_options;
  3885.     lo_FormElementOptionData *option_data, *new_option_data;
  3886.  
  3887.     if ((option_cnt <= 0)||(options == NULL))
  3888.     {
  3889.         return(NULL);
  3890.     }
  3891.  
  3892.     /*
  3893.      * Allocate an array of lo_FormElementOptionData
  3894.      */
  3895.     new_options = PA_ALLOC(option_cnt * sizeof(lo_FormElementOptionData));
  3896.  
  3897.     if (new_options == NULL)
  3898.     {
  3899.         return(NULL);
  3900.     }
  3901.  
  3902.     PA_LOCK(option_data, lo_FormElementOptionData *, options);
  3903.     PA_LOCK(new_option_data, lo_FormElementOptionData *, new_options);
  3904.  
  3905.     XP_MEMCPY(new_option_data, option_data,
  3906.         option_cnt * sizeof(lo_FormElementOptionData));
  3907.  
  3908.     /*
  3909.      * Some of the members also need to be copied
  3910.      */
  3911.     for (i=0; i < option_cnt; i++)
  3912.     {
  3913.         if (option_data[i].text_value != NULL)
  3914.         {
  3915.             new_option_data[i].text_value = lo_dup_block(
  3916.                 option_data[i].text_value);
  3917.             new_option_data[i].value = lo_dup_block(option_data[i].value);
  3918.  
  3919.             if ((PA_ALLOC_FAILED(new_option_data[i].text_value,
  3920.                     option_data[i].text_value))||
  3921.                 (PA_ALLOC_FAILED(new_option_data[i].value,
  3922.                     option_data[i].value)))
  3923.             {
  3924.                 /*
  3925.                  * Free any data we've already allocated
  3926.                  */
  3927.                 while (i >= 0)
  3928.                 {
  3929.                     if (new_option_data[i].text_value != NULL)
  3930.                     {
  3931.                         PA_FREE(new_option_data[i].text_value);
  3932.                     }
  3933.  
  3934.                     if (new_option_data[i].value != NULL)
  3935.                     {
  3936.                         PA_FREE(new_option_data[i].value);
  3937.                     }
  3938.  
  3939.                     i--;
  3940.                 }
  3941.  
  3942.                 PA_UNLOCK(options);
  3943.                 PA_UNLOCK(new_options);
  3944.                 PA_FREE(new_options);
  3945.                 return(NULL);
  3946.             }
  3947.         }
  3948.     }
  3949.  
  3950.     PA_UNLOCK(options);
  3951.     PA_UNLOCK(new_options);
  3952.     return(new_options);
  3953. }
  3954.  
  3955. /*
  3956.  * Clone a form element data structure
  3957.  */
  3958. static LO_FormElementData *
  3959. lo_clone_form_element_data(LO_FormElementData *element_data)
  3960. {
  3961.     LO_FormElementData *new_element_data = XP_NEW(LO_FormElementData);
  3962.  
  3963.     if (new_element_data != NULL)
  3964.     {
  3965.         XP_MEMCPY(new_element_data, element_data, sizeof(LO_FormElementData));
  3966.  
  3967.         /*
  3968.          * The old FE data isn't meaningful
  3969.          */
  3970.         new_element_data->ele_text.FE_Data = NULL;
  3971.  
  3972.         /*
  3973.          * Some of the form element types have members that must be copied
  3974.          */
  3975.         switch (new_element_data->type)
  3976.         {
  3977.             case FORM_TYPE_RADIO:
  3978.             case FORM_TYPE_CHECKBOX:
  3979.                 {
  3980.                     lo_FormElementToggleData *form_data, *new_form_data;
  3981.  
  3982.                     form_data = (lo_FormElementToggleData *)element_data;
  3983.                     new_form_data = (lo_FormElementToggleData *)new_element_data;
  3984.  
  3985.                     new_form_data->name = lo_dup_block(form_data->name);
  3986.                     new_form_data->value = lo_dup_block(form_data->value);
  3987.  
  3988.                     if ((PA_ALLOC_FAILED(new_form_data->name,
  3989.                             form_data->name))||
  3990.                         (PA_ALLOC_FAILED(new_form_data->value,
  3991.                             form_data->value)))
  3992.                     {
  3993.                         lo_FreeFormElementData(new_element_data);
  3994.                         XP_DELETE(new_element_data);
  3995.                         return(NULL);
  3996.                     }
  3997.                 }
  3998.                 break;
  3999.  
  4000.             case FORM_TYPE_SUBMIT:
  4001.             case FORM_TYPE_RESET:
  4002.             case FORM_TYPE_BUTTON:
  4003.             case FORM_TYPE_HIDDEN:
  4004.             case FORM_TYPE_KEYGEN:
  4005.             case FORM_TYPE_READONLY:
  4006.                 {
  4007.                     lo_FormElementMinimalData *form_data, *new_form_data;
  4008.  
  4009.                     form_data = (lo_FormElementMinimalData *)element_data;
  4010.                     new_form_data = (lo_FormElementMinimalData *)new_element_data;
  4011.  
  4012.                     new_form_data->name = lo_dup_block(form_data->name);
  4013.                     new_form_data->value = lo_dup_block(form_data->value);
  4014.  
  4015.                     if ((PA_ALLOC_FAILED(new_form_data->name,
  4016.                             form_data->name))||
  4017.                         (PA_ALLOC_FAILED(new_form_data->value,
  4018.                             form_data->value)))
  4019.                     {
  4020.                         lo_FreeFormElementData(new_element_data);
  4021.                         XP_DELETE(new_element_data);
  4022.                         return(NULL);
  4023.                     }
  4024.                 }
  4025.                 break;
  4026.  
  4027.             case FORM_TYPE_TEXT:
  4028.             case FORM_TYPE_PASSWORD:
  4029.             case FORM_TYPE_FILE:
  4030.                 {
  4031.                     lo_FormElementTextData *form_data, *new_form_data;
  4032.  
  4033.                     form_data = (lo_FormElementTextData *)element_data;
  4034.                     new_form_data = (lo_FormElementTextData *)new_element_data;
  4035.  
  4036.                     new_form_data->name = lo_dup_block(form_data->name);
  4037.                     new_form_data->default_text = lo_dup_block(form_data->default_text);
  4038.                     new_form_data->current_text = lo_dup_block(form_data->current_text);
  4039.                     new_form_data->encoding = form_data->encoding;
  4040.  
  4041.                     if ((PA_ALLOC_FAILED(new_form_data->name,
  4042.                             form_data->name))||
  4043.                         (PA_ALLOC_FAILED(new_form_data->default_text,
  4044.                             form_data->default_text))||
  4045.                         (PA_ALLOC_FAILED(new_form_data->current_text,
  4046.                             form_data->current_text)))
  4047.                     {
  4048.                         lo_FreeFormElementData(new_element_data);
  4049.                         XP_DELETE(new_element_data);
  4050.                         return(NULL);
  4051.                     }
  4052.                 }
  4053.                 break;
  4054.  
  4055.             case FORM_TYPE_TEXTAREA:
  4056.                 {
  4057.                     lo_FormElementTextareaData *form_data, *new_form_data;
  4058.  
  4059.                     form_data = (lo_FormElementTextareaData *)element_data;
  4060.                     new_form_data = (lo_FormElementTextareaData *)new_element_data;
  4061.  
  4062.                     new_form_data->name = lo_dup_block(form_data->name);
  4063.                     new_form_data->default_text = lo_dup_block(form_data->default_text);
  4064.                     new_form_data->current_text = lo_dup_block(form_data->current_text);
  4065.  
  4066.                     if ((PA_ALLOC_FAILED(new_form_data->name,
  4067.                             form_data->name))||
  4068.                         (PA_ALLOC_FAILED(new_form_data->default_text,
  4069.                             form_data->default_text))||
  4070.                         (PA_ALLOC_FAILED(new_form_data->current_text,
  4071.                             form_data->current_text)))
  4072.                     {
  4073.                         lo_FreeFormElementData(new_element_data);
  4074.                         XP_DELETE(new_element_data);
  4075.                         return(NULL);
  4076.                     }
  4077.                 }
  4078.                 break;
  4079.  
  4080.             case FORM_TYPE_SELECT_ONE:
  4081.             case FORM_TYPE_SELECT_MULT:
  4082.                 {
  4083.                     lo_FormElementSelectData *form_data, *new_form_data;
  4084.  
  4085.                     form_data = (lo_FormElementSelectData *)element_data;
  4086.                     new_form_data = (lo_FormElementSelectData *)new_element_data;
  4087.  
  4088.                     new_form_data->name = lo_dup_block(form_data->name);
  4089.                     new_form_data->options = lo_copy_select_options(
  4090.                         form_data->option_cnt, form_data->options);
  4091.  
  4092.                     if ((PA_ALLOC_FAILED(new_form_data->name,
  4093.                             form_data->name))||
  4094.                         (PA_ALLOC_FAILED(new_form_data->options,
  4095.                             form_data->options)))
  4096.                     {
  4097.                         lo_FreeFormElementData(new_element_data);
  4098.                         XP_DELETE(new_element_data);
  4099.                         return(NULL);
  4100.                     }
  4101.                 }
  4102.                 break;
  4103.  
  4104.             case FORM_TYPE_OBJECT:
  4105.                 {
  4106.                     lo_FormElementObjectData *form_data, *new_form_data;
  4107.  
  4108.                     form_data = (lo_FormElementObjectData *)element_data;
  4109.                     new_form_data = (lo_FormElementObjectData *)new_element_data;
  4110.  
  4111.                     new_form_data->name = lo_dup_block(form_data->name);
  4112.                     new_form_data->object = form_data->object;
  4113.  
  4114.                     if (PA_ALLOC_FAILED(new_form_data->name, form_data->name))
  4115.                     {
  4116.                         lo_FreeFormElementData(new_element_data);
  4117.                         XP_DELETE(new_element_data);
  4118.                         return(NULL);
  4119.                     }
  4120.                 }
  4121.                 break;
  4122.         }
  4123.     }
  4124.  
  4125.     return(new_element_data);
  4126. }
  4127.  
  4128. /*
  4129.  * Clone the form list data and hang it off the specified URL_Struct
  4130.  */
  4131. void
  4132. LO_CloneFormData(SHIST_SavedData* savedData, MWContext *context,
  4133.             URL_Struct *url_struct)
  4134. {
  4135.     int i;
  4136.     LO_FormElementData **src_data_list, **dst_data_list;
  4137.     lo_SavedFormListData *fptr, *copyptr;
  4138.  
  4139.     if (savedData == NULL || context == NULL || url_struct == NULL)
  4140.     {
  4141.         return;
  4142.     }
  4143.  
  4144.     fptr = savedData->FormList;
  4145.  
  4146.     if (fptr == NULL)
  4147.     {
  4148.         return;
  4149.     }
  4150.  
  4151.     if (fptr->data_count <= 0)
  4152.     {
  4153.         return;
  4154.     }
  4155.  
  4156.     /*
  4157.      * The destination URL_Struct had better not already have form data
  4158.      */
  4159.     if (url_struct->savedData.FormList != NULL)
  4160.     {
  4161.         return;
  4162.     }
  4163.  
  4164.     /*
  4165.      * Allocate a form list data structure
  4166.      */
  4167.     url_struct->savedData.FormList = lo_NewDocumentFormListData();
  4168.  
  4169.     if (url_struct->savedData.FormList == NULL)
  4170.     {
  4171.         return;
  4172.     }
  4173.  
  4174.     copyptr = (lo_SavedFormListData *)url_struct->savedData.FormList;
  4175.  
  4176.     /*
  4177.      * Allocate an array to copy the form element data into
  4178.      */
  4179.     copyptr->data_list = PA_ALLOC(fptr->data_count
  4180.         * sizeof(LO_FormElementData *));
  4181.  
  4182.     if (copyptr->data_list == NULL)
  4183.     {
  4184.         XP_DELETE(url_struct->savedData.FormList);
  4185.         url_struct->savedData.FormList = NULL;
  4186.         return;
  4187.     }
  4188.  
  4189.     /*
  4190.      * Copy the form element data
  4191.      */
  4192.     copyptr->valid = TRUE;
  4193.     PA_LOCK(src_data_list, LO_FormElementData **, fptr->data_list);
  4194.     PA_LOCK(dst_data_list, LO_FormElementData **, copyptr->data_list);
  4195.     if ((src_data_list != NULL)&&(dst_data_list != NULL))
  4196.     {
  4197.         for (i=0; i < (fptr->data_count); i++)
  4198.         {
  4199.         if (src_data_list[i] != NULL)
  4200.         {
  4201.             dst_data_list[i] = lo_clone_form_element_data(src_data_list[i]);
  4202.  
  4203.             if (dst_data_list[i] == NULL)
  4204.             {
  4205.                 PA_UNLOCK(fptr->data_list);
  4206.                 PA_UNLOCK(copyptr->data_list);
  4207.                 lo_FreeDocumentFormListData(context, copyptr);
  4208.                 XP_DELETE(copyptr);
  4209.                 url_struct->savedData.FormList = NULL;
  4210.                 return;
  4211.             }
  4212.  
  4213.             copyptr->data_count++;
  4214.         }
  4215.         }
  4216.     }
  4217.     PA_UNLOCK(fptr->data_list);
  4218.     PA_UNLOCK(copyptr->data_list);
  4219. }
  4220.  
  4221. #ifdef TEST_16BIT
  4222. #undef XP_WIN16
  4223. #endif /* TEST_16BIT */
  4224.  
  4225. #ifdef PROFILE
  4226. #pragma profile off
  4227. #endif
  4228.  
  4229.