/* 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 : Save.c */ /* */ /* Purpose: Save functions for the browser. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 04-Dec-96: Created. */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "swis.h" #include "flex.h" #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "window.h" #include "menu.h" #include "saveas.h" #include "svcprint.h" #include "Global.h" #include "Utils.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "Filetypes.h" #include "Hotlist.h" #include "Protocols.h" #include "URLutils.h" #include "Save.h" /*************************************************/ /* save_save_source() */ /* */ /* Saves the document source for a given browser */ /* to the given path, setting the filetype as */ /* HTML or text as appropriate. */ /* */ /* Parameters: Pointer to a null-terminated */ /* pathname to save to; */ /* */ /* Pointer to a browser_data struct */ /* owning the source to save. */ /*************************************************/ _kernel_oserror * save_save_source(char * path, browser_data * b) { _kernel_oserror * e; /* Sanity checks */ if (!b || !b->source || !path || !*path) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_save_source: %p, %p (source %p)", path, b, b ? b->source : NULL); return &erb; #else return NULL; #endif } /* Save the file - lock flex heap to ensure save transfer */ flex_set_budge(0); e = _swix(OS_File, _INR(0,2) | _INR(4,5), 10, /* Save block of memory as a typed file */ path, b->page_is_text ? FileType_TEXT : FileType_HTML, b->source, ((char *) b->source) + flex_size((flex_ptr) &b->source)); /* Unlock flex */ flex_set_budge(1); return e; } /*************************************************/ /* save_transfer_source() */ /* */ /* Save a browser's page source as an HTML file, */ /* through a RAM transfer buffer with */ /* Wimp_TransferBlock. */ /* */ /* Intended to be called as a response to a */ /* Message_RAMFetch from another task. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the document source; */ /* */ /* Pointer to an int, in which the */ /* amount of data transferred so */ /* far should be stored on entry; */ /* */ /* Pointer to the WimpMessage struct */ /* corresponding to the */ /* Message_RAMFetch that led to this */ /* function being called. */ /* */ /* Returns: The contents of the int holding */ /* the amount of data transferred */ /* prior to the function call are */ /* updated with the new amount */ /* transferred. Callers should use */ /* this in any future calls, and it */ /* *must* be checked for a value of */ /* -1, which indicates the transfer */ /* is complete (so any tidying up */ /* should be done if there is an */ /* error returned, or if the int is */ /* filled in with a value of -1). */ /* */ /* Assumes: The various pointers may be NULL, */ /* though if they are the function */ /* does nothing (it just exits). */ /*************************************************/ _kernel_oserror * save_transfer_source(browser_data * b, int * transferred, WimpMessage * m) { _kernel_oserror * e = NULL; int size = save_source_size(b); int left; int write; /* Sanity check */ if (!b || !b->source || !transferred || !m) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_transfer_source: %p (source %p), %p, %p", b, b ? b->source : NULL, transferred, m); return &erb; #else return NULL; #endif } left = size - *transferred; /* If we have data to transfer, do so */ if (left >= 0) { /* Use either the buffer size, or the bytes left, whichever */ /* is the smallest. */ write = left > m->data.ram_fetch.buffer_size ? m->data.ram_fetch.buffer_size : left; if (write) { /* Transfer the data - must lock the flex heap for the */ /* duration of this... */ flex_set_budge(0); e = wimp_transfer_block(task_handle, (char *) b->source + (*transferred), m->hdr.sender, m->data.ram_fetch.buffer, write); /* Unlock flex and report any errors */ flex_set_budge(1); if (e) return e; } /* If we have any data left to send, reply with a Message_RAMTransmit */ e = protocols_atats_send_ram_transmit(m, write, write < m->data.ram_fetch.buffer_size); /* Increment the transferred counter */ *transferred += write; left -= write; } /* Finished */ return e; } /*************************************************/ /* save_source_size() */ /* */ /* Returns the size that a given HTML source */ /* document would take on disc. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* owning the source to save. */ /* */ /* Returns: Size the file will be. */ /*************************************************/ int save_source_size(browser_data * b) { /* Sanity check */ if (!b || !b->source) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_source_size: %p (source %p)", b, b ? b->source : NULL); show_error_ret(&erb); #endif return 0; } /* For now this is trivially simple, but in future it */ /* could take account of, for example, inserting a */ /* <BASE> tag into the document. */ return flex_size((flex_ptr) &b->source); } /*************************************************/ /* save_save_object() */ /* */ /* Called when a fetch is to be spooled to disc. */ /* Handles saving as much data as is already */ /* fetched, and setting the relevant parts of */ /* the given browser_data structure up with the */ /* output file details. */ /* */ /* Parameters: Pointer to a null-terminated */ /* pathname to save to; */ /* */ /* Pointer to a browser_data struct */ /* relevant to the object to save. */ /*************************************************/ _kernel_oserror * save_save_object(char * path, browser_data * b) { /* Sanity check */ if (!b || !path || !*path) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_save_object: %p, %p", path, b); return &erb; #else return NULL; #endif } /* If using a small fetch window, set the title to the save pathname */ if (b->small_fetch) { char title[Limits_Title]; StrNCpy0(title, path); /* Don't treat any errors here as fatal */ show_error_ret(window_set_title(0, b->self_id, title)); } /* Open the file */ b->save_file = fopen(path, "wb"); if (!b->save_file) { fetch_stop(b, 0); RetLastE; } else if (b->source) { int bytes; /* Set the filetype to DEADDEAD, to represent an incomplete */ /* file (particularly good on later Filers, which display */ /* a special sprite for this). */ _swix(OS_File, _INR(0,2), 2, /* Set load address */ path, 0xdeaddead); _swix(OS_File, _INR(0,1) | _IN(3), 3, /* Set exec address */ path, 0xdeaddead); /* Any data in the source store represents already */ /* fetched bits of the file. Must lock flex down */ /* over the save to make sure the heap doesn't */ /* shift over the call to fwrite. */ flex_set_budge(0); bytes = fwrite(b->source, 1, flex_size((flex_ptr) &b->source), b->save_file); flex_set_budge(1); /* If we didn't transfer as much as we expected, complain */ if (bytes != flex_size((flex_ptr) &b->source)) { /* Report any errors */ fetch_stop(b, 0); RetLastE; } else { /* Otherwise, get rid of the data in the source store */ /* as it's been written to the file. */ flex_free((flex_ptr) &b->source); b->source = NULL; } } return NULL; } /*************************************************/ /* save_object_size() */ /* */ /* Returns the estimated size that a given */ /* object will be after being spooled through */ /* the fetcher. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the object to save. */ /* */ /* Returns: *Estimated* size of the object. */ /*************************************************/ int save_object_size(browser_data * b) { /* For now, we just don't know this information... */ return 4096; } /*************************************************/ /* save_save_uri() */ /* */ /* Save the contents of a link as a URI file. */ /* */ /* Parameters: Pointer to a null-terminated */ /* pathname to save to; */ /* */ /* Pointer to the URL to save; */ /* */ /* 0 to save as a URI file, else */ /* save as a non-terminated string */ /* with type FileType_URL (ANT */ /* suite URL file). */ /*************************************************/ _kernel_oserror * save_save_uri(char * path, char * url, int write_url) { _kernel_oserror * e = NULL; FILE * file; /* Sanity check */ if (!path || !*path || !url || !*url) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_save_uri: %p, %p, %d", path, url, write_url); return &erb; #else return NULL; #endif } /* Try and open the file */ file = fopen(path, "wb"); if (!file) RetLastE; /* Write the contents */ if (!write_url) { /* URI file */ if ( fprintf(file, "URI\t100\r\t# %s v", lookup_token("_TaskName",1,0)) < 0 ) e = _kernel_last_oserror(), erb = *e; else if ( fprintf(file, "%s\r\r\t%s", lookup_token("Version:(Unknown!)",0,0), url) < 0 ) e = _kernel_last_oserror(), erb = *e; } else { /* URL file */ if (fprintf(file, url) < 0) e = _kernel_last_oserror(), erb = *e; } /* Close the file and return any error that may have */ /* happened during the file writing stage */ fclose(file); if (e) return &erb; /* Exit via. setting the filetype */ return _swix(OS_File, _INR(0,2), 18, /* Set type of named object */ path, write_url ? FileType_URL : FileType_URI); } /*************************************************/ /* save_transfer_uri() */ /* */ /* Save the contents of a link as a URI file, */ /* through a RAM transfer buffer with */ /* Wimp_TransferBlock. */ /* */ /* Intended to be called as a response to a */ /* Message_RAMFetch from another task. */ /* */ /* Parameters: Pointer to the URL to save; */ /* */ /* 0 to save as a URI file, else */ /* save as a non-terminated string */ /* with type FileType_URL (ANT */ /* suite URL file); */ /* */ /* Pointer to an int, in which the */ /* amount of data transferred so */ /* far should be stored on entry; */ /* */ /* Pointer to the WimpMessage struct */ /* corresponding to the */ /* Message_RAMFetch that led to this */ /* function being called. */ /* */ /* Returns: The contents of the int holding */ /* the amount of data transferred */ /* prior to the function call are */ /* updated with the new amount */ /* transferred. Callers should use */ /* this in any future calls, and it */ /* *must* be checked for a value of */ /* -1, which indicates the transfer */ /* is complete (so any tidying up */ /* should be done if there is an */ /* error returned, or if the int is */ /* filled in with a value of -1). */ /* */ /* Assumes: The various pointers may be NULL, */ /* though if they are the function */ /* does nothing (it just exits). */ /*************************************************/ _kernel_oserror * save_transfer_uri(char * url, int write_url, int * transferred, WimpMessage * m) { _kernel_oserror * e = NULL; char * uri_file = NULL; int size = save_uri_size(url, write_url); int left; int write; /* Sanity check */ if (!url || !*url || !transferred || !m) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_transfer_uri: %p, %d, %p, %p", url, write_url, transferred, m); return &erb; #else return NULL; #endif } left = size - *transferred; /* Each time the function is called, rebuild the URI file in a */ /* temporary buffer. */ if (size > 0 && left > 0) { uri_file = malloc(size + 1); /* + 1 to account for terminators */ if (!uri_file) { e = make_no_memory_error(10); goto save_transfer_uri_exit; } /* Build the URI or URL file */ if (!write_url) { int written; /* URI file */ written = sprintf(uri_file, "URI\t100\r\t# %s v", lookup_token("_TaskName",1,0)); sprintf(uri_file + written, "%s\r\r\t%s", lookup_token("Version:(Unknown!)",0,0), url); } else { /* URL file */ strcpy(uri_file, url); } } /* If we have data to transfer, do so */ if (left >= 0) { /* Use either the buffer size, or the bytes left, whichever */ /* is the smallest. */ write = left > m->data.ram_fetch.buffer_size ? m->data.ram_fetch.buffer_size : left; if (write) { /* Transfer the data */ e = wimp_transfer_block(task_handle, uri_file + (*transferred), m->hdr.sender, m->data.ram_fetch.buffer, write); if (e) goto save_transfer_uri_exit; } /* If we have any data left to send, reply with a Message_RAMTransmit */ e = protocols_atats_send_ram_transmit(m, write, write < m->data.ram_fetch.buffer_size); /* Increment the transferred counter */ *transferred += write; left -= write; } /* Finished */ save_transfer_uri_exit: /* Free the URI file buffer, if we claimed one */ if (uri_file) free (uri_file); return e; } /*************************************************/ /* save_uri_size() */ /* */ /* Returns the size, in bytes, that a URI or URL */ /* file will be. */ /* */ /* Parameters: Pointer to the URL that would be */ /* saved; */ /* */ /* 0 to find the length of a URI */ /* file, 1 to find the length of a */ /* URL file (as in save_save_uri). */ /* */ /* Returns: The size, in bytes, that the file */ /* will be. */ /*************************************************/ int save_uri_size(char * url, int write_url) { int len = 0; /* Sanity check */ if (!url || !*url) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid parameters to save_uri_size: %p, %d", url, write_url); show_error_ret(&erb); #endif return 0; } if (!write_url) { /* URI file */ len = strlen("URI\t100\r\t# "); len += strlen(lookup_token("_TaskName",1,0)); len += strlen(" v"); len += strlen(lookup_token("Version:(Unknown!)",0,0)); len += strlen("\r\r\t"); len += strlen(url); } else { /* URL file */ len = strlen(url); /* (No terminator needed in URL files, so no '+ 1') */ } return len; }