/* 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 : Protocols.c */ /* */ /* Purpose: Handle some common protocol stuff, */ /* such as inter-application data */ /* transfer. */ /* */ /* Function naming convention is as usual */ /* a source leafname derived prefix, then */ /* a code based on the protocol being */ /* dealt with: */ /* */ /* _atats_ App To App Transfer, Save */ /* _atatl_ App To App Transfer, Load */ /* _pp_ Printer Protocol */ /* _auh_ Acorn URI Handler */ /* _ih_ Interactive Help */ /* _aub_ ANT URL Broadcast */ /* _multi_ Message is used in more than */ /* one message protocol scheme */ /* _util_ A utility function not */ /* directly connected with a */ /* specific protocol. */ /* */ /* This is followed by the direction, so */ /* to speak - i.e. '_got_' for got a */ /* message, '_send_' for sending a */ /* message. Alternatively, a prefix */ /* '_bounced' is used for messages which */ /* return as a UserMessage_Acknowledge */ /* event. */ /* */ /* Because the Plug-In message protocol */ /* is such a large and self-contained */ /* entity, this is kept separate, in */ /* PlugIn.c. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 29-Aug-97: Created. */ /* */ /* 06-Sep-97: Significant rewriting to */ /* stop various clashes and */ /* increase flexibility. */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "swis.h" #include "kernel.h" #include "URI.h" /* URI handler API, in URILib:h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "svcprint.h" #include "Global.h" #include "MiscDefs.h" #include "Utils.h" #include "Browser.h" #include "FetchPage.h" #include "Filetypes.h" #include "History.h" #include "Hotlist.h" #include "Images.h" #include "MimeMap.h" #include "Printing.h" #include "Save.h" #include "SaveDraw.h" #include "SaveFile.h" #include "SaveObject.h" #include "SaveText.h" #include "Toolbars.h" #include "URLutils.h" #include "Windows.h" #include "Protocols.h" /* Conditional includes */ #ifdef TRACE #include "Trace.h" #endif /* Local definitions */ #define RTB_Size 4096 /* RAM transfer buffer size, in bytes */ /* Local variables */ /* Need to retain information across function calls about the */ /* different processes going on. Since an object save could */ /* be in progress whilst other saves go on above it, all of */ /* the remembered items have to be independent. Consequently, */ /* a lot of separate statics are needed. */ /* View source - broadcast loading */ static int data_open_reference = 0; /* Saving the page source */ static int save_source_reference = 0; static int save_source_transmitted = 0; static browser_data * save_source_browser = NULL; /* Exporting the page as text */ static int save_as_text_reference = 0; static browser_data * save_as_text_browser = NULL; /* Exporting the page as Draw */ static int save_as_draw_reference = 0; static browser_data * save_as_draw_browser = NULL; static int save_as_draw_backgrounds = 0; /* Saving a link */ static int save_link_reference = 0; static int save_link_transmitted = 0; static browser_data * save_link_browser = NULL; static HStream * save_link_token = NULL; static int save_link_as_url = 0; /* Saving the current location */ static int save_location_reference = 0; static int save_location_transmitted = 0; static browser_data * save_location_browser = NULL; static int save_location_as_url = 0; #ifndef REMOTE_HOTLIST /* Saving a hotlist item */ static int save_hotlist_entry_reference = 0; static int save_hotlist_entry_transmitted = 0; static hotlist_item * save_hotlist_entry_item = NULL; static int save_hotlist_entry_as_url = 0; /* Saving a hotlist selection */ static int save_hotlist_selection_reference = 0; static int save_hotlist_selection_transmitted = 0; /* Saving the entire hotlist */ static int save_entire_hotlist_reference = 0; static int save_entire_hotlist_transmitted = 0; #endif /* Saving the History */ static int save_history_reference = 0; static browser_data * save_history_browser = NULL; /* Saving an object through the fetcher */ static int save_object_reference = 0; static int save_object_transmitted = 0; static browser_data * save_object_browser = NULL; static int save_object_through_scrap = 0; /* Exporting an image as a sprite */ static int save_image_reference = 0; static int save_image_transmitted = 0; static browser_data * save_image_browser = NULL; static HStream * save_image_token = NULL; static int save_image_as_original = 0; /* Loading data. For RAM transfer, buffers must be */ /* visible to all functions so they can be freed */ /* in the event of a transfer failure. */ static WimpMessage * pending_data_save_ack = NULL; static char * data_save_suggested_leafname = NULL; static void * rtb = NULL; static int ram_fetch_reference = 0; static char * ram_load_uri_buffer = NULL; static int ram_load_buffer_size = 0; static int ram_load_started = 0; /* Printing */ static int print_save_reference = 0; /* Static function prototypes */ static _kernel_oserror * protocols_atats_got_data_save_ack (WimpMessage * m); static _kernel_oserror * protocols_pp_got_data_save_ack (WimpMessage * m); static void protocols_util_update_reference (int old_ref, int new_ref); /*************************************************/ /* protocols_atats_send_data_open() */ /* */ /* Broadcasts a Message_DataOpen for the given */ /* filetype and given pathname. */ /* */ /* Parameters: The filetype to use; */ /* */ /* Pointer to a null-terminated */ /* pathname to use. */ /*************************************************/ _kernel_oserror * protocols_atats_send_data_open(int filetype, char * pathname) { WimpMessage dop; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_send_data_open: Called\n"); #endif /* Fill in the header */ dop.hdr.your_ref = 0; dop.hdr.action_code = Wimp_MDataOpen; /* Fill in the message body */ dop.data.data_open.window_handle = 0; dop.data.data_open.x = 0; dop.data.data_open.y = 0; dop.data.data_open.file_type = filetype; StrNCpy0(dop.data.data_open.path_name, pathname); dop.hdr.size = (int) WordAlign(strlen(dop.data.data_open.path_name) + 45); /* (44 for stuff up to the pathname, plus 1 for terminator) */ /* Send the message */ RetError(wimp_send_message(Wimp_EUserMessageRecorded, &dop, 0, 0, NULL)); /* Record my_ref in case it bounces */ data_open_reference = dop.hdr.my_ref; return NULL; } /*************************************************/ /* protocols_atats_data_open_bounced() */ /* */ /* For a View Source function, the browser */ /* broadcasts a Message_DataOpen. If this */ /* bounces, attempt to start an editor instead, */ /* with the pathname specified in the message. */ /* */ /* See PRM 3-265. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atats_data_open_bounced(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_data_open_bounced: Called\n"); #endif if (m->hdr.my_ref == data_open_reference) { _kernel_oserror * e; char * combuf; char * comstart = "If \"Alias$@RunType_FFF\" <> \"\" Then @RunType_FFF "; int len; data_open_reference = 0; /* Want to run '@RunType_FFF' with the given pathname as a parameter; */ /* need to assemble this command string. Work out how long it will be. */ len = strlen(comstart) + strlen(m->data.data_open.path_name) + 1; /* Allocate space for it (complain if this fails). */ combuf = malloc(len); if (!combuf) return make_no_memory_error(9); /* Assemble the string */ strcpy(combuf, comstart); strcat(combuf, m->data.data_open.path_name); /* Execute the command */ e = _swix(Wimp_StartTask, _IN(0), combuf); /* Free the command buffer and return the value the _swix call gave back */ free(combuf); combuf = NULL; return e; } #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Message reference %x not recognised in protocols_atats_data_open_bounced", m->hdr.your_ref); return &erb; } #endif return NULL; } /*************************************************/ /* protocols_atats_send_data_save() */ /* */ /* Send out a Message_DataSave to initiate */ /* saving of data to another applicaion. */ /* */ /* See PRM 3-250 to 3-252. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the save (or NULL); */ /* */ /* Pointer to an item that will vary */ /* depending on what is being saved */ /* - e.g. an HStream struct, a */ /* hotlist item, or NULL... full */ /* details by the definition of the */ /* protocols_saving enumeration in */ /* Protocols.h; */ /* */ /* Pointer to a null terminated */ /* leafname to use; */ /* */ /* If possible, the estimated size */ /* of the data, else -1; */ /* */ /* Filetype to quote; */ /* */ /* A protocols_saving value to say */ /* what is being saved (see */ /* Protocols.h); */ /* */ /* A WimpGetPointerInfo block */ /* pointer, from which the window */ /* and icon handle to send to, and */ /* x and y coords to send to, are */ /* read. */ /*************************************************/ _kernel_oserror * protocols_atats_send_data_save(browser_data * b, void * extra, char * leaf, int estimated_size, int filetype, protocols_saving saving, WimpGetPointerInfoBlock * info) { WimpMessage m; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_send_data_save: Called\n"); #endif /* Fill in the header */ m.hdr.sender = task_handle; m.hdr.your_ref = 0; m.hdr.action_code = Wimp_MDataSave; /* Fill in the message body */ m.data.data_save.destination_window = info->window_handle; m.data.data_save.destination_icon = info->icon_handle; m.data.data_save.destination_x = info->x; m.data.data_save.destination_y = info->y; m.data.data_save.estimated_size = estimated_size; m.data.data_save.file_type = filetype; /* Copy in the leafname and work out the message size */ StrNCpy0(m.data.data_save.leaf_name, leaf); m.hdr.size = (int) WordAlign(strlen(m.data.data_save.leaf_name) + 45); /* Send it */ RetError(wimp_send_message(Wimp_EUserMessage, &m, info->window_handle, info->icon_handle, NULL)); /* Remember various details */ switch (saving) { /* Save the document source */ case protocols_saving_document_source: { save_source_reference = m.hdr.my_ref; save_source_transmitted = 0; save_source_browser = b; } break; /* Export the document as text */ case protocols_saving_document_as_text: { save_as_text_reference = m.hdr.my_ref; save_as_text_browser = b; } break; /* Export the document as text */ case protocols_saving_document_as_draw: { save_as_draw_reference = m.hdr.my_ref; save_as_draw_browser = b; save_as_draw_backgrounds = savefile_alternative_selected(); } break; /* Save a link as a URI file */ case protocols_saving_link: { save_link_reference = m.hdr.my_ref; save_link_transmitted = 0; save_link_browser = b; save_link_token = (HStream *) extra; save_link_as_url = savefile_alternative_selected(); } break; /* Save the current location as a URI file */ case protocols_saving_frame_location: { save_location_reference = m.hdr.my_ref; save_location_transmitted = 0; save_location_browser = b; save_location_as_url = savefile_alternative_selected(); } break; #ifndef REMOTE_HOTLIST /* Save a hotlist item as a URI file */ case protocols_saving_hotlist_entry: { save_hotlist_entry_reference = m.hdr.my_ref; save_hotlist_entry_transmitted = 0; save_hotlist_entry_item = (hotlist_item *) extra; save_hotlist_entry_as_url = filetype == FileType_URI ? 0 : 1; } break; /* Save a selection of hotlist items as an HTML file */ case protocols_saving_hotlist_selection: { save_hotlist_selection_reference = m.hdr.my_ref; save_hotlist_selection_transmitted = 0; } break; /* Save the entire hotlist as an HTML file */ case protocols_saving_entire_hotlist: { save_entire_hotlist_reference = m.hdr.my_ref; save_entire_hotlist_transmitted = 0; } break; #endif /* Save an object through the fetcher */ case protocols_saving_object: { save_object_reference = m.hdr.my_ref; save_object_transmitted = 0; save_object_browser = b; save_object_through_scrap = 0; } break; /* Save an image as a sprite */ case protocols_saving_image_sprite: { save_image_reference = m.hdr.my_ref; save_image_transmitted = 0; save_image_browser = b; save_image_token = (HStream *) extra; save_image_as_original = savefile_alternative_selected(); } break; /* Saving the local or global history */ case protocols_saving_local_history: { save_history_reference = m.hdr.my_ref; save_history_browser = b; } break; case protocols_saving_global_history: { save_history_reference = m.hdr.my_ref; save_history_browser = NULL; } break; } /* Finished */ return NULL; } /*************************************************/ /* protocols_atats_data_save_bounced() */ /* */ /* Deals with a Message_DataSave bouncing. */ /* */ /* See PRM 3-252. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atats_data_save_bounced(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_data_save_bounced: Called\n"); #endif /* We have nothing to do here at present; this */ /* is only here to be complete. */ return NULL; } /*************************************************/ /* protocols_atats_got_ram_fetch() */ /* */ /* After the browser sends a Message_DataSave to */ /* an application, it may reply with */ /* Message_RAMFetch rather than */ /* Message_DataSaveAck if it can handle RAM */ /* transfer. In that case, we should see if we */ /* can do RAM transfer for this filetype */ /* ourselves, and if so, transfer data. */ /* */ /* See PRM 3-255 and 256. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the Message_RAMFetch. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atats_got_ram_fetch(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_got_ram_fetch: Called\n"); #endif /* Only the transfer methods by which RAM saving is currently */ /* supported are listed in the switch. For others, we just do */ /* nothing. The other application will see its message bounce */ /* and should send Message_DataSaveAck to continue the save */ /* through a temporary file on disc. If not, no loss - from */ /* the user's perspective, nothing will have happened. */ /* */ /* Note all the functions called in the switch statement call */ /* Protocols.c back again with requests to send a reply of */ /* Message_RAMTransmit if they're successful. */ /* */ /* Stop press. C can't cope - you can't have a non-constant */ /* in a case statement. Good grief. So, this nice elegant */ /* case statement gets degraded into a grotty if...else */ /* ladder. Yuk, yuk, yuk, yuk, yuk. I *hate* this language. */ if (m->hdr.your_ref && m->hdr.your_ref == save_source_reference) { /* Save document source */ if ( is_known_browser(save_source_browser) ) return save_transfer_source(save_source_browser, &save_source_transmitted, m); } else if (m->hdr.your_ref && m->hdr.your_ref == save_link_reference) { if (is_known_browser(save_link_browser)) { if (save_link_token) { /* Save a link as a URI file */ return save_transfer_uri(save_link_token->anchor, NULL, save_link_as_url, &save_link_transmitted, m); } else { /* Save the current location as a URI file */ char * url = browser_current_url (save_link_browser); char * title = browser_current_title(save_link_browser); if (!url) url = " "; return save_transfer_uri(url, title, save_link_as_url, &save_link_transmitted, m); } } } else if (m->hdr.your_ref && m->hdr.your_ref == save_location_reference) { /* Save the current location as a URI file */ if (is_known_browser(save_location_browser)) { char * title = browser_current_title(save_location_browser); return save_transfer_uri(browser_current_url(save_location_browser), title, save_location_as_url, &save_location_transmitted, m); } } #ifndef REMOTE_HOTLIST else if (m->hdr.your_ref && m->hdr.your_ref == save_hotlist_entry_reference) { /* Save a hotlist item as a URI file */ if ( save_hotlist_entry_item ) return save_transfer_uri(save_hotlist_entry_item->data.url, save_hotlist_entry_item->name, save_hotlist_entry_as_url, &save_hotlist_entry_transmitted, m); } #endif return NULL; } /*************************************************/ /* protocols_atats_send_ram_transmit() */ /* */ /* Send out a Message_RAMTransmit in response to */ /* a Message_RAMFetch from another application, */ /* as part of an ongoing dialogue for RAM */ /* transfer. */ /* */ /* See PRM 3-255 and 256. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the Message_RAMFetch. The */ /* contents will be modified and */ /* used in a reply; */ /* */ /* The number of bytes written to */ /* the buffer given in the */ /* Message_RAMFetch; */ /* */ /* 1 if this is the last message in */ /* the transfer (so it won't be sent */ /* UserMessageRecorded and raise an */ /* error when it doesn't get */ /* acknowledged...). */ /*************************************************/ _kernel_oserror * protocols_atats_send_ram_transmit(WimpMessage * m, int transmitted, int last) { int old_ref = m->hdr.your_ref; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_send_ram_transmit: Called\n"); #endif /* Fill in the parts that need changing */ m->hdr.your_ref = m->hdr.my_ref; m->hdr.action_code = Wimp_MRAMTransmit; m->data.ram_transmit.nbytes = transmitted; #ifdef TRACE /* Show the contents of the transmission buffer */ if (tl & (1u<<28)) { void * local = malloc(m->data.ram_transmit.nbytes); if (local) { if ( !wimp_transfer_block(m->hdr.sender, m->data.ram_transmit.buffer, task_handle, local, m->data.ram_transmit.nbytes) ) { trace_dump_buffer(m->data.ram_transmit.buffer, m->data.ram_transmit.nbytes, 1); } else Printf("\n(Cannot dump transmission buffer - error from Wimp_TransferBlock)\n\n"); } else { Printf("\n(Cannot dump transmission buffer - not enough memory for local copy)\n\n"); } } #endif /* Send the reply */ RetError(wimp_send_message(last ? Wimp_EUserMessage : Wimp_EUserMessageRecorded, m, m->hdr.sender, 0, NULL)); /* Update the records of my_ref for subsequent replies and bounces */ protocols_util_update_reference(old_ref, m->hdr.my_ref); /* If this is the last item, may need to do some tidying up */ /* (don't do this before sending the message, as here we */ /* close the menu tree - if the window we were sending to */ /* was in a menu... Well, things Go Wrong. */ if (last) { #ifndef REMOTE_HOTLIST if (m->hdr.my_ref == save_hotlist_entry_reference) RetError(hotlist_clear_selection()); #endif if ( m->hdr.my_ref == save_source_reference || m->hdr.my_ref == save_link_reference || m->hdr.my_ref == save_location_reference #ifndef REMOTE_HOTLIST || m->hdr.my_ref == save_hotlist_entry_reference #endif ) { _swix(Wimp_CreateMenu, _IN(1), -1); } } /* Finished */ return NULL; } /*************************************************/ /* protocols_atats_ram_transmit_bounced() */ /* */ /* If a RAMTransmit is not acknowledged, we */ /* should abort file transfer and raise an */ /* error. */ /* */ /* See PRM 3-255 and 256. */ /* */ /* Parameters Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atats_ram_transmit_bounced(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_ram_transmit_bounced: Called\n"); #endif /* There's no tidying up to do; just raise an error. */ erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("RecvDied:Data transfer failed - receiver died.", 0, 0)); return &erb; } /*************************************************/ /* protocols_atats_got_data_save_ack() */ /* */ /* Once we've sent out Message_DataSave we could */ /* get Message_RAMFetch back and proceed with */ /* RAM transfer. Or the other task could respond */ /* with a Message_DataSaveAck, for transfer via */ /* a temporary file on disc. This can also */ /* happen if the other application responds with */ /* a Message_RAMFetch but we decide we can't do */ /* RAM transfer for that particular object; */ /* the application sees its Message_RAMFetch */ /* bounce and drops back to Message_DataSaveAck */ /* instead. */ /* */ /* See PRM 3-250, 251 and 253. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ static _kernel_oserror * protocols_atats_got_data_save_ack(WimpMessage * m) { _kernel_oserror * e = NULL; int ok = 0; /* 0 = problem, 1 = OK, send DataLoad, 2 = OK, but don't send DataLoad */ char * path = m->data.data_save_ack.leaf_name; /* (Daft structure definition - it's a path, not a leaf...) */ #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_got_data_save_ack: Called\n"); #endif /* First, save the file. Yes, it's another nasty if...else ladder */ /* because C can't handle it as a switch statement... */ if (m->hdr.your_ref && m->hdr.your_ref == save_source_reference) { /* Save the document source */ if (is_known_browser(save_source_browser)) { e = save_save_source(path, save_source_browser); if (!e) ok = 1; } } else if (m->hdr.your_ref && m->hdr.your_ref == save_as_text_reference) { /* Export the document as text */ if (is_known_browser(save_as_text_browser)) { e = savetext_save_text(save_as_text_browser, path); if (!e) ok = 1; } } else if (m->hdr.your_ref && m->hdr.your_ref == save_as_draw_reference) { /* Export the document as Draw */ if (is_known_browser(save_as_draw_browser)) { e = savedraw_save_draw(save_as_draw_browser, path, save_as_draw_backgrounds); if (!e) ok = 1; } } else if (m->hdr.your_ref && m->hdr.your_ref == save_link_reference) { if (is_known_browser(save_link_browser)) { if (save_link_token) { /* Save a link as a URI file */ e = save_save_uri(path, save_link_token->anchor, NULL, save_link_as_url); if (!e) ok = 1; } else { char * url = browser_current_url (save_link_browser); char * title = browser_current_title(save_link_browser); /* Save the current location as a URI file */ if (!url) url = " "; e = save_save_uri(path, url, title, 0); if (!e) ok = 1; } } } else if (m->hdr.your_ref && m->hdr.your_ref == save_location_reference) { /* Save the current location as a URI file */ if (is_known_browser(save_location_browser)) { char * title = browser_current_title(save_location_browser); e = save_save_uri(path, browser_current_url(save_location_browser), title, save_location_as_url); if (!e) ok = 1; } } #ifndef REMOTE_HOTLIST else if (m->hdr.your_ref && m->hdr.your_ref == save_hotlist_entry_reference) { /* Save a hotlist item as a URI file */ if (save_hotlist_entry_item) { e = save_save_uri(path, save_hotlist_entry_item->data.url, save_hotlist_entry_item->name, save_hotlist_entry_as_url); if (!e) { ok = 1; e = hotlist_clear_selection(); } } } else if (m->hdr.your_ref && m->hdr.your_ref == save_hotlist_selection_reference) { /* Save a hotlist selection as an HTML file */ e = hotlist_save_hotlist(path, NULL, 1); if (!e) { ok = 1; e = hotlist_clear_selection(); } } else if (m->hdr.your_ref && m->hdr.your_ref == save_entire_hotlist_reference) { /* Save the whole hotlist */ e = hotlist_save_hotlist(path, NULL, 0); if (!e) ok = 1; } #endif else if (m->hdr.your_ref && m->hdr.your_ref == save_history_reference) { /* Save the local or global history */ if (is_known_browser(save_history_browser)) { e = history_save_as_html(path, save_history_browser); if (!e) ok = 1; } else { e = history_save_as_html(path, NULL); if (!e) ok = 1; } } else if (m->hdr.your_ref && m->hdr.your_ref == save_object_reference) { if (is_known_browser(save_object_browser)) { /* First, hide the Save Object dialogue */ e = saveobject_close(save_object_browser); if (!e) { /* If this is through scrap, use a different filename */ if (m->data.data_save_ack.estimated_size == -1) { /* Need to store the Message_DataLoad for later */ save_object_browser->pending_data_load = malloc(sizeof(WimpMessage)); if (!save_object_browser->pending_data_load) return make_no_memory_error(13); #ifdef TRACE malloccount += sizeof(WimpMessage); if (tl & (1u<<13)) Printf("** malloccount (protocols_atats_got_data_save_ack): \0211%d\0217\n",malloccount); #endif *save_object_browser->pending_data_load = *m; /* Change the filename to something unique and */ /* update the message length */ protocols_util_make_unique_name(save_object_browser->pending_data_load->data.data_load.leaf_name, sizeof(save_object_browser->pending_data_load->data.data_load.leaf_name)); save_object_browser->pending_data_load->hdr.size = (int) WordAlign(strlen(save_object_browser->pending_data_load->data.data_load.leaf_name) + 45); /* Exit through the save routine */ return save_save_object(save_object_browser->pending_data_load->data.data_load.leaf_name, save_object_browser); } /* Otherwise, save as normal */ else { e = save_save_object(path, save_object_browser); if (!e) ok = 1; } } } } else if (m->hdr.your_ref && m->hdr.your_ref == save_image_reference) { if (is_known_browser(save_image_browser)) { if (!save_image_as_original) { /* Save as a sprite */ e = image_export_sprite(path, save_image_browser, save_image_token); if (!e) ok = 1; } else { /* Save original image - similar to Save Object code. So, */ /* if this is through scrap, use a different filename. */ if (m->data.data_save_ack.estimated_size == -1) { WimpMessage * pending; /* Need to store the Message_DataLoad for later */ pending = malloc(sizeof(WimpMessage)); if (!pending) return make_no_memory_error(13); #ifdef TRACE malloccount += sizeof(WimpMessage); if (tl & (1u<<13)) Printf("** malloccount (protocols_atats_got_data_save_ack): \0211%d\0217\n",malloccount); #endif *pending = *m; /* Change the filename to something unique and */ /* update the message length */ protocols_util_make_unique_name(pending->data.data_load.leaf_name, sizeof(pending->data.data_load.leaf_name)); pending->hdr.size = (int) WordAlign(strlen(pending->data.data_load.leaf_name) + 45); /* Exit through the save routine */ e = image_export_original(pending->data.data_load.leaf_name, save_image_browser, save_image_token); if (!e) { save_image_browser = last_browser; save_image_browser->pending_data_load = pending; ok = 2; } } /* Otherwise, save as normal */ else { e = image_export_original(path, save_image_browser, save_image_token); if (!e) { save_image_browser = last_browser; ok = 2; } } } } } /* If everything is OK, send out a Message_DataLoad in reply */ if (ok && !e) { if (ok == 1) e = protocols_atats_send_data_load(m); /* Don't close the menu before sending the message, as if the item we are */ /* sending to is within a menu tree, an Illegal Window Handle error may */ /* be raised. */ _swix(Wimp_CreateMenu, _IN(1), -1); } /* Finished */ return e; } /*************************************************/ /* protocols_atats_send_data_load() */ /* */ /* Send out a Message_DataLoad in response to a */ /* Message_DataSaveAck from another application, */ /* as part of an ongoing dialogue for file */ /* transfer. */ /* */ /* See PRM 3-251 and 253. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the Message_DataSaveAck. The */ /* contents will be modified and */ /* used in the reply. */ /*************************************************/ _kernel_oserror * protocols_atats_send_data_load(WimpMessage * m) { int old_ref = m->hdr.your_ref; int found = 0; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_send_data_load: Called\n"); #endif /* Fill in the parts that need changing */ m->hdr.your_ref = m->hdr.my_ref; m->hdr.action_code = Wimp_MDataLoad; /* Find out the file size and type */ RetError(_swix(OS_File, _INR(0,1) | _OUT(0) | _OUT(4) | _OUT(6), 23, /* Read catalogue info for named, stamped object */ m->data.data_save_ack.leaf_name, &found, &m->data.data_load.estimated_size, &m->data.data_load.file_type)); if (found != 1) { /* Object not found - woo, weird (but it happens!) */ #ifdef TRACE { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, "Can't find the file I'm supposed to tell someone else to load in protocols_atats_send_data_load"); show_error_ret(&erb); } #endif return NULL; } /* Send the reply */ RetError(wimp_send_message(Wimp_EUserMessageRecorded, m, m->data.data_save_ack.destination_window, m->data.data_save_ack.destination_icon, NULL)); /* Update the records of my_ref for subsequent replies and bounces */ protocols_util_update_reference(old_ref, m->hdr.my_ref); /* Finished */ return NULL; } /*************************************************/ /* protocols_atats_data_load_bounced() */ /* */ /* Called if a Message_DataLoad bounces. Need to */ /* delete any scrap files written and report an */ /* appropriate error. */ /* */ /* See PRM 3-253, 254. */ /* */ /* Parameters Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atats_data_load_bounced(WimpMessage * m) { int scrap_was_opened = 0; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_data_load_bounced: Called\n"); #endif /* Do we recognise this message? If so, deal with it, otherwise */ /* ignore it (or raise a warning in TRACE builds). */ if ( m->hdr.my_ref == save_source_reference || m->hdr.my_ref == save_as_text_reference || m->hdr.my_ref == save_as_draw_reference || m->hdr.my_ref == save_link_reference || m->hdr.my_ref == save_location_reference || #ifndef REMOTE_HOTLIST m->hdr.my_ref == save_hotlist_entry_reference || m->hdr.my_ref == save_hotlist_selection_reference || m->hdr.my_ref == save_entire_hotlist_reference || #endif m->hdr.my_ref == save_object_reference || m->hdr.my_ref == save_image_reference || m->hdr.my_ref == save_history_reference ) { /* Not interested in any errors here - just get rid of scrap if we can */ if ( !strcmp(m->data.data_load.leaf_name, Save_ScrapFile) ) { /* Special case - if saving an object (Shift+Click on a link */ /* or whatever) through scrap, so the send of a pending */ /* Message_DataLoad led to this bounce, don't delete the */ /* scrap file as it's the only copy of the data that we */ /* have. Instead, open the scrap directory. Otherwise, do as */ /* PRM 3-254 and delete the scrap file. */ if (!save_object_through_scrap) remove (m->data.data_load.leaf_name); else { char * combuf; int comlen; char new_name[Limits_OS_Pathname]; save_object_through_scrap = 0; /* The first thing we need to do is change the filename away */ /* from Scrap, or it could get overwritten when someone else */ /* does a transfer. */ protocols_util_make_unique_name(new_name, sizeof(new_name)); comlen = strlen("Rename ") + strlen(m->data.data_load.leaf_name) + 1 + /* Space between the two names */ strlen(new_name) + 1; /* Terminating byte */ /* Allocate space for the Rename command; if it fails, fine */ /* - just don't rename. */ combuf = malloc(comlen); if (combuf) { sprintf(combuf, "%s%s%c%s", "Rename ", m->data.data_load.leaf_name, ' ', new_name); /* Execute the command */ _swix(Wimp_StartTask, _IN(0), combuf); /* Free the buffer */ free(combuf); combuf = NULL; } /* Try and allocate a buffer for the Filer_OpenDir command. */ /* If this fails, let it do so silently. */ comlen = strlen("Filer_OpenDir ") + strlen(Save_ScrapDir) + 1; combuf = malloc(comlen); if (combuf) { /* Copy in the command */ strcpy(combuf, "Filer_OpenDir "); strcat(combuf, Save_ScrapDir); /* Execute it - if there was no error, flag that Scrap was opened */ if ( !_swix(Wimp_StartTask, _IN(0), combuf) ) scrap_was_opened = 1; /* Free the temporary buffer */ free(combuf); } } } /* Report an appropriate message */ erb.errnum = Utils_Error_Custom_Message; if (!scrap_was_opened) { StrNCpy0(erb.errmess, lookup_token("RecvDied:Data transfer failed - receiver died.", 0, 0)); } else { StrNCpy0(erb.errmess, lookup_token("RecvDiedKept:Data transfer failed - receiver died. The temporary file has been kept on disc so the fetched data can be recovered.", 0, 0)); } return &erb; } #ifdef TRACE /* In TRACE builds, raise a warning if we don't recognise the message */ else { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Message reference %x not recognised in protocols_atats_data_load_bounced", m->hdr.your_ref); return &erb; } #endif return NULL; } /*************************************************/ /* protocols_atats_got_data_load_ack() */ /* */ /* Deals with a Message_DataLoadAck - completion */ /* of app to app transfer from the browser. */ /* */ /* See PRM 3-250, 251, 254. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atats_got_data_load_ack(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atats_got_data_load_ack: Called\n"); #endif /* We have nothing to do here at present; this */ /* is only here to be complete. */ return NULL; } /*************************************************/ /* protocols_atats_send_any_pendings() */ /* */ /* Sends any pending messages related to the */ /* given browser, in the context of application */ /* to application saving. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the pending messages, */ /* if any. */ /*************************************************/ _kernel_oserror * protocols_atats_send_any_pendings(browser_data * b) { _kernel_oserror * e = NULL; if (!b || !is_known_browser(b)) return NULL; /* Pending Message_DataLoad - an object has been saved */ /* through the fetcher to a temporary file. */ if (b->pending_data_load) { char * combuf; int comlen; int type; b->pending_data_load->hdr.my_ref = 0; /* Update the other state variables */ save_object_reference = b->pending_data_load->hdr.your_ref; save_object_transmitted = 0; save_object_browser = b; save_object_through_scrap = 1; /* Delete scrap if present, rename the file we've written to */ /* ScrapFile, and alter the message back to using this */ /* filename. */ remove(Save_ScrapFile); /* Does Scrap still exist? The above may have failed because */ /* Save_ScrapFile was in use elsewhere. If so, then leave */ /* the filename as-is. */ type = 1; _swix(OS_File, _INR(0,1) | _OUT(0), 17, /* Read catalogue info for object */ Save_ScrapFile, &type); if (!type) { /* Allocate space for the buffer */ comlen = strlen("Rename ") + strlen(b->pending_data_load->data.data_load.leaf_name) + 1 + /* The space between the two names */ strlen(Save_ScrapFile) + 1; /* Terminating byte */ combuf = malloc(comlen); /* If we can't allocate space, as with the case of the scrap */ /* file being undeletable, stick with the existing filename. */ if (combuf) { /* We can allocate space, so build the command string. */ sprintf(combuf, "%s%s%c%s", "Rename ", b->pending_data_load->data.data_load.leaf_name, ' ', Save_ScrapFile); /* Do it. If the command fails, use the original filename. */ if ( !_swix(Wimp_StartTask, _IN(0), combuf) ) { /* The command worked, so change the message appropriately. */ StrNCpy0(b->pending_data_load->data.data_load.leaf_name, Save_ScrapFile); b->pending_data_load->hdr.size = (int) WordAlign(strlen(Save_ScrapFile) + 45); } /* Free the command buffer */ free(combuf); } } /* At last, send the message */ e = protocols_atats_send_data_load(b->pending_data_load); /* We don't need the message block in the browser_data structure */ /* any more, so free it. */ free(b->pending_data_load); b->pending_data_load = NULL; } return e; } /*************************************************/ /* protocols_atatl_got_data_open() */ /* */ /* Handle reception of a Message_DataOpen - we */ /* may want to load a given file. It is an */ /* application to application related the */ /* consideration as we are transfering data */ /* from the Filer, in a sense. */ /* */ /* See PRM 3-265. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atatl_got_data_open(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_open: Called\n"); #endif /* Don't load it if we're the originator */ if (m->hdr.sender == task_handle) return NULL; /* Don't want to load a text or data file from double-clicking, */ /* only by dragging to a window or the icon bar icon. Similarly */ /* ANT's URL files should only be loaded if dragged on, and the */ /* same is true of URI files if we are using the URI handler. */ /* Since there is no native TIFF support, drop that out too. */ if ( m->data.data_open.file_type == FileType_TEXT || m->data.data_open.file_type == FileType_DATA || m->data.data_open.file_type == FileType_DOS || /* (Equivalent to FileType_DATA for PC files, so to speak) */ m->data.data_open.file_type == FileType_TIFF || m->data.data_open.file_type == FileType_URL || ( m->data.data_open.file_type == FileType_URI && uri_module_present ) ) return NULL; /* Now treat as a DataLoad message to avoid duplicating load code. */ m->data.data_load.destination_window = 0; /* Force a new window to open */ m->data.data_load.destination_icon = -1; m->data.data_load.estimated_size = 0; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_open: Exitting through protocols_atatl_got_data_load\n"); #endif return protocols_atatl_got_data_load(m); } /*************************************************/ /* protocols_atatl_got_data_load() */ /* */ /* Deals with a Message_DataLoad - if we can */ /* handle the file, load it. */ /* */ /* See PRM 3-253. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atatl_got_data_load(WimpMessage * m) { int filetype = m->data.data_load.file_type; ComponentId c; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_load: Called\n"); #endif /* Was the URL writable targetted? In this case, if it was a text file, */ /* assume it contained a URL - modify the Wimp Message block to contain */ /* an ANT URL file filetype. */ RetError(window_wimp_to_toolbox(0, m->data.data_save.destination_window, m->data.data_save.destination_icon, NULL, &c)); if (c == URLBarWrit && filetype == FileType_TEXT) filetype = FileType_URL; /* If we've got a Data or DOS filetype, can we get anything */ /* more from the filename? */ if ( filetype == FileType_DATA || filetype == FileType_DOS ) { char * ext = strrchr(m->data.data_load.leaf_name, '/'); /* Since under RISC OS, filename extensions will start with '/' */ if (ext) { ext++; if (mimemap_extension_to_riscos(ext, &filetype)) filetype = FileType_DATA; } } /* Proceed only if it's a filetype we can handle */ if ( filetype == FileType_HTML || filetype == FileType_TEXT || filetype == FileType_GIF || filetype == FileType_JPEG || filetype == FileType_PNG || filetype == FileType_TIFF || filetype == FileType_URL || filetype == FileType_URI ) { char url [Limits_URL]; char title[Limits_Title]; int apptoapp = m->hdr.your_ref ? 1 : 0; /* your_ref is zero if from filer, else filled in for app to app */ #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_load: Can handle this filetype (0x%03x)\n", filetype); #endif /* Multiuser builds, if not logged in, just acknowledge */ /* the message to stop (e.g.) another browser being */ /* launched by the Filer, then complain. */ #ifndef SINGLE_USER #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_load: Not logged in\n"); #endif if (!logged_in) { show_error_ret(protocols_atatl_send_data_load_ack(m)); erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("MustLogIn:The browser cannot fetch Web pages until you log in.", 0, 0)); show_error_ret(&erb); return NULL; } #endif /* Process the file */ if ( filetype != FileType_URI && filetype != FileType_URL ) { /* Not a URI or URL file, so text, HTML, image... */ StrNCpy0(url, m->data.data_load.leaf_name); urlutils_pathname_to_url(url, sizeof(url)); /* For text and HTML, we can use an internal URL scheme */ /* to allow the fetcher to load the scrap file and then */ /* remove it, as it should. For other types, the main */ /* fetcher modules must be used; so we can't get rid */ /* of the scrap file. If something else trashes it, */ /* tough. */ if ( apptoapp && ( filetype == FileType_TEXT || filetype == FileType_HTML ) ) { StrNCpy0(url, Internal_URL ForScrapFile ":"); /* Append the application suggested leafname */ if (!data_save_suggested_leafname || !*data_save_suggested_leafname) { if (strlen(url) + 9 <= sizeof(url)) strcat(url, "HTMLfile"); } else { if (strlen(url) + strlen(data_save_suggested_leafname) + 1 <= sizeof(url)) strcat(url, data_save_suggested_leafname); } /* Don't need a leafname record now */ if (data_save_suggested_leafname) { free(data_save_suggested_leafname); data_save_suggested_leafname = NULL; } } } else { urlutils_load_uri_file(url, sizeof(url), title, sizeof(title), m->data.data_load.leaf_name); /* Delete scrap if used - we've finished with the */ /* file now, certainly. */ if (apptoapp) remove(m->data.data_load.leaf_name); } /* Take appropriate action */ if (m->data.data_load.destination_window <= 0) { /* Load file to icon bar - i.e. open a new window. */ ChkError(windows_create_browser(url, NULL, NULL, NULL, Windows_CreateBrowser_Normal)); } #ifndef REMOTE_HOTLIST else { int handled = 0; /* We allow two places for loading - a browser window (or bits of it), */ /* and for URI / URL files, the hotlist window. Check the latter. */ if ( filetype == FileType_URI || filetype == FileType_URL ) { ObjectId this; /* If we can get the window object ID... */ if ( !window_wimp_to_toolbox(0, m->data.data_load.destination_window, -1, &this, NULL) ) { /* ...and it matches that of the hotlist, add the item. */ if (this == hotlist_return_window_id()) { char * leaf = NULL; /* If we have a title for the URL, use it, else try other methods... */ if (!*title) { /* For the description, use the source leafname, unless this */ /* is from another app (your_ref is non-zero), in which case */ /* use the URL, as <Wimp$Scrap> isn't very friendly or */ /* unique. */ if (!m->hdr.your_ref) leaf = strrchr(m->data.data_load.leaf_name, '.'); if (!leaf) leaf = url; else leaf ++; } ChkError(hotlist_add_position(m->data.data_load.destination_x, m->data.data_load.destination_y, *title ? title : leaf, url)); handled = 1; } } } /* We can also load HTML files, in a fashion, to the hotlist. */ if (filetype == FileType_HTML) { ObjectId this; /* If we can get the window object ID... */ if ( !window_wimp_to_toolbox(0, m->data.data_load.destination_window, -1, &this, NULL) ) { /* ...and it matches that of the hotlist, add the item. */ if (this == hotlist_return_window_id()) { char * path = m->data.data_load.leaf_name; ChkError(hotlist_add_html_file(m->data.data_load.destination_x, m->data.data_load.destination_y, path)); handled = 1; } } } /* If not handled yet, deal with the file */ if (!handled) { browser_data * b = NULL; /* Otherwise, load file to a browser window. Need to find */ /* its browser_data structure for this. */ utils_browser_from_window(m->data.data_load.destination_window, &b); if (b && !b->small_fetch) ChkError(fetchpage_new(b, url, 1, 0)); } } #endif ChkError(protocols_atatl_send_data_load_ack(m)); } return NULL; } /*************************************************/ /* protocols_atatl_send_data_load_ack() */ /* */ /* In response to a Message_DataLoad, reply with */ /* a Message_DataLoadAck. */ /* */ /* See PRM 3-252 and 254. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atatl_send_data_load_ack(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_send_data_load_ack: Called\n"); #endif m->hdr.your_ref = m->hdr.my_ref; m->hdr.action_code = Wimp_MDataLoadAck; return wimp_send_message(Wimp_EUserMessage, m, m->hdr.sender, 0, NULL); } /*************************************************/ /* protocols_atatl_got_data_save() */ /* */ /* Handle reception of a Message_DataSave - load */ /* data from another application. Handles RAM */ /* transfer for some filetypes. */ /* */ /* See PRM 3-252, 253, 255 and 256. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atatl_got_data_save(WimpMessage * m) { _kernel_oserror * e = NULL; int filetype = m->data.data_save.file_type; int ram = 0; WimpMessage * reply; ComponentId c; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_save: Called\n"); #endif /* Was the URL writable targetted? In this case, if it was a text file, */ /* assume it contained a URL - modify the Wimp Message block to contain */ /* an ANT URL file filetype. */ RetError(window_wimp_to_toolbox(0, m->data.data_save.destination_window, m->data.data_save.destination_icon, NULL, &c)); if (c == URLBarWrit && filetype == FileType_TEXT) filetype = FileType_URL; /* Can we do RAM transfer for this file type? */ if ( filetype == FileType_URI || filetype == FileType_URL ) ram = 1; /* Can't do anything if <Wimp$Scrap> isn't defined and we want to */ /* use it for file transfer. Note that the checking function will */ /* raise an appropriate error in passing ('<Wimp$Scrap> not */ /* defined', for example). */ if (!ram && utils_check_scrap()) return NULL; /* Free any allocated data left over from previous calls */ if (pending_data_save_ack) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_save: Freeing old pending Acknowledge block\n"); #endif free(pending_data_save_ack); pending_data_save_ack = NULL; } if (data_save_suggested_leafname) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_save: Freeing old suggested leafname block\n"); #endif free(data_save_suggested_leafname); data_save_suggested_leafname = NULL; } /* Record the leafname. Thus, when the Message_DataLoad comes along */ /* or the RAM transfer is finished, we can use this recorded leaf in */ /* some meaningful place (such as the URL bar). Otherwise, we have */ /* no record (only e.g. '<Wimp$Scrap>' in a Message_DataLoad) and */ /* things get a bit more ugly at the front-end. */ if (*m->data.data_save.leaf_name) { /* Allocate the block */ data_save_suggested_leafname = malloc(strlen(m->data.data_save_ack.leaf_name) + 1); /* Do nothing if this should fail; assuming we managed */ /* to load the file, allow the load routines to default */ /* down to a general alternative in the absence of this */ /* record. */ if (data_save_suggested_leafname) strcpy(data_save_suggested_leafname, m->data.data_save_ack.leaf_name); } /* Deal with RAM transfer - send out a RAMFetch. If this */ /* bounces, we'll need to drop back to scrap files. */ if (ram) { /* First, we may need to use file transfer so fill in */ /* a pending DataSaveAck block for later use. */ pending_data_save_ack = malloc(sizeof(WimpMessage)); if (!pending_data_save_ack) return make_no_memory_error(11); #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_save: Allocated new pending Acknowledge block\n"); #endif reply = pending_data_save_ack; } else { /* Otherwise, just point back to the existing message and modify */ /* its contents for a reply in the normal fashion. */ reply = m; } /* Fill it in */ *reply = *m; reply->hdr.your_ref = m->hdr.my_ref; reply->hdr.action_code = Wimp_MDataSaveAck; reply->data.data_save_ack.estimated_size = -1; /* Write the filename for Scrap to the message block */ /* and update the size field in the header. */ StrNCpy0(reply->data.data_save_ack.leaf_name, Save_ScrapFile); reply->hdr.size = (int) WordAlign(strlen(Save_ScrapFile) + 45); /* (44 for stuff up to the pathname, plus 1 for terminator) */ /* For RAM transfer, send a Message_RAMFetch */ if (ram) { WimpMessage * raf = m; /* Free any existing RAM transfer buffer and allocate a new one */ if (rtb) free(rtb); rtb = malloc(RTB_Size); /* If the allocation fails, drop through to a scrap file method */ if (rtb) { /* Fill in the message details */ #ifdef TRACE malloccount += RTB_Size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_data_save): \0211%d\0217\n",malloccount); #endif raf->hdr.size = 28; raf->hdr.your_ref = m->hdr.my_ref; raf->hdr.action_code = Wimp_MRAMFetch; raf->data.ram_fetch.buffer = rtb; raf->data.ram_fetch.buffer_size = RTB_Size; /* Send it */ #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_data_save: Sending Message_RAMFetch in response\n"); #endif RetError(wimp_send_message(Wimp_EUserMessageRecorded, raf, m->hdr.sender, 0, NULL)); /* Remember my_ref in case it bounces */ ram_fetch_reference = raf->hdr.my_ref; /* Flag that we've not started transfer of actual data yet */ ram_load_started = 0; } else ram = 0; /* So that the Message_DataSaveAck goes out instead */ } /* Otherwise send a Message_DataSaveAck reply */ if (!ram) /* Must use this as the RAM transfer code will set 'ram' to 0 if it can't claim a transfer buffer */ { RetError(wimp_send_message(Wimp_EUserMessage, /* Not interested in it bouncing */ reply, m->hdr.sender, 0, NULL)); } return e; } /*************************************************/ /* protocols_atatl_ram_fetch_bounced() */ /* */ /* Following getting a Message_DataSave, */ /* protocols_atatl_got_data_save may send out a */ /* Message_RAMFetch. If this bounces, this */ /* function is called. If the bounce is indeed */ /* due to the RAMFetch we sent, then send out */ /* a Message_DataSaveAck instead, to try and use */ /* scrap file transfer. This is stored in the */ /* 'pending' block by the same function that */ /* sends the Message_RAMFetch. */ /* */ /* Alternatively, a Message_RAMFetch being sent */ /* in reply to a Message_RAMTransmit *during* */ /* RAM transfer could bounce, and this function */ /* would be called. In that case, we should */ /* abort data transfer. The other end is meant */ /* to raise an error (which is odd, since it */ /* seems likely that it will have died - since */ /* it's sending, the changes of running out of */ /* memory at that end are slim). */ /* */ /* See PRM 3-255. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_atatl_ram_fetch_bounced(WimpMessage * m) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_ram_fetch_bounced: Called\n"); #endif if (m->hdr.my_ref == ram_fetch_reference) { if (!ram_load_started && pending_data_save_ack) { /* The bounce is from the first Message_RAMFetch, so try using */ /* scrap file transfer instead. */ _kernel_oserror * e; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_ram_fetch_bounced: Recognised bounce for a new transfer - using Scrap instead\n"); #endif /* Before doing this, make sure Scrap is present - the call */ /* will raise an error if not, before returning here */ if (utils_check_scrap()) return NULL; /* Send the pending message */ e = wimp_send_message(Wimp_EUserMessage, pending_data_save_ack, pending_data_save_ack->hdr.sender, 0, NULL); /* Free the block and return any error that may have been generated */ free(pending_data_save_ack); pending_data_save_ack = NULL; return e; } else { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_ram_fetch_bounced: Recognised bounce for an ongoing transfer - aborting\n"); #endif /* The bounce is from an ongoing RAM transfer, so abort that */ /* transfer - free any in-use buffers. */ if (ram_load_uri_buffer) { free(ram_load_uri_buffer); ram_load_uri_buffer = NULL; #ifdef TRACE malloccount -= ram_load_buffer_size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_ram_fetch_bounced): \0212%d\0217\n",malloccount); #endif } ram_load_buffer_size = 0; if (rtb) { free(rtb); rtb = NULL; #ifdef TRACE malloccount -= RTB_Size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_ram_fetch_bounced): \0212%d\0217\n",malloccount); #endif } /* Free the pending Message_DataSaveAck block, if present */ if (pending_data_save_ack) { free(pending_data_save_ack); pending_data_save_ack = 0; } } } return NULL; } /*************************************************/ /* protocols_atatl_got_ram_transmit() */ /* */ /* Deals with a Message_RAMTransmit - we have */ /* some data in the 'rtb' buffer. */ /* */ /* See PRM 3-255, 256. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_atatl_got_ram_transmit(WimpMessage * m) { _kernel_oserror * e = NULL; int ok = 1; int finished = 0; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_ram_transmit: Called with %d bytes to receive\n", m->data.ram_transmit.nbytes); #endif /* Flag that transfer is in progress */ ram_load_started = 1; /* Flag if we've finished, too */ if (m->data.ram_transmit.nbytes < RTB_Size) finished = 1; else if (m->data.ram_transmit.nbytes > RTB_Size) m->data.ram_transmit.nbytes = RTB_Size; /* You *never* know...! */ /* We should know where the buffer is */ #ifdef TRACE if (m->data.ram_transmit.buffer != rtb) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Expected to get buffer %p but got %p instead, in protocols_atatl_got_ram_transmit", rtb, m->data.ram_transmit.buffer); e = &erb; ok = 0; } #else if (m->data.ram_transmit.buffer != rtb) ok = 0; #endif /* The action here depends on the type of file being transferred; */ /* we know from here on in that the 'rtb' buffer is the buffer */ /* that has been filled in (see above), so we can use this rather */ /* than the more cumbersome 'm->data.ram_transmit.buffer'. */ if (ok && pending_data_save_ack) { ComponentId c; int filetype = pending_data_save_ack->data.data_save_ack.file_type; /* Was this dragged to the URL writable, and thus should be */ /* treated as an ANT URL file (if text)? */ RetError(window_wimp_to_toolbox(0, pending_data_save_ack->data.data_save_ack.destination_window, pending_data_save_ack->data.data_save_ack.destination_icon, NULL, &c)); if (c == URLBarWrit && filetype == FileType_TEXT) filetype = FileType_URL; switch (filetype) { /* For URI / URL files, copy data from the file transfer */ /* buffer (which may deliver the file in several small */ /* chunks) to a cumulative file buffer, and then process */ /* that whole thing when finished. */ case FileType_URL: /* Same as for URI files, so no 'break' */ case FileType_URI: { int first = 0; /* Only proceed with transfer if there are some bytes to get */ /* (otherwise, this was the last message with the final chunk */ /* of data having exactly filled the buffer last time - so */ /* act upon the buffer contents now, without trying to */ /* transfer zero bytes first). */ if (m->data.ram_transmit.nbytes) { /* Allocate or extend the local buffer to take in the URI file */ if (!ram_load_uri_buffer) { /* Note we allocate 1 byte more than needed to allow a terminator to */ /* be inserted after the URL string when the transfer has ended; */ /* this is because a URI file may end simply by EOF, it does not */ /* need a terminator (and in any case, that terminator may be a */ /* control char such as ASCII 10 or 13, which C would not treat as a */ /* string terminator). */ ram_load_uri_buffer = malloc(m->data.ram_transmit.nbytes + 1); first = 1; /* Complain if the allocation fails */ if (!ram_load_uri_buffer) { e = make_no_memory_error(7); ok = 0; } #ifdef TRACE else { malloccount += m->data.ram_transmit.nbytes + 1; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_ram_transmit): \0211%d\0217\n",malloccount); } #endif } else { void * local; /* realloc to a new size */ local = realloc(ram_load_uri_buffer, ram_load_buffer_size + m->data.ram_transmit.nbytes); if (!local) { /* If the allocation fails, free the whole thing */ free(ram_load_uri_buffer); ram_load_uri_buffer = NULL; #ifdef TRACE malloccount -= ram_load_buffer_size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_ram_transmit): \0212%d\0217\n",malloccount); #endif ram_load_buffer_size = 0; e = make_no_memory_error(7); ok = 0; } /* Otherwise record a possibly new buffer address */ else { ram_load_uri_buffer = local; #ifdef TRACE malloccount += m->data.ram_transmit.nbytes; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_ram_transmit): \0211%d\0217\n",malloccount); #endif } } if (ok) { /* Copy the data from the file transfer buffer into */ /* the cumulative URI file buffer */ memcpy(ram_load_uri_buffer + ram_load_buffer_size - !first, rtb, m->data.ram_transmit.nbytes); /* Increment the buffer size counter, remembering to add 1 if this */ /* is the first time we've allocated data, to allow room for a */ /* string terminator when the transfer finishes. */ ram_load_buffer_size += m->data.ram_transmit.nbytes + !!first; /* If tracing the process of the transfer, show the buffer contents */ /* (but don't bother showing the uninitialised last byte). */ #ifdef TRACE if (tl & (1u<<28)) trace_dump_buffer(ram_load_uri_buffer, ram_load_buffer_size - 1, 2); #endif } } /* If the transfer has finished, fetch the URL */ if (finished) { /* Remember we allocated 1 byte more than needed at the start, */ /* so that this terminator could be inserted. This is required */ /* for URL files, and won't hurt for URI files. */ ram_load_uri_buffer[ram_load_buffer_size - 1] = 0; /* This is capable of dealing with URI or URL files */ urlutils_extract_uri(ram_load_uri_buffer, ram_load_buffer_size); if (pending_data_save_ack->data.data_save_ack.destination_window <= 0) { /* The original Message_DataSave was for no specific window */ e = windows_create_browser(ram_load_uri_buffer, NULL, NULL, NULL, Windows_CreateBrowser_Normal); } #ifndef REMOTE_HOTLIST else { /* As with DataLoad, this can go to a Hotlist window or a browser; */ /* the hotlist is the simpler case, check that first. */ ObjectId this; int handled = 0; /* If we can get the window object ID... */ if ( !window_wimp_to_toolbox(0, pending_data_save_ack->data.data_save_ack.destination_window, -1, &this, NULL) ) { /* ...and it matches that of the hotlist, add the item. */ if (this == hotlist_return_window_id()) { /* Use the title, if we have one */ if (*(ram_load_uri_buffer + strlen(ram_load_uri_buffer) + 1)) { ChkError(hotlist_add_position(pending_data_save_ack->data.data_save_ack.destination_x, pending_data_save_ack->data.data_save_ack.destination_y, ram_load_uri_buffer + strlen(ram_load_uri_buffer) + 1, ram_load_uri_buffer)); } else { ChkError(hotlist_add_position(pending_data_save_ack->data.data_save_ack.destination_x, pending_data_save_ack->data.data_save_ack.destination_y, ram_load_uri_buffer, ram_load_uri_buffer)); } handled = 1; } } if (!handled) { browser_data * b; /* The message was for a specific window, so find out which one */ utils_browser_from_window(pending_data_save_ack->data.data_save_ack.destination_window, &b); if (b && !b->small_fetch) e = fetchpage_new(b, ram_load_uri_buffer, 1, 0); } } #endif free (ram_load_uri_buffer); ram_load_uri_buffer = NULL; #ifdef TRACE malloccount -= ram_load_buffer_size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_ram_transmit): \0212%d\0217\n",malloccount); #endif ram_load_buffer_size = 0; if (!e) ok = 0; } } break; default: { /* If we don't recognise the filetype, something is very wrong... */ #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Unrecognised filetype 0x%03x (%x) in protocols_atatl_got_ram_transmit", pending_data_save_ack->data.data_save_ack.file_type, pending_data_save_ack->data.data_save_ack.file_type); e = &erb; ok = 0; #else ok = 0; #endif } break; } } if (ok && !finished) { /* If things are OK still, send a RAMFetch to get the */ /* next chunk, provided that there is more to get. */ /* */ /* If things are not OK, no reply is given, thereby */ /* abandoning the transfer (PRM 3-256). */ WimpMessage * raf = m; raf->hdr.size = 28; raf->hdr.your_ref = m->hdr.my_ref; raf->hdr.action_code = Wimp_MRAMFetch; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_ram_transmit: Sending RAMFetch in reply\n"); #endif e = wimp_send_message(Wimp_EUserMessageRecorded, raf, m->hdr.sender, 0, NULL); ram_fetch_reference = m->hdr.my_ref; } /* Either we've finished or there was an error higher up */ if (finished || !ok) { /* Free the RAM transfer buffer, if required. */ if (rtb) free(rtb); rtb = NULL; #ifdef TRACE malloccount -= RTB_Size; if (tl & (1u<<13)) Printf("** malloccount (protocols_atatl_got_ram_transmit): \0212%d\0217\n",malloccount); #endif /* Free any pending Message_DataSaveAck */ if (pending_data_save_ack) { #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_atatl_got_ram_transmit: Freeing old pending Acknowledge block\n"); #endif free(pending_data_save_ack); pending_data_save_ack = NULL; } } return e; } /*************************************************/ /* protocols_pp_send_print_save() */ /* */ /* First stage of the Print Protocol - broadcast */ /* a Message_PrintSave. */ /* */ /* See PRM 3-259, 262. */ /*************************************************/ _kernel_oserror * protocols_pp_send_print_save(void) { WimpMessage m; /* Fill in the header */ m.hdr.your_ref = 0; m.hdr.action_code = Browser_Message_PrintSave; /* Fill in the body */ m.data.data_save.destination_window = 0; m.data.data_save.destination_icon = 0; m.data.data_save.destination_x = 0; m.data.data_save.destination_y = 0; m.data.data_save.estimated_size = 4096; m.data.data_save.file_type = FileType_POUT; StrNCpy0(m.data.data_save.leaf_name, lookup_token("PrintName:WebPage",0,0)); /* Work out the message size */ m.hdr.size = (strlen(m.data.data_save.leaf_name) + 44); if (m.hdr.size & 3) m.hdr.size = (m.hdr.size & ~3) + 4; /* Send the message */ RetError(wimp_send_message(Wimp_EUserMessageRecorded, &m, 0, 0, NULL)); /* A Message_DataSaveAck returns, so to distinguish this from */ /* any other Message_DataSaveAck, remember my_ref and check */ /* it against the returned your_ref in future. */ print_save_reference = m.hdr.my_ref; return NULL; } /*************************************************/ /* protocols_pp_print_save_bounced() */ /* */ /* If a Message_PrintSave bounces, the browser */ /* tried to use the printer protocol to do a */ /* print job but the printer wasn't loaded. In */ /* that case, print directly to the 'printer:' */ /* device. */ /* */ /* See PRM 3-259 for details of where this fits */ /* into the protocol, or 3-262 for the message */ /* structure. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_pp_print_save_bounced(WimpMessage * m) { if (m->hdr.my_ref && m->hdr.my_ref == print_save_reference) { print_save_reference = 0; /* Go for it. */ print_print(NULL); } #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Message reference %x not recognised in protocols_pp_print_save_bounced", m->hdr.your_ref); return &erb; } #endif return NULL; } /*************************************************/ /* protocols_pp_got_print_error() */ /* */ /* Handle reception of a Message_PrintError - */ /* report an error from the printer driver. */ /* */ /* See PRM 3-262. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_pp_got_print_error(WimpMessage * m) { if (m->hdr.size == 20) { /* RISC OS 2 printer manager's PrintBusy response */ erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("PrintBusy:The printer is currently busy.", 0, 0)); show_error_ret(&erb); } /* RISC OS 3 !Printers-generated specific error response */ else show_error_ret((_kernel_oserror *) &m->data); return NULL; } /*************************************************/ /* protocols_pp_got_data_save_ack() */ /* */ /* Handle reception of a Message_DataSaveAck */ /* where the your_ref field shows that it has */ /* been sent in relation to a print job. Only */ /* call in those circumstances... */ /* */ /* See PRM 3-259 / 3-260 for details of where */ /* this fits into the protocol, or PRM 3-253 */ /* for details on the message structure. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ static _kernel_oserror * protocols_pp_got_data_save_ack(WimpMessage * m) { _kernel_oserror * e; WimpMessage * dl = m; int file_size; #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_pp_got_data_save_ack: Called\n"); #endif /* Print to a file in the !Printers-given file, then send */ /* a DataLoad to the printer manager to tell it to put */ /* the file into the print queue. */ print_save_reference = 0; print_print(m->data.data_save.leaf_name); e = _swix(OS_File, _INR(0,1) | _OUT(4), 23, /* Read catalogue info */ m->data.data_save.leaf_name, &file_size); if (e) return e; dl->hdr.size = 64; dl->hdr.your_ref = m->hdr.my_ref; dl->hdr.action_code = Wimp_MDataLoad; dl->data.data_load.estimated_size = file_size; dl->data.data_load.file_type = FileType_POUT; e = _swix(OS_File, _INR(0,2), 18, /* Set filetype of named object */ m->data.data_save_ack.leaf_name, FileType_POUT); strcpy(dl->data.data_load.leaf_name, m->data.data_save_ack.leaf_name); /* Send the DataLoad - a UserMessage, not UserMessageRecorded, */ /* so it can't bounce back. */ #ifdef TRACE if (tl & (1u<<28)) Printf("protocols_pp_got_data_save_ack: Sending Message_DataLoad in response\n"); #endif return wimp_send_message(Wimp_EUserMessage, dl, m->hdr.sender, 0, NULL); } /*************************************************/ /* protocols_pp_got_print_type_odd() */ /* */ /* Handle reception of a Message_PrintTypeOdd. */ /* */ /* If this is sent directly to the task, we can */ /* print immediately to 'printer:'. */ /* */ /* The use of an Alias$PrintType_FF4 system */ /* variable makes it unnecessary to deal with */ /* the case of a broadcast PrintTypeOdd. This */ /* happens when a queued PrintOut file that the */ /* browser has been asked to print rises to the */ /* top of !Printers' queue. Bizarrely, !Printers */ /* doesn't recognise the filetype and raises the */ /* message. We allow this to fall back to the */ /* system variable, which copies the PrintOut */ /* file to the 'printer:' device. */ /* */ /* This is a hole in an otherwise workable, if */ /* cumbersome, protocol. */ /* */ /* See PRM 3-263. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_pp_got_print_type_odd(WimpMessage * m) { WimpMessage * ptk = m; if (m->hdr.your_ref && m->hdr.your_ref == print_save_reference) { /* The printer manager sent PrintTypeOdd as a reply to this */ /* task (not a broadcast), so go ahead and print. */ print_save_reference = 0; /* Send PrintTypeKnown */ ptk->hdr.size = 20; ptk->hdr.your_ref = m->hdr.my_ref; ptk->hdr.action_code = Browser_Message_PrintTypeKnown; RetError(wimp_send_message(Wimp_EUserMessage, ptk, m->hdr.sender, 0, NULL)); print_print(NULL); } #ifdef TRACE else if (m->hdr.your_ref) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Message reference %x unrecognised in protocols_pp_got_print_type_odd", m->hdr.your_ref); return &erb; } #endif // Commented out as the Alias$@PrintType_FF4 system variable does this job // anyway, and if we don't claim this message then anything else which may // have a better idea of what to do at least gets a chance to try. // // This currently doesn't work, incidentally; the conditions on the 'if' // are wrong (print_save_ref has probably been set to 0, but I never // got the chance to properly debug this before removing it due to time // constraints...). // // else if (print_save_ref && m->data.data_save.file_type == FileType_POUT) // { // /* If the printer doesn't understand PrintOut files, then */ // /* it may be broken (!) / PostScript. So reply, and copy */ // /* the file to the printer device directly. */ // // print_save_ref = 0; // // ptk->hdr.size = 20; // ptk->hdr.your_ref = m->hdr.my_ref; // ptk->hdr.action_code = Browser_Message_PrintTypeKnown; // // ChkError(wimp_send_message(Wimp_EUserMessage, ptk, m->hdr.sender, 0, NULL)); // // _swix(OS_FSControl, // _INR(0,3), // // 26, // m->data.data_save.leaf_name, // "printer:", // 2); /* Flags - 'Force' set, but no others. */ // } return NULL; } /*************************************************/ /* protocols_auh_got_process() */ /* */ /* Handle reception of a URI_MProcess - process */ /* a URI from the URI handler, replying if we */ /* can handle the URI. */ /* */ /* See 1307,260/FS. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_auh_got_process(WimpMessage * m) { URIProcessMessage * uri = (URIProcessMessage *) &m->data; int ok; unsigned int sender = m->hdr.sender; /* Can we handle this URI? */ ok = urlutils_check_protocols(uri->uri); #ifdef TRACE if (tl & (1u<<21)) Printf("protocols_auh_got_process: URI_MProcess '%s', ok = %d\n",uri->uri,ok); #endif /* If so, reply to the message and possibly start a fetch */ if (ok) { #ifndef SINGLE_USER if (logged_in) { #endif /* Only fetch if the flags bits don't say we're to just */ /* check the URI could be handled. */ if (!uri->flags.bits.check) { uri_queue * entry = urlutils_find_queue_entry(uri->uri_handle); if (entry) { RetError(fetchpage_postprocess_uri(entry->b, uri ->uri, entry->flags & URIQueue_RecordInHistory ? 1 : 0)); /* Don't remove it from the queue of uri_queue structures yet - */ /* wait for the ReturnResult message for that. */ } else RetError(windows_create_browser(uri->uri, NULL, NULL, NULL, Windows_CreateBrowser_Normal)); } #ifndef SINGLE_USER } else { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("MustLogIn:The browser cannot fetch Web pages until you log in.", 0, 0)); show_error_ret(&erb); } #endif /* Now reply, saying that we've handled the message */ m->hdr.sender = task_handle; m->hdr.your_ref = m->hdr.my_ref; m->hdr.action_code = URI_MProcessAck; RetError(wimp_send_message(Wimp_EUserMessage, m, sender, 0, NULL)); } return NULL; } /*************************************************/ /* protocols_auh_got_return_result() */ /* */ /* Handle reception of a URI_MReturnResult - */ /* the URI handler is reporting what happened to */ /* a URI we dispatched through it. */ /* */ /* See 1307,260/FS. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_auh_got_return_result(WimpMessage * m) { URIReturnResultMessage * uri = (URIReturnResultMessage *) &m->data; #ifdef TRACE if (tl & (1u<<21)) Printf("protocols_auh_got_return_result: URI_MReturnResult, not_claimed = %d\n",uri->flags.bits.not_claimed); #endif /* Remove the entry from the queue */ RetError(urlutils_remove_from_queue(uri->uri_handle)); /* If the URI was not claimed by anyone, give an appropriate error */ if (uri->flags.bits.not_claimed) { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("CannotFetch:The browser does not have a method of fetching the requested site.", 0,0)); show_error_ret(&erb); } return NULL; } /*************************************************/ /* protocols_auh_got_dying() */ /* */ /* Handle reception of a URI_MDying - the URI */ /* handler is closing down. */ /* */ /* See 1307,260/FS. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_auh_got_dying(WimpMessage * m) { /* If the URI handler is dying, don't try and use it anymore... */ uri_module_present = 0; return NULL; } /*************************************************/ /* protocols_ih_send_help_request() */ /* */ /* Sends out HelpRequest messages for the item */ /* the mouse pointer is currently over, every */ /* 20 centiseconds or so. */ /* */ /* Parameters are as standard for a Wimp NULL */ /* event handler. */ /*************************************************/ int protocols_ih_send_help_request(int eventcode, WimpPollBlock * block, IdBlock * idb, void * handle) { int time_now; static int last_time = 0; static int last_window = 0; static int last_icon = 0; /* Only proceed if the Controls say to do so */ if (controls.claim_help) { /* Don't sent out requests too often */ _swix(OS_ReadMonotonicTime, _OUT(0), &time_now); if (time_now - last_time > 20) { WimpGetPointerInfoBlock i; WimpMessage m; last_time = time_now; ChkError(wimp_get_pointer_info(&i)); /* Don't send a request if the pointer isn't over a */ /* browser-owned window. */ if (task_handle == task_from_window(i.window_handle)) { /* Don't send out multiple requests for the same window/icon. */ if (i.icon_handle != last_icon || i.window_handle != last_window) { last_icon = i.icon_handle; last_window = i.window_handle; } else return 0; /* Build the message block and send the request */ m.hdr.size = 40; m.hdr.sender = task_handle; m.hdr.my_ref = 0; m.hdr.your_ref = 0; m.hdr.action_code = Wimp_MHelpRequest; m.data.help_request.mouse_x = i.x; m.data.help_request.mouse_y = i.y; m.data.help_request.buttons = i.button_state; m.data.help_request.window_handle = i.window_handle; m.data.help_request.icon_handle = i.icon_handle; ChkError(wimp_send_message(Wimp_EUserMessageRecorded, &m, i.window_handle, i.icon_handle, NULL)); } } } return 0; } /*************************************************/ /* protocols_ih_help_request_bounced() */ /* */ /* If a Message_HelpRequest comes in as a */ /* UserMessage_Acknowledge, then the browser */ /* tried to send out such a message and it */ /* bounced - there is no help on that item. */ /* In this case, if we're displaing help items */ /* in the status bar, return to a non-help */ /* status string. */ /* */ /* See PRM 3-244 for details of the message or */ /* protocols_ih_send_help_request for the */ /* message origin. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_ih_help_request_bounced(WimpMessage * m) { if (controls.claim_help) { WimpGetPointerInfoBlock i; browser_data * b = NULL; ObjectId o, a = -1; RetError(wimp_get_pointer_info(&i)); RetError(window_wimp_to_toolbox(0, i.window_handle, i.icon_handle, &o, NULL)); /* If we can get an ancestor, the pointer is over e.g. a toolbar */ /* - otherwise, assume it is over a browser window. */ toolbox_get_ancestor(0, o, &a, NULL); if (a) { toolbox_get_client_handle(0, a, (void *) &b); } else toolbox_get_client_handle(0, o, (void *) &b); /* If we haven't got a valid client handle, exit */ if (!is_known_browser(b)) return NULL; /* Update the status line */ if (b->status_help != NULL) { b->status_help = NULL; RetError(toolbars_cancel_status(b, Toolbars_Status_Help)); } } return NULL; } /*************************************************/ /* protocols_ih_got_help_reply() */ /* */ /* On receiving a Message_HelpReply, we may want */ /* to display the Help text in the status bar. */ /* */ /* See PRM 3-245. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_ih_got_help_reply(WimpMessage * m) { static char last_help[Limits_StatusBarStatus]; /* Don't do anything if the Controls say not to. */ if (controls.claim_help) { WimpGetPointerInfoBlock i; browser_data * b = NULL; ObjectId o, a = 0; RetError(wimp_get_pointer_info(&i)); RetError(window_wimp_to_toolbox(0, i.window_handle, i.icon_handle, &o, NULL)); /* If we can get an ancestor, the pointer is over e.g. a toolbar */ /* - otherwise, assume it is over a browser window. */ toolbox_get_ancestor(0, o, &a, NULL); if (a) { toolbox_get_client_handle(0, a, (void *) &b); } else toolbox_get_client_handle(0, o, (void *) &b); /* If we haven't got a valid client handle, exit. */ if (!is_known_browser(b)) return NULL; /* If this is a small fetch window, don't display anything either */ if (b->small_fetch) return NULL; /* If the text is empty, there was no help for that item, */ /* so restore the old status display, if there was a */ /* help display already there. */ if (!*m->data.help_reply.text) { if (b->status_help != NULL) { b->status_help = NULL; RetError(toolbars_cancel_status(b, Toolbars_Status_Help)); } } else { /* Otherwise update the status bar with the help text, */ /* if the text has changed. */ if ( !b->status_help || ( b->status_help && strcmp(b->status_help, m->data.help_reply.text) ) ) { StrNCpy0(last_help, m->data.help_reply.text); b->status_help = last_help; RetError(toolbars_update_status(b, Toolbars_Status_Help)); } } } return NULL; } /*************************************************/ /* protocols_aub_got_open_url() */ /* */ /* Handle ANT Open URL broadcasts. */ /* */ /* See http://www.ant.co.uk/support/tech/ */ /* notes/url.html (15 Sep 1997). */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. The */ /* contents will be modified and */ /* used in a reply. */ /*************************************************/ _kernel_oserror * protocols_aub_got_open_url(WimpMessage * m) { ant_open_url * open = (ant_open_url *) &m->data; int ok = 0; char * url; char * target; /* If 'tag' is non-NULL, the data is a URL string */ if (open->tag) url = (char *) open, target = NULL; /* Otherwise, it's indirected */ else { char * file; char * mimetype; /* Entries are either NULL, an offset into the */ /* message block (but we have to ensure that it */ /* is a valid offset), or a pointer. This */ /* protocol sucks, big time. */ if (!open->file.offset) file = NULL; else if (open->file.offset < 0x1800000) { if (open->file.offset >= sizeof(m->data.bytes)) file = NULL; else file = ((char *) open) + open->file.offset; } else file = open->file.ptr; if (!open->mimetype.offset) mimetype = NULL; else if (open->mimetype.offset < 0x1800000) { if (open->mimetype.offset >= sizeof(m->data.bytes)) mimetype = NULL; else mimetype = ((char *) open) + open->mimetype.offset; } else mimetype = open->mimetype.ptr; /* Can't handle file or mimetype requests */ if (!file && !mimetype) { if (!open->url.offset) url = NULL; else if (open->url.offset < 0x1800000) { if (open->url.offset >= sizeof(m->data.bytes)) url = NULL; else url = ((char *) open) + open->url.offset; } else url = open->url.ptr; if (!open->target.offset) target = NULL; else if (open->target.offset < 0x1800000) { if (open->target.offset >= sizeof(m->data.bytes)) target = NULL; else target = ((char *) open) + open->target.offset; } else target = open->target.ptr; } else url = NULL, target = NULL; } /* Check the protocol - can we handle this? */ if (url) ok = urlutils_check_protocols(url); /* If so, do so */ if (ok) { /* Send out the URL */ RetError(windows_create_browser(url, NULL, NULL, target, Windows_CreateBrowser_Normal)); /* Acknowledge the message */ m->hdr.your_ref = m->hdr.my_ref; return wimp_send_message(Wimp_EUserMessageAcknowledge, m, m->hdr.sender, 0, NULL); } return NULL; } /*************************************************/ /* protocols_multi_got_data_save_ack() */ /* */ /* Got a DataSaveAck - this could be part of the */ /* print protocol, or standard file transfer */ /* between applications. */ /* */ /* Parameters: Pointer to the WimpMessage struct */ /* for the received message. */ /*************************************************/ _kernel_oserror * protocols_multi_got_data_save_ack(WimpMessage * m) { if (m->hdr.your_ref && m->hdr.your_ref == print_save_reference) return protocols_pp_got_data_save_ack(m); else return protocols_atats_got_data_save_ack(m); } /*************************************************/ /* protocols_util_update_reference() */ /* */ /* When a message is sent out as part of an */ /* ongoing conversation, this function should be */ /* called after Wimp_SendMessage to update the */ /* internal records of known my_ref numbers. */ /* */ /* Parameters: The value of the your_ref field */ /* in the *original* message, before */ /* a reply was generated (so you */ /* will need to remember this before */ /* setting your_ref to my_ref prior */ /* to replying); */ /* */ /* The value of the my_ref field */ /* filled in by the Wimp after */ /* Wimp_SendMessage was called to */ /* send the reply. */ /*************************************************/ static void protocols_util_update_reference(int old_ref, int new_ref) { /* This would look really great as a switch statement. But hey, */ /* I'm sure C is really an excellent language. Really. */ if (old_ref == save_source_reference) save_source_reference = new_ref; else if (old_ref == save_as_text_reference) save_as_text_reference = new_ref; else if (old_ref == save_as_draw_reference) save_as_draw_reference = new_ref; else if (old_ref == save_link_reference) save_link_reference = new_ref; else if (old_ref == save_location_reference) save_location_reference = new_ref; #ifndef REMOTE_HOTLIST else if (old_ref == save_hotlist_entry_reference) save_hotlist_entry_reference = new_ref; else if (old_ref == save_hotlist_selection_reference) save_hotlist_selection_reference = new_ref; else if (old_ref == save_entire_hotlist_reference) save_entire_hotlist_reference = new_ref; #endif else if (old_ref == save_object_reference) save_object_reference = new_ref; else if (old_ref == save_image_reference) save_image_reference = new_ref; else if (old_ref == save_history_reference) save_history_reference = new_ref; else if (old_ref == print_save_reference) print_save_reference = new_ref; #ifdef TRACE else { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Old message reference %x not recognised in protocols_util_update_reference (has a new save method been created, but not added to this function?)", old_ref); show_error_ret(&erb); } #endif } /*************************************************/ /* protocols_util_make_unique_name() */ /* */ /* Generates a browser-unique pathname in the */ /* given buffer, based on Wimp$ScrapDir. This is */ /* hopefully system-unique as the function */ /* keeps going until it can't find a file under */ /* the name it has constructed. */ /* */ /* Parameters: Pointer to the buffer; */ /* */ /* Size of the buffer. */ /* */ /* Assumes: Well it won't crash if you give */ /* it a NULL buffer pointer or a */ /* buffer size of less than 2 bytes, */ /* but there's not exactly a huge */ /* amount of worth in calling the */ /* function under those conditions! */ /*************************************************/ void protocols_util_make_unique_name(char * buffer, int buffer_size) { int filecount = 0; int type; char * leaf; if (!buffer || buffer_size < 2) return; /* Clear the buffer first */ memset(buffer, 0, buffer_size); /* Write '<Wimp$ScrapDir>.' (or whatever is defined in Save.h) */ /* to the buffer - +9 is 8 letters for the leafname (see code */ /* below) plus 1 for a terminator. */ if (strlen(Save_ScrapPath) + 9 <= buffer_size) strcpy(buffer, Save_ScrapPath); else return; /* Append with a unique 8 letter leafname */ leaf = buffer + strlen(buffer); do { sprintf(leaf, "BTF%05x", filecount++); /* Can we find the file? */ type = 1; _swix(OS_File, _INR(0,1) | _OUT(0), 17, /* Read catalogue info for object */ buffer, &type); /* Keep going until we run out of files (!) or find an unused name */ } while (type != 0 && filecount <= 0xfffff); /* Woo - did we run out? */ if (filecount > 0xfffff) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, "Blimey! Ran out of filenames in protocols_util_make_unique_name. Going to try to use Save_ScrapFile instead..."); show_error_ret(&erb); #endif *buffer = 0; if (strlen(Save_ScrapFile) + 1 <= buffer_size) strcpy(buffer, Save_ScrapFile); return; } /* Finished */ return; }