/* 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 : PlugIn.c */ /* */ /* Purpose: Supporting the generic RISC OS browser */ /* Plug-In interface. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 05-Oct-97: 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 "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "Utils.h" #include "Browser.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "FetchHTML.h" #include "FetchPage.h" #include "Filetypes.h" #include "Frames.h" #include "Handlers.h" #include "Images.h" #include "MimeMap.h" #include "MiscDefs.h" #include "Object.h" #include "Protocols.h" #include "Redraw.h" #include "Reformat.h" #include "RMA.h" #include "TokenUtils.h" #include "Toolbars.h" #include "URLveneer.h" #include "Windows.h" #include "PlugIn.h" /**************************************************************************************************/ /* */ /* Allocation of browser handles for the Plug-In protocol */ /* ====================================================== */ /* */ /* In the Plug-In protocol, a browser supplies a private word (the browser instance handle) and */ /* the Plug-In supplies a private word (the Plug-In instance handle). Each is considered an */ /* opaque value to the other. */ /* */ /* Because the browser, in this case, needs to know both the browser_data structure owning a */ /* Plug-In and the HStream structure representing it, the plugin_insts structure is used to form */ /* a linked list containing information on a Plug-In. The browser points to items in this list */ /* to create the browser instance handle. */ /* */ /* When streaming data, two new handles are used, one for the Plug-In's side of the stream, and */ /* one for the browser's side. In this case, we only need to know the browser_data struct that is */ /* handling the fetching of data, so the browser stream instance handle is a pointer to that */ /* structure. This structure has a 'pstream' field which points to a plugin_stream structure. */ /* This is used to hold a lot of information on the fetch, and is an externally visible structure */ /* unlike plugin_insts. */ /* */ /* */ /* Other structures */ /* ================ */ /* */ /* Less related to the protocol are two other important structures - the plugin_files struct and */ /* the plugin_queue. The plugin_queue is a simple structure added to whenever the browser finds */ /* a token representing a Plug-In and wants to try launching that Plug-In. The head item of the */ /* queue is launched and removed when the protocol completes (successfully or otherwise), */ /* allowing the next item to rise to the head and be launched, and so-forth. */ /* */ /* The plugin_files struct is used in place of a browser cache. Since the core browser has no */ /* cache itself, and given that the Plug-In protocol expects one (no method for deleting */ /* temporary files is provided other than implicit cache expiry), an alternative is needed. */ /* Whenever a temporary file is created as part of Plug-In streaming (i.e. everything except the */ /* Params file used at launch time), an entry holding the URL relating to the file, and its */ /* pathname, is placed in the list. Instead of fetching new data as soon as asked to by a Plug-In */ /* the browser will first scan the list, and if a matching URL is found, use the existing file */ /* instead. */ /* */ /* Files are cached for the duration of a session, and are deleted on browser shutdown. */ /**************************************************************************************************/ /* Local structures */ typedef struct plugin_files { struct plugin_files * next; /* When a Plug-In fetch to a file has successfully completed, */ /* this records the filename so it can be deleted on shutdown. */ char * url; char * pathname; } plugin_files; typedef struct plugin_insts { struct plugin_insts * next; /* This is what a browser instance handle is actually a pointer to */ /* (but not a browser stream instance handle; see comments above). */ browser_data * browser; HStream * token; unsigned int plugin_task_handle; } plugin_insts; /* Statics */ static plugin_queue * plugin_queue_head = NULL; static plugin_files * plugin_files_head = NULL; static plugin_insts * plugin_insts_head = NULL; static int plugin_open_reference = 0; static int plugin_open_tried_once = 0; static char * plugin_open_filename = NULL; static int plugin_stream_new_reference = 0; /* Static function prototypes */ static browser_data * plugin_return_browser (unsigned int browser_instance_handle); static _kernel_oserror * plugin_write_params_word (int fh, int word); static _kernel_oserror * plugin_write_params_string (int fh, const char * string); static _kernel_oserror * plugin_write_params_entry (int fh, int type, const char * name, const char * data, const char * mime); static _kernel_oserror * plugin_remove_head_item (void); static _kernel_oserror * plugin_broadcast_open (void); static int plugin_close_stream (int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle); static _kernel_oserror * plugin_add_file_entry (const char * pathname, const char * url); static const char * plugin_find_file (const char * url); static void plugin_flush_files (void); static _kernel_oserror * plugin_add_instance_entry (browser_data * b, HStream * t, unsigned int task); static plugin_insts * plugin_find_instance_entry (browser_data * b, HStream * t); static void plugin_remove_instance_entry (plugin_insts * remove); /*************************************************/ /* plugin_return_string() */ /* */ /* Takes a message block and string_value from */ /* within it, and returns the string it points */ /* to. */ /* */ /* Parameters: Pointer to a WimpMessage struct */ /* holding the string_value field; */ /* */ /* Pointer to the string_value field */ /* inside that message. */ /* */ /* Returns: Pointer to the string the */ /* string_value references, or NULL */ /* if the value seems invalid. */ /*************************************************/ const char * plugin_return_string(WimpMessage * m, string_value * sv) { int offset = ((char *) sv) - ((char *) m); if (!m || !sv || !sv->offset) return NULL; /* Is the offset of the string_value field within the message */ /* block out of range (i.e. the string_value does not appear */ /* to lie in the given message block)? */ if (offset >= m->hdr.size || offset < sizeof(m->hdr)) return NULL; /* Now read the string_value field itself */ if (sv->offset < 256) { if (sizeof(m->hdr) + offset >= m->hdr.size) return NULL; else return (const char *) (((char *) m) + sizeof(m->hdr) + sv->offset); } else return (const char *) sv->offset; } /*************************************************/ /* plugin_write_params_word() */ /* */ /* Writes a word to a given parameters file, */ /* in little-endian order. */ /* */ /* Parameters: RISC OS file handle of the file; */ /* */ /* Word to write. */ /*************************************************/ static _kernel_oserror * plugin_write_params_word(int fh, int word) { char integer[4]; /* #define Brain_Off... */ integer[0] = (word & 0xff); integer[1] = ((word & 0xff00) >> 8); integer[2] = ((word & 0xff0000) >> 16); integer[3] = ((word & 0xff000000) >> 24); RetError(_swix(OS_BPut, _INR(0,1), integer[0], fh)); RetError(_swix(OS_BPut, _INR(0,1), integer[1], fh)); RetError(_swix(OS_BPut, _INR(0,1), integer[2], fh)); RetError(_swix(OS_BPut, _INR(0,1), integer[3], fh)); return NULL; } /*************************************************/ /* plugin_return_browser() */ /* */ /* Converts a browser instance handle to a */ /* browser_data structure pointer. */ /* */ /* Parameters: A browser instance handle. */ /* */ /* Returns: Pointer to a browser_data struct */ /* represented by the instance */ /* handle, or NULL if none is found. */ /*************************************************/ static browser_data * plugin_return_browser(unsigned int browser_instance_handle) { browser_data * b; if (!browser_instance_handle) return NULL; b = ((plugin_insts *) browser_instance_handle)->browser; if (!is_known_browser(b)) return NULL; return b; } /*************************************************/ /* plugin_write_params_string() */ /* */ /* Writes a string to a given parameters file, */ /* padding with zeros to a length which is a */ /* multiple of 4. If the string length, not */ /* including terminator, is already a multiple */ /* of four, no extra bytes are written. */ /* */ /* Parameters: RISC OS file handle of the file; */ /* */ /* Pointer to the string. */ /*************************************************/ static _kernel_oserror * plugin_write_params_string(int fh, const char * string) { const char * s; int i = 0; int pad; /* Write the main string */ s = string ? string : ""; while (s[i]) { RetError(_swix(OS_BPut, _INR(0,1), s[i], fh)); i++; } /* Pad if necessary */ pad = 4 - (strlen(s) % 4); if (pad < 4) { for (i = 0; i < pad; i ++) { RetError(_swix(OS_BPut, _INR(0,1), '\0', fh)); } } return NULL; } /*************************************************/ /* plugin_write_params_entry() */ /* */ /* Writes an entry to the given parameters file. */ /* */ /* Parameters: RISC OS file handle of the file; */ /* */ /* Type of the entry (see */ /* PlugIn.h); */ /* */ /* Pointer to the name string; */ /* */ /* Pointer to the data string; */ /* */ /* Pointer to the Mime string. */ /* */ /* Assumes: Any of the pointers may be NULL */ /* or a zero length string to write */ /* a zero length field for that */ /* item. */ /*************************************************/ static _kernel_oserror * plugin_write_params_entry(int fh, int type, const char * name, const char * data, const char * mime) { int length; const char * n; const char * d; const char * m; /* Make life easier */ n = name ? name : ""; d = data ? data : ""; m = mime ? mime : ""; /* Write the type */ RetError(plugin_write_params_word(fh, type)); /* Calculate and write the entry length */ length = 4 + strlen(n); length = (int) WordAlign(length); length += 4 + strlen(d); length = (int) WordAlign(length); length += 4 + strlen(m); length = (int) WordAlign(length); RetError(plugin_write_params_word(fh, length)); /* The name field */ RetError(plugin_write_params_word(fh, strlen(n))); RetError(plugin_write_params_string(fh, n)); /* The data field */ RetError(plugin_write_params_word(fh, strlen(d))); RetError(plugin_write_params_string(fh, d)); /* The mime type field */ RetError(plugin_write_params_word(fh, strlen(m))); RetError(plugin_write_params_string(fh, m)); return NULL; } /*************************************************/ /* plugin_write_params() */ /* */ /* Writes a parameters file to a unique filename */ /* based on the given HStream. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the HStream; */ /* */ /* Pointer to the HStream struct */ /* representing the OBJECT, APPLET */ /* or EMBED tag that the parameters */ /* file is for; */ /* */ /* Buffer for the filename that was */ /* used, or if the buffer size given */ /* is zero, pointer to the filename */ /* to use; */ /* */ /* Size of the buffer, or zero if */ /* the above parameter is a pointer */ /* to the filename to use instead of */ /* a pointer to a buffer to receive */ /* a locally generated system unique */ /* filename; */ /* */ /* Pointer to a BBox describing the */ /* size of the Plug-In window. */ /*************************************************/ _kernel_oserror * plugin_write_params(browser_data * b, HStream * t, char * buffer, int buffer_size, BBox * position) { _kernel_oserror * e = NULL; int fh = 0; char * data; char version[5]; char number [64]; if (buffer_size) protocols_util_make_unique_name(buffer, buffer_size); RetError(_swix(OS_Find, _INR(0,1) | _OUT(0), 0x8c, /* Create empty file with r/w access, return errors */ buffer, &fh)); /* Write the browser special fields */ data = browser_current_url(b); if (!data) data = browser_fetch_url(b); e = plugin_write_params_entry(fh, PlugIn_ParamType_BrowserSpecial, "BASEHREF", data, NULL); if (e) goto plugin_write_params_exit; data = lookup_token("_TaskName", 1, 0); e = plugin_write_params_entry(fh, PlugIn_ParamType_BrowserSpecial, "USERAGENT", data, NULL); if (e) goto plugin_write_params_exit; data = lookup_token("Version", 1, 0); StrNCpy0(version, data); e = plugin_write_params_entry(fh, PlugIn_ParamType_BrowserSpecial, "UAVERSION", version, NULL); if (e) goto plugin_write_params_exit; e = plugin_write_params_entry(fh, PlugIn_ParamType_BrowserSpecial, "APIVERSION", "1.10", NULL); if (e) goto plugin_write_params_exit; if (redraw_backcol(b) != -1) { char word[9]; sprintf(word, "%08x", redraw_backcol(b)); e = plugin_write_params_entry(fh, PlugIn_ParamType_BrowserSpecial, "BGCOLOR", word, NULL); } /* Now write details based on the Object type */ if ( ( HtmlOBJECTclassid(t) && *HtmlOBJECTclassid(t) ) ) { /* A code object, e.g. Java applet */ const char * cis = HtmlOBJECTclassid(t); const char * cie; /* Get details from the CLASSID attribute, giving just the leafname */ cie = cis + strlen(cis) - 1; while (cie > cis && *cie != '/') cie --; if (*cie == '/') cie++; e = plugin_write_params_entry(fh, PlugIn_ParamType_URLFromOBJECT, "CLASSID", cie, HtmlOBJECTcodetype(t)); if (e) goto plugin_write_params_exit; /* CODEBASE, if we have it */ if (HtmlOBJECTcodebase(t) && *HtmlOBJECTcodebase(t)) { e = plugin_write_params_entry(fh, PlugIn_ParamType_DataFromOBJECT, "CODEBASE", HtmlOBJECTcodebase(t), NULL); if (e) goto plugin_write_params_exit; } } else if (HtmlOBJECTdata(t) && *HtmlOBJECTdata(t)) { /* A data object, e.g. Shockwave movie */ e = plugin_write_params_entry(fh, PlugIn_ParamType_URLFromOBJECT, "DATA", HtmlOBJECTdata(t), HtmlOBJECTtype(t)); } /* Some generic bits */ if (HtmlOBJECTstandby(t) && *HtmlOBJECTstandby(t)) { e = plugin_write_params_entry(fh, PlugIn_ParamType_DataFromOBJECT, "STANDBY", HtmlOBJECTstandby(t), NULL); if (e) goto plugin_write_params_exit; } /* Width and height */ sprintf(number, "%d", (position->ymax - position->ymin) / 2); e = plugin_write_params_entry(fh, PlugIn_ParamType_DataFromOBJECT, "HEIGHT", number, NULL); if (e) goto plugin_write_params_exit; sprintf(number, "%d", (position->xmax - position->xmin) / 2); e = plugin_write_params_entry(fh, PlugIn_ParamType_DataFromOBJECT, "WIDTH", number, NULL); if (e) goto plugin_write_params_exit; /* If we have a child token stream, look for PARAM tags */ if (HtmlOBJECTstream(t)) { HStream * child = HtmlOBJECTstream(t); while (child) { if (child->tagno == TAG_PARAM) { int type; /* Get the entry type from the valuetype field of the tag */ switch (HtmlPARAMvaluetype(child)) { default: case paramtype_DATA: type = PlugIn_ParamType_DataFromPARAM; break; case paramtype_OBJECT: type = PlugIn_ParamType_ObjectFromPARAM; break; case paramtype_REF: type = PlugIn_ParamType_URLFromPARAM; break; } /* Write the entry */ e = plugin_write_params_entry(fh, type, HtmlPARAMname(child), HtmlPARAMvalue(child), HtmlPARAMtype(child)); if (e) goto plugin_write_params_exit; } child = child->next; } } /* Write the terminating entry */ RetError(plugin_write_params_word(fh, PlugIn_ParamType_Terminator)); plugin_write_params_exit: /* Exit by closing the file and returning any */ /* generated error. */ if (fh) { _swix(OS_Find, _INR(0,1), 0, /* Close file */ fh); /* Set the filetype */ _swix(OS_File, _INR(0,2), 18, buffer, FileType_DATA); } return e; } /*************************************************/ /* plugin_add_queue_item() */ /* */ /* Add details of a new Plug-In to the queue of */ /* Plug-Ins. If there were none already in the */ /* queue, then start this new one immediately. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to the HStream struct */ /* representing the OBJECT, APPLET */ /* or EMBED tag (Object) that the */ /* message is for; */ /* */ /* Pointer to a BBox describing the */ /* where the Plug-In should open, in */ /* parent window coordinates. */ /*************************************************/ _kernel_oserror * plugin_add_queue_item(browser_data * b, HStream * t, BBox * position) { plugin_queue * new; int start_now = 0; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_queue_item: Called for %p, %p\n",b,t); #endif /* Allocate memory for the item */ new = malloc(sizeof(plugin_queue)); if (!new) return make_no_memory_error(21); if (plugin_queue_head) { /* Insert the new item in between the existing first and second items */ new->next = plugin_queue_head->next; plugin_queue_head->next = new; } else { new->next = NULL; plugin_queue_head = new; /* This is the only item in the queue, so try to start a Plug-In */ /* for it as soon as possible. */ start_now = 1; } /* Fill in the rest of the structure */ new->browser = b; new->token = t; new->position = *position; /* If required, try to start the Plug-In */ if (start_now) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_queue_item: Exitting through plugin_broadcast_open\n"); #endif return plugin_broadcast_open(); } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_queue_item: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_remove_item() */ /* */ /* Remove an item from the Plug-In queue. */ /* */ /* Parameters: Pointer to the plugin_queue */ /* struct to remove. */ /*************************************************/ _kernel_oserror * plugin_remove_item(plugin_queue * remove) { plugin_queue * prev; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_item: Called for %p\n",remove); #endif /* Can't do anything if there are no items */ if (!plugin_queue_head || !remove) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "NULL queue head (0x%08x) or remove item (0x%08x)in plugin_remove_item", (int) plugin_queue_head, (int) remove); return &erb; #endif return NULL; } /* Find the previous item */ prev = plugin_queue_head; while (prev && prev->next != remove) prev = prev->next; /* If we've not found the item we were asked to remove, and */ /* the remove item isn't at the queue head, 'remove' must */ /* be invalid - so exit. */ if (!prev && remove != plugin_queue_head) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Can't find item that points to given structure %0x08x in plugin_remove_item", (int) remove); return &erb; #endif return NULL; } /* OK, unlink it */ if (prev) prev->next = remove->next; else plugin_queue_head = remove->next; /* Free the item - finished. */ free(remove); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_item: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_remove_head_item() */ /* */ /* Remove the head item from the Plug-In queue, */ /* launching the next item if there is one. */ /*************************************************/ static _kernel_oserror * plugin_remove_head_item(void) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_head_item: Called\n"); #endif RetError(plugin_remove_item(plugin_queue_head)); if (plugin_queue_head) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_head_item: Exitting through plugin_broadcast_open\n"); #endif return plugin_broadcast_open(); } else { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_head_item: Successful\n"); #endif return NULL; } } /*************************************************/ /* plugin_flush_queue() */ /* */ /* Remove selected, or all Plug-Ins in the */ /* queue. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Plug-Ins to */ /* remove, or NULL for all items; */ /* */ /* If one of the removed items was */ /* at the head of the queue, 1 to */ /* launch the new head item Plug-In, */ /* else 0. */ /*************************************************/ _kernel_oserror * plugin_flush_queue(browser_data * b, int start_now) { plugin_queue * old_head = plugin_queue_head; plugin_queue * current; plugin_queue * next; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_queue: Called for %p\n",b); #endif current = plugin_queue_head; /* For each item, remove it only if it belongs to the given */ /* browser, or the given browser is NULL. */ while (current) { next = current->next; if (!b || (b && next->browser == b)) RetError(plugin_remove_item(current)); current = next; } /* If there are still queue items, the head item has changed and */ /* the start_now parameter passed in says to do so, launch the */ /* new head item Plug-In. */ if ( plugin_queue_head && plugin_queue_head != old_head && start_now ) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_queue: Exitting through plugin_broadcast_open\n"); #endif return plugin_broadcast_open(); } else { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_queue: Successful\n"); #endif return NULL; } } /*************************************************/ /* plugin_broadcast_open() */ /* */ /* Where it all starts - broadcast a */ /* Message_PlugIn_Open for the Plug-In at the */ /* head of the queue. */ /* */ /* External functions should invoke this by */ /* adding to the Plug-In queue, not by a direct */ /* call here. */ /*************************************************/ static _kernel_oserror * plugin_broadcast_open(void) { _kernel_oserror * e; char params[Limits_OS_Pathname]; const char * type; WimpMessage m; MPlugIn_Open * open = (MPlugIn_Open *) &m.data; browser_data * b; unsigned int browser_instance; HStream * t; BBox * position; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_broadcast_open: Called, head item is %p\n", plugin_queue_head); #endif /* Can't do anything if there are no queue items */ if (!plugin_queue_head) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "NULL queue head in plugin_broadcast_open"); return &erb; #endif return NULL; } /* Make life a bit less verbose... */ b = plugin_queue_head->browser; t = plugin_queue_head->token; position = &plugin_queue_head->position; #ifdef TRACE if (tl & (1u<<30)) { char debugbuf[1024]; sprintf(debugbuf,"plugin_broadcast_open: Open at BBox %d, %d, %d, %d",position->xmin,position->ymin,position->xmax,position->ymax); Printf("%s\n",debugbuf); } #endif /* Write the parameters file */ RetError(plugin_write_params(b, t, params, sizeof(params), position)); // For debugging, this may be useful... // // plugin_write_params(b, t, "ADFS::4.$.DebugParam", 0, position); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_broadcast_open: Params file is at '%s'\n",params); #endif /* Fill in the header */ m.hdr.size = sizeof(MPlugIn_Open) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_Open; /* Get an instance handle */ RetError(plugin_obtain_instance(b, t, &browser_instance)); /* Fill in the body */ open->flags = 0; open->reserved = 0; open->browser_instance_handle = browser_instance; open->parent_window_handle = b->window_handle; open->parent_area = *position; open->file_type = 0; /* Get the Mime type */ type = HtmlOBJECTcodetype(t); if (!type || !*type) type = HtmlOBJECTtype(t); /* If we've got one, ask the Mime Mapper what RISC OS filetype this is */ if (type && *type) { if (mimemap_mime_to_riscos(type, &open->file_type)) open->file_type = FileType_DATA; } /* Otherwise get it from the filename extension */ else { const char * data = HtmlOBJECTclassid(t); const char * ext; open->file_type = FileType_DATA; if (!data || !*data) data = HtmlOBJECTdata(t); if (data && * data) { ext = data + strlen(data) - 1; while (ext >= data && *ext != '.') ext--; if (*ext == '.') { if (mimemap_extension_to_riscos(ext, &open->file_type)) open->file_type = FileType_DATA; } } } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_broadcast_open: Filetype to use: 0x%03X\n", open->file_type); #endif /* If we already have RMA space for the filename, free it */ if (plugin_open_filename) { rma_release(NULL, plugin_open_filename); plugin_open_filename = NULL; } /* (Re)claim RMA space for the filename */ e = rma_claim(NULL, strlen(params) + 1, (void **) &plugin_open_filename); if (e) return e; if (!plugin_open_filename) return NULL; /* Copy it in and fill in the message field */ strcpy(plugin_open_filename, params); open->file_name.ptr = plugin_open_filename; /* Broadcast the message */ RetError(wimp_send_message(Wimp_EUserMessageRecorded, &m, 0, 0, NULL)); /* Record my_ref in case it bounces */ plugin_open_reference = m.hdr.my_ref; plugin_open_tried_once = 0; /* We haven't tried once until we get the first bounce */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_broadcast_open: Successful\n",b,t); #endif return NULL; } /*************************************************/ /* plugin_open_bounced() */ /* */ /* Handle a Message_PlugIn_Open bounce. */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* holding the bounced message. */ /*************************************************/ _kernel_oserror * plugin_open_bounced(WimpMessage * m) { browser_data * b; MPlugIn_Open * open = (MPlugIn_Open *) &m->data; #ifdef TRACE if (!plugin_open_tried_once) { if (tl & (1u<<30)) Printf("plugin_open_bounced: Called\n"); } else { if (tl & (1u<<30)) Printf("plugin_open_bounced: Called again\n"); } #endif /* For a bounce, we get the same message back - so the message reference */ /* is still in my_ref, it hasn't been copied to your_ref by a receiver. */ if (m->hdr.my_ref == plugin_open_reference) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_open_bounced: Message reference %x is known\n", m->hdr.my_ref); #endif if (plugin_open_tried_once) { /* Yuk, everything collapsed in a nasty great heap */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_open_bounced: Plug-In launch failed\n"); #endif /* Delete the parameters file */ remove(plugin_open_filename); /* Need to free up the RMA space used for the filename */ rma_release(NULL, plugin_open_filename); plugin_open_filename = NULL; plugin_open_reference = 0; plugin_open_tried_once = 0; /* Remove the item from the queue, launching a new one */ /* if there is anything else there. */ RetError(plugin_remove_head_item()); } else { char combuf[16]; /* Size of '@PlugInType_xxx' plus terminator */ char sysvar[22]; /* As above, preceeded by 'Alias$' */ _kernel_swi_regs r; int required; BBox new; /* Try launching the Plug-In through Wimp_StartTask */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_open_bounced: Attempting Plug-In launch\n"); #endif plugin_open_tried_once = 1; if (open->file_type >= 0 && open->file_type <= 4095) sprintf(combuf, "@PlugInType_%03x", open->file_type); else sprintf(combuf, "@PlugInType_%03x", FileType_DATA); strcpy(sysvar, "Alias$"); strcat(sysvar, combuf); /* Does the system variable exist? */ r.r[0] = (int) sysvar; r.r[1] = (int) NULL; r.r[2] = -1; r.r[3] = 0; r.r[4] = 0; /* _swix will not work correctly for this particular SWI if */ /* requiring the returned R2 value. Something to do with */ /* the call relying on generating an error, but _swix spots */ /* it and pulls out earlier than the call expects. Or some */ /* such thing... */ _kernel_swi(OS_ReadVarVal, &r, &r); required = -r.r[2]; if (required) { show_error_ret(_swix(Wimp_StartTask, _IN(0), combuf)); } #ifdef TRACE else { if (tl & (1u<<30)) Printf("plugin_open_bounced: System variable '%s' is not set\n", sysvar); } #endif /* Now rebroadcast the message. Note we can't use the same position, */ /* as between the two redrawing may have occurred that has changed */ /* where the Object now sits. */ b = plugin_return_browser(open->browser_instance_handle); if (!b) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_open_bounced: \0211Invalid browser instance handle suspected.\0217\n"); #endif return NULL; } if ( !object_get_token_object_box(b, ((plugin_insts *) open->browser_instance_handle)->token, &new) ) open->parent_area = new; #ifdef TRACE if (tl & (1u<<30)) { char debugbuf[1024]; sprintf(debugbuf,"plugin_open_bounced: New BBox %d, %d, %d, %d",new.xmin,new.ymin,new.xmax,new.ymax); Printf("%s\n",debugbuf); if (tl & (1u<<30)) Printf("plugin_open_bounced: Rebroadcasting Message_PlugIn_Open\n"); } #endif m->hdr.my_ref = m->hdr.your_ref = 0; RetError(wimp_send_message(Wimp_EUserMessageRecorded, m, 0, 0, NULL)); /* Record my_ref in case it bounces for a second time */ plugin_open_reference = m->hdr.my_ref; } } #ifdef TRACE else { if (tl & (1u<<30)) Printf("plugin_open_bounced: Message reference %x is not known\n", m->hdr.my_ref); erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Unknown message reference %x in plugin_open_bounced", m->hdr.my_ref); return &erb; } if (tl & (1u<<30)) Printf("plugin_open_bounced: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_got_opening() */ /* */ /* Handle reception of a Message_PlugIn_Opening. */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* relevant to the message. */ /*************************************************/ _kernel_oserror * plugin_got_opening(WimpMessage * m) { _kernel_oserror * e = NULL; browser_data * b; MPlugIn_Opening * opening = (MPlugIn_Opening *) &m->data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_opening: Called\n"); #endif if (m->hdr.your_ref == plugin_open_reference) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_opening: Message reference %x is known\n", m->hdr.your_ref); #endif if (plugin_open_filename) { if (!(opening->flags & MPlugIn_Opening_WillDeleteParamsItself)) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_opening: Removing parameters file\n"); #endif remove(plugin_open_filename); } /* Need to free up the RMA space used for the filename */ rma_release(NULL, plugin_open_filename); plugin_open_filename = NULL; } b = plugin_return_browser(opening->browser_instance_handle); if (!b) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_opening: \0211Invalid browser instance handle suspected.\0217\n"); #endif return NULL; } /* Tell the Object the PlugIn details */ object_set_token_object_plugin(b, ((plugin_insts *) opening->browser_instance_handle)->token, opening->plugin_instance_handle, m->hdr.sender); /* Deal with cases where the Plug-In wants stuff fetching */ if (opening->flags & MPlugIn_Opening_WantsDataResourceFetched) { const char * url = NULL; if (b) url = HtmlRelativiseURL(browser_current_url(b), HtmlOBJECTdata(((plugin_insts *) opening->browser_instance_handle)->token), b->stream); if (!url) url = HtmlOBJECTdata(((plugin_insts *) opening->browser_instance_handle)->token); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_opening: Plug-In wants data resource fetched\n"); #endif e = plugin_start_new_stream(opening->browser_instance_handle, url, opening->plugin_instance_handle, m->hdr.sender); } plugin_open_reference = 0; plugin_open_tried_once = 0; plugin_open_filename = NULL; if (e) return e; /* Remove the item from the queue, launching a new one */ /* if there is anything else there. */ RetError(plugin_remove_head_item()); } #ifdef TRACE else { if (tl & (1u<<30)) Printf("plugin_got_opening: Message reference %x is not known\n", m->hdr.my_ref); erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Unknown message reference %x in plugin_got_opening", m->hdr.your_ref); return &erb; } if (tl & (1u<<30)) Printf("plugin_got_opening: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_send_close() */ /* */ /* Tell a Plug-In to close down. */ /* */ /* Parameters: Browser instance handle for the */ /* browser owning the Plug-In; */ /* */ /* Task handle for the Plug-In; */ /* */ /* Plug-In instance handle. */ /*************************************************/ _kernel_oserror * plugin_send_close(unsigned int b, unsigned int task, unsigned int instance) { _kernel_oserror * e; WimpMessage m; MPlugIn_Close * close = (MPlugIn_Close *) &m.data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_send_close: Called\n"); #endif /* Fill in the header... */ m.hdr.size = sizeof(MPlugIn_Close) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_Close; /* ...and the body... */ close->flags = 0; close->plugin_instance_handle = instance; close->browser_instance_handle = b; /* ...then send it. */ e = wimp_send_message(Wimp_EUserMessageRecorded, &m, task, 0, NULL); #ifdef TRACE if (tl & (1u<<30)) { if (e) Printf("plugin_send_close: Exitting with error\n"); else Printf("plugin_send_close: Successful\n"); } #endif return e; } /*************************************************/ /* plugin_got_reshape_request() */ /* */ /* Handle reception of a */ /* Message_PlugIn_ReshapeRequest. */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* relevant to the message. */ /*************************************************/ _kernel_oserror * plugin_got_reshape_request(WimpMessage * m) { MPlugIn_ReshapeRequest * request = (MPlugIn_ReshapeRequest *) &m->data; browser_data * b; HStream * t; unsigned int plugin_task; int line; BBox size; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_reshape_request: Called\n"); #endif /* Does this look valid? */ if (!request->browser_instance_handle) { /* No; do nothing */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_reshape_request: Message held a NULL browser instance handle\n"); #endif return NULL; } /* Find the Object representing this Plug-In */ b = plugin_return_browser(request->browser_instance_handle); if ( !is_known_browser(b) || !object_return_info(b, request->plugin_instance_handle, &t, &plugin_task) ) { /* Can't find the Object / not a valid browser */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_reshape_request: %p isn't a known browser, or can't find an Object to match the given handle\n", b); #endif return NULL; } /* Does the task handle match? */ if (plugin_task != (unsigned int) m->hdr.sender) { /* No, so exit */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_reshape_request: Senders task handle of %08x doens't match Object's handle, %08x\n", m->hdr.sender, plugin_task); #endif return NULL; } /* Right, this looks like a valid request. Find out */ /* the ancestor line it lies in so we can reformat */ /* the page from here. */ line = tokenutils_find_ancestor_line(b, t); /* Get the object's current size */ RetError(object_get_token_object_size(b, t, &size)); /* Only proceed if the size has changed */ if ( size.xmax - size.xmin != request->width || size.ymax - size.ymin != request->height ) { size.xmin = 0; size.ymin = 0; size.xmax = request->width; size.ymax = request->height; RetError(object_set_token_object_size(b, t, &size)); /* Do a reformat if we had a valid line */ if (line >= 0) RetError(reformat_format_from(b, line - 1, 1, 0)); } return NULL; } /*************************************************/ /* plugin_send_original_reshape() */ /* */ /* Tell a Plug-In to reposition or resize itself */ /* - not as part of a Plug-In request to resize. */ /* */ /* Parameters: Browser instance handle for the */ /* browser owning the Plug-In; */ /* */ /* Plug-In task handle; */ /* */ /* Plug-In instance handle; */ /* */ /* New bounding box for the Plug-In */ /* child window (in (parent) window */ /* coordinates). */ /*************************************************/ _kernel_oserror * plugin_send_original_reshape(unsigned int b, unsigned int task, unsigned int instance, BBox * position) { _kernel_oserror * e; WimpMessage m; MPlugIn_Reshape * reshape = (MPlugIn_Reshape *) &m.data; #ifdef TRACE if (tl & (1u<<30)) { char debugbuf[1024]; sprintf(debugbuf,"plugin_send_original_reshape: Called for %p to move instance 0x%08x to %d, %d, %d, %d",(plugin_insts *) b,instance,position->xmin,position->ymin,position->xmax,position->ymax); Printf("%s\n",debugbuf); } #endif /* Fill in the header... */ m.hdr.size = sizeof(MPlugIn_Reshape) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_Reshape; /* ...and the body... */ reshape->flags = 0; reshape->plugin_instance_handle = instance; reshape->browser_instance_handle = b; reshape->parent_window_handle = ((plugin_insts *) b)->browser->window_handle; reshape->parent_area = *position; /* ...then send it. */ e = wimp_send_message(Wimp_EUserMessageRecorded, &m, task, 0, NULL); #ifdef TRACE if (tl & (1u<<30)) { if (e) Printf("plugin_send_original_reshape: Exitting with error\n"); else Printf("plugin_send_original_reshape: Successful\n"); } #endif return e; } /*************************************************/ /* plugin_got_url_access() */ /* */ /* Handle reception of a */ /* Message_PlugIn_URLAccess */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* relevant to the message. */ /*************************************************/ _kernel_oserror * plugin_got_url_access(WimpMessage * m) { MPlugIn_URLAccess * access = (MPlugIn_URLAccess *) &m->data; const char * url; const char * target; browser_data * targetted; browser_data * b = plugin_return_browser(access->browser_instance_handle); browser_data * ancestor = utils_ancestor(b); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_url_access: Called\n"); #endif url = plugin_return_string(m, &access->url); target = plugin_return_string(m, &access->target); #ifdef TRACE if (tl & (1u<<30)) { if (url) Printf("plugin_got_url_access: URL '%s'\n", url); else Printf("plugin_got_url_access: No URL\n"); if (target) Printf("plugin_got_url_access: Target '%s'\n", target); else Printf("plugin_got_url_access: No Target\n"); } #endif if (url) { /* Relativise the URL if possible */ if (b) { char * new_url = HtmlRelativiseURL(browser_current_url(b), url, b->stream); if (new_url) url = new_url; } if (target) { /* If a target is given, this is a standard URL fetch in a window */ if (target) targetted = frames_find_target(b, target); else targetted = NULL; /* Don't want to ever open a new window if configured */ /* to run full screen. */ if (targetted || choices.full_screen) { /* If a named target was found, open in that. Otherwise we must */ /* be running full screen, so can't open a new window; in this */ /* case, open in the ancestor. */ RetError(fetchpage_new(targetted ? targetted : ancestor, url, 1, 1)); } else { /* If we've reached here, a named target wasn't found but the */ /* browser isn't running full screen either, so open a new */ /* window with the name specified in the link. */ RetError(windows_create_browser((char *) url, NULL, NULL, (char *) target, Windows_CreateBrowser_Normal)); } } else { /* If a target is not given, we're supposed to fetch a file */ /* on behalf of a Plug-In. */ RetError(plugin_start_new_stream(access->browser_instance_handle, url, access->plugin_instance_handle, m->hdr.sender)); } } return NULL; } /*************************************************/ /* plugin_got_status() */ /* */ /* Handle reception of a Message_PlugIn_Status. */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* relevant to the message. */ /*************************************************/ _kernel_oserror * plugin_got_status(WimpMessage * m) { MPlugIn_Status * status = (MPlugIn_Status *) &m->data; browser_data * b = plugin_return_browser(status->browser_instance_handle); browser_data * ancestor = utils_ancestor(b); const char * message; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_status: Called\n"); #endif if (!b || !ancestor) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_status: \0211Can't find a valid [ancestor] browser\0217\n"); #endif return NULL; } message = plugin_return_string(m, &status->status); if (!message || !*message) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_status: Null message string or pointer; cancelling Plug-in message status\n"); #endif free(ancestor->plugin_status); ancestor->plugin_status = NULL; return toolbars_cancel_status(ancestor, Toolbars_Status_PlugIn); } /* Otherwise, we need to allocate space for the message in */ /* the browser_data structure so the Toolbar routines can */ /* get at it. */ free(ancestor->plugin_status); ancestor->plugin_status = malloc(strlen(message) + 1); if (ancestor->plugin_status) { /* Allocation successful - copy the string over and update */ /* the status bar. */ strcpy(ancestor->plugin_status, message); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_status: Successful with '%s'\n", message); #endif return toolbars_update_status(ancestor, Toolbars_Status_PlugIn); } else { /* Allocation failed - cancel any existing Plug-In message */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_status: Allocation for message string failed, cancelling status\n"); #endif return toolbars_cancel_status(ancestor, Toolbars_Status_PlugIn); } } /*************************************************/ /* plugin_got_busy() */ /* */ /* Handle reception of a Message_PlugIn_Busy. */ /* */ /* Parameters: Pointer to a Wimp_Message struct */ /* relevant to the message. */ /*************************************************/ _kernel_oserror * plugin_got_busy(WimpMessage * m) { MPlugIn_Busy * busy = (MPlugIn_Busy *) &m->data; browser_data * b = plugin_return_browser(busy->browser_instance_handle); browser_data * ancestor = utils_ancestor(b); int active; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_busy: Called\n"); #endif if (!b || !ancestor) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_busy: \0211Can't find a valid [ancestor] browser\0217\n"); #endif return NULL; } /* Are we setting or clearing a busy state? */ active = busy->flags & MPlugIn_Busy_IsBusy; if (ancestor->plugin_active != active) { ancestor->plugin_active = active; /* Are we turning it off? */ if (!active) { /* If we've only got a handler because of the Plug-In, turn it off */ /* and if required go to the drift handler instead. */ if (!b->anim_handler) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation,b); b->anim_handler = 0; /* If the Controls say to install the 'drift' handler to ensure */ /* the animation finishes on the first frame, and that handler is */ /* not already installed, install it. */ if (controls.anim_drift && !b->anim_drift) { register_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation_drift,b); b->anim_drift = 1; } } } /* The animation should be turned on / kept on */ else { /* Deregister any existing drift handler */ if (b->anim_drift) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation_drift,b); b->anim_drift = 0; } /* Register the full time animation handler, if it isn't already registered */ if (!b->anim_handler) { /* Is there an appropriate gadget in the status bar? */ ObjectId lower = toolbars_get_lower(b); BBox box; if (!gadget_get_bbox(0, lower, StatusBarAnimAnim, &box)) { /* Yes, so install an animation handler. Don't set the */ /* anim_handler flag! The fact that anim_handler is */ /* unset and plugin_active is set is used by other */ /* bits of code. */ register_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation,b); } } } } return NULL; } /*************************************************/ /* plugin_setup_stream() */ /* */ /* Sets up a plugin_stream structure in a new */ /* browser so it may fetch data for a plugin */ /* owned by another browser. */ /* */ /* Not all fields are filled in. The browser */ /* and token details are, and the URL field is */ /* filled in. The Mime type is also filled in */ /* on the basis of a filename extension from the */ /* URL, if possible. Other fields are zeroed. */ /* */ /* All string_value values are allocated in the */ /* RMA. It is therefore essential to ensure that */ /* these are always completely freed. */ /* */ /* Parameters: Browser instance handle for the */ /* browser owning the Plug-In; */ /* */ /* Pointer to a browser_data struct */ /* for the browser that will fetch */ /* the data; */ /* */ /* URL to fetch. */ /*************************************************/ _kernel_oserror * plugin_setup_stream(unsigned int owner, browser_data * fetcher, const char * url) { plugin_stream * stream; HStream * object = ((plugin_insts *) owner)->token; if (!url) return NULL; /* Allocate memory for the item */ stream = calloc(1, sizeof(plugin_stream)); if (!stream) return make_no_cont_memory_error(11); /* Now fill it in */ fetcher->pstream = stream; stream->browser_instance_handle = owner; stream->token = object; /* Claim RMA space for the URL */ RetError(rma_claim(fetcher, strlen(url) + 1, (void **) &stream->url.ptr)); strcpy(stream->url.ptr, url); /* Fill in the Mime type if there's a filename extension */ if (strrchr(url, '.')) { char mimetype[MimeMap_MaximumBufferSizeRequired]; if (!mimemap_extension_to_mime(strrchr(url, '.'), mimetype, sizeof(mimetype))) { RetError(rma_claim(fetcher, strlen(mimetype) + 1, (void **) &stream->mime.ptr)); strcpy(stream->mime.ptr, mimetype); } else stream->mime.ptr = NULL; } else stream->mime.ptr = NULL; /* Finished */ return NULL; } /*************************************************/ /* plugin_start_new_stream() */ /* */ /* Begin a fetch to a temporary file. When we */ /* have enough data to know the data type, */ /* the fetcher will start the stream message */ /* protocol, by calling */ /* plugin_send_original_stream_new. */ /* */ /* Parameters: Browser instance handle for the */ /* browser owning the Plug-In; */ /* */ /* URL to fetch; */ /* */ /* Plug-In instance handle; */ /* */ /* Plug-In task handle. */ /*************************************************/ _kernel_oserror * plugin_start_new_stream(unsigned int b, const char * data, unsigned int instance, unsigned int task) { plugin_stream * pstream; const char * file; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_start_new_stream: Called for %p, instance 0x%08x\n",(plugin_insts *) b,instance); #endif if (!data || !*data) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_start_new_stream: No URL to fetch - exitting\n"); #endif return NULL; } /* See if we've already got a temporary file in Scrap relating to this URL */ file = plugin_find_file(data); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_start_new_stream: Initiate fetch for '%s'\n",data); #endif /* Initiate a fetch for this item. If we've got a file holding */ /* the data already, give a null URL - windows_create_browser */ /* knows what this means (in the context of an object fetch). */ RetError(windows_create_browser(file ? NULL : (char *) data, NULL, NULL, NULL, Windows_CreateBrowser_ForPlugIn)); /* Add stream related information to the browser */ RetError(plugin_setup_stream(b, last_browser, data)); /* Fill in more information for the stream we're going to */ /* try and establish */ pstream = last_browser->pstream; pstream->browser_instance_handle = b; pstream->token = ((plugin_insts *) b)->token; /* (Because this is externally visible, whereas plugin_insts structures aren't) */ pstream->plugin_instance_handle = instance; pstream->plugin_task_handle = task; if (file) { /* If we've got a file already, need to remember its filename and */ /* start the message protocol to tell the Plug-In about it. */ RetError(rma_claim(last_browser, strlen(file) + 1, (void **) &pstream->filename.ptr)); strcpy(pstream->filename.ptr, file); RetError(plugin_send_original_stream_new(last_browser)); } /* OK, finished. The fetcher will now be called on Nulls (since we */ /* did windows_create_browser with a URL to start fetching on and */ /* set the flag to say 'for a Plug-In'), so the fetcher will now */ /* deal with things from here for a while. */ return NULL; } /*************************************************/ /* plugin_send_original_stream_new() */ /* */ /* Sent out a Message_PlugIn_StreamNew to start */ /* a fetch on a Plug-Ins behalf. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the stream - its */ /* 'pstream' field should point to a */ /* valid plugin_stream struct. */ /*************************************************/ _kernel_oserror * plugin_send_original_stream_new(browser_data * b) { WimpMessage m; MPlugIn_StreamNew * stream = (MPlugIn_StreamNew *) &m.data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_send_original_stream_new: Called for %p\n",b); #endif if (!b->pstream) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_send_original_stream_new: No plugin_stream - exitting\n"); #endif return NULL; } /* Fill in the header... */ m.hdr.size = sizeof(MPlugIn_StreamNew) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_StreamNew; /* ...and the body... */ stream->flags = 0; stream->plugin_instance_handle = b->pstream->plugin_instance_handle; stream->browser_instance_handle = (unsigned int) b->pstream->browser_instance_handle; stream->browser_stream_instance_handle = (unsigned int) b; stream->url.ptr = b->pstream->url.ptr; stream->eos = 0; stream->last_modified = 0; stream->notify = 0; stream->mime_type.ptr = b->pstream->mime.ptr; stream->window_target.ptr = b->pstream->target.ptr; /* Now send it. The reply should give us details on the flags (type */ /* of stream) and the plugin's stream instance handle. */ /* */ /* Of course, if it bounces we need to cancel the fetch, free up */ /* all the various bits and pieces assocated with the stream */ /* including the RMA space, and so-forth. */ RetError(wimp_send_message(Wimp_EUserMessageRecorded, &m, b->pstream->plugin_task_handle, -1, NULL)); plugin_stream_new_reference = m.hdr.my_ref; return NULL; } /*************************************************/ /* plugin_got_stream_new() */ /* */ /* Handles reception of a */ /* Message_PlugIn_StreamNew. Will consequently */ /* continue a fetch on behalf of a Plug-In, */ /* issuing Message_PlugIn_StreamAsFile when the */ /* fetch is complete. */ /* */ /* True streaming is not supported yet. */ /* */ /* Parameters: Pointer to a WimpMessage struct */ /* holding the message details. */ /*************************************************/ _kernel_oserror * plugin_got_stream_new(WimpMessage * m) { MPlugIn_StreamNew * stream = (MPlugIn_StreamNew *) &m->data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_stream_new: Called\n"); #endif if (m->hdr.your_ref == plugin_stream_new_reference) { browser_data * b; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_stream_new: Message reference %x is known\n", m->hdr.your_ref); #endif /* Get the browser that is fetching - this is stored as the */ /* stream instance handle. */ b = (browser_data *) stream->browser_stream_instance_handle; if (!is_known_browser(b)) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_stream_new: Browser %p is not known...\n", b); #endif return NULL; } b->pstream->plugin_stream_handle = stream->plugin_stream_instance_handle; b->pstream->stream_flags = stream->flags; /* We should take different action according to the flags, but at */ /* the moment only 'fetch as file' is supported. */ if (b->pstream->stream_flags & MPlugIn_StreamNew_StreamTypeMask != MPlugIn_StreamNew_StreamTypeAsFileOnly) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_got_stream_new: Can't handle stream type %d\n", b->pstream->stream_flags & MPlugIn_StreamNew_StreamTypeMask); erb.errnum = Utils_Error_Custom_Message; sprintf(erb.errmess, "Can't handle stream type %d in plugin_got_stream_new", b->pstream->stream_flags & MPlugIn_StreamNew_StreamTypeMask); show_error_ret(&erb); #endif return plugin_send_original_stream_destroy(b, MPlugIn_StreamDestroy_Reason_Error); } /* OK, we can handle the stream type. In that case, just exit; */ /* the fetcher will keep fetching, and when complete, will give */ /* the file to the Plug-In. */ /* */ /* So that it knows to do this, mark the stream as active. */ b->pstream->active = 1; } #ifdef TRACE else { if (tl & (1u<<30)) Printf("plugin_got_stream_new: Message reference %x is not known\n", m->hdr.your_ref); erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Unknown message reference %x in plugin_got_stream_new", m->hdr.your_ref); return &erb; } if (tl & (1u<<30)) Printf("plugin_got_stream_new: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_stream_new_bounced() */ /* */ /* Handles a Message_PlugIn_StreamNew bounce, */ /* aborting any associated fetch. */ /* */ /* Parameters: Pointer to a WimpMessage struct */ /* holding the message details. */ /*************************************************/ _kernel_oserror * plugin_stream_new_bounced(WimpMessage * m) { MPlugIn_StreamNew * stream = (MPlugIn_StreamNew *) &m->data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_stream_new_bounced: Called\n"); #endif /* Do we recognise the message (checking my_ref not your_ref since this */ /* is a bounce, not a reply)? */ if (m->hdr.my_ref == plugin_stream_new_reference) { browser_data * b; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_stream_new_bounced: Message reference %x is known\n", m->hdr.my_ref); #endif /* Get the browser that is fetching - this is stored as the */ /* stream instance handle. */ b = (browser_data *) stream->browser_stream_instance_handle; if (!is_known_browser(b)) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_stream_new_bounced: Browser %p is not known...\n", b); #endif return NULL; } /* The browser is known (current), so close it down. This takes */ /* care of everything, including memory management issues. */ windows_close_browser(b); } #ifdef TRACE else { if (tl & (1u<<30)) Printf("plugin_stream_new_bounced: Message reference %x is not known\n", m->hdr.my_ref); erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Unknown message reference %x in plugin_stream_new_bounced", m->hdr.my_ref); return &erb; } if (tl & (1u<<30)) Printf("plugin_stream_new_bounced: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_send_original_stream_destroy() */ /* */ /* Send a Message_PlugIn_StreamDestroy to a */ /* Plug-In, to close down a stream between a */ /* browser and a Plug-In. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* that was fetching data for the */ /* Plug-In, not the one that owns */ /* the actual Plug-In instance. */ /* */ /* Reason for shutting down the */ /* stream (see reason code */ /* definitions in PlugIn.h). */ /*************************************************/ _kernel_oserror * plugin_send_original_stream_destroy(browser_data * b, int reason) { WimpMessage m; MPlugIn_StreamDestroy * destroy = (MPlugIn_StreamDestroy *) &m.data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_send_original_stream_destroy: Called for %p\n",b); #endif /* Can't do anything if we don't have a browser with an */ /* associated plugin_stream structure */ if (!b || !b->pstream) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_send_original_stream_destroy: Null browser or plugin_stream pointer; exitting\n"); #endif return NULL; } /* Fill in the header... */ m.hdr.size = sizeof(MPlugIn_StreamDestroy) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_StreamDestroy; /* ...and the body... */ destroy->flags = 0; destroy->plugin_instance_handle = b->pstream->plugin_instance_handle; destroy->browser_instance_handle = b->pstream->browser_instance_handle; destroy->plugin_stream_instance_handle = b->pstream->plugin_stream_handle; destroy->browser_stream_instance_handle = (unsigned int) b; destroy->url.ptr = b->pstream->url.ptr; destroy->eos = b->pstream->eos; destroy->last_modified = b->pstream->last_modified; destroy->notify = b->pstream->notify; destroy->reason = reason; /* Send it */ return wimp_send_message(Wimp_EUserMessage, &m, b->pstream->plugin_task_handle, -1, NULL); } /*************************************************/ /* plugin_abort_stream() */ /* */ /* Stop any fetch on behalf of a Plug-In, and */ /* free all associated structures (with the */ /* exception of the fetching browser_data */ /* struct itself). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* which was dealing with the data */ /* streaming. */ /*************************************************/ _kernel_oserror * plugin_abort_stream(browser_data * b) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_abort_stream: Called for browser %p\n", b); #endif if (!b) return NULL; /* Do we have an active stream? If so, must tell the Plug-In */ /* that the stream is being destroyed. */ if (b->pstream->active) { RetError(plugin_send_original_stream_destroy(b, MPlugIn_StreamDestroy_Reason_User)); /* If we have a temporary file, remove it */ if (b->pstream->filename.ptr) remove(b->pstream->filename.ptr); } /* Now free the various RMA components */ if (b->pstream->url.ptr) rma_release(b, b->pstream->url.ptr); if (b->pstream->mime.ptr) rma_release(b, b->pstream->mime.ptr); if (b->pstream->target.ptr) rma_release(b, b->pstream->target.ptr); if (b->pstream->filename.ptr) rma_release(b, b->pstream->filename.ptr); /* Finally, free the plugin_stream structure itself */ free(b->pstream); b->pstream = NULL; /* Finished */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_abort_stream: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_fetch_completed() */ /* */ /* Called when a fetch for a Plug-In has been */ /* completed (e.g. by fetchpage_fetch). */ /* */ /* Parameters: Pointer to the browser_data */ /* struct doing the fetch, with its */ /* 'pstream' field pointing to a */ /* valid plugin_stream struct. */ /*************************************************/ _kernel_oserror * plugin_fetch_completed(browser_data * b) { WimpMessage m; MPlugIn_StreamAsFile * stream = (MPlugIn_StreamAsFile *) &m.data; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_fetch_completed: Called for %p\n", b); #endif if (!b || !b->pstream) return NULL; if (!b->pstream->active) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_fetch_completed: Stream is inactive, exitting\n"); erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Stream associated with browser %p is not active in plugin_fetch_completed", b); show_error_ret(&erb); #endif return NULL; } /* First, tell the Plug-In about the stream */ m.hdr.size = sizeof(MPlugIn_StreamAsFile) + sizeof(m.hdr); m.hdr.your_ref = 0; m.hdr.action_code = Message_PlugIn_StreamAsFile; /* Fill in the body */ stream->flags = 0; stream->plugin_instance_handle = b->pstream->plugin_instance_handle; stream->browser_instance_handle = b->pstream->browser_instance_handle; stream->plugin_stream_instance_handle = b->pstream->plugin_stream_handle; stream->browser_stream_instance_handle = (int) b; stream->url.ptr = b->pstream->url.ptr; stream->eos = b->pstream->eos; stream->last_modified = b->pstream->last_modified; stream->notify = b->pstream->notify; stream->pathname.ptr = b->pstream->filename.ptr; /* Send the message */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_fetch_completed: Sending Message_PlugIn_StreamAsFile\n"); #endif RetError(wimp_send_message(Wimp_EUserMessage, &m, b->pstream->plugin_task_handle, -1, NULL)); /* Install a null handler to close the stream down. Must do this */ /* to give the Plug-In time to deal with the message we've sent */ /* before we free all the strings it points to! */ /* */ /* Mark that this has been installed in the plugin_stream struct */ /* so fetcher functions know not to close the window themselves. */ b->pstream->will_close_itself = 1; register_null_claimant(Wimp_ENull, (WimpEventHandler *) plugin_close_stream, b); /* OK, finished. */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_fetch_completed: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_close_stream() */ /* */ /* Closes down a stream for a browser by marking */ /* it as inactive and calling */ /* windows_close_browser. */ /* */ /* Parameters are as for a standard Wimp event */ /* handler (this is called on null events). */ /* The handle should point to a browser_data */ /* struct that is dealing with the stream. */ /*************************************************/ static int plugin_close_stream(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_close_stream: Called for %p\n",handle); #endif /* Only proceed if this is a known browser */ if (is_known_browser(handle)) { handle->pstream->active = 0; handle->pstream->will_close_itself = 0; /* We've flagged the stream as inactive, so windows_close_browser */ /* (see below) won't end up sending Message_PlugIn_StreamDestroy */ /* to the Plug-In. So we must send it now (quoting a reason code */ /* of success, rather than error or user, as would have been sent */ /* via. windows_close_browser if we'd left the stream flagged as */ /* active). */ plugin_send_original_stream_destroy(handle, MPlugIn_StreamDestroy_Reason_Success); /* Record the temporary file details so it can be removed on shutdown. */ /* Only do this if the browser had a URL to fetch, since otherwise, */ /* we went through an existing file entry. */ plugin_add_file_entry(handle->pstream->filename.ptr, handle->pstream->url.ptr); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_close_stream: Calling windows_close_browser\n"); #endif /* Now shut the fetch down, freeing browser allocated memory */ /* associated with the stream in passing. */ windows_close_browser(handle); } #ifdef TRACE else { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_close_stream: This is not a recognised current browser...\n"); #endif } #endif /* Deregister the handler */ deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) plugin_close_stream, handle); /* Finished */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_close_stream: Successful\n"); #endif return 0; } /*************************************************/ /* plugin_add_file_entry() */ /* */ /* Adds a record of a Plug-In temporary file to */ /* the list of such records. Such files are */ /* deleted later, for example, on calling */ /* plugin_shutdown. */ /* */ /* Parameters: Pointer to the pathname to */ /* record; */ /* */ /* Pointer to the URL this relates */ /* to, or NULL if unknown. */ /*************************************************/ static _kernel_oserror * plugin_add_file_entry(const char * pathname, const char * url) { plugin_files * entry; int plen, ulen; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_file_entry: Called\n"); #endif if (!pathname || !*pathname) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_file_entry: Null pathname or null string; exitting\n"); #endif return NULL; } /* Is this entry already present? */ entry = plugin_files_head; while (entry) { /* If so, just exit */ if (entry->url && url && !strcmp(entry->url, url)) return NULL; entry = entry->next; } /* Find out string lengths */ plen = strlen(pathname); ulen = url ? strlen(url) : 0; /* Allocate memory for the structure itself */ entry = malloc(sizeof(plugin_files)); if (!entry) return make_no_memory_error(23); /* Allocate memory for the strings and copy them in */ if (plen) { entry->pathname = malloc(plen + 1); if (!entry->pathname) return make_no_memory_error(23); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_file_entry: Adding pathname '%s'\n", pathname); #endif strcpy(entry->pathname, pathname); } else entry->pathname = NULL; if (ulen) { entry->url = malloc(ulen + 1); if (!entry->url) return make_no_memory_error(23); #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_file_entry: Adding URL '%s'\n", url); #endif strcpy(entry->url, url); } else entry->url = NULL; /* Link the item in */ entry->next = plugin_files_head; plugin_files_head = entry; /* Finished */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_file_entry: Successful\n"); #endif return NULL; } /*************************************************/ /* plugin_find_file() */ /* */ /* Checks the records of Plug-In temporary files */ /* to see if one matches the given URL, and if */ /* so returns a pointer to the filename. */ /* */ /* Parameters: Pointer to the URL to check. */ /* */ /* */ /* Returns: Pointer to the filename relates */ /* to, or NULL if unknown. */ /*************************************************/ static const char * plugin_find_file(const char * url) { plugin_files * entry = plugin_files_head; while (entry) { if (entry->url && !strcmp(entry->url, url)) return entry->pathname; else entry = entry->next; } return NULL; } /*************************************************/ /* plugin_flush_files() */ /* */ /* Removes all records of Plug-In temporary */ /* files, deleteing (sp?) the files as it goes. */ /*************************************************/ static void plugin_flush_files(void) { plugin_files * entry = plugin_files_head; plugin_files * next; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_files: Called\n"); #endif while (entry) { next = entry->next; if (entry->url) { /* Free the URL string */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_files: Free URL '%s'\n", entry->url); #endif free(entry->url); } if (entry->pathname) { /* Delete the temporary file and free the pathname string */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_files: Remove and free pathname '%s'\n", entry->pathname); #endif remove(entry->pathname); free (entry->pathname); } /* Free the structure itself */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_files: Free entry '%p'\n", entry); #endif free(entry); /* Move to the next item */ entry = next; } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_files: Successful\n"); #endif plugin_files_head = NULL; return; } /*************************************************/ /* plugin_add_instance_entry() */ /* */ /* Adds a record of a Plug-In to the list of */ /* records, which the browser points to in the */ /* browser instance handles quoted back to those */ /* Plug-Ins. This allows a one word handle to */ /* give back information on the browser, token, */ /* Plug-In task handle, etc. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* which owns the Plug-In; */ /* */ /* Pointer to an HStream struct */ /* representing the Plug-In; */ /* */ /* The Plug-In task handle, if */ /* known (else 0). */ /*************************************************/ static _kernel_oserror * plugin_add_instance_entry(browser_data * b, HStream * t, unsigned int task) { plugin_insts * entry; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_instance_entry: Called for %p, %p, 0x%08x\n",b,t,task); #endif /* Allocate space for the entry */ entry = malloc(sizeof(plugin_insts)); if (!entry) return make_no_memory_error(24); /* Fill the entry in */ entry->browser = b; entry->token = t; entry->plugin_task_handle = task; entry->next = plugin_insts_head; plugin_insts_head = entry; /* Finished */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_add_instance_entry: Successful (new entry %p)\n",entry); #endif return NULL; } /*************************************************/ /* plugin_find_instance_entry() */ /* */ /* Finds an entry in the list of structures */ /* holding information on Plug-Ins, based on the */ /* owning browser and representing HStream */ /* struct. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* which owns the Plug-In; */ /* */ /* Pointer to an HStream struct */ /* representing the Plug-In. */ /* */ /* Returns: Pointer to the entry, or NULL if */ /* not found. */ /*************************************************/ static plugin_insts * plugin_find_instance_entry(browser_data * b, HStream * t) { plugin_insts * entry = plugin_insts_head; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_find_instance_entry: Called for %p, %p\n",b,t); #endif while (entry) { if (entry->browser == b && entry->token == t) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_find_instance_entry: Found one, returning %p\n",entry); #endif return entry; } entry = entry->next; } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_find_instance_entry: No entry found, returning NULL\n"); #endif return NULL; } /*************************************************/ /* plugin_obtain_instance() */ /* */ /* Returns an instance handle for a Plug-In */ /* based on the owning browser and representing */ /* HStream struct. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* which owns the Plug-In; */ /* */ /* Pointer to an HStream struct */ /* representing the Plug-In; */ /* */ /* Pointer to an unsigned int, in */ /* which the handle is written. */ /* */ /* Assumes: The int pointer may *not* be */ /* NULL. */ /*************************************************/ _kernel_oserror * plugin_obtain_instance(browser_data * b, HStream * t, unsigned int * instance) { plugin_insts * browser_instance = NULL; *instance = 0; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_obtain_instance: Called for %p, %p\n",b,t); #endif browser_instance = plugin_find_instance_entry(b, t); if (!browser_instance) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_obtain_instance: No existing item, creating a new one\n"); #endif RetError(plugin_add_instance_entry(b, t, 0)); browser_instance = plugin_insts_head; } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_obtain_instance: Returning %p\n",b,t); #endif *instance = (unsigned int) browser_instance; return NULL; } /*************************************************/ /* plugin_remove_instance_entry() */ /* */ /* Removes a record of a Plug-In from the list */ /* of such records. */ /* */ /* Parameters: Pointer to the entry (i.e. the */ /* browser instance handle quoted to */ /* the Plug-In to which the entry */ /* refers). */ /*************************************************/ static void plugin_remove_instance_entry(plugin_insts * remove) { plugin_insts * entry = plugin_insts_head; plugin_insts * prev = NULL; #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_instance_entry: Called for %p\n",remove); #endif /* Find the item */ while (entry) { if (entry == remove) { /* Found item, so remove it, linking the previous */ /* item to its next item as required. */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_instance_entry: Found it, removing item\n"); #endif if (prev) prev->next = entry->next; else plugin_insts_head = entry->next; free(entry); break; } /* Not found it, so move on to the next item */ prev = entry; entry = entry->next; } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_remove_instance_entry: Successful\n"); #endif return; } /*************************************************/ /* plugin_flush_instance_entries() */ /* */ /* Removes all Plug-In instance entries for a */ /* given browser, or unconditionally, all items. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* for which items will be removed, */ /* or NULL for all of them. */ /*************************************************/ void plugin_flush_instance_entries(browser_data * b) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_instance_entries: Called for %p\n",b); #endif if (!b) { /* Simple case first */ while (plugin_insts_head) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_instance_entries: Removing entry %p\n", plugin_insts_head); #endif plugin_remove_instance_entry(plugin_insts_head); } } else { plugin_insts * entry = plugin_insts_head; plugin_insts * next; /* Slightly more complex case for a specific browser */ while (entry) { next = entry->next; if (entry->browser == b) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_instance_entries: Removing entry %p\n", entry); #endif plugin_remove_instance_entry(entry); } entry = next; } } #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_flush_instance_entries: Successful %p\n",b); #endif return; } /*************************************************/ /* plugin_shutdown() */ /* */ /* Closes down all activities, flushing the */ /* Plug-In queue and freeing any RMA associated */ /* with string_value fields for in-transit */ /* messages. */ /*************************************************/ void plugin_shutdown(void) { #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_shutdown: Called\n"); #endif /* In transit Message_PlugIn_Open broadcasts */ if (plugin_open_filename) { rma_release(NULL, plugin_open_filename); plugin_open_filename = NULL; } /* Clear other message fields */ plugin_open_reference = 0; plugin_open_tried_once = 0; /* For now that's all we have to do for messages. Now */ /* flush out the various queues and lists. */ plugin_flush_queue(NULL, 0); plugin_flush_files(); plugin_flush_instance_entries(NULL); /* Finished */ #ifdef TRACE if (tl & (1u<<30)) Printf("plugin_shutdown: Successful\n"); #endif return; }