/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "xp.h" #include "net.h" #include "shist.h" #include "pa_parse.h" #include "layout.h" #ifdef JAVA #include "java.h" #elif defined(OJI) #include "np.h" #include "np2.h" #endif #include "laylayer.h" #include "libevent.h" #include "libimg.h" /* Image Library public API. */ #include "libi18n.h" /* For the character code set conversions */ #include "intl_csi.h" #include "secnav.h" /* For SECNAV_GenKeyFromChoice and SECNAV_GetKeyChoiceList protos */ #ifdef XP_MAC #include "prpriv.h" /* for NewNamedMonitor */ #include "prinrval.h" /* for PR_IntervalNow */ #else #include "private/prpriv.h" /* for NewNamedMonitor */ #endif #ifdef PROFILE #pragma profile on #endif #include "privacy.h" #ifdef TRANSACTION_RECEIPTS #include "receipt.h" #endif #ifndef XP_TRACE # define XP_TRACE(X) fprintf X #endif #ifdef TEST_16BIT #define XP_WIN16 #endif /* TEST_16BIT */ #ifdef XP_WIN16 #define SIZE_LIMIT 32000 #endif /* XP_WIN16 */ #define DEF_ISINDEX_PROMPT "This is a searchable index. Enter search keywords: " #define ISINDEX_TAG_TEXT "name=isindex>" #define DEF_FILE_ELE_VALUE "Choose File" #define DEF_RESET_BUTTON_NAME "reset" #define DEF_RESET_BUTTON_TEXT "Reset" #define DEF_SUBMIT_BUTTON_NAME "submit" #define DEF_SUBMIT_BUTTON_TEXT "Submit Query" #define DEF_BUTTON_TEXT " " #define DEF_TOGGLE_VALUE "on" #define DEF_TEXT_ELE_SIZE 20 #define DEF_TEXTAREA_ELE_ROWS 1 #define DEF_TEXTAREA_ELE_COLS 20 #define DEF_SELECT_ELE_SIZE 1 #define MAX_BUTTON_WIDTH 1000 #define MAX_BUTTON_HEIGHT 1000 static PA_Block lo_dup_block(PA_Block); /* forward declaration */ /* VERY IMPORTANT * * the form_list linked list is in REVERSE * order. Therefore if there is more than * one form on a page the different forms * are in the list in the REVERSE order * that they appear on the page. */ PRIVATE LO_FormElementStruct * lo_return_next_form_element(MWContext *context, LO_FormElementStruct *current_element, XP_Bool reverse_order) { int32 doc_id; int i; lo_TopState *top_state; lo_DocState *state; lo_FormData *form_list; lo_FormData *prev_form_list=NULL; LO_Element **ele_list; LO_FormElementStruct *form_ele; /* * Get the unique document ID, and retreive this * documents layout state. */ doc_id = XP_DOCID(context); top_state = lo_FetchTopState(doc_id); if ((top_state == NULL)||(top_state->doc_state == NULL)) { return(NULL); } state = top_state->doc_state; /* * XXX BUGBUG This and the corresponding routines, only deal * with forms in the main document and not forms in layers. */ /* * Extract the list of all forms in this doc. */ form_list = top_state->doc_lists.form_list; while(form_list) { PA_LOCK(ele_list, LO_Element **, form_list->form_elements); for (i=0; iform_ele_cnt; i++) { form_ele = (LO_FormElementStruct *)ele_list[i]; if(NULL == current_element && FALSE == reverse_order) { /* since the passed in element was NULL * or we set the current element below * since we wanted the next element * return the first element we encounter. */ PA_UNLOCK(form_list->form_elements); return(form_ele); } else if(form_ele == current_element) { if(reverse_order) { if(i > 0) { PA_UNLOCK(form_list->form_elements); return((LO_FormElementStruct *)ele_list[i-1]); } else if(NULL == form_list->next) { PA_UNLOCK(form_list->form_elements); return NULL; /* first element in whole list*/ } else { /* if there is a next form_list * then return the last element * of the next form_list */ PA_UNLOCK(form_list->form_elements); form_list = form_list->next; if(form_list->form_ele_cnt == 0) return NULL; PA_LOCK(ele_list, LO_Element **, form_list->form_elements); form_ele = (LO_FormElementStruct *) ele_list[form_list->form_ele_cnt-1]; PA_UNLOCK(form_list->form_elements); return(form_ele); } } else { if(i+1form_ele_cnt) { PA_UNLOCK(form_list->form_elements); return((LO_FormElementStruct *)ele_list[i+1]); } else if(NULL == prev_form_list) { PA_UNLOCK(form_list->form_elements); return NULL; /* last element in whole list*/ } else { /* choose the first element of the * previous form list */ PA_UNLOCK(form_list->form_elements); if(prev_form_list->form_ele_cnt == 0) return NULL; PA_LOCK(ele_list, LO_Element **, prev_form_list->form_elements); form_ele = (LO_FormElementStruct *) ele_list[0]; PA_UNLOCK(prev_form_list->form_elements); return(form_ele); } } } } PA_UNLOCK(form_list->form_elements); if(NULL == current_element && TRUE == reverse_order) { /* since the passed in element was NULL * return the last element we encountered. */ return(form_ele); } prev_form_list = form_list; form_list = form_list->next; } if(current_element == NULL) return NULL; /* the element was not found in the list * something must be wrong, lets assert! */ XP_ASSERT(0); return NULL; } /* return the next form element in layouts list of form elements * * If NULL is passed in, this function returns the first element. * * If the last element is passed in, this function returns NULL * * If a garbage pointer is passed in, this function returns NULL */ PUBLIC LO_FormElementStruct * LO_ReturnNextFormElement(MWContext *context, LO_FormElementStruct *current_element) { return(lo_return_next_form_element(context, current_element, FALSE)); } /* return the previous form element in layouts list of form elements * * If NULL is passed in, this function returns the last element. * * If the first element is passed in, this function returns NULL * * If a garbage pointer is passed in, this function returns NULL */ PUBLIC LO_FormElementStruct * LO_ReturnPrevFormElement(MWContext *context, LO_FormElementStruct *current_element) { return(lo_return_next_form_element(context, current_element, TRUE)); } /* #ifndef NO_TAB_NAVIGATION */ /* for Form element type FORM_TYPE_RADIO and FORM_TYPE_CHECKBOX, if the element has focus, the Text elment following it needs to draw the Tab Focus(dotted box). */ Bool LO_isFormElementNeedTextTabFocus( LO_FormElementStruct *pElement ) { if( pElement == NULL || pElement->type != LO_FORM_ELE ) return(FALSE); /* * Under bizarre cases, this may be an invalid form element * with no form data. */ if (pElement->element_data == NULL) return(FALSE); if( pElement->element_data->type == FORM_TYPE_RADIO || pElement->element_data->type == FORM_TYPE_CHECKBOX ) return(TRUE); return(FALSE); } /* Function LO_isTabableFormElement() is copied from PUBLIC LO_FormElementStruct * LO_ReturnNextFormElementInTabGroup(MWContext *context, */ Bool LO_isTabableFormElement( LO_FormElementStruct * next_ele ) { /* * Under bizarre cases, this may be an invalid form element * with no form data. */ if (next_ele->element_data == NULL) return(FALSE); if (next_ele->element_data->type == FORM_TYPE_TEXT || next_ele->element_data->type == FORM_TYPE_SUBMIT || next_ele->element_data->type == FORM_TYPE_RESET || next_ele->element_data->type == FORM_TYPE_PASSWORD || next_ele->element_data->type == FORM_TYPE_BUTTON || next_ele->element_data->type == FORM_TYPE_RADIO || next_ele->element_data->type == FORM_TYPE_CHECKBOX || next_ele->element_data->type == FORM_TYPE_SELECT_ONE || next_ele->element_data->type == FORM_TYPE_SELECT_MULT || next_ele->element_data->type == FORM_TYPE_TEXTAREA || next_ele->element_data->type == FORM_TYPE_FILE #ifdef ENDER || next_ele->element_data->type == FORM_TYPE_HTMLAREA #endif /*ENDER*/ ) { return(TRUE); } else return( FALSE ); } /* NO_TAB_NAVIGATION */ /* NO_TAB_NAVIGATION, LO_ReturnNextFormElementInTabGroup() is used to tab through form elements. Since the winfe now has TAB_NAVIGATION, it is not used any more. If mac and Unix don't use it either, it can be removed. */ /* return the next tabable form element struct * * Current tabable elements are: * * FORM_TYPE_TEXT * FORM_TYPE_SUBMIT * FORM_TYPE_RESET * FORM_TYPE_PASSWORD * FORM_TYPE_BUTTON * FORM_TYPE_FILE * FORM_TYPE_RADIO * FORM_TYPE_CHECKBOX * FORM_TYPE_SELECT_ONE * FORM_TYPE_SELECT_MULT * FORM_TYPE_TEXTAREA * FORM_TYPE_HTMLAREA * * If the last element is passed in the first element is returned. * If garbage is passed in the first element is returned. */ PUBLIC LO_FormElementStruct * LO_ReturnNextFormElementInTabGroup(MWContext *context, LO_FormElementStruct *current_element, XP_Bool go_backwards) { LO_FormElementStruct *next_ele; /* * Under bizarre cases, this may be an invalid form element * with no form data. */ if (current_element->element_data == NULL) return(NULL); while((next_ele = lo_return_next_form_element(context, current_element, go_backwards)) != NULL) { if (next_ele->element_data->type == FORM_TYPE_TEXT || next_ele->element_data->type == FORM_TYPE_SUBMIT || next_ele->element_data->type == FORM_TYPE_RESET || next_ele->element_data->type == FORM_TYPE_PASSWORD || next_ele->element_data->type == FORM_TYPE_BUTTON || next_ele->element_data->type == FORM_TYPE_RADIO || next_ele->element_data->type == FORM_TYPE_CHECKBOX || next_ele->element_data->type == FORM_TYPE_SELECT_ONE || next_ele->element_data->type == FORM_TYPE_SELECT_MULT || next_ele->element_data->type == FORM_TYPE_TEXTAREA || next_ele->element_data->type == FORM_TYPE_FILE #ifdef ENDER || next_ele->element_data->type == FORM_TYPE_HTMLAREA #endif /*ENDER*/ ) { return(next_ele); } else { current_element = next_ele; } } /* return the first element */ return(lo_return_next_form_element(context, NULL, go_backwards)); } void lo_BeginForm(MWContext *context, lo_DocState *state, PA_Tag *tag) { lo_FormData *form; PA_Block buff; char *str; lo_DocLists *doc_lists; form = XP_NEW(lo_FormData); if (form == NULL) { state->top_state->out_of_memory = TRUE; return; } doc_lists = lo_GetCurrentDocLists(state); state->top_state->in_form = TRUE; doc_lists->current_form_num++; form->id = doc_lists->current_form_num; form->form_ele_cnt = 0; form->form_ele_size = 0; form->form_elements = NULL; form->next = NULL; #ifdef MOCHA form->name = lo_FetchParamValue(context, tag, PARAM_NAME); form->mocha_object = NULL; #endif buff = lo_FetchParamValue(context, tag, PARAM_ACTION); if (buff != NULL) { char *url; PA_LOCK(str, char *, buff); url = NET_MakeAbsoluteURL(state->top_state->base_url, str); PA_UNLOCK(buff); PA_FREE(buff); if (url == NULL) { buff = NULL; } else { buff = PA_ALLOC(XP_STRLEN(url) + 1); if (buff != NULL) { PA_LOCK(str, char *, buff); XP_STRCPY(str, url); PA_UNLOCK(buff); } else { state->top_state->out_of_memory = TRUE; } XP_FREE(url); } } else if (state->top_state->base_url != NULL) { buff = PA_ALLOC(XP_STRLEN(state->top_state->base_url) + 1); if (buff != NULL) { PA_LOCK(str, char *, buff); XP_STRCPY(str, state->top_state->base_url); PA_UNLOCK(buff); } else { state->top_state->out_of_memory = TRUE; } } form->action = buff; form->encoding = lo_FetchParamValue(context, tag, PARAM_ENCODING); buff = lo_FetchParamValue(context, tag, PARAM_TARGET); if (buff != NULL) { int32 len; char *target; PA_LOCK(target, char *, buff); len = lo_StripTextWhitespace(target, XP_STRLEN(target)); if ((*target == '\0')|| (lo_IsValidTarget(target) == FALSE)) { PA_UNLOCK(buff); PA_FREE(buff); buff = NULL; } else { PA_UNLOCK(buff); } } /* * If there was no target use the default one. * (default provided by BASE tag) */ if ((buff == NULL)&&(state->top_state->base_target != NULL)) { buff = PA_ALLOC(XP_STRLEN(state->top_state->base_target) + 1); if (buff != NULL) { char *targ; PA_LOCK(targ, char *, buff); XP_STRCPY(targ, state->top_state->base_target); PA_UNLOCK(buff); } else { state->top_state->out_of_memory = TRUE; } } form->window_target = buff; form->method = FORM_METHOD_GET; buff = lo_FetchParamValue(context, tag, PARAM_METHOD); if (buff != NULL) { PA_LOCK(str, char *, buff); if (pa_TagEqual("post", str)) { form->method = FORM_METHOD_POST; } PA_UNLOCK(buff); PA_FREE(buff); } form->next = doc_lists->form_list; doc_lists->form_list = form; #ifdef MOCHA if (!state->in_relayout) { lo_BeginReflectForm(context, state, tag, form); } #endif } void lo_EndForm(MWContext *context, lo_DocState *state) { intn i, form_id; lo_FormData *form_list; LO_Element **ele_list; LO_FormElementStruct *single_text_ele; lo_DocLists *doc_lists; state->top_state->in_form = FALSE; doc_lists = lo_GetCurrentDocLists(state); form_id = doc_lists->current_form_num; form_list = doc_lists->form_list; while (form_list != NULL) { if (form_list->id == form_id) { break; } form_list = form_list->next; } if (form_list == NULL) { return; } single_text_ele = NULL; PA_LOCK(ele_list, LO_Element **, form_list->form_elements); for (i=0; iform_ele_cnt; i++) { LO_FormElementStruct *form_ele; form_ele = (LO_FormElementStruct *)ele_list[i]; if (form_ele->element_data == NULL) { continue; } if ((form_ele->element_data->type == FORM_TYPE_TEXT)|| (form_ele->element_data->type == FORM_TYPE_PASSWORD)) { if (single_text_ele != NULL) { single_text_ele = NULL; break; } else { single_text_ele = form_ele; } } } PA_UNLOCK(form_list->form_elements); if (single_text_ele != NULL) { FE_FormTextIsSubmit(context, single_text_ele); } #ifdef MOCHA if (!state->in_relayout) { lo_EndReflectForm(context, form_list); } #endif } int32 lo_ResolveInputType(char *type_str) { if (type_str == NULL) { return(FORM_TYPE_TEXT); } if (pa_TagEqual(S_FORM_TYPE_TEXT, type_str)) { return(FORM_TYPE_TEXT); } else if (pa_TagEqual(S_FORM_TYPE_RADIO, type_str)) { return(FORM_TYPE_RADIO); } else if (pa_TagEqual(S_FORM_TYPE_CHECKBOX, type_str)) { return(FORM_TYPE_CHECKBOX); } else if (pa_TagEqual(S_FORM_TYPE_HIDDEN, type_str)) { return(FORM_TYPE_HIDDEN); } else if (pa_TagEqual(S_FORM_TYPE_SUBMIT, type_str)) { return(FORM_TYPE_SUBMIT); } else if (pa_TagEqual(S_FORM_TYPE_RESET, type_str)) { return(FORM_TYPE_RESET); } else if (pa_TagEqual(S_FORM_TYPE_PASSWORD, type_str)) { return(FORM_TYPE_PASSWORD); } else if (pa_TagEqual(S_FORM_TYPE_BUTTON, type_str)) { return(FORM_TYPE_BUTTON); } else if (pa_TagEqual(S_FORM_TYPE_FILE, type_str)) { return(FORM_TYPE_FILE); } else if (pa_TagEqual(S_FORM_TYPE_IMAGE, type_str)) { return(FORM_TYPE_IMAGE); } else if (pa_TagEqual(S_FORM_TYPE_OBJECT, type_str)) { return(FORM_TYPE_OBJECT); } else if (pa_TagEqual(S_FORM_TYPE_JOT, type_str)) { return(FORM_TYPE_JOT); } else if (pa_TagEqual(S_FORM_TYPE_READONLY, type_str)) { return(FORM_TYPE_READONLY); } else { return(FORM_TYPE_TEXT); } } static void lo_recolor_form_element_bg(lo_DocState *state, LO_FormElementStruct *form_ele, LO_Color *bg_color) { LO_TextAttr *old_attr; LO_TextAttr *attr; LO_TextAttr tmp_attr; attr = NULL; old_attr = form_ele->text_attr; if (old_attr != NULL) { lo_CopyTextAttr(old_attr, &tmp_attr); /* don't recolor the background if it was * explicitly set to another color */ if(tmp_attr.no_background == TRUE) { tmp_attr.bg.red = bg_color->red; tmp_attr.bg.green = bg_color->green; tmp_attr.bg.blue = bg_color->blue; } /* removed by Lou 4-3-97. Allow text to * overlap correctly in tables */ /* tmp_attr.no_background = FALSE; */ attr = lo_FetchTextAttr(state, &tmp_attr); } form_ele->text_attr = attr; } static LO_FormElementStruct * new_form_element(MWContext *context, lo_DocState *state, int32 type) { LO_FormElementStruct *form_element; lo_DocLists *doc_lists; #ifdef XP_WIN XP_Bool attr_change; LO_TextAttr tmp_attr; #endif doc_lists = lo_GetCurrentDocLists(state); form_element = (LO_FormElementStruct *)lo_NewElement(context, state, LO_FORM_ELE, NULL, 0); if (form_element == NULL) { return(NULL); } form_element->type = LO_FORM_ELE; form_element->ele_id = NEXT_ELEMENT; form_element->x = state->x; form_element->y = state->y; form_element->x_offset = 0; form_element->y_offset = 0; form_element->border_vert_space = 0; form_element->border_horiz_space = 0; form_element->width = 0; form_element->height = 0; form_element->next = NULL; form_element->prev = NULL; form_element->form_id = doc_lists->current_form_num; form_element->layer_id = lo_CurrentLayerId(state); form_element->element_data = NULL; form_element->element_index = 0; #ifdef MOCHA form_element->mocha_object = NULL; form_element->event_handler_present = FALSE; #endif if (state->font_stack == NULL) { form_element->text_attr = NULL; } else { form_element->text_attr = state->font_stack->text_attr; /* * Possibly inherit the background color attribute * of a parent table cell. */ if (state->is_a_subdoc == SUBDOC_CELL) { lo_DocState *up_state; /* * Find the parent subdoc's state. */ up_state = state->top_state->doc_state; while ((up_state->sub_state != NULL)&& (up_state->sub_state != state)) { up_state = up_state->sub_state; } if ((up_state->sub_state != NULL)&& (up_state->current_ele != NULL)&& (up_state->current_ele->type == LO_SUBDOC)&& (up_state->current_ele->lo_subdoc.backdrop.bg_color != NULL)) { lo_recolor_form_element_bg(state, form_element, up_state->current_ele->lo_subdoc.backdrop.bg_color); } } } #ifdef XP_WIN attr_change = FALSE; attr_change = FE_CheckFormTextAttributes(context, form_element->text_attr, &tmp_attr, type); if (attr_change != FALSE) { form_element->text_attr = lo_FetchTextAttr(state, &tmp_attr); } #endif form_element->ele_attrmask = 0; form_element->sel_start = -1; form_element->sel_end = -1; return(form_element); } /* * If this document already has a list of form * data elements, return a pointer to the next form element data * structure. Otherwise allocate a new data element structure, and * put the pointer to it in the document's list of * form data elements before returning it. */ static LO_FormElementData * lo_next_element_data(lo_DocState *state, int32 type) { lo_SavedFormListData *all_ele; int32 index; LO_FormElementData **data_list; LO_FormElementData *data_ele; all_ele = state->top_state->savedData.FormList; index = all_ele->data_index++; /* * This only happens if we didn't have a pre-saved * data list, so we grow this one and create a new element. */ if (all_ele->data_index > all_ele->data_count) { PA_Block old_data_list; /* really a (LO_FormElementData **) */ #ifdef XP_WIN16 if ((all_ele->data_index * sizeof(LO_FormElementData *)) > SIZE_LIMIT) { all_ele->data_index--; return(NULL); } #endif /* XP_WIN16 */ all_ele->data_count = all_ele->data_index; old_data_list = NULL; if (all_ele->data_count == 1) { all_ele->data_list = PA_ALLOC(all_ele->data_count * sizeof(LO_FormElementData *)); } else { old_data_list = all_ele->data_list; all_ele->data_list = PA_REALLOC( all_ele->data_list, (all_ele->data_count * sizeof(LO_FormElementData *))); } if (all_ele->data_list == NULL) { all_ele->data_list = old_data_list; all_ele->data_index--; all_ele->data_count--; state->top_state->out_of_memory = TRUE; return(NULL); } PA_LOCK(data_list, LO_FormElementData **, all_ele->data_list); data_list[index] = XP_NEW_ZAP(LO_FormElementData); if (data_list[index] != NULL) { data_list[index]->type = FORM_TYPE_NONE; } else { state->top_state->out_of_memory = TRUE; } PA_UNLOCK(all_ele->data_list); } PA_LOCK(data_list, LO_FormElementData **, all_ele->data_list); data_ele = data_list[index]; /* * If the type is changing, someone may be attacking us via server push * or JavaScript document.write and history.go(0), substituting a file * upload input for a text input from the previous version of the doc * that has its value field set to "/etc/passwd". */ if ((data_ele->type != FORM_TYPE_NONE) && (data_ele->type != type)) { lo_FreeFormElementData(data_ele); XP_BZERO(data_ele, sizeof(*data_ele)); data_ele->type = FORM_TYPE_NONE; } PA_UNLOCK(all_ele->data_list); /* * If we are reusing an old structure, clean it of old memory */ lo_CleanFormElementData(data_ele); return(data_ele); } static LO_FormElementStruct * lo_form_input_text(MWContext *context, lo_DocState *state, PA_Tag *tag, int32 type) { LO_FormElementStruct *form_element; lo_FormElementTextData *form_data; PA_Block buff; #if defined(XP_MAC)&&defined(MOCHA) PA_Block keydown, keypress, keyup; #endif /* defined(XP_MAC)&&defined(MOCHA) */ char *str; char *tptr; int16 charset; form_element = new_form_element(context, state, type); if (form_element == NULL) { return(NULL); } form_element->element_data = lo_next_element_data(state, type); if (form_element->element_data == NULL) { lo_FreeElement(context, (LO_Element *)form_element, FALSE); return(NULL); } form_element->element_index = state->top_state->savedData.FormList->data_index - 1; form_data = (lo_FormElementTextData *)form_element->element_data; /* * IF our starting type is NONE, this is a new element, * an we need to initialize the locations that will later * hold persistent data. */ if (form_data->type == FORM_TYPE_NONE) { form_data->FE_Data = NULL; form_data->current_text = NULL; } form_data->encoding = INPUT_TYPE_ENCODING_NORMAL; /* default */ form_data->type = type; form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME); buff = lo_FetchParamValue(context, tag, PARAM_VALUE); PA_LOCK(tptr, char *, buff); /* * strip newlines from single line text * default values. */ if ((tptr != NULL)&&(type != FORM_TYPE_PASSWORD)) { int32 len; len = XP_STRLEN(tptr); len = lo_StripTextNewlines(tptr, len); } charset = form_element->text_attr->charset; tptr = FE_TranslateISOText(context, charset, tptr); PA_UNLOCK(buff); form_data->default_text = buff; #ifdef OLD_FILE_UPLOAD if ((form_data->default_text == NULL)&&(type == FORM_TYPE_FILE)) { form_data->default_text = PA_ALLOC( (XP_STRLEN(DEF_FILE_ELE_VALUE) + 1) * sizeof(char)); if (form_data->default_text != NULL) { PA_LOCK(tptr, char *, form_data->default_text); XP_STRCPY(tptr, DEF_FILE_ELE_VALUE); PA_UNLOCK(form_data->default_text); } } #else /* * File upload forms cannot default to a filename */ if ((form_data->default_text != NULL)&&(type == FORM_TYPE_FILE)) { PA_FREE(form_data->default_text); form_data->default_text = NULL; } #endif /* OLD_FILE_UPLOAD */ form_data->read_only = FALSE; if (type != FORM_TYPE_FILE) { buff = lo_FetchParamValue(context, tag, PARAM_READONLY); if (buff != NULL) { PA_FREE(buff); form_data->read_only = TRUE; } } form_data->size = DEF_TEXT_ELE_SIZE; buff = lo_FetchParamValue(context, tag, PARAM_SIZE); if (buff != NULL) { PA_LOCK(str, char *, buff); form_data->size = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); if (form_data->size < 1) { form_data->size = 1; } } #ifdef OLD_FILE_UPLOAD else if ((type == FORM_TYPE_FILE)&&(form_data->default_text != NULL)) { int32 len; PA_LOCK(tptr, char *, form_data->default_text); len = XP_STRLEN(tptr); PA_UNLOCK(form_data->default_text); if (len > 0) { form_data->size = len; } } #endif /* OLD_FILE_UPLOAD */ buff = lo_FetchParamValue(context, tag, PARAM_ENCODING); if (buff != NULL) { PA_LOCK(str, char *, buff); if(!XP_STRCASECMP(str, "MACBINARY")) form_data->encoding = INPUT_TYPE_ENCODING_MACBIN; PA_UNLOCK(buff); PA_FREE(buff); } form_data->max_size = -1; buff = lo_FetchParamValue(context, tag, PARAM_MAXLENGTH); if (buff != NULL) { PA_LOCK(str, char *, buff); form_data->max_size = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); } #if defined(XP_MAC)&&defined(MOCHA) keydown = lo_FetchParamValue(context, tag, PARAM_ONKEYDOWN); keypress = lo_FetchParamValue(context, tag, PARAM_ONKEYPRESS); keyup = lo_FetchParamValue(context, tag, PARAM_ONKEYUP); /* Text fields need this info which needs to be carried across table cell relayouts. Only the mac FE checks the event_handler_present bit. */ if (keydown || keypress || keyup) form_element->event_handler_present = TRUE; if (keydown) PA_FREE(keydown); if (keypress) PA_FREE(keypress); if (keyup) PA_FREE(keyup); #endif /* defined(XP_MAC)&&defined(MOCHA) */ return(form_element); } static LO_FormElementStruct * lo_form_textarea(MWContext *context, lo_DocState *state, PA_Tag *tag, int32 type) { LO_FormElementStruct *form_element; lo_FormElementTextareaData *form_data; PA_Block buff; #if defined(XP_MAC)&&defined(MOCHA) PA_Block keydown, keypress, keyup; #endif /* defined(XP_MAC)&&defined(MOCHA) */ char *str; form_element = new_form_element(context, state, type); if (form_element == NULL) { return(NULL); } form_element->element_data = lo_next_element_data(state, type); if (form_element->element_data == NULL) { lo_FreeElement(context, (LO_Element *)form_element, FALSE); return(NULL); } form_element->element_index = state->top_state->savedData.FormList->data_index - 1; form_data = (lo_FormElementTextareaData *)form_element->element_data; /* * IF our starting type is NONE, this is a new element, * an we need to initialize the locations that will later * hold persistent data. */ if (form_data->type == FORM_TYPE_NONE) { form_data->FE_Data = NULL; form_data->current_text = NULL; } form_data->type = type; form_data->name = lo_FetchParamValue(context, tag, PARAM_NAME); form_data->default_text = NULL; form_data->rows = DEF_TEXTAREA_ELE_ROWS; buff = lo_FetchParamValue(context, tag, PARAM_ROWS); if (buff != NULL) { PA_LOCK(str, char *, buff); form_data->rows = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); if (form_data->rows < 1) { form_data->rows = 1; } } form_data->cols = DEF_TEXTAREA_ELE_COLS; buff = lo_FetchParamValue(context, tag, PARAM_COLS); if (buff != NULL) { PA_LOCK(str, char *, buff); form_data->cols = XP_ATOI(str); PA_UNLOCK(buff); PA_FREE(buff); if (form_data->cols < 1) { form_data->cols = 1; } } form_data->disabled = FALSE; buff = lo_FetchParamValue(context, tag, PARAM_DISABLED); if (buff != NULL) { PA_FREE(buff); form_data->disabled = TRUE; } form_data->read_only = FALSE; buff = lo_FetchParamValue(context, tag, PARAM_READONLY); if (buff != NULL) { PA_FREE(buff); form_data->read_only = TRUE; } form_data->auto_wrap = TEXTAREA_WRAP_OFF; buff = lo_FetchParamValue(context, tag, PARAM_WRAP); if (buff != NULL) { PA_LOCK(str, char *, buff); if (pa_TagEqual("off", str)) { form_data->auto_wrap = TEXTAREA_WRAP_OFF; } else if (pa_TagEqual("hard", str)) { form_data->auto_wrap = TEXTAREA_WRAP_HARD; } else if (pa_TagEqual("soft", str)) { form_data->auto_wrap = TEXTAREA_WRAP_SOFT; } /* * Make