/* Copyright 1996 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.
 */
/* Title: -> c.xfersend
 * Purpose: generalised data transfer to a concurrent wimp program.
 * IDJ: 15-Jan-90: As war is about to break out in the Gulf, bug found
 *                 in printing.  previously receiver variable unset
 *                 so everything worked except after RAM transfer
 *                 Now this should also be "re-entrant" even if client
 *                 polls wimp during printing.
 * ECN: 08-May-91: #ifndefed out unused ROM functions
 * IDJ: 01-Jul-91: don't truncate leafnames in xfersend
 * JRC 5 Apr '92: New protocol for printing implemented in xfersend__unknowns ():
 *    now always queues for printing, printing immediately if necessary. Affects
 *    the use of xfersend_print () (extra argument) and xfersend () (the printproc
 *    is used if necessary).
 */

#define BOOL int
#define TRUE 1
#define FALSE 0

#define USE_DRAGASPRITE 1

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "trace.h"
#include "swis.h"
#include "os.h"
#include "bbc.h"
#include "wimp.h"
#include "wimpt.h"
#include "win.h"
#include "dbox.h"
#include "xfersend.h"
#include "fileicon.h"
#include "werr.h"
#include "menu.h"
#include "event.h"
#include "msgs.h"
#include "dragasprit.h"
#include "h.verintern.messages"

static int rcvbufsize;
static int xfersend__msgid = 0;           /* my_ref of last DataSave message */
static xfersend_saveproc xfersend__saveproc;
static xfersend_sendproc xfersend__sendproc;
static xfersend_printproc xfersend__printproc;
static int xfersend__filetype;
static void *xfersend__savehandle;
static int xfersend__estsize = 0;
static wimp_t xfersend__receiver;
static BOOL xfersend__fileissafe;
static char *xfersend__filename;  /*[256]*/

static int Unused; /*future expansion?*/

#ifdef SHARED_C_LIBRARY
static wimp_mousestr xfersend__mousestr = {};
static wimp_msgstr xfersend__msg = {};
#else
static wimp_mousestr xfersend__mousestr;
static wimp_msgstr xfersend__msg;
#endif

static BOOL xfersend__close = FALSE;
static wimp_w xfersend__w;

void xfersend_close_on_xfer (BOOL do_we_close, wimp_w w)
{  xfersend__close = do_we_close;
   xfersend__w = w;
}

static void xfersend__winclose (void)
{  wimp_eventdata e;
   e.o.w = xfersend__w;
   wimpt_noerr (wimp_sendwmessage (wimp_ECLOSE, (wimp_msgstr*) &e, e.o.w, -1));
}

#if USE_DRAGASPRITE
static BOOL xfersend__using_dragasprite (void)
{
   int r1, r2;

   r1 = 0x1c;
   os_byte (161, &r1, &r2);   /* read CMOS flag */
   return r2 & 0x02;
}
#endif

static BOOL xfersend__unknowns (wimp_eventstr *e, void *handle)

