From d7627cecebad4abb64840561d7afa46a62e1dd6d Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Fri, 13 Aug 2004 00:55:59 +0000 Subject: [project @ 2004-08-13 00:55:59 by jmb] Rewrite of plugin handling. This is now much nicer than before although it has about the same amount of functionality. Note: This is now configurable via an option (defaults to OFF) This has only really been tested with the Flash plugin and seems to work reasonably. svn path=/import/netsurf/; revision=1216 --- riscos/gui.c | 25 +- riscos/options.h | 7 +- riscos/plugin.c | 2289 ++++++++++++++++++++++++++---------------------------- riscos/plugin.h | 78 +- 4 files changed, 1142 insertions(+), 1257 deletions(-) (limited to 'riscos') diff --git a/riscos/gui.c b/riscos/gui.c index 5cda9a0ee..82cc07f49 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -1001,24 +1001,47 @@ void ro_gui_user_message(wimp_event_no event, wimp_message *message) #endif #ifdef WITH_PLUGIN case message_PLUG_IN_OPENING: + plugin_opening(message); + break; case message_PLUG_IN_CLOSED: + plugin_closed(message); + break; case message_PLUG_IN_RESHAPE_REQUEST: + plugin_reshape_request(message); + break; case message_PLUG_IN_FOCUS: + break; case message_PLUG_IN_URL_ACCESS: + plugin_url_access(message); + break; case message_PLUG_IN_STATUS: + plugin_status(message); + break; case message_PLUG_IN_BUSY: + break; case message_PLUG_IN_STREAM_NEW: + plugin_stream_new(message); + break; case message_PLUG_IN_STREAM_WRITE: + break; case message_PLUG_IN_STREAM_WRITTEN: + plugin_stream_written(message); + break; case message_PLUG_IN_STREAM_DESTROY: + break; case message_PLUG_IN_OPEN: + if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) + plugin_open_msg(message); + break; case message_PLUG_IN_CLOSE: + if (event == wimp_USER_MESSAGE_ACKNOWLEDGE) + plugin_close_msg(message); + break; case message_PLUG_IN_RESHAPE: case message_PLUG_IN_STREAM_AS_FILE: case message_PLUG_IN_NOTIFY: case message_PLUG_IN_ABORT: case message_PLUG_IN_ACTION: - plugin_msg_parse(message, event == wimp_USER_MESSAGE_ACKNOWLEDGE); break; #endif #ifdef WITH_PRINT diff --git a/riscos/options.h b/riscos/options.h index 71cd06026..34e2b837a 100644 --- a/riscos/options.h +++ b/riscos/options.h @@ -47,6 +47,7 @@ extern bool option_buffer_animations; extern bool option_buffer_everything; extern char *option_homepage_url; extern bool option_open_browser_at_startup; +extern bool option_plugins; #define EXTRA_OPTION_DEFINE \ bool option_use_mouse_gestures = false;\ @@ -79,7 +80,8 @@ bool option_background_blending = true; \ bool option_buffer_animations = true; \ bool option_buffer_everything = false; \ char *option_homepage_url = 0; \ -bool option_open_browser_at_startup = false; +bool option_open_browser_at_startup = false; \ +bool option_plugins = false; #define EXTRA_OPTION_TABLE \ { "use_mouse_gestures", OPTION_BOOL, &option_use_mouse_gestures },\ @@ -112,5 +114,6 @@ bool option_open_browser_at_startup = false; { "buffer_animations", OPTION_BOOL, &option_buffer_animations }, \ { "buffer_everything", OPTION_BOOL, &option_buffer_everything }, \ { "homepage_url", OPTION_STRING, &option_homepage_url }, \ -{ "open_browser_at_startup",OPTION_BOOL, &option_open_browser_at_startup } +{ "open_browser_at_startup",OPTION_BOOL, &option_open_browser_at_startup }, \ +{ "plugins", OPTION_BOOL, &option_plugins } #endif diff --git a/riscos/plugin.c b/riscos/plugin.c index 61e907409..da939d2c8 100644 --- a/riscos/plugin.c +++ b/riscos/plugin.c @@ -2,21 +2,34 @@ * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 John M Bell + * Copyright 2003,4 John M Bell */ -/* - * TODO: - * - Reshaping plugin by request [Plugin_Reshape_Request (&4d545)] - * - Finish off stream protocol implementation (data from plugin) - * - Parse and act upon the rest of the Plugin_Opening flags - * - Implement remaining messages [Plugin_URL_Access, Plugin_Focus, - * Plugin_Busy, Plugin_Action, Plugin_Abort, Plugin_Inform(ed)?] - * - Handle standalone objects +/** \file + * Acorn Plugin protocol (implementation) + * + * This file implements the Acorn plugin protocol. + * See http://www.ecs.soton.ac.uk/~jmb202/riscos/acorn/funcspec.html + * for more details. + * + * The are still a number of outstanding issues: + * + * Stream Protocol: + * Fetching data, then streaming it to a plugin is not supported + * Streaming data from a plugin is not supported + * + * Messages: + * Most Plugin_Opening flags not supported + * No support for Plugin_Focus, Plugin_Busy, Plugin_Action + * No support for Plugin_Abort, Plugin_Inform, Plugin_Informed + * Plugin_URL_Access is only part-implemented + * + * No support for "helper" applications + * No support for standalone objects (must be embedded in HTML page) + * + * */ -// #define NDEBUG - #include #include #include @@ -24,6 +37,14 @@ #include #include +#include "oslib/mimemap.h" +#include "oslib/os.h" +#include "oslib/osfile.h" +#include "oslib/osfind.h" +#include "oslib/osgbpb.h" +#include "oslib/plugin.h" +#include "oslib/wimp.h" + #include "netsurf/utils/config.h" #include "netsurf/content/content.h" #include "netsurf/desktop/browser.h" @@ -31,1386 +52,1242 @@ #include "netsurf/render/html.h" #include "netsurf/render/box.h" #include "netsurf/riscos/gui.h" +#include "netsurf/riscos/options.h" #include "netsurf/riscos/plugin.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/utils.h" -#include "oslib/mimemap.h" -#include "oslib/os.h" -#include "oslib/osfile.h" -#include "oslib/osfind.h" -#include "oslib/osgbpb.h" -#include "oslib/plugin.h" -#include "oslib/wimp.h" #ifdef WITH_PLUGIN -/* parameters file creation */ -void plugin_write_parameters_file(struct object_params *params); -int plugin_calculate_rsize(char* name, char* data, char* mime); -struct plugin_param_item *plugin_add_item_to_pilist(struct plugin_param_item *pilist, int type, char* name, char* value, char* mime_type); - -/* stream handling */ -void plugin_create_stream(struct browser_window *bw, - struct object_params *params, struct content *c); -void plugin_write_stream(struct browser_window *bw, struct object_params *params, struct content *c); -void plugin_write_stream_as_file(struct browser_window *bw, - struct object_params *params, - struct content *c); -void plugin_destroy_stream(struct browser_window *bw, - struct object_params *params, struct content *c); - -/* linked list handling */ -struct plugin_message *plugin_add_message_to_linked_list(plugin_b browser, - plugin_p plugin, - wimp_message *m, - struct plugin_message *reply); -void plugin_remove_message_from_linked_list(struct plugin_message* m); -struct plugin_message *plugin_get_message_from_linked_list(int ref); -void plugin_add_instance_to_list(struct content *c, - struct browser_window *bw, - struct content *page, struct box *box, - struct object_params *params, void **state); -void plugin_remove_instance_from_list(struct object_params *params); -struct plugin_list *plugin_get_instance_from_list(plugin_b browser, - plugin_p plugin); - -/* message handling */ -void plugin_open_msg(wimp_message *message); -void plugin_opening(wimp_message *message); -void plugin_close_msg(wimp_message *message); -void plugin_closed(wimp_message *message); -void plugin_reshape_request(wimp_message *message); -void plugin_stream_new(wimp_message *message); -void plugin_stream_written(wimp_message *message); -void plugin_url_access(wimp_message *message); -void plugin_status(wimp_message *message); -char *plugin_get_string_value(os_string_value string, char *msg); - -/* others */ -void plugin_create_sysvar(const char *mime_type, char *sysvar); -int plugin_process_opening(struct object_params *params, - struct plugin_message *message); -void plugin_force_redraw(struct content *object, struct content *c, - unsigned int i); - -/*-------------------------------------------------------------------------*/ -/* Linked List pointers */ -/*-------------------------------------------------------------------------*/ - -static struct plugin_message pm = {0, 0, 0, 0, 0, &pm, &pm}; -static struct plugin_message *pmlist = ± - -static struct plugin_list pl = {0, 0, 0, 0, 0, 0, &pl, &pl}; -static struct plugin_list *plist = &pl; - -static int need_reformat = 0; - -/*-------------------------------------------------------------------------*/ -/* Externally visible functions */ -/*-------------------------------------------------------------------------*/ +static const char * const ALIAS_PREFIX = "Alias$@PlugInType_"; + +typedef enum { + PLUGIN_PARAMETER_DATA = 1, + PLUGIN_PARAMETER_URL = 2, + PLUGIN_PARAMETER_OBJECT = 3, + PLUGIN_PARAMETER_SPECIAL = 4 +} plugin_parameter_type; + +struct plugin_param_item { + + plugin_parameter_type type; + int rsize; + int nsize; + char *name; + int npad; + int vsize; + char *value; + int vpad; + int msize; + char *mime_type; + int mpad; + + struct plugin_param_item *next; +}; + +static bool plugin_create_sysvar(const char *mime_type, char* sysvar); +static void plugin_create_stream(struct content *c); +static void plugin_write_stream(struct content *c, unsigned int consumed); +static void plugin_write_stream_as_file(struct content *c); +static void plugin_destroy_stream(struct content *c); +static bool plugin_write_parameters_file(struct content *c, + struct object_params *params); +static int plugin_calculate_rsize(const char* name, const char* data, + const char* mime); +static bool plugin_add_item_to_pilist(struct plugin_param_item **pilist, + plugin_parameter_type type, const char* name, + const char* value, const char* mime_type); +static char *plugin_get_string_value(os_string_value string, char *msg); +static bool plugin_active(struct content *c); /** * Initialises plugin system in readiness for receiving object data + * + * \param c The content to hold the data + * \param params Parameters associated with the content + * \return true on success, false otherwise */ bool plugin_create(struct content *c, const char *params[]) { - union content_msg_data msg_data; - - c->data.plugin.data = calloc(0, 1); - if (!c->data.plugin.data) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - warn_user("NoMemory", 0); - return false; - } - c->data.plugin.length = 0; - /* we can't create the plugin here, because this is only called - * once, even if the object appears several times */ + LOG(("plugin_create")); + c->data.plugin.bw = 0; + c->data.plugin.page = 0; + c->data.plugin.box = 0; + c->data.plugin.taskname = 0; + c->data.plugin.filename = 0; + c->data.plugin.datafile = 0; + c->data.plugin.opened = false; + c->data.plugin.repeated = 0; + c->data.plugin.browser = 0; + c->data.plugin.plugin = 0; + c->data.plugin.browser_stream = 0; + c->data.plugin.plugin_stream = 0; + c->data.plugin.plugin_task = 0; + c->data.plugin.consumed = 0; + c->data.plugin.reformat_pending = false; + c->data.plugin.width = 0; + c->data.plugin.height = 0; + c->data.plugin.stream_waiting = false; + c->data.plugin.file_stream_waiting = false; return true; } /** - * The content has been added to a page somewhere: launch the plugin. - * This may be called anytime after plugin_create any number of times. - * Each must launch a new plugin. + * Convert a plugin ready for display (does nothing) * - * bw is the window which the plugin is in - * page, box, params are 0 if the object is standalone - * state may be use to store a pointer to state data + * \param c The content to convert + * \param width Width of available space + * \param height Height of available space + * \return true on success, false otherwise */ -void plugin_add_instance(struct content *c, struct browser_window *bw, - struct content *page, struct box *box, - struct object_params *params, void **state) +bool plugin_convert(struct content *c, int width, int height) { - char sysvar[40]; - char *varval, *filename, *p; - os_error *e; - wimp_message m; - plugin_message_open *pmo; - os_box b; - struct plugin_message *npm = xcalloc(1, sizeof(*npm)); - struct plugin_message *temp; - struct plugin_list *npl = xcalloc(1, sizeof(*npl)); - int flags = 0; - - if (params == 0) { - /* create object_params struct */ -/* struct object_params *nparams = xcalloc(1, sizeof(*nparams)); - params = nparams; - params->basehref = xstrdup(c->url); -*/ fprintf(stderr, - "Cannot handle standalone objects\n"); - gui_window_set_status(bw->window, - "Plugin Error: Cannot handle standalone objects"); - xfree(npm); - xfree(npl); - return; - } - - /* write parameters file */ - plugin_write_parameters_file(params); - - /* Get contents of Alias$@PlugInType_xxx system variable. */ - plugin_create_sysvar(c->mime_type, sysvar); - varval = getenv(sysvar); - LOG(("%s: %s", sysvar, varval)); - - /* Broadcast Message_PlugIn_Open (&4D540) and listen for response - * Message_PlugIn_Opening (&4D541). If no response, try to launch - * plugin by Wimp_StartTask(sysvar). Then re-broadcast Message_PlugIn_Open - * and listen for response. If there is still no response, give up. - * NB: For the bounding box in Message_PlugIn_Open, we choose arbitrary - * values outside the area displayed. This is corrected when - * plugin_reshape_instance is called. - */ - /* Initialise bounding box */ - b.x0 = -100; - b.x1 = 0; - b.y0 = 0; - b.y1 = 100; - - /* populate plugin_message_open struct */ - pmo = (plugin_message_open*)&m.data; - pmo->flags = 0; - pmo->reserved = 0; - pmo->browser = (plugin_b)params->browser; - pmo->parent_window = bw->window->window; - pmo->bbox = b; - xmimemaptranslate_mime_type_to_filetype(c->mime_type, &pmo->file_type); - pmo->filename.pointer = params->filename; - - m.size = 60; - m.your_ref = 0; - m.action = message_PLUG_IN_OPEN; - - /* add message to list */ - temp = plugin_add_message_to_linked_list((plugin_b)params->browser, (plugin_p)0, &m, (struct plugin_message*)0); - - LOG(("Sending Message: &4D540")); - e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, &m, wimp_BROADCAST); - - if (e) { - LOG(("Error: %s", e->errmess)); - plugin_remove_message_from_linked_list(temp); - xfree(npm); - xfree(npl); - return; - } - - /* wait for wimp poll */ - while(temp->poll == 0) - gui_poll(true); - - if(temp->plugin != 0 && temp->reply != 0) { - - /* ok, we got a reply */ - LOG(("Reply to message %p: %p", temp, temp->reply)); - flags = plugin_process_opening(params, temp); - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); - xfree(npm); - xfree(npl); - } else { - - /* no reply so issue Wimp_StartTask(varval) */ - LOG(("No reply to message %p", temp)); - plugin_remove_message_from_linked_list(temp); - - LOG(("Starting task: %s", varval)); - e = xwimp_start_task((char const*)varval, NULL); - - if (e) { - LOG(("Error: %s", e->errmess)); - xfree(npm); - xfree(npl); - return; - } - - /* hmm, deja-vu */ - temp = plugin_add_message_to_linked_list((plugin_b)params->browser, (plugin_p)0, &m, (struct plugin_message*)0); - LOG(("Re-Sending Message &4D540")); - e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, &m, - wimp_BROADCAST); - - if (e) { - LOG(("Error: %s", e->errmess)); - xfree(npm); - xfree(npl); - return; - } - - /* wait for wimp poll */ - while(temp->poll == 0) - gui_poll(true); - - if(temp->plugin != 0 && temp->reply != 0) { - - /* ok, we got a reply */ - LOG(("Reply to message %p: %p", temp, temp->reply)); - flags = plugin_process_opening(params, temp); - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); - xfree(npm); - xfree(npl); - } else { - - /* no reply so give up */ - LOG(("No reply to message %p", temp)); - plugin_remove_message_from_linked_list(temp); - xfree(npm); - xfree(npl); - return; - } - } - - /* At this point, it's certain that we can handle this object so - * add it to the list of plugin instances. - */ - plugin_add_instance_to_list(c, bw, page, box, params, state); - - /* TODO - handle other flags (see below) */ - if(flags & 0x4) { /* wants data fetching */ - plugin_create_stream(bw, params, c); - plugin_destroy_stream(bw, params, c); - - /* delete file_as_stream file - * (we don't care if the file doesn't exist) - */ - filename = strdup(params->filename); - p = strrchr((const char*)filename, 'p'); - filename[(p-filename)] = 'd'; - xosfile_delete((char const*)filename, NULL, NULL, - NULL, NULL, NULL); - } - - if (!(flags & 0x08)) /* will delete parameters file */ - xosfile_delete((char const*)params->filename, NULL, NULL, - NULL, NULL, NULL); + LOG(("plugin_convert")); + c->width = width; + c->height = height; + + /* deal with a plugin waiting for a normal stream */ + /** \todo I can see no reason for waiting for all the data + * If the plugin app wants to be streamed to, then it should + * be able to cope with repeated PLUG_IN_WRITE/PLUG_IN_WRITTEN + * message pairs (until all the data has been streamed. + * (In fact, the only reason we wait at all is because !Flash + * dies otherwise) + */ + if (c->data.plugin.stream_waiting) { + c->data.plugin.stream_waiting = false; + plugin_write_stream(c, 0); + } -} + /* deal with a plugin waiting for a file stream */ + if (c->data.plugin.file_stream_waiting) { + c->data.plugin.file_stream_waiting = false; + plugin_write_stream_as_file(c); + } + c->status = CONTENT_STATUS_DONE; + return true; +} /** - * Handle a window containing a CONTENT_PLUGIN being opened. + * Destroy a plugin content + * + * \param c The content to destroy */ - -void plugin_open(struct content *c, struct browser_window *bw, - struct content *page, struct box *box, - struct object_params *params) +void plugin_destroy(struct content *c) { + LOG(("plugin_destroy")); + if (c->data.plugin.taskname) + free(c->data.plugin.taskname); + if (c->data.plugin.filename) + free(c->data.plugin.filename); + if (c->data.plugin.datafile) + free(c->data.plugin.datafile); } - /** - * Process plugin_opening message flags - * NB: this is NOT externally visible. - * it's just here because it's referred to in the TODO above + * Redraw a content + * + * \param c The content to redraw + * \param x Left of content box + * \param y Top of content box + * \param width Width of content box + * \param height Height of content box + * \param clip[xy][01] Clipping rectangle + * \param scale Scale of page (1.0 = 100%) */ -int plugin_process_opening(struct object_params *params, - struct plugin_message *message) { - - plugin_message_opening *pmo; - - params->plugin = (int)message->reply->plugin; - params->plugin_task = (unsigned int)message->reply->m->sender; - - pmo = (plugin_message_opening*)&message->reply->m->data; -/* LOG(("pmo->flags = %x", pmo->flags)); - if(pmo->flags & 0x1) - LOG(("accepts input focus")); - if(pmo->flags & 0x2) - LOG(("wants code fetching")); - if(pmo->flags & 0x10) - LOG(("still busy")); - if(pmo->flags & 0x20) - LOG(("supports extended actions")); - if(pmo->flags & 0x40) - LOG(("has helper window")); -*/ - return (int)pmo->flags; +bool plugin_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale) +{ + /* do nothing */ + LOG(("plugin_redraw")); + return true; } + /** - * A plugin is no longer required, eg. the page containing it has - * been closed. + * Handle a window containing a CONTENT_PLUGIN being opened * - * Any storage associated with state must be freed. + * \param c The content to open + * \param bw The window to add the content to + * \param page The containing content + * \param box The containing box + * \param params Any parameters associated with the content + * \param state State data pointer */ -void plugin_remove_instance(struct content *c, struct browser_window *bw, - struct content *page, struct box *box, - struct object_params *params, void **state) +void plugin_open(struct content *c, struct browser_window *bw, + struct content *page, struct box *box, + struct object_params *params) { - wimp_message m; - plugin_message_close *pmc; - struct plugin_message *temp; + char sysvar[25]; + char *varval; + plugin_full_message_open pmo; + os_error *error; - if (params == 0) { - return; - } + if (!option_plugins) + return; - pmc = (plugin_message_close*)&m.data; - pmc->flags = 0; - pmc->plugin = (plugin_p)params->plugin; - pmc->browser = (plugin_b)params->browser; - m.size = 32; - m.your_ref = 0; - m.action = message_PLUG_IN_CLOSE; - - temp = plugin_add_message_to_linked_list(pmc->browser, pmc->plugin, &m, 0); - LOG(("Sending message &4D542")); - xwimp_send_message(wimp_USER_MESSAGE_RECORDED, &m, - (wimp_t)params->plugin_task); - - /* wait for wimp poll */ - while (temp == 0) - gui_poll(true); - - if (temp->reply != 0){ - - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); - } - else { - LOG(("message_PLUG_IN_CLOSE bounced")); - plugin_remove_message_from_linked_list(temp); - } - - /* delete instance from list */ - plugin_remove_instance_from_list(params); -} + /** \todo Standalone plugins */ + if (!params) { + LOG(("cannot handle standalone plugins")); + return; + } + /* we only do this here cos the box is needed by + * write_parameters_file. Ideally it would be at the + * end of this function with the other writes to c->data.plugin + */ + c->data.plugin.box = box; + + LOG(("writing parameters file")); + if (!plugin_write_parameters_file(c, params)) + return; + + LOG(("creating sysvar")); + /* get contents of Alias$@PlugInType_xxx variable */ + if (!plugin_create_sysvar(c->mime_type, sysvar)) + return; + + LOG(("getenv")); + varval = getenv(sysvar); + LOG(("%s: '%s'", sysvar, varval)); + if(!varval) { + return; + } -/** - * Handle a window containing a CONTENT_PLUGIN being closed. - */ + /* The browser instance handle is the content struct pointer */ + c->data.plugin.browser = (unsigned int)c; + + pmo.size = 60; + pmo.your_ref = 0; + pmo.action = message_PLUG_IN_OPEN; + pmo.flags = 0; + pmo.reserved = 0; + pmo.browser = (plugin_b)c->data.plugin.browser; + pmo.parent_window = bw->window->window; + pmo.bbox.x0 = -100; + pmo.bbox.x1 = pmo.bbox.y0 = 0; + pmo.bbox.y1 = 100; + error = xmimemaptranslate_mime_type_to_filetype(c->mime_type, + &pmo.file_type); + if (error) { + return; + } + pmo.filename.pointer = c->data.plugin.filename; -void plugin_close(struct content *c) -{ -} + c->data.plugin.repeated = 0; + LOG(("sending message")); + error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *)&pmo, wimp_BROADCAST); + if (error) { + LOG(("xwimp_send_message: 0x%x: %s", + error->errnum, error->errmess)); + return; + } -/** - * The box containing the plugin has moved or resized, - * or the window containing the plugin has resized if standalone. - */ -void plugin_reshape_instance(struct content *c, struct browser_window *bw, - struct content *page, struct box *box, - struct object_params *params, void **state) -{ - /* By now, we've got the plugin up and running in a nested window - * off the viewable page area. Now we want to display it in its place. - * Therefore, broadcast a Message_PlugIn_Reshape (&4D544) with the values - * given to us. - */ - wimp_message m; - plugin_message_reshape *pmr; - os_box bbox; - int x, y; - - if (params == 0) { - return; - } - - box_coords(box, (int*)&x, (int*)&y); - bbox.x0 = (x << 1); - bbox.y1 = -(y << 1); - bbox.x1 = (bbox.x0 + (box->width << 1)); - bbox.y0 = (bbox.y1 - (box->height << 1)); - - LOG(("Box w, h: %d %d", box->width, box->height)); - LOG(("BBox: [(%d,%d),(%d,%d)]", bbox.x0, bbox.y0, bbox.x1, bbox.y1)); - - pmr = (plugin_message_reshape*)&m.data; - pmr->flags = 0; - pmr->plugin = (plugin_p) params->plugin; - pmr->browser = (plugin_b) params->browser; - pmr->parent_window = (wimp_w) bw->window->window; - pmr->bbox = bbox; - - m.size = 52; - m.your_ref = 0; - m.action = message_PLUG_IN_RESHAPE; - - LOG(("Sending Message &4D544")); - xwimp_send_message(wimp_USER_MESSAGE, &m, (wimp_t)params->plugin_task); + c->data.plugin.bw = bw; + c->data.plugin.page = page; + c->data.plugin.taskname = strdup(varval); + LOG(("done")); } -static const char * const ALIAS_PREFIX = "Alias$@PlugInType_"; - /** - * Creates system variable from mime type - * NB: this is NOT externally visible - * it just makes sense to keep it with the ALIAS_PREFIX definition above. + * Handle a window containing a CONTENT_PLUGIN being closed. + * + * \param c The content to close */ -void plugin_create_sysvar(const char *mime_type, char* sysvar) +void plugin_close(struct content *c) { - unsigned int *fv; - os_error *e; - - e = xmimemaptranslate_mime_type_to_filetype(mime_type, (bits *) &fv); + plugin_full_message_close pmc; + os_error *error; + + LOG(("plugin_close")); + + if (!plugin_active(c) || !c->data.plugin.opened) + return; + + pmc.size = 32; + pmc.your_ref = 0; + pmc.action = message_PLUG_IN_CLOSE; + pmc.flags = 0; + pmc.browser = (plugin_b)c->data.plugin.browser; + pmc.plugin = (plugin_p)c->data.plugin.plugin; + + LOG(("sending message")); + error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *)&pmc, (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } - sprintf(sysvar, "%s%x", ALIAS_PREFIX, (unsigned int)fv); + /* delete the data file used to send the data to the plugin */ + if (c->data.plugin.datafile != 0) + xosfile_delete(c->data.plugin.datafile, 0, 0, 0, 0, 0); } /** - * Tests whether we can handle an object using a browser plugin - * returns true if we can handle it, false if we can't. + * Reformat a plugin content on a page + * + * \param c The content to reformat + * \param width New width + * \param height New height */ -bool plugin_handleable(const char *mime_type) +void plugin_reformat(struct content *c, int width, int height) { - char sysvar[40]; - unsigned int *fv; - os_error *e; - - e = xmimemaptranslate_mime_type_to_filetype(mime_type, (bits *) &fv); - if (e) { - LOG(("xmimemaptranslate_mime_type_to_filetype failed: %s", e->errmess)); - return false; - } - - sprintf(sysvar, "%s%x", ALIAS_PREFIX, (unsigned int)fv); - LOG(("%s, %s", mime_type, sysvar)); - if (getenv(sysvar) == 0) - return false; - return true; + plugin_full_message_reshape pmr; + int x, y; + os_error *error; + + LOG(("plugin_reformat")); + + if (!plugin_active(c)) + return; + + /* if the plugin hasn't yet been opened, queue the reformat */ + if (!c->data.plugin.opened) { + LOG(("queuing")); + c->data.plugin.reformat_pending = true; + c->data.plugin.width = width; + c->data.plugin.height = height; + return; + } + + box_coords(c->data.plugin.box, &x, &y); + pmr.size = 52; + pmr.your_ref = 0; + pmr.action = message_PLUG_IN_RESHAPE; + pmr.flags = 0; + + pmr.plugin = (plugin_p)c->data.plugin.plugin; + pmr.browser = (plugin_b)c->data.plugin.browser; + pmr.parent_window = c->data.plugin.bw->window->window; + pmr.bbox.x0 = x * 2; + pmr.bbox.y1 = -y * 2; + pmr.bbox.x1 = pmr.bbox.x0 + c->data.plugin.box->width * 2; + pmr.bbox.y0 = pmr.bbox.y1 - c->data.plugin.box->height * 2; + + LOG(("sending message")); + error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message *) &pmr, + (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } } /** - * processes data retrieved by the fetch process + * Creates a system variable from the mimetype + * + * \param mime_type The mime type + * \param sysvar Pointer to buffer into which the string should be written + * \return true on success, false otherwise. */ -bool plugin_process_data(struct content *c, char *data, unsigned int size) +bool plugin_create_sysvar(const char *mime_type, char* sysvar) { + unsigned int *fv; + os_error *e; - /* If the plugin requests, we send the data to it via the - * plugin stream protocol. - * Also, we should listen for Message_PlugIn_URL_Access (&4D54D) - * as the plugin may need us to retrieve URLs for it. - * We should also listen for Message_PlugIn_Closed (&4D543). - * If this occurs, the plugin has exited with an error. - * Therefore, we need to stop the fetch and exit. - */ - - /* I think we should just buffer the data here, in case the - * plugin requests it sometime in the future. - James */ - - char *plugin_data; - union content_msg_data msg_data; - - plugin_data = realloc(c->data.plugin.data, c->data.plugin.length + size); - if (!plugin_data) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - warn_user("NoMemory", 0); - return false; - } - c->data.plugin.data = plugin_data; - memcpy(c->data.plugin.data + c->data.plugin.length, data, size); - c->data.plugin.length += size; - c->size += size; - return true; -} + e = xmimemaptranslate_mime_type_to_filetype(mime_type, (bits *) &fv); + if (e) { + return false; + } -/** - * This isn't needed by the plugin system as all the data processing is done - * externally. Therefore, just tell NetSurf that everything's OK. - */ -bool plugin_convert(struct content *c, int width, int height) -{ - c->status=CONTENT_STATUS_DONE; - return true; -} + sprintf(sysvar, "%s%03x", ALIAS_PREFIX, (unsigned int)fv); -void plugin_reformat(struct content *c, int width, int height) -{ + return true; } /** - * Called when completely finished with an object. - * Simply frees buffered data + * Determines whether a content is handleable by a plugin + * + * \param mime_type The mime type of the content + * \return true if the content is handleable, false otherwise */ -void plugin_destroy(struct content *c) +bool plugin_handleable(const char *mime_type) { - /* simply free buffered data */ - free(c->data.plugin.data); -} + char sysvar[25]; -/** - * Redraw plugin on page. - */ -bool plugin_redraw(struct content *c, int x, int y, - int width, int height, - int clip_x0, int clip_y0, int clip_x1, int clip_y1, - float scale) -{ - struct plugin_list *npl; - - if(need_reformat) { - content_reformat(c, c->available_width, 0); - for(npl = plist->next; npl != plist; npl = npl->next) - plugin_reshape_instance(npl->c, npl->bw, npl->page, - npl->box, npl->params, - npl->state); - need_reformat = 0; - } - return true; + if (plugin_create_sysvar(mime_type, sysvar)) { + if (getenv(sysvar) != 0) { + return true; + } + } + + return false; } -/*-------------------------------------------------------------------------*/ -/* Parameters file handling functions */ -/*-------------------------------------------------------------------------*/ /** - * Writes the parameters file. + * Handle a bounced plugin_open message + * + * \param message The message to handle */ -void plugin_write_parameters_file(struct object_params *params) +void plugin_open_msg(wimp_message *message) { - struct plugin_params* temp; - struct plugin_param_item* ppi; - struct plugin_param_item* pilist = 0; - int *time; - char *tstr; - FILE *fp; - - /* Create the file */ - xosfile_create_dir(".WWW", 77); - xosfile_create_dir(".WWW.NetSurf", 77); - /* path + filename + terminating NUL */ - params->filename = xcalloc(strlen(getenv("Wimp$ScrapDir"))+13+10+1, - sizeof(char)); - xos_read_monotonic_time((int*)&time); - tstr = xcalloc(40, sizeof(char)); - sprintf(tstr, "%01u", (unsigned int)time<<8); - sprintf(params->filename, "%s.WWW.NetSurf.p%1.9s", - getenv("Wimp$ScrapDir"), tstr); - params->browser = (unsigned int)time<<8; - xfree(tstr); - LOG(("filename: %s", params->filename)); - - /* Write object attributes first */ - - /* classid is checked first */ - if(params->classid != 0 && params->codetype != 0) { - - pilist = plugin_add_item_to_pilist(pilist, 1, "CLASSID", - params->classid, - params->codetype); - } - /* otherwise, we check the data attribute */ - else if(params->data !=0 && params->type != 0) { - - pilist = plugin_add_item_to_pilist(pilist, 1, "DATA", - params->data, - params->type); - } - - /* if codebase is specified, write it as well */ - if(params->codebase != 0) { - - pilist = plugin_add_item_to_pilist(pilist, 1, - "CODEBASE", - params->codebase, NULL); - - } - - /* Iterate through the parameter list, creating the parameters - * file as we go. We can free up the memory as we go. - */ - while(params->params != 0) { - - LOG(("name: %s", params->params->name == 0 ? "not set" : params->params->name)); - LOG(("value: %s", params->params->value == 0 ? "not set" : params->params->value)); - LOG(("type: %s", params->params->type == 0 ? "not set" : params->params->type)); - LOG(("valuetype: %s", params->params->valuetype)); - - - if(strcasecmp(params->params->valuetype, "data") == 0) - pilist = plugin_add_item_to_pilist(pilist, 1, - params->params->name, - params->params->value, - params->params->type); - if(strcasecmp(params->params->valuetype, "ref") == 0) - pilist = plugin_add_item_to_pilist(pilist, 2, - params->params->name, - params->params->value, - params->params->type); - if(strcasecmp(params->params->valuetype, "object") == 0) - pilist = plugin_add_item_to_pilist(pilist, 3, - params->params->name, - params->params->value, - params->params->type); - - temp = params->params; - params->params = params->params->next; - xfree(temp); - } - - /* Now write mandatory special parameters */ - - /* BASEHREF */ - pilist = plugin_add_item_to_pilist(pilist, 4, "BASEHREF", - params->basehref, NULL); - - /* USERAGENT */ - pilist = plugin_add_item_to_pilist(pilist, 4, "USERAGENT", - "NetSurf", NULL); - - /* UAVERSION */ - pilist = plugin_add_item_to_pilist(pilist, 4, "UAVERSION", - "0.01", NULL); - - /* APIVERSION */ - pilist = plugin_add_item_to_pilist(pilist, 4, "APIVERSION", - "1.10", NULL); - - /* BGCOLOR - needs fixing to work properly. - * Currently, it assumes FFFFFF00 (BBGGRR00) */ - pilist = plugin_add_item_to_pilist(pilist, 4, "BGCOLOR", - "FFFFFF00", NULL); - - /* Write file */ - fp = fopen(params->filename, "wb+"); - - while (pilist != 0) { - - fwrite(&pilist->type, (unsigned int)sizeof(int), 1, fp); - fwrite(&pilist->rsize, (unsigned int)sizeof(int), 1, fp); - - fwrite(&pilist->nsize, (unsigned int)sizeof(int), 1, fp); - fwrite(pilist->name, (unsigned int)strlen(pilist->name), 1, fp); - for(; pilist->npad != 0; pilist->npad--) - fputc('\0', fp); - - fwrite(&pilist->vsize, (unsigned int)sizeof(int), 1, fp); - fwrite(pilist->value, (unsigned int)strlen(pilist->value), 1, fp); - for(; pilist->vpad != 0; pilist->vpad--) - fputc('\0', fp); - - fwrite(&pilist->msize, (unsigned int)sizeof(int), 1, fp); - if(pilist->msize > 0) { - fwrite(pilist->mime_type, - (unsigned int)strlen(pilist->mime_type), 1, fp); - for(; pilist->mpad != 0; pilist->mpad--) - fputc('\0', fp); - } - - ppi = pilist; - pilist = pilist->next; - - xfree(ppi); - } - - fwrite("\0", sizeof(char), 4, fp); - - fclose(fp); -} + struct content *c; + os_error *error; + plugin_message_open *pmo = (plugin_message_open *)&message->data; -/** - * Calculates the size of a parameter file record - */ -int plugin_calculate_rsize(char* name, char* data, char* mime) { + /* retrieve our content */ + c = (struct content *)pmo->browser; - int ret = 0; - ret += (4 + strlen(name) + 3) / 4 * 4; /* name */ - ret += (4 + strlen(data) + 3) / 4 * 4; /* data */ + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; - if (mime != NULL) - ret += (4 + strlen(mime) + 3) / 4 * 4; /* mime type */ - else - ret += 4; + LOG(("bounced")); - return ret; -} - -/** - * Adds an item to the list of parameter file records - */ -struct plugin_param_item *plugin_add_item_to_pilist(struct plugin_param_item *pilist, int type, char* name, char* value, char* mime_type) { - - struct plugin_param_item *ppi = xcalloc(1, sizeof(*ppi)); - - /* initialise struct */ - ppi->type = 0; - ppi->rsize = 0; - ppi->nsize = 0; - ppi->name = 0; - ppi->npad = 0; - ppi->vsize = 0; - ppi->value = 0; - ppi->vpad = 0; - ppi->msize = 0; - ppi->mime_type = 0; - ppi->mpad = 0; - - ppi->type = type; - ppi->rsize = plugin_calculate_rsize(name, value, mime_type); - ppi->nsize = strlen(name); - ppi->name = xstrdup(name); - ppi->npad = 4 - (ppi->nsize%4 == 0 ? 4 : ppi->nsize%4); - ppi->vsize = strlen(value); - ppi->value = xstrdup(value); - ppi->vpad = 4 - (ppi->vsize%4 == 0 ? 4 : ppi->vsize%4); - if(mime_type != 0) { - ppi->msize = strlen(mime_type); - ppi->mime_type = xstrdup(mime_type); - ppi->mpad = 4 - (ppi->msize%4 == 0 ? 4 : ppi->msize%4); - } - - ppi->next = pilist; - return ppi; -} + /* bail if we've already tried twice */ + if (c->data.plugin.repeated >= 1) + return; -/*-------------------------------------------------------------------------*/ -/* Plugin Stream handling functions */ -/*-------------------------------------------------------------------------*/ + /* start plugin app */ + error = xwimp_start_task((char const*)c->data.plugin.taskname, 0); + if (error) { + return; + } -/** - * Creates a plugin stream - */ -void plugin_create_stream(struct browser_window *bw, struct object_params *params, struct content *c) { - - wimp_message m; - plugin_message_stream_new *pmsn; - struct plugin_message *temp; - - pmsn = (plugin_message_stream_new*)&m.data; - pmsn->flags = 0; - pmsn->plugin = (plugin_p)params->plugin; - pmsn->browser = (plugin_b)params->browser; - pmsn->stream = (plugin_s)0; - pmsn->browser_stream = (plugin_bs)params->browser; - pmsn->url.pointer = c->url; - pmsn->end = c->data.plugin.length; - pmsn->last_modified_date = 0; - pmsn->notify_data = 0; - pmsn->mime_type.pointer = c->mime_type; - pmsn->target_window.offset = 0; - - m.size = 64; - m.your_ref = 0; - m.action = message_PLUG_IN_STREAM_NEW; - - temp = plugin_add_message_to_linked_list(pmsn->browser, pmsn->plugin, &m, 0); - - LOG(("Sending message &4D548")); - xwimp_send_message(wimp_USER_MESSAGE_RECORDED, &m, (wimp_t)params->plugin_task); - - /* wait for wimp poll */ - while(temp->poll == 0) - gui_poll(true); - - pmsn = (plugin_message_stream_new*)&temp->reply->m->data; - params->browser_stream = params->browser; - params->plugin_stream = (int)pmsn->stream; - - if((pmsn->flags == 0) || (pmsn->flags == 1) || (pmsn->flags == 2)) { - plugin_write_stream(bw, params, c); - } - else if((pmsn->flags == 3)) { - plugin_write_stream_as_file(bw, params, c); - } - - /* clean up */ - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); -} + /* indicate we've already sent this message once */ + c->data.plugin.repeated++; -/** - * Writes to an open stream - */ -void plugin_write_stream(struct browser_window *bw, struct object_params *params, struct content *c) { - - wimp_message m; - plugin_message_stream_write *pmsw; - plugin_message_stream_written *pmswt; - struct plugin_message *temp; - unsigned int consumed = 0; - - pmsw = (plugin_message_stream_write*)&m.data; - - pmsw->flags = 0; - pmsw->plugin = (plugin_p)params->plugin; - pmsw->browser = (plugin_b)params->browser; - pmsw->stream = (plugin_s)params->plugin_stream; - pmsw->browser_stream = (plugin_bs)params->browser_stream; - pmsw->url.pointer = c->url; - pmsw->end = c->data.plugin.length; - pmsw->last_modified_date = 0; - pmsw->notify_data = 0; - pmsw->offset = 0; - pmsw->length = c->data.plugin.length; - pmsw->data = (byte*)c->data.plugin.data; - - m.size = 68; - m.your_ref = 0; - m.action = message_PLUG_IN_STREAM_WRITE; - - while (consumed < c->data.plugin.length) { - - pmsw->length = c->data.plugin.length; - - temp = plugin_add_message_to_linked_list(pmsw->browser, pmsw->plugin, &m, 0); - - LOG(("Sending message &4D54A")); - xwimp_send_message(wimp_USER_MESSAGE_RECORDED, &m, (wimp_t)params->plugin_task); - - /* wait for wimp poll */ - while(temp->poll == 0) - gui_poll(true); - - pmswt = (plugin_message_stream_written*)&temp->reply->m->data; - if(pmswt->length > 0) { - consumed += pmswt->length; - pmsw->offset += pmswt->length + 1; - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); - } - else { - plugin_remove_message_from_linked_list(temp->reply); - plugin_remove_message_from_linked_list(temp); - return; - } - } + /* and resend the message */ + LOG(("resending")); + message->your_ref = 0; + error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, message, + wimp_BROADCAST); + if (error) { + return; + } } /** - * Writes a stream as a file + * Handle a plugin_opening message + * + * \param message The message to handle */ -void plugin_write_stream_as_file(struct browser_window *bw, struct object_params *params, struct content *c) { - - wimp_message m; - plugin_message_stream_as_file *pmsaf; - unsigned int filetype; - char *filename = strdup(params->filename), *p; - - pmsaf = (plugin_message_stream_as_file*)&m.data; - - pmsaf->flags = 0; - pmsaf->plugin = (plugin_p)params->plugin; - pmsaf->browser = (plugin_b)params->browser; - pmsaf->stream = (plugin_s)params->plugin_stream; - pmsaf->browser_stream = (plugin_bs)params->browser_stream; - pmsaf->url.pointer = c->url; - pmsaf->end = 0; - pmsaf->last_modified_date = 0; - pmsaf->notify_data = 0; - - p = strrchr((const char*)filename, 'p'); - filename[(p-filename)] = 'd'; - pmsaf->filename.pointer = filename; - - m.size = 60; - m.your_ref = 0; - m.action = message_PLUG_IN_STREAM_AS_FILE; - - xmimemaptranslate_mime_type_to_filetype(c->mime_type, (bits *) &filetype); - xosfile_save_stamped((char const*)filename, filetype, c->data.plugin.data, c->data.plugin.data + c->data.plugin.length); - - LOG(("Sending message &4D54C")); - xwimp_send_message(wimp_USER_MESSAGE, &m, (wimp_t)params->plugin_task); -} +void plugin_opening(wimp_message *message) +{ + struct content *c; + plugin_message_opening *pmo = + (plugin_message_opening *)&message->data; -/** - * Destroys a plugin stream - */ -void plugin_destroy_stream(struct browser_window *bw, struct object_params *params, struct content *c) { - - wimp_message m; - plugin_message_stream_destroy *pmsd; - - pmsd = (plugin_message_stream_destroy*)&m.data; - - pmsd->flags = 0; - pmsd->plugin = (plugin_p)params->plugin; - pmsd->browser = (plugin_b)params->browser; - pmsd->stream = (plugin_s)params->plugin_stream; - pmsd->browser_stream = (plugin_bs)params->browser_stream; - pmsd->url.pointer = c->url; - pmsd->end = 0; - pmsd->last_modified_date = 0; - pmsd->notify_data = 0; - pmsd->reason = plugin_STREAM_DESTROY_FINISHED; - - m.size = 60; - m.your_ref = 0; - m.action = message_PLUG_IN_STREAM_DESTROY; - - LOG(("Sending message &4D549")); - xwimp_send_message(wimp_USER_MESSAGE, &m, (wimp_t)params->plugin_task); -} + /* retrieve our content */ + c = (struct content *)pmo->browser; -/*-------------------------------------------------------------------------*/ -/* Linked List handling functions */ -/*-------------------------------------------------------------------------*/ + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; -/** - * Adds a message to the list of pending messages - */ -struct plugin_message *plugin_add_message_to_linked_list(plugin_b browser, plugin_p plugin, wimp_message *m, struct plugin_message *reply) { + c->data.plugin.repeated = 2; /* make sure open_msg does nothing */ + c->data.plugin.plugin = (unsigned int)pmo->plugin; + c->data.plugin.plugin_task = (unsigned int)message->sender; + c->data.plugin.opened = true; - struct plugin_message *npm = xcalloc(1, sizeof(*npm)); + LOG(("opening")); - npm->poll = 0; - npm->browser = browser; - npm->plugin = plugin; - npm->m = m; - npm->reply = reply; - npm->prev = pmlist->prev; - npm->next = pmlist; - pmlist->prev->next = npm; - pmlist->prev = npm; + /* if there's a reformat pending, do so now */ + if (c->data.plugin.reformat_pending) { + LOG(("do pending reformat")); + plugin_reformat(c, c->data.plugin.width, + c->data.plugin.height); + } - LOG(("Added Message: %p", npm)); + if (pmo->flags & 0x04) { /* plugin wants the data fetching */ + LOG(("wants stream")); + plugin_create_stream(c); + } - return pmlist->prev; + if (!(pmo->flags & 0x08)) { + LOG(("we delete file")); + /* we don't care if this fails */ + xosfile_delete(c->data.plugin.filename, 0, 0, 0, 0, 0); + } } /** - * Removes a message from the list of pending messages + * Handle a bounced plugin_close message + * + * \param message The message to handle */ -void plugin_remove_message_from_linked_list(struct plugin_message* m) { - - m->prev->next = m->next; - m->next->prev = m->prev; - LOG(("Deleted Message: %p", m)); - xfree(m); +void plugin_close_msg(wimp_message *message) +{ + plugin_message_close *pmc = (plugin_message_close *)&message->data; + /* not necessarily true - some plugins don't stop this bouncing */ + LOG(("failed to close plugin: %p", pmc->plugin)); } /** - * Retrieves a message from the list of pending messages - * returns NULL if no message is found + * Handle a plugin_closed message + * + * \param message The message to handle */ -struct plugin_message *plugin_get_message_from_linked_list(int ref) { - - struct plugin_message *npm; +void plugin_closed(wimp_message *message) +{ + struct content *c; + plugin_message_closed *pmc = (plugin_message_closed *)&message->data; - if(ref == 0) - return NULL; + /* retrieve our content */ + c = (struct content*)pmc->browser; - for(npm = pmlist->next; npm != pmlist && npm->m->my_ref != ref; - npm = npm->next) - ; + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; - if(npm != pmlist) { - LOG(("Got message: %p", npm)); - return npm; - } + LOG(("died")); + c->data.plugin.opened = false; - return NULL; + if (pmc->flags & 0x4) { + LOG(("plugin_closed: 0x%x: %s", pmc->error_number, + pmc->error_text)); + /* not really important enough to do a warn_user */ + gui_window_set_status(c->data.plugin.bw->window, + pmc->error_text); + } } /** - * Adds a plugin instance to the list of plugin instances. + * Handles receipt of plugin_reshape_request messages + * + * \param message The message to handle */ -void plugin_add_instance_to_list(struct content *c, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params, void **state) { - - struct plugin_list *npl = xcalloc(1, sizeof(*npl)); - - npl->c = c; - npl->bw = bw; - npl->page = page; - npl->box = box; - npl->params = params; - npl->state = state; - npl->prev = plist->prev; - npl->next = plist; - plist->prev->next = npl; - plist->prev = npl; +void plugin_reshape_request(wimp_message *message) +{ + struct content *c; + union content_msg_data data; + plugin_message_reshape_request *pmrr = (plugin_message_reshape_request*)&message->data; + + /* retrieve our content */ + c = (struct content *)pmrr->browser; + + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; + + LOG(("handling reshape request")); + + /* should probably shift by x and y eig values here */ + c->width = pmrr->size.x / 2; + c->height = pmrr->size.y / 2; + c->data.plugin.box->style->width.width = CSS_WIDTH_AUTO; + c->data.plugin.box->style->height.height = CSS_HEIGHT_AUTO; + + /* force a reformat of the parent */ + content_reformat(c->data.plugin.page, + c->data.plugin.page->available_width, 0); + /* redraw the window */ + content_broadcast(c->data.plugin.bw->current_content, + CONTENT_MSG_REFORMAT, data); + /* reshape the plugin */ + plugin_reformat(c, c->width, c->height); } /** - * Removes a plugin instance from the list of plugin instances + * Handles receipt of plugin_status messages + * + * \param message The message to handle */ -void plugin_remove_instance_from_list(struct object_params *params) { +void plugin_status(wimp_message *message) +{ + struct content *c; + plugin_message_status *pms = (plugin_message_status*)&message->data; + + /* retrieve our content */ + c = (struct content *)pms->browser; - struct plugin_list *temp = - plugin_get_instance_from_list((plugin_b)params->browser, - (plugin_p)params->plugin); - if(temp != NULL) { + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; + + gui_window_set_status(c->data.plugin.bw->window, + (const char*)plugin_get_string_value(pms->message, + (char*)pms)); +} - temp->prev->next = temp->next; - temp->next->prev = temp->prev; - xfree(temp); - } +/** + * Handles receipt of plugin_stream_new messages + * + * \param message The message to handle + */ +void plugin_stream_new(wimp_message *message) +{ + struct content *c; + int stream_type; + plugin_message_stream_new *pmsn = + (plugin_message_stream_new*)&message->data; + + LOG(("plugin_stream_new")); + + /* retrieve our content */ + c = (struct content *)pmsn->browser; + + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; + + /* response to a message we sent */ + if (message->my_ref != 0) { + c->data.plugin.browser_stream = (unsigned int)pmsn->browser; + c->data.plugin.plugin_stream = (unsigned int)pmsn->stream; + + LOG(("flags: %x", pmsn->flags)); + + stream_type = pmsn->flags & 0xF; /* bottom four bits */ + + if (stream_type == 3) { + LOG(("as file")); + if (c->source_size == c->total_size) + plugin_write_stream_as_file(c); + else { + LOG(("waiting for data")); + c->data.plugin.file_stream_waiting = true; + } + } + else if (stream_type < 3) { + LOG(("write stream")); + /* this sucks - see plugin_convert for why */ + if (c->source_size == c->total_size) + plugin_write_stream(c, 0); + else { + LOG(("waiting for data")); + c->data.plugin.stream_waiting = true; + } + } + } + /* new stream, initiated by plugin */ + else { + /** \todo plugin-initiated streams */ + } } /** - * Retrieves an instance of a plugin from the list of plugin instances - * returns NULL if no instance is found + * Handles receipt of plugin_stream_written messages + * + * \param message The message to handle */ -struct plugin_list *plugin_get_instance_from_list(plugin_b browser, plugin_p plugin) { +void plugin_stream_written(wimp_message *message) +{ + struct content *c; + plugin_message_stream_written *pmsw = + (plugin_message_stream_written*)&message->data; - struct plugin_list *npl; + /* retrieve our box */ + c = (struct content *)pmsw->browser; - for(npl = plist->next; (npl != plist) - && (((plugin_b)npl->params->browser != browser) - && ((plugin_p)npl->params->plugin != plugin)); - npl = npl->next) - ; + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; - if(npl != plist) - return npl; + LOG(("got written")); - return NULL; + plugin_write_stream(c, pmsw->length); } -/*-------------------------------------------------------------------------*/ -/* WIMP Message processing functions */ -/*-------------------------------------------------------------------------*/ - /** - * Parses wimp messages + * Handles plugin_url_access messages + * + * \param message The message to handle */ -void plugin_msg_parse(wimp_message *message, int ack) +void plugin_url_access(wimp_message *message) { - LOG(("Parsing message")); - switch(message->action) { - - case message_PLUG_IN_OPENING: - plugin_opening(message); - break; - case message_PLUG_IN_CLOSED: - plugin_closed(message); - break; - case message_PLUG_IN_RESHAPE_REQUEST: - plugin_reshape_request(message); - break; - case message_PLUG_IN_FOCUS: - // plugin_focus(); - break; - case message_PLUG_IN_URL_ACCESS: - plugin_url_access(message); - break; - case message_PLUG_IN_STATUS: - plugin_status(message); - break; - case message_PLUG_IN_BUSY: - // plugin_busy(); - break; - /* OSLib doesn't provide this, as it's - * reasonably new and not obviously documented. - * We ignore it for now. - - case message_PLUG_IN_INFORMED: - */ - case message_PLUG_IN_STREAM_NEW: - plugin_stream_new(message); - break; - case message_PLUG_IN_STREAM_WRITE: - // plugin_stream_write(); - break; - case message_PLUG_IN_STREAM_WRITTEN: - plugin_stream_written(message); - break; - case message_PLUG_IN_STREAM_DESTROY: - // plugin_stream_destroy(); - break; - - /* These cases occur when a message is bounced - * For simplicity, we do nothing unless the message came in - * a wimp_USER_MESSAGE_ACKNOWLEDGE (ie ack = 1) - */ - case message_PLUG_IN_OPEN: - if(ack) - plugin_open_msg(message); - break; - case message_PLUG_IN_CLOSE: - if(ack) - plugin_close_msg(message); - break; - case message_PLUG_IN_RESHAPE: - case message_PLUG_IN_STREAM_AS_FILE: - case message_PLUG_IN_NOTIFY: - case message_PLUG_IN_ABORT: - case message_PLUG_IN_ACTION: - default: - break; - } + struct content *c; + plugin_full_message_notify pmn; + os_error *error; + plugin_message_url_access *pmua = + (plugin_message_url_access*)&message->data; + bool notify = false, post = false, file = false; + char *url = plugin_get_string_value(pmua->url, (char*)pmua); + char *window; + + if (pmua->flags & 0x01) notify = true; + if (pmua->flags & 0x02) post = true; + if (pmua->flags & 0x04) file = true; + + /* retrieve our content */ + c = (struct content *)pmua->browser; + + /* check we expect this message */ + if (!c || !plugin_active(c)) + return; + + /* fetch url to window */ + if (pmua->target_window.offset != 0 && + pmua->target_window.pointer != 0) { + window = plugin_get_string_value(pmua->target_window, + (char*)pmua); + LOG(("flags: %d, url: %s, window: %s", pmua->flags, url, window)); + /** \todo proper _parent and _self support (needs frames) + * other window names + */ + if (!post) { /* GET request */ + if (strcasecmp(window, "_self") == 0 || + strcasecmp(window, "_parent") == 0 || + strcasecmp(window, "_top") == 0 || + strcasecmp(window, "") == 0) { + browser_window_go(c->data.plugin.bw, url); + } + else if (strcasecmp(window, "_blank") == 0) { + browser_window_create(url, NULL); + } + } + else { /* POST request */ + /* fetch URL */ + } + } + /* fetch data and stream to plugin */ + else { + if (!post) { /* GET request */ + /* fetch URL */ + } + else { /* POST request */ + /* fetch URL */ + } + + /* stream data to plugin */ + } + + if (notify) { + /* send message_plugin_notify to plugin task */ + pmn.size = 44; + pmn.your_ref = message->my_ref; + pmn.action = message_PLUG_IN_NOTIFY; + pmn.flags = 0; + pmn.plugin = pmua->plugin; + pmn.browser = pmua->browser; + pmn.url.pointer = url; + pmn.reason = (plugin_notify_reason)0; + pmn.notify_data = pmua->notify_data; + + error = xwimp_send_message(wimp_USER_MESSAGE, + (wimp_message*)&pmn, message->sender); + if (error) { + return; + } + } } /** - * Handles receipt of plugin_open messages + * Creates a plugin stream + * + * \param c The content to fetch the data for */ -void plugin_open_msg(wimp_message *message) { - - struct plugin_message *npm = plugin_get_message_from_linked_list(message->my_ref); - - LOG(("Acknowledgement of %p", npm)); - /* notify plugin_open message entry in list */ - if (npm != NULL) - npm->poll = 1; +void plugin_create_stream(struct content *c) +{ + plugin_full_message_stream_new pmsn; + os_error *error; + + pmsn.size = 64; + pmsn.your_ref = 0; + pmsn.action = message_PLUG_IN_STREAM_NEW; + pmsn.flags = 0; + pmsn.plugin = (plugin_p)c->data.plugin.plugin; + pmsn.browser = (plugin_b)c->data.plugin.browser; + pmsn.stream = (plugin_s)0; + pmsn.browser_stream = (plugin_bs)c->data.plugin.browser; + pmsn.url.pointer = c->url; + pmsn.end = c->total_size; + pmsn.last_modified_date = 0; + pmsn.notify_data = 0; + pmsn.mime_type.pointer = c->mime_type; + pmsn.target_window.offset = 0; + + LOG(("Sending message &4D548")); + error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message*)&pmsn, (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } } /** - * Handles receipt of plugin_open messages + * Writes to an open stream + * + * \param c The content to write data to + * \param consumed The amount of data consumed */ -void plugin_opening(wimp_message *message) { - - struct plugin_message *npm = plugin_get_message_from_linked_list(message->your_ref); - struct plugin_message *reply; - plugin_message_opening *pmo = (plugin_message_opening*)&message->data; - - /* add this message to linked list */ - reply = plugin_add_message_to_linked_list(pmo->browser, pmo->plugin, message, 0); - - /* notify plugin_open message entry in list */ - if (npm != NULL) { - - npm->poll = 1; - npm->plugin = pmo->plugin; - npm->reply = reply; - } +void plugin_write_stream(struct content *c, unsigned int consumed) +{ + plugin_full_message_stream_write pmsw; + os_error *error; + + c->data.plugin.consumed += consumed; + + pmsw.size = 68; + pmsw.your_ref = 0; + pmsw.action = message_PLUG_IN_STREAM_WRITE; + pmsw.flags = 0; + pmsw.plugin = (plugin_p)c->data.plugin.plugin; + pmsw.browser = (plugin_b)c->data.plugin.browser; + pmsw.stream = (plugin_s)c->data.plugin.plugin_stream; + pmsw.browser_stream = (plugin_bs)c->data.plugin.browser_stream; + pmsw.url.pointer = c->url; + /* end of stream is total_size + * (which is conveniently 0 if unknown) + */ + pmsw.end = c->total_size; + pmsw.last_modified_date = 0; + pmsw.notify_data = 0; + /* offset into data is amount of data consumed by plugin already */ + pmsw.offset = c->data.plugin.consumed; + /* length of data available */ + pmsw.length = c->source_size - c->data.plugin.consumed; + /* pointer to available data */ + pmsw.data = (byte*)c->source_data + c->data.plugin.consumed; + + /* still have data to send */ + if (c->data.plugin.consumed < c->source_size) { + LOG(("Sending message &4D54A")); + error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, + (wimp_message *)&pmsw, + (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } + } + /* no further data => destroy stream */ + else { + plugin_destroy_stream(c); + } } /** - * Handles receipt of plugin_close messages + * Writes a stream as a file + * + * \param c The content to write data to */ -void plugin_close_msg(wimp_message *message) { +void plugin_write_stream_as_file(struct content *c) +{ + plugin_full_message_stream_as_file pmsaf; + unsigned int filetype; + os_error *error; + + c->data.plugin.datafile = + calloc(strlen(getenv("Wimp$ScrapDir"))+13+10, sizeof(char)); + + if (!c->data.plugin.datafile) { + LOG(("malloc failed")); + warn_user("NoMemory", 0); + plugin_destroy_stream(c); + return; + } - struct plugin_message *npm = plugin_get_message_from_linked_list(message->my_ref); + /* create filename */ + sprintf(c->data.plugin.datafile, "%s.WWW.NetSurf.d%x", + getenv("Wimp$ScrapDir"), + (unsigned int)c->data.plugin.box->object_params); + + pmsaf.size = 60; + pmsaf.your_ref = 0; + pmsaf.action = message_PLUG_IN_STREAM_AS_FILE; + pmsaf.flags = 0; + pmsaf.plugin = (plugin_p)c->data.plugin.plugin; + pmsaf.browser = (plugin_b)c->data.plugin.browser; + pmsaf.stream = (plugin_s)c->data.plugin.plugin_stream; + pmsaf.browser_stream = (plugin_bs)c->data.plugin.browser_stream; + pmsaf.url.pointer = c->url; + pmsaf.end = 0; + pmsaf.last_modified_date = 0; + pmsaf.notify_data = 0; + pmsaf.filename.pointer = c->data.plugin.datafile; + + error = xmimemaptranslate_mime_type_to_filetype(c->mime_type, + (bits *) &filetype); + if (error) { + return; + } + + error = xosfile_save_stamped((char const*)c->data.plugin.datafile, + filetype, c->source_data, + c->source_data + c->source_size); + if (error) { + return; + } - /* notify plugin_open message entry in list */ - if (npm != NULL) - npm->poll = 1; + LOG(("Sending message &4D54C")); + error = xwimp_send_message(wimp_USER_MESSAGE, + (wimp_message *)&pmsaf, (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } } /** - * Handles receipt of plugin_closed messages + * Destroys a plugin stream + * + * \param c The content to destroy */ -void plugin_closed(wimp_message *message) { - - struct plugin_message *npm = plugin_get_message_from_linked_list(message->your_ref); - struct plugin_message *reply; - plugin_message_closed *pmc = (plugin_message_closed*)&message->data; - struct plugin_list *npl = plugin_get_instance_from_list(pmc->browser, pmc->plugin); - - /* add this message to linked list */ - reply = plugin_add_message_to_linked_list(pmc->browser, pmc->plugin, message, 0); - - /* notify plugin_open message entry in list */ - if (npm != NULL) { - - npm->poll = 1; - npm->reply = reply; - } - /* This is not the result of a plugin_open message */ - else { - if(pmc->flags & 0x2) { - LOG(("Err Mess: %s", pmc->error_text)); - gui_window_set_status(npl->bw->window, - (const char*)pmc->error_text); - } - plugin_remove_message_from_linked_list(reply); - } +void plugin_destroy_stream(struct content *c) +{ + plugin_full_message_stream_destroy pmsd; + os_error *error; + + pmsd.size = 60; + pmsd.your_ref = 0; + pmsd.action = message_PLUG_IN_STREAM_DESTROY; + pmsd.flags = 0; + pmsd.plugin = (plugin_p)c->data.plugin.plugin; + pmsd.browser = (plugin_b)c->data.plugin.browser; + pmsd.stream = (plugin_s)c->data.plugin.plugin_stream; + pmsd.browser_stream = (plugin_bs)c->data.plugin.browser_stream; + pmsd.url.pointer = c->url; + pmsd.end = 0; + pmsd.last_modified_date = 0; + pmsd.notify_data = 0; + pmsd.reason = plugin_STREAM_DESTROY_FINISHED; + + LOG(("Sending message &4D549")); + error = xwimp_send_message(wimp_USER_MESSAGE, + (wimp_message *)&pmsd, (wimp_t)c->data.plugin.plugin_task); + if (error) { + return; + } } /** - * Handles receipt of plugin_reshape_request messages + * Writes the plugin parameters file + * + * \param c Content to write parameters for + * \param params Plugin parameters struct + * \return true on success, false otherwise */ -void plugin_reshape_request(wimp_message *message) { - - struct plugin_list *npl; - plugin_message_reshape_request *pmrr = (plugin_message_reshape_request*)&message->data; - unsigned int i; +bool plugin_write_parameters_file(struct content *c, + struct object_params *params) +{ + struct plugin_params *temp; + struct plugin_param_item *ppi; + struct plugin_param_item *pilist = 0; + char bgcolor[10] = {0}; + FILE *fp; + + /* Create the file */ + xosfile_create_dir(".WWW", 77); + xosfile_create_dir(".WWW.NetSurf", 77); + /* path + filename + terminating NUL */ + c->data.plugin.filename = + calloc(strlen(getenv("Wimp$ScrapDir"))+13+10, sizeof(char)); + + if (!c->data.plugin.filename) { + LOG(("malloc failed")); + warn_user("NoMemory", 0); + return false; + } + sprintf(c->data.plugin.filename, "%s.WWW.NetSurf.p%x", + getenv("Wimp$ScrapDir"), (unsigned int)params); + LOG(("filename: %s", c->data.plugin.filename)); + + /* Write object attributes first */ + + /* classid is checked first */ + if (params->classid != 0 && params->codetype != 0) { + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_DATA, "CLASSID", + (const char*)params->classid, + (const char*)params->codetype)) + goto error; + } + /* otherwise, we check the data attribute */ + else if (params->data !=0 && params->type != 0) { + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_DATA, "DATA", + (const char *)params->data, + (const char *)params->type)) + goto error; + } - npl = plugin_get_instance_from_list(pmrr->browser, pmrr->plugin); + /* if codebase is specified, write it as well */ + if (params->codebase != 0) { + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_DATA, "CODEBASE", + (const char *)params->codebase, + NULL)) + goto error; + } - for (i = 0; i != npl->page->data.html.object_count && - npl->page->data.html.object[i].content != npl->c; - i++) ; + /* Iterate through the parameter list, creating the parameters + * file as we go. We can free up the memory as we go. + */ + while (params->params != 0) { + LOG(("name: %s", params->params->name == 0 ? "not set" : params->params->name)); + LOG(("value: %s", params->params->value == 0 ? "not set" : params->params->value)); + LOG(("type: %s", params->params->type == 0 ? "not set" : params->params->type)); + LOG(("valuetype: %s", params->params->valuetype)); + + + if (strcasecmp(params->params->valuetype, "data") == 0) + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_DATA, + (const char *)params->params->name, + (const char *)params->params->value, + (const char *)params->params->type)) + goto error; + if (strcasecmp(params->params->valuetype, "ref") == 0) + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_URL, + (const char *)params->params->name, + (const char *)params->params->value, + (const char *)params->params->type)) + goto error; + if (strcasecmp(params->params->valuetype, "object") == 0) + if (!plugin_add_item_to_pilist(&pilist, + PLUGIN_PARAMETER_OBJECT, + (const char *)params->params->name, + (const char *)params->params->value, + (const char *)params->params->type)) + goto error; + + temp = params->params; + params->params = params->params->next; + + free(temp->name); + free(temp->value); + free(temp->type); + free(temp->valuetype); + temp->name = temp->value = temp->type = temp->valuetype = 0; + free(temp); + temp = 0; + } - if (i != npl->page->data.html.object_count) { - /* should probably shift by x and y eigen values here */ - npl->c->width = pmrr->size.x >> 1; - npl->c->height = pmrr->size.y >> 1; - plugin_force_redraw(npl->c, npl->page, i); - } + /* Now write mandatory special parameters */ + + /* BASEHREF */ + if (!plugin_add_item_to_pilist(&pilist, PLUGIN_PARAMETER_SPECIAL, + "BASEHREF", + (const char *)params->basehref, + NULL)) + goto error; + + /* USERAGENT */ + if (!plugin_add_item_to_pilist(&pilist, PLUGIN_PARAMETER_SPECIAL, + "USERAGENT", "NetSurf", NULL)) + goto error; + + /* UAVERSION */ + if (!plugin_add_item_to_pilist(&pilist, PLUGIN_PARAMETER_SPECIAL, + "UAVERSION", "0.01", NULL)) + goto error; + + /* APIVERSION */ + if (!plugin_add_item_to_pilist(&pilist, PLUGIN_PARAMETER_SPECIAL, + "APIVERSION", "1.10", NULL)) + goto error; + + /* BGCOLOR */ + if (c->data.plugin.box->style->background_color <= 0xFFFFFF) + sprintf(bgcolor, "%X00", + (unsigned int)c->data.plugin.box->style->background_color); + else + sprintf(bgcolor, "FFFFFF"); + if (!plugin_add_item_to_pilist(&pilist, PLUGIN_PARAMETER_SPECIAL, + "BGCOLOR", + (const char *)bgcolor, + NULL)) + goto error; + + /* Write file */ + fp = fopen(c->data.plugin.filename, "wb+"); + + while (pilist != 0) { + fwrite(&pilist->type, (unsigned int)sizeof(int), 1, fp); + fwrite(&pilist->rsize, (unsigned int)sizeof(int), 1, fp); + + fwrite(&pilist->nsize, (unsigned int)sizeof(int), 1, fp); + fwrite(pilist->name, (unsigned int)strlen(pilist->name), 1, fp); + for (; pilist->npad != 0; pilist->npad--) + fputc('\0', fp); + + fwrite(&pilist->vsize, (unsigned int)sizeof(int), 1, fp); + fwrite(pilist->value, (unsigned int)strlen(pilist->value), 1, fp); + for(; pilist->vpad != 0; pilist->vpad--) + fputc('\0', fp); + + fwrite(&pilist->msize, (unsigned int)sizeof(int), 1, fp); + if (pilist->msize > 0) { + fwrite(pilist->mime_type, + (unsigned int)strlen(pilist->mime_type), 1, fp); + for (; pilist->mpad != 0; pilist->mpad--) + fputc('\0', fp); + } + + ppi = pilist; + pilist = pilist->next; + + free(ppi->name); + free(ppi->value); + free(ppi->mime_type); + ppi->name = ppi->value = ppi->mime_type = 0; + free(ppi); + ppi = 0; + } - LOG(("requested (width, height): (%d, %d)", pmrr->size.x, pmrr->size.y)); -} + fwrite("\0", sizeof(char), 4, fp); -/** - * Handles receipt of plugin_stream_new messages - */ -void plugin_stream_new(wimp_message *message) { + fclose(fp); - struct plugin_message *npm = plugin_get_message_from_linked_list(message->your_ref); - struct plugin_message *reply; - plugin_message_stream_new *pmsn = (plugin_message_stream_new*)&message->data; + return true; - /* add this message to linked list */ - reply = plugin_add_message_to_linked_list(pmsn->browser, pmsn->plugin, message, 0); +error: + while (pilist != 0) { + ppi = pilist; + pilist = pilist->next; + + free(ppi->name); + free(ppi->value); + free(ppi->mime_type); + ppi->name = ppi->value = ppi->mime_type = 0; + free(ppi); + ppi = 0; + } - /* notify plugin_open message entry in list */ - if(npm != NULL) { + while (params->params) { + temp = params->params; + params->params = params->params->next; + + free(temp->name); + free(temp->value); + free(temp->type); + free(temp->valuetype); + temp->name = temp->value = temp->type = temp->valuetype = 0; + free(temp); + temp = 0; + } - npm->poll = 1; - npm->plugin = pmsn->plugin; - npm->reply = reply; - } + free(c->data.plugin.filename); + c->data.plugin.filename = 0; + return false; } /** - * Handles receipt of plugin_stream_written messages + * Calculates the size of a parameter file record + * + * \param name Record name + * \param data Record data + * \param mime Record mime type + * \return length of record */ -void plugin_stream_written(wimp_message *message) { - - struct plugin_message *npm = plugin_get_message_from_linked_list(message->your_ref); - struct plugin_message *reply; - plugin_message_stream_written *pmswt = (plugin_message_stream_written*)&message->data; +int plugin_calculate_rsize(const char* name, const char* data, + const char* mime) +{ + int ret = 0; - /* add this message to linked list */ - reply = plugin_add_message_to_linked_list(pmswt->browser, pmswt->plugin, message, 0); + ret += (4 + strlen(name) + 3) / 4 * 4; /* name */ + ret += (4 + strlen(data) + 3) / 4 * 4; /* data */ - /* notify plugin_open message entry in list */ - if(npm != NULL) { + if (mime != NULL) + ret += (4 + strlen(mime) + 3) / 4 * 4; /* mime type */ + else + ret += 4; - npm->poll = 1; - npm->plugin = pmswt->plugin; - npm->reply = reply; - } + return ret; } /** - * Handles plugin_url_access messages + * Adds an item to the list of parameter file records + * + * \param pilist Pointer to list of parameters + * \param type Type of record to add + * \param name Name of record + * \param value Value of record + * \param mime_type Mime type of record + * \return true on success, false otherwise */ -void plugin_url_access(wimp_message *message) { - - wimp_message m; - struct plugin_list *npl; - plugin_message_url_access *pmua = (plugin_message_url_access*)&message->data; - plugin_message_notify *pmn = (plugin_message_notify*)&m.data; - int notify = 0, post = 0, file = 0; - char *url = plugin_get_string_value(pmua->url, (char*)pmua); - char *window; - - npl = plugin_get_instance_from_list(pmua->browser, pmua->plugin); - - if (pmua->flags & 0x01) notify = 1; - if (pmua->flags & 0x02) post = 1; - if (pmua->flags & 0x04) file = 1; - - /* fetch url to window */ - if (pmua->target_window.offset != 0 && - pmua->target_window.pointer != 0) { - window = plugin_get_string_value(pmua->target_window, - (char*)pmua); - LOG(("flags: %d, url: %s, window: %s", pmua->flags, url, window)); - /* TODO: proper _parent and _self support (needs frames) - * other window names - */ - if (!post) { /* GET request */ - if (strcasecmp(window, "_self") == 0 || - strcasecmp(window, "_parent") == 0 || - strcasecmp(window, "_top") == 0 || - strcasecmp(window, "") == 0) { - browser_window_go(npl->bw, url); - } - else if (strcasecmp(window, "_blank") == 0) { - browser_window_create(url, NULL); - } - } - else { /* POST request */ - /* fetch URL */ - } - } - /* fetch data and stream to plugin */ - else { - if (!post) { /* GET request */ - /* fetch URL */ - } - else { /* POST request */ - /* fetch URL */ - } - - /* stream data to plugin */ - } - - if (notify) { - /* send message_plugin_notify to plugin task */ - pmn->flags = 0; - pmn->plugin = pmua->plugin; - pmn->browser = pmua->browser; - pmn->url.pointer = url; - pmn->reason = (plugin_notify_reason)0; - pmn->notify_data = pmua->notify_data; - - m.size = 44; - m.your_ref = message->my_ref; - m.action = message_PLUG_IN_NOTIFY; - xwimp_send_message(wimp_USER_MESSAGE, &m, message->sender); - } -} +bool plugin_add_item_to_pilist(struct plugin_param_item **pilist, + plugin_parameter_type type, const char* name, + const char* value, const char* mime_type) +{ + struct plugin_param_item *ppi = calloc(1, sizeof(*ppi)); + + if (!ppi) + return false; + + /* initialise struct */ + ppi->type = 0; + ppi->rsize = 0; + ppi->nsize = 0; + ppi->name = 0; + ppi->npad = 0; + ppi->vsize = 0; + ppi->value = 0; + ppi->vpad = 0; + ppi->msize = 0; + ppi->mime_type = 0; + ppi->mpad = 0; + + ppi->type = type; + ppi->rsize = plugin_calculate_rsize(name, value, mime_type); + ppi->nsize = strlen(name); + ppi->name = strdup(name); + if (!ppi->name) { + free(ppi); + return false; + } -/** - * Handles receipt of plugin_status messages - */ -void plugin_status(wimp_message *message) { + ppi->npad = 4 - (ppi->nsize%4 == 0 ? 4 : ppi->nsize%4); + ppi->vsize = strlen(value); + ppi->value = strdup(value); + if (!ppi->value) { + free(ppi->name); + free(ppi); + return false; + } - plugin_message_status *pms = (plugin_message_status*)&message->data; - struct plugin_list *npl = plugin_get_instance_from_list(pms->browser, pms->plugin); + ppi->vpad = 4 - (ppi->vsize%4 == 0 ? 4 : ppi->vsize%4); + if(mime_type != 0) { + ppi->msize = strlen(mime_type); + ppi->mime_type = strdup(mime_type); + if (!ppi->mime_type) { + free(ppi->name); + free(ppi->value); + free(ppi); + return false; + } + + ppi->mpad = 4 - (ppi->msize%4 == 0 ? 4 : ppi->msize%4); + } - gui_window_set_status(npl->bw->window, - (const char*)plugin_get_string_value(pms->message, - (char*)pms)); + ppi->next = (*pilist); + (*pilist) = ppi; + return true; } /** * Utility function to grab string data from plugin message blocks + * + * \param string Containing structure + * \param msg Containing message + * \return the string data */ -char *plugin_get_string_value(os_string_value string, char *msg) { - - if(string.offset == 0 || string.offset > 256) { - return string.pointer; - } - return &msg[string.offset]; +char *plugin_get_string_value(os_string_value string, char *msg) +{ + if(string.offset == 0 || string.offset > 256) { + return string.pointer; + } + return &msg[string.offset]; } -void plugin_force_redraw(struct content *object, struct content *c, - unsigned int i) { - - struct box *box = c->data.html.object[i].box; - - box->object = object; - - box->width = box->min_width = box->max_width = object->width; - box->height = object->height; +/** + * Determines whether a content is still active + * + * \param c The content to examine + * \return true if active, false otherwise + */ +bool plugin_active(struct content *c) +{ + struct content *d; - box->style->width.width = CSS_WIDTH_LENGTH; - box->style->width.value.length.unit = CSS_UNIT_PX; - box->style->width.value.length.value = object->width; + if (c->user_list == 0) + return false; - box->style->height.height = CSS_HEIGHT_LENGTH; - box->style->height.length.unit = CSS_UNIT_PX; - box->style->height.length.value = object->height; + for (d = content_list; d; d = d->next) { + if (d == c) + return true; + } - need_reformat = 1; - /* We don't call content_reformat here - because doing so breaks things :-) - */ + return false; } #endif diff --git a/riscos/plugin.h b/riscos/plugin.h index 72ff798f5..8d3bfd798 100644 --- a/riscos/plugin.h +++ b/riscos/plugin.h @@ -18,60 +18,30 @@ struct content; struct object_params; struct content_plugin_data { - char *data; /* object data */ - unsigned long length; /* object length */ - char *sysvar; /* system variable set by plugin */ -}; - -struct plugin_state { - int dummy; -}; - -struct plugin_message { - - int poll; - plugin_b browser; - plugin_p plugin; - wimp_message *m; - struct plugin_message *reply; - struct plugin_message *next; - struct plugin_message *prev; -}; - -struct plugin_list { - - struct content *c; - struct browser_window *bw; - struct content *page; - struct box *box; - struct object_params *params; - void **state; - struct plugin_list *next; - struct plugin_list *prev; -}; - -struct plugin_param_item { - - int type; - int rsize; - int nsize; - char *name; - int npad; - int vsize; - char *value; - int vpad; - int msize; - char *mime_type; - int mpad; - - struct plugin_param_item *next; + struct browser_window *bw; /* window containing this content */ + struct content *page; /* parent content */ + struct box *box; /* box containing this content */ + char *taskname; /* plugin task to launch */ + char *filename; /* filename of parameters file */ + char *datafile; /* filename of filestreamed file */ + bool opened; /* has this plugin been opened? */ + int repeated; /* indication of opening state */ + unsigned int browser; /* browser handle */ + unsigned int plugin; /* plugin handle */ + unsigned int browser_stream; /* browser stream handle */ + unsigned int plugin_stream; /* plugin stream handle */ + unsigned int plugin_task; /* plugin task handle */ + unsigned int consumed; /* size of data consumed by plugin */ + bool reformat_pending; /* is a reformat pending? */ + int width, height; /* reformat width & height */ + bool stream_waiting; /* waiting to stream a datastream */ + bool file_stream_waiting; /* waiting to stream as file */ }; /* function definitions */ bool plugin_handleable(const char *mime_type); void plugin_msg_parse(wimp_message *message, int ack); bool plugin_create(struct content *c, const char *params[]); -bool plugin_process_data(struct content *c, char *data, unsigned int size); bool plugin_convert(struct content *c, int width, int height); void plugin_reformat(struct content *c, int width, int height); void plugin_destroy(struct content *c); @@ -84,5 +54,17 @@ void plugin_open(struct content *c, struct browser_window *bw, struct object_params *params); void plugin_close(struct content *c); +/* message handlers */ +void plugin_open_msg(wimp_message *message); +void plugin_opening(wimp_message *message); +void plugin_close_msg(wimp_message *message); +void plugin_closed(wimp_message *message); +void plugin_reshape_request(wimp_message *message); +void plugin_status(wimp_message *message); +void plugin_stream_new(wimp_message *message); +void plugin_stream_written(wimp_message *message); +void plugin_url_access(wimp_message *message); + + #endif -- cgit v1.2.3