/* Title: -> c.xfersend * Purpose: generalised data transfer to a concurrent wimp program. */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Steel library. * * Steel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Steel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Steel. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define BOOL int #define TRUE 1 #define FALSE 0 #include #include #include #include "trace.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 "swis.h" static int rcvbufsize ; static int xfersend__msgid; 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; static wimp_t xfersend__receiver ; static BOOL xfersend__fileissafe ; static char xfersend__filename[256]; static wimp_mousestr xfersend__mousestr; static wimp_msgstr xfersend__msg; static BOOL xfersend__close; static wimp_w xfersend__w; static wimp_i xfersend__i; static BOOL xfersend__finishedXfer; static void xfersend__iconDel(wimp_w w,wimp_i i,BOOL del) { if (wimpt_options() & wimpt_OREMSAVEICON) { if (del) wimp_set_icon_state(w,i,(1<<23)+(1<<7),(1<<23)+(1<<7)); else wimp_set_icon_state(w,i,0,(1<<23)+(1<<7)); } } 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)); } static BOOL xfersend__unknowns(wimp_eventstr *e, void *handle) { handle = handle ; tracef1("xfersend raw event %i.\n", e->e); switch (e->e) { case wimp_EUSERDRAG: tracef0("drag event received.\n"); { wimp_get_point_info(&xfersend__mousestr); if (xfersend__mousestr.w == -1) { tracef0("drag to no window: has no effect.\n"); xfersend__finishedXfer=TRUE; /* do nothing */ } else { 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 tail; char name[256]; strncpy(name,xfersend__filename, 256); tail = strlen(name); /* point at the zero */ while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':') tail--; strncpy(msg.data.datasave.leaf, name + tail, 210); msg.data.dataload.name[211] = 0; /* Avoid boundcheck warning */ msg.hdr.size = (48+strlen(msg.data.datasave.leaf)) & ~3; tracef1("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]); }; wimpt_noerr(wimp_sendwmessage( wimp_ESENDWANTACK, &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. */ }; }; return TRUE; case wimp_ESEND: case wimp_ESENDWANTACK: #if TRACE tracef("xfersend msg %x received: %i %i.\n", e->data.msg.hdr.action,e->data.msg.hdr.your_ref,xfersend__msgid); #endif 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)); xfersend__finishedXfer=TRUE; if(xfersend__close) xfersend__winclose(); else xfersend__iconDel(xfersend__w,xfersend__i,FALSE); } else { tracef0("the send failed.\n"); xfersend__iconDel(xfersend__w,xfersend__i,FALSE); xfersend__finishedXfer=TRUE; }; return TRUE; } else { if (getenv("Wimp$Scrap")==0) xfersend__finishedXfer=TRUE; /*** The other application reports an error, and I don't get my *** *** no-acknowledgement message to tell me to abort the data *** *** transfer. ***/ } break ; case wimp_MPrintFile: /* was dropped on a printer application */ if (xfersend__printproc != 0) { int res ; tracef0("print request acceptable\n"); xfersend__fileissafe = FALSE ; res = xfersend__printproc(&e->data.msg.data.print.name[0], xfersend__savehandle) ; 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_ESENDWANTACK, &xfersend__msg, xfersend__receiver)); xfersend__msgid=xfersend__msg.hdr.my_ref; if (res==xfersend_printPrinted) { xfersend__finishedXfer=TRUE; if(xfersend__close) xfersend__winclose(); else xfersend__iconDel(xfersend__w,xfersend__i,FALSE); } else if (res==xfersend_printFailed) xfersend__iconDel(xfersend__w,xfersend__i,FALSE); return TRUE; } break ; case wimp_MDATALOADOK: xfersend__finishedXfer=TRUE; if(xfersend__close) xfersend__winclose(); else xfersend__iconDel(xfersend__w,xfersend__i,FALSE); 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]); tracef1("save to filename '%s'.\n", (int) &e->data.msg.data.datasaveok.name[0]); xfersend__fileissafe = e->data.msg.data.datasaveok.estsize >= 0 ; if (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)); xfersend__msgid=xfersend__msg.hdr.my_ref; } else { /* he has already reported the error: nothing more to do. */ tracef0("save was not successful.\n"); xfersend__iconDel(xfersend__w,xfersend__i,FALSE); xfersend__finishedXfer=TRUE; }; return TRUE; } } return FALSE ; /* unknown not dealt with */ case wimp_EACK: if (e->data.msg.hdr.my_ref == xfersend__msgid) { switch (e->data.msg.hdr.action) { case 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("he hasn't ack'd our data load of temp file, so delete the file.\n"); werr(FALSE, msgs_lookup("xfersend1:Bad data transfer, receiver dead.")); sprintf(a, "%%delete %s", &xfersend__msg.data.dataload.name[0]); os_cli(a) ; xfersend__iconDel(xfersend__w,xfersend__i,FALSE); xfersend__finishedXfer=TRUE; } break; case wimp_MDATASAVE: xfersend__finishedXfer=TRUE; xfersend__iconDel(xfersend__w,xfersend__i,FALSE); break; } }; return TRUE; default: 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_dragstr dr; wimp_wstate wstate; wimp_icon icon; wimp_w w = e->data.but.m.w; os_regset r; xfersend__saveproc = saver; xfersend__sendproc = sender; xfersend__printproc = printer; xfersend__filetype = filetype; xfersend__estsize = estsize; xfersend__savehandle = handle; if(filename == 0) strcpy(xfersend__filename, msgs_lookup("xfersend2:Selection")); else strncpy(xfersend__filename,filename,256); if (e->e==wimp_EBUT) { xfersend__w = e->data.but.m.w; xfersend__i = e->data.but.m.i; tracef0("Initiate a drag.\n"); r.r[0]=161; /* Read CMOS */ r.r[1]=0x1c; /* Support DragASrite? */ wimpt_noerr(os_swix(XOS_Byte,&r)); wimp_get_wind_state(w, &wstate); wimp_get_icon_info(w, e->data.but.m.i, &icon); dr.box.x0 = wstate.o.box.x0 - wstate.o.x + icon.box.x0; dr.box.y0 = wstate.o.box.y1 - wstate.o.y + icon.box.y0; dr.box.x1 = wstate.o.box.x0 - wstate.o.x + icon.box.x1; dr.box.y1 = wstate.o.box.y1 - wstate.o.y + icon.box.y1; if ((r.r[2] & 2) && wimpt_getVersion()>=300) { r.r[0]=0xC5; /* Centre, whole-screen, drop-shadow */ r.r[1]=1; r.r[2]=(int)fileicon_spriteName(filetype,filename); r.r[3]=(int)&dr.box; xfersend__iconDel(xfersend__w,xfersend__i,TRUE); wimpt_noerr(os_swix(XDragASprite_Start,&r)); } else { /* Pedestrian drag-box */ dr.window = w; /* not relevant. */ dr.type = wimp_USER_FIXED; dr.parent.x0 = 0; dr.parent.y0 = 0; dr.parent.x1 = wimpt_scwidth(); dr.parent.y1 = wimpt_scheight(); wimp_drag_box(&dr); } } win_add_unknown_event_processor(xfersend__unknowns, 0); xfersend__finishedXfer=FALSE; while (xfersend__finishedXfer==FALSE) event_process(); win_remove_unknown_event_processor(xfersend__unknowns, 0); xfersend__w=0; return TRUE; } BOOL xfersend_file_is_safe() { return xfersend__fileissafe ; } void xfersend_set_fileissafe(BOOL value) { xfersend__fileissafe = value; } /* * BOOL xfersend_sendBlock(void *block,size_t length,int *maxbuf) * * Use * Sends a block to xfersend_sendbuf() a chunk at a time. * * Parameters * void *block == pointer to the block * size_t length == length of block * int *maxbuf == pointer to the length of the destination task's buffer * * Returns * TRUE if successful, FALSE if it failed. If this returns FALSE, you must * return FALSE immediately. */ BOOL xfersend_sendBlock(void *block,int length,int *maxbuf) { char *p=(char *)block; int left=length; int send; while (left) { if (left<=(*maxbuf)) send=left; else send=*maxbuf; if (xfersend_sendbuf(p,send)==FALSE) return (FALSE); left-=send; p+=send; } return (TRUE); } /* end xfersend.c */