{ tracef1 ("xfersend raw event %i.\n", e->e);
  handle = handle;

  switch (e->e)
  { case wimp_EUSERDRAG:
    { /* finish my drag */
      tracef0 ("drag event received.\n");
      #if USE_DRAGASPRITE
        if (xfersend__using_dragasprite)
          dragasprite_stop ();
      #endif
      wimp_get_point_info (&xfersend__mousestr);
      if (xfersend__mousestr.w != -1)
      { wimp_msgstr msg;

        tracef1 ("drag to window %i: offer data.\n", xfersend__mousestr.w);
        msg.hdr.size = sizeof (wimp_msghdr) + sizeof (wimp_msgdatasave);
        msg.hdr.task = xfersend__mousestr.w;
        msg.hdr.your_ref = 0;
        msg.hdr.action = wimp_MDATASAVE;
        msg.data.datasave.w = xfersend__mousestr.w;
        msg.data.datasave.i = xfersend__mousestr.i;
        msg.data.datasave.x = xfersend__mousestr.x;
        msg.data.datasave.y = xfersend__mousestr.y;
        msg.data.datasave.type = xfersend__filetype;
        msg.data.datasave.estsize = xfersend__estsize;

        { int i, tail;
          char name[256];

          if (xfersend__filename == 0) xfersend__filename = malloc (256);
          strncpy (name,xfersend__filename,  256);
          tail = strlen (name); /* point at the zero */
          while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
               tail--;

          for (i = 0; /*i <= 10*/ tail <= strlen (name) && i < 211; i++)
            msg.data.datasave.leaf[i] = name[tail++];

          msg.data.datasave.leaf[i+1] = '\0';     /* force termination */
          tracef1 ("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]);
        }

        wimpt_noerr (wimp_sendwmessage (wimp_ESEND, &msg, xfersend__mousestr.w,
            xfersend__mousestr.i));
        xfersend__msgid = msg.hdr.my_ref; /* filled in by wimp. */
        /* We still get unknown events, so we'll get the reply sometime. */
      }
      else
        /* do nothing */
        tracef0 ("drag to no window: has no effect.\n");

      return TRUE;
    }
    break;

    case wimp_ESEND:
    case wimp_ESENDWANTACK:
      tracef3 ("xfersend msg %x received: %i %i.\n",
          e->data.msg.hdr.action,e->data.msg.hdr.your_ref,xfersend__msgid);

      if (e->data.msg.hdr.your_ref == xfersend__msgid)
        switch (e->data.msg.hdr.action)
        { case wimp_MRAMFETCH:
            if (xfersend__sendproc != 0)
            { xfersend__fileissafe = FALSE;

              /*He wants to do an in-core transfer, and we can do this. Note
                that this can't be other than the first response, as others
                are grabbed by sendbuf*/
              tracef0 ("ram transfer starting.\n");

              /* Prepare the reply record. */
              xfersend__msg = e->data.msg;
              xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
              xfersend__msg.hdr.action = wimp_MRAMTRANSMIT;
              xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
              xfersend__msg.data.ramtransmit.nbyteswritten = 0; /* so far. */
              rcvbufsize = e->data.msg.data.ramfetch.nbytes;

              xfersend__receiver = e->data.msg.hdr.task;
              /*the copy in xfersend__msg.hdr.task is overwritten by the Wimp
                message sending */

              if (xfersend__sendproc (xfersend__savehandle, &rcvbufsize))
              { /* See sendbuf for all the real work for this case... */

                tracef0 ("The send succeeded; send final RAMTRANSMIT.\n");

                /*We may have transferred some data but not yet told the
                  other end about it. xfersend__msg contains a final RAMTRANSMIT,
                  which does not quite fill his buffer (or we'd have sent it
                  already) thus signalling to him that the transfer is over.*/

                wimpt_noerr (wimp_sendmessage (wimp_ESEND, &xfersend__msg,
                    xfersend__receiver));
              }
              else
                tracef0 ("the send failed.\n");

              if (xfersend__close) xfersend__winclose ();
              return TRUE;
            }
          break;

          case wimp_MPrintFile: /* was dropped on a printer application*/
            /*From RISC O S 3.00, we always bounce this message. Printers will
              respond with a Message_DataSaveAck (if it wants a copy of the
              file), or Message_PrintTypeOdd (if it wants the file to be printed
              now).*/
            return TRUE;

            #if 0
            /*what it used to do ...*/
            if (xfersend__printproc != 0)
            { int res;
              wimp_t xfersend__printer = 0;

              tracef0 ("print request acceptable\n");
              xfersend__fileissafe = FALSE;

              res = xfersend__printproc (&e->data.msg.data.print.name[0],
                  xfersend__savehandle);

              xfersend__printer = e->data.msg.hdr.task;
              xfersend__msg = e->data.msg;
              xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
              xfersend__msg.hdr.action =
              res >= 0 ? wimp_MDATALOAD : wimp_MWillPrint;
              xfersend__msg.data.print.type = res;  /* in case it's been saved */
              wimpt_noerr (wimp_sendmessage (wimp_ESEND, &xfersend__msg,
                  xfersend__printer));
              if (xfersend__close) xfersend__winclose ();
              return TRUE;
            }
            #endif
          break;

          case wimp_MPrintTypeOdd: /*was dropped on a printer application with
              queue empty - print immediately*/
            if (xfersend__printproc != NULL)
            { wimp_t xfersend__printer;

              win_remove_unknown_event_processor (&xfersend__unknowns, 0);

              tracef0 ("immediate print request acceptable\n");
              xfersend__fileissafe = FALSE;

              /*Print the file now.*/
              (void) (*xfersend__printproc) (e->data.msg.data.print.name,
                  xfersend__savehandle);
                  /*reports errors, if any*/

              xfersend__printer = e->data.msg.hdr.task;
              xfersend__msg = e->data.msg;
              xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
              xfersend__msg.hdr.action = wimp_MPrintTypeKnown;
              wimpt_noerr (wimp_sendmessage (wimp_ESEND, &xfersend__msg,
                  xfersend__printer));
              if (xfersend__close) xfersend__winclose ();
            }
            /*If we weren't given a printproc, Printers' message bounces and
              it tries to copy the data away for printing via Message_
              DataSaveAck.*/

            /*In either case, the message has been handled successfully, and
               I finally get to fix this bug! J R C 4th Oct 1993*/
            return TRUE;
          break;

          /* JSR 18-1-94 Added response to MPrintError */
          /* Only report error if there is one. J R C 21st Jan 1994*/
          case wimp_MPrintError:
            if (e->data.msg.hdr.size > 24)
              werr(FALSE, &e->data.msg.data.chars[4]);
            win_remove_unknown_event_processor (&xfersend__unknowns, 0);
            if (xfersend__close) xfersend__winclose ();
            return TRUE;
          break;

          case wimp_MDATASAVEOK:
            tracef4 ("datasaveok %i %i %i %i.\n",
                e->data.msg.hdr.size,
                e->data.msg.hdr.task,
                e->data.msg.hdr.your_ref,
                e->data.msg.hdr.my_ref);
            tracef4 ("datasaveok %x %x %x %x.\n",
                e->data.msg.data.words[0],
                e->data.msg.data.words[1],
                e->data.msg.data.words[2],
                e->data.msg.data.words[3]);
            tracef1 ("it's the datasaveok, to file '%s'.\n",
                (int) &e->data.msg.data.datasaveok.name[0]);

            win_remove_unknown_event_processor (&xfersend__unknowns, 0);

            tracef1 ("save to filename '%s'.\n",
                (int) &e->data.msg.data.datasaveok.name[0]);

            xfersend__fileissafe = e->data.msg.data.datasaveok.estsize >= 0;
              /* BUG before 4.13 */

            if (xfersend__saveproc != NULL &&
                xfersend__saveproc (&e->data.msg.data.datasaveok.name[0],
                xfersend__savehandle))
            { tracef0 ("the save succeeded: send dataload\n");

              xfersend__msg = e->data.msg;
                  /* sets hdr.size, data.w,i,x,y, size, name */
              xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref;
              xfersend__msg.hdr.action = wimp_MDATALOAD;
              xfersend__msg.data.dataload.type = xfersend__filetype;
              wimpt_noerr (wimp_sendmessage (wimp_ESENDWANTACK, &xfersend__msg,
                  e->data.msg.hdr.task));
            }
            else
              /* he has already reported the error: nothing more to do. */
              tracef0 ("save was not successful.\n");

            if (xfersend__close) xfersend__winclose ();
            return xfersend__saveproc != NULL;
          break;
        }
    break;

    #if FALSE
    /*This is a pile of garbage - never recognised cos msgid == my_ref, not
      your_ref!). In any case this is a silly error message and should not be
      displayed*/
    case wimp_EACK:
    if (e->data.msg.hdr.your_ref == xfersend__msgid &&
        e->data.msg.hdr.action == wimp_MDATALOAD)
    {
      /* It looks as if he hasn't acknowledged my DATALOAD acknowledge:
      thus it may be a loose scrap file, and must be deleted. */
      char a[256];
      tracef0 ("unack'd data load of temp file, so delete the file\n");
      werr (FALSE, msgs_lookup (MSGS_xfersend1));
      sprintf (a, "%%delete %s", &xfersend__msg.data.dataload.name[0]);
      os_cli (a);
    }
    return TRUE;
    #endif

    case wimp_EACK:
      /*If this is our Message_PrintSave being bounced, then we have to print the
         file now (according to the revised protocol 3 Apr '92). JRC.*/
      if (e->data.msg.hdr.action == wimp_MPrintSave &&
          e->data.msg.hdr.my_ref == xfersend__msgid)
      { tracef0 ("no printer manager - printing direct\n");

        if (xfersend__printproc != NULL)
          (void) (*xfersend__printproc) (e->data.msg.data.print.name,
              xfersend__savehandle);
            /*This reports errors itself.*/
        else
          tracef0 ("no printing function supplied\n");

        return TRUE;
      }
    break;
  }
  return FALSE;
}

static int sendbuf__state;

static BOOL sendbuf__unknowns (wimp_eventstr *e, void *h)
{
 h = h;

 tracef4 ("sendbuf__unknowns %d %d %d %d\n",
          e->data.msg.hdr.my_ref, e->data.msg.hdr.your_ref,
          xfersend__msg.hdr.your_ref, xfersend__msg.hdr.my_ref);

 if ( (e->e == wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
     e->data.msg.hdr.your_ref == xfersend__msg.hdr.my_ref &&
     e->data.msg.hdr.action == wimp_MRAMFETCH)
 {
  /* Prepare xfersend__msg as the next RAMTRANSMIT. Most of
  the fields are already set up. */

  xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
  xfersend__msg.data.ramtransmit.nbyteswritten = 0;
  xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref;
  rcvbufsize = e->data.msg.data.ramfetch.nbytes;

  tracef2 ("RAMFETCH received: continue with buffer at %x, size %d\n",
          (int) xfersend__msg.data.ramtransmit.addr, rcvbufsize);

  sendbuf__state = 1;
  return TRUE;      /* We've had another RAMFETCH: off we go again */
 }

 if (e->e == wimp_EACK &&
    e->data.msg.hdr.my_ref == xfersend__msg.hdr.my_ref)
 {
  sendbuf__state = 2;
  tracef0 ("xfersend RAMTRANSMIT bounced; set failed state\n");
  return TRUE;/* our message bounced back; give up */
 }

 return FALSE;    /* we don't want it */
}


BOOL xfersend_sendbuf (char *buffer, int size)
{

/* Called by his sendproc when sending things in memory. The
reply record is in xfersend__msg. */

 tracef2 ("xfersend_sendbuf %i %i\n", (int) buffer, size);

 /* Make the data transfer */
 tracef3 ("transfer block of %d from %x to %x\n", size, (int) buffer,
          (int) (xfersend__msg.data.ramtransmit.addr +
            xfersend__msg.data.ramtransmit.nbyteswritten));

 wimpt_noerr (wimp_transferblock (wimpt_task (), buffer, xfersend__receiver,
      xfersend__msg.data.ramtransmit.addr +
      xfersend__msg.data.ramtransmit.nbyteswritten,
      size));

 /* record bytes to be sent to the other end */
 xfersend__msg.data.ramtransmit.nbyteswritten += size;
 rcvbufsize -= size;

 /* if size != 0, there are still bytes to send. */

  if (rcvbufsize > 0) return TRUE;

 tracef1 ("xfersend message has put %d into buffer\n",size);
 /* Tell him that you've done it */
 wimpt_noerr (wimp_sendmessage (wimp_ESENDWANTACK,
      &xfersend__msg,
      xfersend__receiver));

  /* Get his reply. Poll and despatch events until get nack or message */

 sendbuf__state = 0;

 win_add_unknown_event_processor (sendbuf__unknowns, 0);
 do event_process (); while (sendbuf__state == 0);
 win_remove_unknown_event_processor (sendbuf__unknowns, 0);

  /* This exit happens in the cases where the buffers at each end
      are of identical size. So, return for another call to sendbuf, or
      so that the sendbuf procedure can return. */

 return sendbuf__state != 2;  /* OK unless state = broken */
}

BOOL xfersend (int filetype, char *filename, int estsize,
   xfersend_saveproc saver, xfersend_sendproc sender, xfersend_printproc printer,
   wimp_eventstr *e, void *handle)

{  wimp_wstate wstate;
   wimp_icon icon;
   wimp_w w = e->data.but.m.w;
   wimp_mousestr mouse_str;
   int
      x_limit = bbc_vduvar (bbc_XWindLimit) << bbc_vduvar (bbc_XEigFactor),
      y_limit = bbc_vduvar (bbc_YWindLimit) << bbc_vduvar (bbc_YEigFactor),
      x0, y0, x1, y1;
   int screen_x0;
   int screen_y0;
#if USE_DRAGASPRITE
   char *name;
   sprite_area *area;
#endif

   xfersend__saveproc = saver;
   xfersend__sendproc = sender;
   xfersend__printproc = printer;
   xfersend__filetype = filetype;
   xfersend__estsize = estsize;
   xfersend__savehandle = handle;
   if (xfersend__filename == 0) xfersend__filename = malloc (256);
   if (filename == 0)
      strcpy (xfersend__filename, msgs_lookup (MSGS_xfersend2));
   else
      strncpy (xfersend__filename,filename,256);

   tracef0 ("Initiate a drag.\n");

   /*Find screen origin*/
   wimp_get_wind_state (w, &wstate);
   screen_x0 = wstate.o.box.x0 - wstate.o.x;
   screen_y0 = wstate.o.box.y1 - wstate.o.y;

   /*Get initial icon position*/
   wimp_get_icon_info (w, e->data.but.m.i, &icon);
   x0 = icon.box.x0 += screen_x0;
   y0 = icon.box.y0 += screen_y0;
   x1 = icon.box.x1 += screen_x0;
   y1 = icon.box.y1 += screen_y0;

#if USE_DRAGASPRITE
   if (xfersend__using_dragasprite ())
   {  /* Find the sprite name and area */
      if (icon.flags & wimp_ITEXT)
      {  area = wimp_spritearea;
         name = strstr ( icon.data.indirecttext.validstring, ";s" ) + 2;
      }
      else
      {  area = icon.data.indirectsprite.spritearea;
         name = icon.data.indirectsprite.name;
      }

      wimpt_complain (dragasprite_start (dragasprite_HJUSTIFY_CENTRE |
          dragasprite_VJUSTIFY_CENTRE | dragasprite_BOUNDTO_SCREEN |
          dragasprite_BOUND_POINTER | dragasprite_DROPSHADOW_PRESENT,
          area, name, &icon.box, NULL));
   }
   else   /* not using dragasprite */
   {  /*Get pointer position to allow icon to be dragged
         partially off-screen. JRC 9 Nov '89*/
      int mouse_x,mouse_y;
      wimp_dragstr dr;
      wimp_get_point_info (&mouse_str);
      mouse_x = mouse_str.x;
      mouse_y = mouse_str.y;

      /*Set up drag*/
      dr.window    = w; /*not relevant*/
      dr.type      = wimp_USER_FIXED;
      dr.box.x0    = x0;
      dr.box.y0    = y0;
      dr.box.x1    = x1;
      dr.box.y1    = y1;
      dr.parent.x0 = x0 - mouse_x; /*Expanded parent by box overlap*/
      dr.parent.y0 = y0 - mouse_y;
      dr.parent.x1 = x1 - mouse_x + x_limit;
      dr.parent.y1 = y1 - mouse_y + y_limit;
      wimp_drag_box (&dr);
   }
#else
   /*Get pointer position to allow icon to be dragged
      partially off-screen. JRC 9 Nov '89*/
   wimp_get_point_info (&mouse_str);
   mouse_x = mouse_str.x;
   mouse_y = mouse_str.y;

   /*Set up drag*/
   dr.window    = w; /*not relevant*/
   dr.type      = wimp_USER_FIXED;
   dr.box.x0    = x0;
   dr.box.y0    = y0;
   dr.box.x1    = x1;
   dr.box.y1    = y1;
   dr.parent.x0 = x0 - mouse_x; /*Expanded parent by box overlap*/
   dr.parent.y0 = y0 - mouse_y;
   dr.parent.x1 = x1 - mouse_x + x_limit;
   dr.parent.y1 = y1 - mouse_y + y_limit;
   wimp_drag_box (&dr);
#endif

   win_add_unknown_event_processor (&xfersend__unknowns, NULL);
   return TRUE;
}

BOOL xfersend_print (int type, char *filename, int estsize,
   xfersend_saveproc saver, xfersend_sendproc sender, xfersend_printproc printer,
   void *handle)

{  xfersend__saveproc = saver;
   xfersend__sendproc = sender;
   xfersend__printproc = printer;
   xfersend__filetype = type;
   xfersend__estsize = estsize;
   xfersend__savehandle = handle;
   if (xfersend__filename == NULL &&
        (xfersend__filename = malloc (256)) == NULL)
      return FALSE;

   sprintf (xfersend__filename, "%.256s", filename != 0? filename:
       msgs_lookup (MSGS_xfersend2));

   /*Broadcast a PrintSave message. The printer will reply with PrintFile
     (which we ignore in RISC O S 3.00)), then DataSaveAck which is caught by
      xfersend__unknowns ().*/
   xfersend__msg.hdr.size = sizeof (wimp_msghdr) +
         sizeof (wimp_msgdatasave);
   xfersend__msg.hdr.your_ref = 0;
   xfersend__msg.hdr.action = wimp_MPrintSave;
   xfersend__msg.data.datasave.estsize = estsize; /*this is PrintSave not
         DataSave, but it matches (apart from w, i, x, y not used)*/
   xfersend__msg.data.datasave.type = type;
   sprintf (xfersend__msg.data.datasave.leaf, "%.*s",
         sizeof xfersend__msg.data.datasave.leaf - 1, xfersend__filename);

   tracef1 ("sending Message_PrintSave \"%s\"\n",
         xfersend__msg.data.datasave.leaf);
   wimpt_noerr (wimp_sendmessage (wimp_ESENDWANTACK, &xfersend__msg, NULL));

   tracef1 ("message id is %d\n", xfersend__msg.hdr.my_ref);
   xfersend__msgid = xfersend__msg.hdr.my_ref; /*Filled in by WIMP.*/

   tracef0 ("adding unknown event processor\n");
   win_add_unknown_event_processor (&xfersend__unknowns, NULL);

   return TRUE;
}

#ifndef UROM
BOOL xfersend_pipe (int filetype, char *filename, int estsize,
                     xfersend_saveproc saver,
                     xfersend_sendproc sender,
                     xfersend_printproc printer,
                     void *handle, wimp_t task)
{

      xfersend__saveproc = saver;
      xfersend__sendproc = sender;
      xfersend__printproc = printer;
      xfersend__filetype = filetype;
      xfersend__estsize = estsize;
      xfersend__savehandle = handle;
      if (xfersend__filename == 0) xfersend__filename = malloc (256);
      if (filename == 0)
        strcpy (xfersend__filename, msgs_lookup (MSGS_xfersend2));
      else
        strncpy (xfersend__filename,filename,256);

        {
        wimp_msgstr msg;

        msg.hdr.size = sizeof (wimp_msghdr) + sizeof (wimp_msgdatasave);
        msg.hdr.task = task;
        msg.hdr.your_ref = 0;
        msg.hdr.action = wimp_MDATASAVE;
        msg.data.datasave.w = 0; /* kludge, it's not being sent to a
                                        window!! Hope the wimp doesn't
                                        check this */
        msg.data.datasave.i = 0;
        msg.data.datasave.x = 0;
        msg.data.datasave.y = 0;
        msg.data.datasave.type = xfersend__filetype;
        msg.data.datasave.estsize = xfersend__estsize;
        {
          int i, tail;
          char name[256];
          if (xfersend__filename == 0) xfersend__filename = malloc (256);
          strncpy (name,xfersend__filename,  256);
          tail = strlen (name); /* point at the zero */
          while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
               tail--;

          for (i = 0; /*i <= 10*/ tail <= strlen (name) && i < 211; i++)
            msg.data.datasave.leaf[i] = name[tail++];
          msg.data.datasave.leaf[i+1] = '\0';     /* force termination */
          tracef1 ("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]);
        };
        wimpt_noerr (wimp_sendmessage (wimp_ESEND, &msg, task));
        xfersend__msgid = msg.hdr.my_ref; /* filled in by wimp. */
      }

      win_add_unknown_event_processor (&xfersend__unknowns, 0);
      return TRUE;
}
#endif

BOOL xfersend_file_is_safe ()
{  return xfersend__fileissafe;
}

void xfersend_set_fileissafe (BOOL value)
{  xfersend__fileissafe = value;
}

void xfersend_clear_unknowns (void)
{
   win_remove_unknown_event_processor (sendbuf__unknowns, 0);
   win_remove_unknown_event_processor (&xfersend__unknowns, 0);
}

int xfersend_read_last_ref (void)
{
  return xfersend__msgid;        /* my_ref of last DataSave message */
}

/* end xfersend.c */