/* 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 "Filetypes.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 "TokenUtils.h"
#include "URLveneer.h"

#include "PlugIn.h"

/* Statics */

static int       plugin_open_reference  = 0;
static int       plugin_open_tried_once = 0;
static char    * plugin_open_filename   = NULL;
static HStream * plugin_open_token      = NULL;

static int       plugin_close_reference = 0;

/* Static function prototypes */

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);

/*************************************************/
/* 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)
{
  _kernel_oserror * e;
  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_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)
{
  _kernel_oserror * e;
  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)
{
  _kernel_oserror * e;
  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.                         */
/*************************************************/

_kernel_oserror * plugin_write_params(browser_data * b, HStream * t, char * buffer, int buffer_size)
{
  _kernel_oserror * e  = NULL;
  int               fh = 0;
  char            * data;
  char              version[5];

  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;

  /* Now write details based on the Object type */

  if (HtmlOBJECTclassid(t) && !strncmp(HtmlOBJECTclassid(t), "java:", 5))
  {
    char         number[64];
    const char * cis = HtmlOBJECTclassid(t);
    const char * cie;

    /* A Java applet. First entry should be called 'code' to match   */
    /* an APPLET tag; we get the 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;
    }

    /* Write 'alt' for the 'standby' text */

    e = plugin_write_params_entry(fh,
                                  PlugIn_ParamType_DataFromOBJECT,
                                  "STANDBY",
                                  HtmlOBJECTstandby(t) ? HtmlOBJECTstandby(t) : "Java",
                                  NULL);

    if (e) goto plugin_write_params_exit;

    /* Width and height */

    sprintf(number, "%d", t->rows);

    e = plugin_write_params_entry(fh,
                                  PlugIn_ParamType_DataFromOBJECT,
                                  "HEIGHT",
                                  number,
                                  NULL);

    if (e) goto plugin_write_params_exit;

    sprintf(number, "%d", t->cols);

    e = plugin_write_params_entry(fh,
                                  PlugIn_ParamType_DataFromOBJECT,
                                  "WIDTH",
                                  number,
                                  NULL);

    if (e) goto plugin_write_params_exit;
  }

  /* Various actions for different builds, if we don't understand */
  /* the token at all.                                            */

  else
  {
    #ifdef TRACE

      erb.errnum = Utils_Error_Custom_Message;

      strcpy(erb.errmess,
        "OBJECT tag type not understood in plugin_write_params");

      e = &erb;

    #else

      data = data;

    #endif
  }

  /* 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_broadcast_plugin_open()                */
/*                                               */
/* Where it all starts - broadcast a             */
/* Message_PlugIn_Open for a given Object.       */
/*                                               */
/* 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 */
/*             window coordinates.               */
/*************************************************/

_kernel_oserror * plugin_broadcast_plugin_open(browser_data * b, HStream * t, BBox * position)
{
  _kernel_oserror * e;
  char              params[Limits_OS_Pathname];
  WimpMessage       m;
  MPlugIn_Open    * open = (MPlugIn_Open *) &m.data;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_broadcast_plugin_open: Called for %p, token %p\n",b,t);
  #endif

  RetError(plugin_write_params(b, t, params, sizeof(params)));

  // For debugging, this may be useful...
  //
  // plugin_write_params(b, t, "ADFS::4.$.DebugParam", 0);

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_broadcast_plugin_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;

  /* Fill in the body */

  open->flags                   = 0;
  open->reserved                = 0;
  open->browser_instance_handle = (int) b;
  open->parent_window_handle    = b->window_handle;
  open->parent_area             = *position;

  plugin_open_token = t;

  open->file_type = 0;
  mimemap_mime_to_riscos(HtmlOBJECTcodetype(t), &open->file_type);
  if (!open->file_type) open->file_type = FileType_DATA;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_broadcast_plugin_open: Filetype to use: %03x\n", open->file_type);
  #endif

  /* If we already have RMA space for the filename, free it */

  _swix(OS_Module,
        _IN(0) | _IN(2),

        7,
        plugin_open_filename);

  plugin_open_filename = NULL;

  /* (Re)claim RMA space for the filename */

  e = _swix(OS_Module,
            _IN(0) | _IN(3) | _OUT(2),

            6,
            strlen(params) + 1,

            &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_plugin_open: Successful\n",b,t);
  #endif

  return NULL;
}

/*************************************************/
/* plugin_plugin_open_bounced()                  */
/*                                               */
/* Handle a Message_PlugIn_Open bounce.          */
/*                                               */
/* Parameters: Pointer to a Wimp_Message struct  */
/*             holding the bounced message.      */
/*************************************************/

_kernel_oserror * plugin_plugin_open_bounced(WimpMessage * m)
{
  _kernel_oserror * e;
  MPlugIn_Open    * open = (MPlugIn_Open *) &m->data;

  #ifdef TRACE
    if (!plugin_open_tried_once)
    {
      if (tl & (1u<<30)) Printf("plugin_plugin_open_bounced: Called\n");
    }
    else
    {
      if (tl & (1u<<30)) Printf("plugin_plugin_open_bounced: Called again\n");
    }
  #endif

  if (m->hdr.my_ref == plugin_open_reference)
  {
    #ifdef TRACE
      if (tl & (1u<<30)) Printf("plugin_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_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 */

      _swix(OS_Module,
            _IN(0) | _IN(2),

            7,
            plugin_open_filename);

      plugin_open_reference  = 0;
      plugin_open_tried_once = 0;
      plugin_open_filename   = NULL;
      plugin_open_token      = NULL;
    }
    else
    {
      char             combuf[16]; /* Size of '@PlugInType_xxx' plus terminator */
      char             sysvar[22]; /* As above, preceeded by 'Alias$'           */
      _kernel_swi_regs r;
      int              required;

      /* Try launching the Plug-In through Wimp_StartTask */

      #ifdef TRACE
        if (tl & (1u<<30)) Printf("plugin_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_plugin_open_bounced: System variable '%s' is not set\n", sysvar);
        }

      #endif

      /* Now rebroadcast the message */

      #ifdef TRACE
        if (tl & (1u<<30)) Printf("plugin_plugin_open_bounced: Rebroadcasting Message_PlugIn_Open\n");
      #endif

      m->hdr.my_ref = m->hdr.your_ref = 0;

      e = wimp_send_message(Wimp_EUserMessageRecorded, m, 0, 0, NULL);

      /* Record my_ref in case it bounces for a second time */

      if (!e) plugin_open_reference = m->hdr.my_ref;
      else return e;
    }
  }

  #ifdef TRACE

    else
    {
      if (tl & (1u<<30)) Printf("plugin_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_broadcast_plugin_open",
              m->hdr.my_ref);

      return &erb;
    }

  #endif

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_plugin_open_bounced: Successful\n");
  #endif

  return NULL;
}

/*************************************************/
/* plugin_got_plugin_opening()                   */
/*                                               */
/* Handle reception of a Message_PlugIn_Opening. */
/*                                               */
/* 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 */
/*             window coordinates.               */
/*************************************************/

_kernel_oserror * plugin_got_plugin_opening(WimpMessage * m)
{
  MPlugIn_Opening * opening = (MPlugIn_Opening *) &m->data;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_got_plugin_opening: Called\n");
  #endif

  if (plugin_open_filename)
  {
    if (!(opening->flags & MPlugIn_Opening_WillDeleteParamsItself))
    {
      #ifdef TRACE
        if (tl & (1u<<30)) Printf("plugin_got_plugin_opening: Removing parameters file\n");
      #endif

      remove(plugin_open_filename);
    }

    /* Need to free up the RMA space used for the filename */

    _swix(OS_Module,
          _IN(0) | _IN(2),

          7,
          plugin_open_filename);
  }

  /* Tell the Object the PlugIn details */

  object_set_token_object_plugin(opening->browser_instance_handle,
                                 plugin_open_token,
                                 opening->plugin_instance_handle,
                                 m->hdr.sender);

  plugin_open_reference  = 0;
  plugin_open_tried_once = 0;
  plugin_open_filename   = NULL;
  plugin_open_token      = NULL;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_got_plugin_opening: Successful\n");
  #endif

  return NULL;
}

/*************************************************/
/* plugin_send_plugin_close()                    */
/*                                               */
/* Tell a Plug-In to close down.                 */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the Plug-In (this is  */
/*             used for the browser instance     */
/*             handle in the Close message);     */
/*                                               */
/*             Plug-In instance handle;          */
/*                                               */
/*             Plug-In task handle.              */
/*************************************************/

_kernel_oserror * plugin_send_plugin_close(browser_data * b, unsigned int instance, unsigned int task)
{
  _kernel_oserror * e;
  WimpMessage       m;
  MPlugIn_Close   * close = (MPlugIn_Close *) &m.data;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_send_plugin_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 = (int) b;

  /* ...then send it. */

  e = wimp_send_message(Wimp_EUserMessageRecorded, &m, task, 0, NULL);

  /* Remember the reference for any replies */

  if (!e) plugin_close_reference = m.hdr.my_ref;

  #ifdef TRACE
    if (tl & (1u<<30))
    {
      if (e) Printf("plugin_send_plugin_close: Exitting with error\n");
      else   Printf("plugin_send_plugin_close: Successful\n");
    }
  #endif

  return e;
}

/*************************************************/
/* plugin_send_original_plugin_reshape()         */
/*                                               */
/* Tell a Plug-In to reposition or resize itself */
/* - not as part of a Plug-In request to resize. */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the Plug-In (this is  */
/*             used for the browser instance     */
/*             handle in the Close message);     */
/*                                               */
/*             Plug-In instance handle;          */
/*                                               */
/*             Plug-In task handle;              */
/*                                               */
/*             New bounding box for the Plug-In  */
/*             child window (in (parent) window  */
/*             coordinates).                     */
/*************************************************/

_kernel_oserror * plugin_send_original_plugin_reshape(browser_data * b, unsigned int instance, unsigned int task, BBox * position)
{
  _kernel_oserror * e;
  WimpMessage       m;
  MPlugIn_Reshape * reshape = (MPlugIn_Reshape *) &m.data;

  #ifdef TRACE
    if (tl & (1u<<30)) Printf("plugin_send_original_plugin_reshape: Called\n");
  #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 = (int) b;
  reshape->parent_window_handle    = b->window_handle;
  reshape->parent_area             = *position;

  /* ...then send it. */

  e = wimp_send_message(Wimp_EUserMessage, &m, task, 0, NULL);

  #ifdef TRACE
    if (tl & (1u<<30))
    {
      if (e) Printf("plugin_send_original_plugin_reshape: Exitting with error\n");
      else   Printf("plugin_send_original_plugin_reshape: Successful\n");
    }
  #endif

  return e;
}