/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /***************************************************/ /* File : FetchPage.c */ /* */ /* Purpose: High-level fetch functions; the main */ /* interface for initiating and control- */ /* ling full page fetches. Compare with */ /* lower level Fetch.c and FetchHTML.c. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 25-Nov-96: Created. */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "flex.h" #include "swis.h" #include "URI.h" /* URI handler API, in URILib:h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "window.h" #include "gadgets.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "MiscDefs.h" #include "Utils.h" #include "Browser.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "Frames.h" #include "Handlers.h" #include "History.h" #include "Images.h" #include "JavaScript.h" #include "Memory.h" #include "PlugIn.h" #include "Protocols.h" #include "Reformat.h" #include "SaveDraw.h" #include "SaveText.h" #include "Toolbars.h" #include "URLutils.h" #include "Windows.h" #include "FetchPage.h" /* Locals */ char * url_buffer = NULL; /* Static function prototypes */ static _kernel_oserror * fetchpage_process_internal (browser_data * b); static _kernel_oserror * fetchpage_preprocessed (browser_data * b, int record, int stop); static _kernel_oserror * fetchpage_postprocessed (browser_data * b, int record); /*************************************************/ /* fetchpage_fetch() */ /* */ /* Handles the initiation of a fetch and the */ /* display of the result in a browser window. */ /* */ /* Parameters are as standard for a Wimp event */ /* handler (this is called on null events). */ /*************************************************/ int fetchpage_fetch(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle) { _kernel_oserror * e; int tf_start, tf_now, priority; int fetching, formatting; #ifdef TRACE { static oldstatus; if ((tl & (1u<<6)) && (handle->fetch_status != oldstatus)) { Printf("\nfetchpage_fetch: Called with new status %d\n",handle->fetch_status); oldstatus = handle->fetch_status; } } #endif if (handle->fetch_status == BS_START) { e = fetch_start(handle); if (e) { handle->save_link = 0; show_error_cont(e); } } /* Call the fetcher / reformatter, allowing a certain */ /* amount of time inside each only. */ _swix(OS_ReadMonotonicTime, _OUT(0), &tf_start); tf_now = tf_start; /* The main fetch/reformat loop */ fetching = fetch_fetching(handle); formatting = reformat_formatting(handle); /* Some fairly crude load balancing. If the fetcher is idle, */ /* but this function is being called, chances are we're */ /* formatting. Otherwise, we may be processing tokens - so */ /* the actual fetch is complete but the fetcher is still */ /* working on the data from HTMLLib. Otherwise, it may be */ /* that the main fetch is active; or we could be spooling */ /* data to a file. */ if (formatting && controls.refo_single) priority = 300; else { if (handle->fetch_status == BS_IDLE) priority = 15; /* Not fetching, may be solid formatting */ else if (handle->fetch_status == BS_PROCESS) priority = 8; /* Processing tokens, but fetch is complete */ else if (handle->fetch_status == BS_FETCHING) priority = 3; /* Fetching tokens (so fetch is incomplete) */ else if (handle->fetch_status == BS_DATAFETCH && handle->save_file) priority = 2; /* Saving data to a file (fetch incomplete) */ else priority = 0; } do { /* If fetching, call the reformatter. */ if (fetching) fetch_fetcher(handle); /* If reformatting, call the reformatter. */ if (formatting) { reformat_reformatter(handle); ChkError(windows_check_tools(handle, NULL)); } fetching = fetch_fetching(handle); formatting = reformat_formatting(handle); /* Re-read the time, and keep going whilst we're */ /* inside the maximum time specified by 'priority' */ /* and fetching and/or formatting. */ _swix(OS_ReadMonotonicTime, _OUT(0), &tf_now); } while ( tf_now - tf_start < priority && (fetching || formatting) ); /* Process images on a lower priority */ if (image_count_specific_pending(handle)) { e = image_process_null(handle); /* Force all errors to be warnings only */ if (e) { if (&erb != e) erb = *e; erb.errnum = Utils_Error_Custom_Message; ChkError(&erb); } } /* Handle jumping to any specified named anchors */ if (handle->display_request == DISPLAY_NAMED) { char * p; HStream * t; t = 0; p = fetch_find_name_tag(browser_current_url(handle)) + 1; t = fetch_find_anchor_token(handle, p); if (t) { handle->display_request = t; handle->display_offset = 0; } } else { if ( handle->display_request && browser_show_token(handle, handle->display_request, handle->display_offset) ) { WimpGetWindowStateBlock s; s.window_handle = handle->window_handle; wimp_get_window_state(&s); if (s.yscroll != handle->display_vscroll) handle->display_vscroll = s.yscroll; else handle->display_request = 0, handle->display_vscroll = 0; } } /* Various actions as things become inactive... */ if (!fetch_fetching(handle)) { /* If we have a JavaScript onLoad command, deal with it */ if (handle->onload) ChkError(javascript_body_onload(handle)); /* Garbage collect images if the main page fetch has finished */ if (handle->clear_images) { // image_discard_unused(handle); handle->clear_images = 0; } if (!reformat_formatting(handle)) { if (!image_count_specific_pending(handle)) { /* There are no pending images, so we seem to have finished - */ /* but is there a reformat pending? */ if (handle->refo_time) { /* Yes, so flush the queue */ reformat_format_from(handle, handle->refo_line, 1, -1); } else { /* No; get rid of null claimants (the call will *install* a new */ /* animation drift handler if the Controls require it). */ if (handle->fetch_handler) fetchpage_release_nulls(handle); /* We may have a pending messages to send */ e = protocols_atats_send_any_pendings(handle); /* If this is a small fetch window, close it */ if (handle->small_fetch) { int close = 1; /* If this is a fetch for a Plug-In, tell the Plug-In about it */ if ( handle->pstream && handle->pstream->active && !handle->pstream->abandoned ) { plugin_fetch_completed(handle); /* Only close the window if the stream won't close itself */ if (handle->pstream->will_close_itself) close = 0; } /* Close the window *afterwards* - or you've */ /* just freed up message structures etc. that */ /* need to be dealt with first. */ if (close) windows_close_browser(handle); } /* Otherwise, proceed as normal */ else { /* Check the page's vertical extent is correct */ ChkError(reformat_check_extent(handle)); /* Update the status bar */ toolbars_cancel_all(handle); toolbars_update_status(handle, Toolbars_Status_Viewing); } /* Report any errors from the pending message sends */ ChkError(e); } } /* Sort out window tool presence */ ChkError(windows_check_tools(handle, NULL)); } } /* Keep the buttons as up to date as possible throughout the fetch */ toolbars_set_button_states(handle); return 0; } /*************************************************/ /* fetchpage_fetch_targetted() */ /* */ /* Fetch a given URL, possibly appending some */ /* given extra data, into a given target window, */ /* an ancestor browser, or a new view. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* which acts as a parent; */ /* */ /* Pointer to the URL to fetch; */ /* */ /* Pointer to a window target name, */ /* or NULL to open in the parent - */ /* if full screen, note that any */ /* target names which would */ /* otherwise have opened a new */ /* window will not do so; */ /* */ /* Pointer to any extra data to */ /* append to the URL, or NULL; */ /* */ /* 1 to open the URL in a new window */ /* (with no name) regardless of the */ /* targetting, else 0 (this will not */ /* be overridden when running full */ /* screen). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the fetch. */ /*************************************************/ _kernel_oserror * fetchpage_fetch_targetted(browser_data * parent, const char * url, const char * target, const char * appnddata, int new) { browser_data * ancestor; browser_data * targetted; /* If we've been asked to open a new window, only the extra data */ /* parameter matters. */ if (new) { if (appnddata) return fetchpage_new_add(NULL, url, 1, 1, appnddata, 1, NULL); else { RetError(windows_create_browser(url, NULL, NULL, NULL, Windows_CreateBrowser_Normal)); RetError(browser_inherit(parent, last_browser)); return NULL; } } /* Otherwise, have a bit more thinking to do */ else { if (!parent) return NULL; ancestor = utils_ancestor(parent); /* Deal with the targetted window case first */ if (target && *target) { targetted = frames_find_target(parent, target); if (targetted) { if (parent != targetted) RetError(browser_inherit_post_data(parent, targetted)); /* We have a specific browser to open the URL in */ if (appnddata) { return fetchpage_new_add(targetted, url, 1, 1, appnddata, 0, NULL); } else { return fetchpage_new(targetted, url, 1, 1); } } else { /* Nothing was found with that name, so create a new window */ /* with the given target name instead. */ if (appnddata) { return fetchpage_new_add(parent, url, 1, 1, appnddata, 1, target); } else { RetError(windows_create_browser(url, NULL, NULL, target, Windows_CreateBrowser_Normal)); RetError(browser_inherit(parent, last_browser)); return NULL; } } } /* Now the untargetted case - open in the parent */ else { if (appnddata) return fetchpage_new_add(parent, url, 1, 1, appnddata, 0, NULL); else return fetchpage_new(parent, url, 1, 1); } } } /*************************************************/ /* fetchpage_process_internal() */ /* */ /* Some internal URLs involve just substituting */ /* the internal URL for some known or easily */ /* discoverable alternative early in the fetch */ /* stage. This function handles such changes. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the fetch. */ /*************************************************/ static _kernel_oserror * fetchpage_process_internal(browser_data * b) { if ( b->displayed == Display_Recovered_Page || b->displayed == Display_Home_Page || b->displayed == Display_Embedded_URL ) { char alt_url[Limits_URL]; memset(alt_url, 0, sizeof(alt_url)); if (b->displayed == Display_Recovered_Page) { /* For a recovered page, try to get back to the page detailed */ /* in Browse$PreviousPage. */ /* */ /* If the variable is unset / can't be read, can't load a page */ /* so set the buffer to hold a null string. */ /* */ /* The call is quivalent to getenv, but the RISC OS */ /* implementation evaluates the system variable as an */ /* expression which we don't want; hence the direct use of the */ /* SWI call. */ if ( _swix(OS_ReadVarVal, _INR(0,4), "Browse$PreviousPage", alt_url, sizeof(alt_url), 0, 4) ) *alt_url = 0; } else if (b->displayed == Display_Embedded_URL) { char * fetch = url_buffer; if (!fetch) fetch = ""; /* There may be a specific URL embedded in the item */ strncpy(alt_url, fetch, sizeof(alt_url) - 1); alt_url[sizeof(alt_url) - 1] = 0; /* Find the URL fragment */ fetch = strstr(alt_url, "?url="); if (!fetch) *alt_url = 0; else { char * copy = alt_url; fetch += sizeof("?url=") - 1; /* Copy the URL to the start of the buffer, */ /* unescaping any escaped characters. */ while (*fetch) { if (*fetch == '%' && *(fetch + 1) && *(fetch + 2)) { char number[3]; number[0] = *(fetch + 1); number[1] = *(fetch + 2); number[2] = '\0'; *(copy ++) = (char) strtoul(number, NULL, 16); fetch += 3; } else *(copy ++) = *(fetch ++); } *copy = '\0'; } } else { /* Alternatively, get the Home Page URL */ urlutils_create_home_url(alt_url, sizeof(alt_url)); } /* Ensure the URL is terminated */ alt_url[sizeof(alt_url) - 1] = 0; /* Reallocate URL buffer space */ if (url_buffer) { #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_process_internal): \0212%d\0217\n",malloccount); #endif free(url_buffer); } url_buffer = malloc(strlen(alt_url) + 128); if (!url_buffer) return make_no_fetch_memory_error(10); #ifdef TRACE malloccount += (strlen(alt_url) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_process_internal): \0211%d\0217\n",malloccount); #endif /* Copy the new URL into the buffer */ strcpy(url_buffer, alt_url); } return NULL; } /*************************************************/ /* fetchpage_preprocessed() */ /* */ /* Fetches a URL, which must be in the */ /* 'url_buffer' malloced block of memory. */ /* Intended to be called from functions such */ /* as fetchpage_new or fetchpage_new_add. */ /* */ /* If using the URI handler, the URL will be */ /* sent through that and won't actually fetch */ /* at this stage, therefore. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to which the new URL refers; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0; */ /* */ /* 1 to stop other page fetches in */ /* any other frames related to this */ /* document, 0 to only stop those in */ /* this frame. */ /*************************************************/ static _kernel_oserror * fetchpage_preprocessed(browser_data * b, int record, int stop) { _kernel_oserror * e; if ( !b->save_link && !b->post_data && /* Must do the fetch even if we could just jump to a named anchor, if a POST */ !b->reloading && /* form is being sent or if we're deliberately force reloading something. */ browser_display_local_reference(b, url_buffer, browser_current_url(b)) ) { // Huh? This just causes redraw glitches... Why was it ever put here? // // if (choices.keyboard_ctrl) browser_move_selection(b, akbd_RightK); return NULL; } /* Last chance to modify any passing URLs... */ if (!strcmp(url_buffer, AboutMethod)) { char * alt_url = Internal_URL ForAbout AboutMethod AboutMethod; /* (sic) */ #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_preprocessed): \0212%d\0217\n",malloccount); #endif free(url_buffer); url_buffer = malloc(strlen(alt_url) + 128); if (!url_buffer) return make_no_fetch_memory_error(10); #ifdef TRACE malloccount += (strlen(alt_url) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_preprocessed): \0211%d\0217\n",malloccount); #endif /* Copy the new URL into the buffer */ strcpy(url_buffer, alt_url); } /* Only cancel stuff if we're allowed to */ if (b->allow_cancel) { e = fetch_cancel(b); if (e) return e; /* If required, stop all fetching in all frames, else leave */ /* images but stop everything else. Note that we don't */ /* touch file fetching - clicking on links will allow those */ /* to continue, so several frames in a frameset could fetch */ /* to a file simultaneously (the progress display in the */ /* status bar is aware of this, and will alter its display */ /* appropriately). */ if (stop) { if (controls.brick_wall) frames_abort_fetching(utils_ancestor(b), 1, 0); else frames_abort_fetching(utils_ancestor(b), 0, 0); } } /* Set the allow_cancel flag back to 1 for future fetches */ b->allow_cancel = 1; /* Set the displayed type for internal / normal URLs, and */ /* carry out any required special actions for the former. */ if (!b->save_link) { /* Before we reset the display type, check if we're displaying */ /* a temporary file. If so, force the 'record' flag off, as */ /* there's no way this can make a meaningful History entry. */ if (b->displayed == Display_Scrap_File) record = 0; /* Right, now go ahead and set the display type */ urlutils_set_displayed(b, url_buffer); if (b->displayed == Display_Previous_Page) return history_fetch_backwards(b, 0); if (b->displayed == Display_Next_Page) return history_fetch_forwards(b, 0); if (b->displayed == Display_Reloaded_Page) { IdBlock id; id.ancestor_id = b->self_id; handle_reload(0, NULL, &id, NULL); return NULL; } } e = fetchpage_process_internal(b); if (e) return e; /* If merging the URL writable and status display, put */ /* it back to status. */ if (b->merged_url) { toolbars_merged_to_status(b, toolbars_get_upper(b)); browser_give_general_focus(b); } if (uri_module_present && strncmp(url_buffer, Internal_URL, Int_URL_Len)) { /* Send the URL through the URI handler if the module is present */ /* and the URL isn't an internal one. */ return urlutils_dispatch(b, url_buffer, record ? URIQueue_RecordInHistory : 0); } else { /* Without the URI handler, deal with the URL immediately */ return fetchpage_postprocessed(b, record); } } /*************************************************/ /* fetchpage_postprocessed() */ /* */ /* Working end to fetchpage_preprocessed, which */ /* will fetch the url in the url_buffer block. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to which the new URL refers; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0. */ /*************************************************/ static _kernel_oserror * fetchpage_postprocessed(browser_data * b, int record) { _kernel_oserror * e; #ifdef TRACE if (tl & (1u<<12)) Printf("fetchpage_postprocessed: Chunk CK_FURL set to %d\n",strlen(url_buffer) + 128); #endif e = memory_set_chunk_size(b, NULL, CK_FURL, strlen(url_buffer) + 128); if (e) return e; strcpy(b->urlfdata, url_buffer); /* Make sure the URL bar is updated with the current URL. */ toolbars_update_url(b); /* Set the fetch status */ b->fetch_status = BS_START; /* Sort out the reloading flag */ if (b->reload_lock) b->reload_lock = 0; else b->reloading = 0; /* Record the start of the fetch, for a parent browser window. */ if (!b->ancestor) { _swix(OS_SetVarVal, _INR(0,4), "Browse$CurrentFetch", url_buffer, strlen(url_buffer), 0, 4); } /* Register event handlers to start off the new fetch */ if (!b->fetch_handler) fetchpage_claim_nulls(b); return NULL; } /*************************************************/ /* fetchpage_postprocess_uri() */ /* */ /* If the URI handler comes back with a */ /* URI_MProcess message and we can handle the */ /* URI it details, then that URI may be fetched */ /* through this function - it is first copied */ /* locally and then passed over to */ /* fetchpage_postprocessed. */ /* */ /* Parameters: Pointer to a browser_data */ /* struct relevant to the URI; */ /* */ /* Pointer to the URI string; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0. */ /*************************************************/ _kernel_oserror * fetchpage_postprocess_uri(browser_data * b, char * uri, int record) { /* Reallocate URL buffer space */ if (url_buffer) { #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_postprocess_uri): \0212%d\0217\n",malloccount); #endif free(url_buffer); } url_buffer = malloc(strlen(uri) + 128); if (!url_buffer) return make_no_fetch_memory_error(14); #ifdef TRACE malloccount += (strlen(uri) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_postprocess_uri): \0211%d\0217\n",malloccount); #endif /* Copy the URI over and fetch it */ strcpy(url_buffer, uri); return fetchpage_postprocessed(b, record); } /*************************************************/ /* fetchpage_new() */ /* */ /* Cancels any old fetch and starts a new one */ /* the given URL. */ /* */ /* The URL is copied to a malloc buffer before */ /* being used, so the pointer to it can be from */ /* pretty much anything (though beware of flex */ /* blocks shifting over the actual function call */ /* boundary...). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to which the new URL refers; */ /* */ /* Pointer to the new URL string; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0; */ /* */ /* 1 to stop other page fetches in */ /* any other frames related to this */ /* document, 0 to only stop those in */ /* this frame. */ /*************************************************/ _kernel_oserror * fetchpage_new(browser_data * b, const char * url, int record, int stop) { /* Don't proceed unless there's something to fetch */ if (!url || !(*url)) return fetch_cancel(b); /* The URL may have been passed in from the 'tokens' buffer, */ /* and fetch cancels etc. might corrupt it. So take a copy */ /* of it before proceeding further, if the URL didn't come */ /* from this buffer already...! */ if (url != url_buffer) { if (url_buffer) { #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new): \0212%d\0217\n",malloccount); #endif free(url_buffer); } url_buffer = malloc(strlen(url) + 128); if (!url_buffer) return make_no_fetch_memory_error(7); #ifdef TRACE malloccount += (strlen(url) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new): \0211%d\0217\n",malloccount); #endif strcpy(url_buffer, url); } #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "Used same buffer in fetchpage_new!"); show_error_ret(&erb); } #endif urlutils_fix_url(url_buffer, strlen(url_buffer) + 128); return fetchpage_preprocessed(b, record, stop); } /*************************************************/ /* fetchpage_new_add() */ /* */ /* As fetchpage_new, but takes a second string, */ /* which is data to be concatenated onto the end */ /* of the given URL. This may be useful for */ /* image maps or forms data. You may also */ /* specify whether this URL is to be fetched in */ /* a new browser window or not. */ /* */ /* Restrictions as for fetchpage_new. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to which the new URL refers; */ /* */ /* Pointer to the new URL string; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0; */ /* */ /* 1 to stop other page fetches in */ /* any other frames related to this */ /* document, 0 to only stop those in */ /* this frame; */ /* */ /* Pointer to the data to add onto */ /* the end of the URL string; */ /* */ /* 1 to fetch the URL in a new */ /* window, else 0; */ /* */ /* If opening in a new window, */ /* pointer to the window name (if */ /* wanted), or NULL. */ /*************************************************/ _kernel_oserror * fetchpage_new_add(browser_data * b, const char * url, int record, int stop, const char * add, int new_window, const char * name) { /* Don't proceed unless there's something to fetch */ if (!url) return fetch_cancel(b); /* The URL may have been passed in from the 'tokens' buffer, */ /* and fetch cancels etc. might corrupt it. So take a copy */ /* of it before proceeding further, if the URL didn't come */ /* from this buffer already. */ if (url != url_buffer) { if (url_buffer) { #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new_add): \0212%d\0217\n",malloccount); #endif free(url_buffer); } url_buffer = malloc(strlen(url) + strlen(add) + 128); if (!url_buffer) return make_no_fetch_memory_error(7); #ifdef TRACE malloccount += (strlen(url) + strlen(add) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new_add): \0211%d\0217\n",malloccount); #endif strcpy(url_buffer, url); strcat(url_buffer, add); } #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "Used same buffer in fetchpage_new_add!"); show_error_ret(&erb); } #endif urlutils_fix_url(url_buffer, strlen(url_buffer) + 128); if (!new_window || b->full_screen) return fetchpage_preprocessed(b, record, stop); else { RetError(windows_create_browser(url_buffer, NULL, NULL, name, Windows_CreateBrowser_Normal)); RetError(browser_inherit(b, last_browser)); return NULL; } } /*************************************************/ /* fetchpage_new_raw() */ /* */ /* Starts a fetch of a given URL, without doing */ /* anything to that URL at all except copying it */ /* over to a malloc buffer (to ensure it doesn't */ /* move around, as it would in a flex block). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to which the new URL refers; */ /* */ /* Pointer to the new URL string; */ /* */ /* 1 to record the previous URL in */ /* the history list, else 0; */ /* */ /* 1 to stop other page fetches in */ /* any other frames related to this */ /* document, 0 to only stop those in */ /* this frame. */ /*************************************************/ _kernel_oserror * fetchpage_new_raw(browser_data * b, const char * url, int record, int stop) { /* Don't proceed unless there's something to fetch */ if (!url || !(*url)) return fetch_cancel(b); /* The URL may have been passed in from the 'tokens' buffer, */ /* and fetch cancels etc. might corrupt it. So take a copy */ /* of it before proceeding further, if the URL didn't come */ /* from this buffer already...! */ if (url != url_buffer) { if (url_buffer) { #ifdef TRACE malloccount -= strlen(url_buffer) + 128; if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new_raw): \0212%d\0217\n",malloccount); #endif free(url_buffer); } url_buffer = malloc(strlen(url) + 128); if (!url_buffer) return make_no_fetch_memory_error(7); #ifdef TRACE malloccount += (strlen(url) + 128); if (tl & (1u<<13)) Printf("** malloccount (fetchpage_new_raw): \0211%d\0217\n",malloccount); #endif strcpy(url_buffer, url); } #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "Used same buffer in fetchpage_new_raw!"); show_error_ret(&erb); } #endif return fetchpage_preprocessed(b, record, stop); } /*************************************************/ /* fetchpage_claim_nulls() */ /* */ /* Installs the relevant null event handlers so */ /* that a fetch may proceed in the Desktop. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the fetch. */ /*************************************************/ void fetchpage_claim_nulls(browser_data * b) { /* Don't register the same handler twice... */ if (!b->fetch_handler) { register_null_claimant(Wimp_ENull,(WimpEventHandler *) fetchpage_fetch,b); b->fetch_handler = 1; } /* Animations only apply to an ancestor window, not frames */ b = utils_ancestor(b); /* If the 'drift' handler, to advance the animation to the */ /* first frame and then stop, is active, remove it as the */ /* full-time animation handler is about to take over. */ if (b->anim_drift) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation_drift,b); b->anim_drift = 0; } /* Register the full time animation handler */ if (!b->anim_handler && !b->plugin_active) { /* Is there an appropriate gadget in the status bar? */ ObjectId lower = toolbars_get_lower(b); BBox box; if (!gadget_get_bbox(0, lower, StatusBarAnimAnim, &box)) { /* Yes, so install an animation handler. */ register_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation,b); b->anim_handler = 1; } } /* Update the button bar */ toolbars_set_button_states(b); /* Record the usage of the animation handler. This will increment */ /* once in the ancestor object for every child fetch, so that */ /* the animation handler can finally be released when all the */ /* child fetches have stopped. */ b->current_fetches++; } /*************************************************/ /* fetchpage_release_nulls() */ /* */ /* Releases all relevant null event handlers */ /* used for a fetch in the Desktop, *EXCEPT* for */ /* an animation drift handler, which, if the */ /* Controls dictate it, will be installed. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the fetch. */ /*************************************************/ void fetchpage_release_nulls(browser_data * b) { /* Don't register the same handler twice... */ if (b->fetch_handler) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) fetchpage_fetch,b); b->fetch_handler = 0; } /* Animations only apply to an ancestor window, not frames */ b = utils_ancestor(b); /* Only remove the handlers if there are no fetches in any */ /* children, etc. (see fetchpage_claim_nulls comments). */ b->current_fetches--; if (!b->current_fetches) { /* Deregister the full time animation handler */ if (b->anim_handler && !b->plugin_active) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation,b); b->anim_handler = 0; } /* If the Controls say to install the 'drift' handler to ensure */ /* the animation finishes on the first frame, and that handler is */ /* not already installed, install it. */ if (controls.anim_drift && !b->anim_drift && !b->plugin_active) { register_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation_drift,b); b->anim_drift = 1; } } /* Update the button bar */ toolbars_set_button_states(b); }