Initial revision
[ssr] / StraySrc / Libraries / Steel / c / xfersend
CommitLineData
2ee739cc 1/* Title: -> c.xfersend
2 * Purpose: generalised data transfer to a concurrent wimp program.
3 */
4
5/*----- Licensing note ----------------------------------------------------*
6 *
7 * This file is part of Straylight's Steel library.
8 *
9 * Steel is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * Steel is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Steel. If not, write to the Free Software Foundation,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#define BOOL int
25#define TRUE 1
26#define FALSE 0
27
28#include <string.h>
29#include <stdio.h>
30#include <stdlib.h>
31
32#include "trace.h"
33#include "os.h"
34#include "bbc.h"
35#include "wimp.h"
36#include "wimpt.h"
37#include "win.h"
38#include "dbox.h"
39#include "xfersend.h"
40#include "fileicon.h"
41#include "werr.h"
42#include "menu.h"
43#include "event.h"
44#include "msgs.h"
45#include "swis.h"
46
47static int rcvbufsize ;
48static int xfersend__msgid;
49static xfersend_saveproc xfersend__saveproc;
50static xfersend_sendproc xfersend__sendproc;
51static xfersend_printproc xfersend__printproc;
52static int xfersend__filetype;
53static void *xfersend__savehandle;
54static int xfersend__estsize;
55static wimp_t xfersend__receiver ;
56static BOOL xfersend__fileissafe ;
57static char xfersend__filename[256];
58
59static wimp_mousestr xfersend__mousestr;
60static wimp_msgstr xfersend__msg;
61static BOOL xfersend__close;
62static wimp_w xfersend__w;
63static wimp_i xfersend__i;
64
65static BOOL xfersend__finishedXfer;
66
67static void xfersend__iconDel(wimp_w w,wimp_i i,BOOL del)
68{
69 if (wimpt_options() & wimpt_OREMSAVEICON)
70 {
71 if (del)
72 wimp_set_icon_state(w,i,(1<<23)+(1<<7),(1<<23)+(1<<7));
73 else
74 wimp_set_icon_state(w,i,0,(1<<23)+(1<<7));
75 }
76}
77
78void xfersend_close_on_xfer(BOOL do_we_close, wimp_w w)
79{
80 xfersend__close = do_we_close;
81 xfersend__w = w;
82}
83
84static void xfersend__winclose(void)
85{
86 wimp_eventdata e;
87 e.o.w = xfersend__w;
88 wimpt_noerr(wimp_sendwmessage(wimp_ECLOSE, (wimp_msgstr*) &e, e.o.w, -1));
89}
90
91
92static BOOL xfersend__unknowns(wimp_eventstr *e, void *handle) {
93 handle = handle ;
94 tracef1("xfersend raw event %i.\n", e->e);
95 switch (e->e) {
96 case wimp_EUSERDRAG:
97 tracef0("drag event received.\n");
98 {
99 wimp_get_point_info(&xfersend__mousestr);
100 if (xfersend__mousestr.w == -1) {
101 tracef0("drag to no window: has no effect.\n");
102 xfersend__finishedXfer=TRUE;
103 /* do nothing */
104 } else {
105 wimp_msgstr msg;
106
107 tracef1("drag to window %i: offer data.\n", xfersend__mousestr.w);
108 /* msg.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasave); */
109 msg.hdr.task = xfersend__mousestr.w;
110 msg.hdr.your_ref = 0;
111 msg.hdr.action = wimp_MDATASAVE;
112 msg.data.datasave.w = xfersend__mousestr.w;
113 msg.data.datasave.i = xfersend__mousestr.i;
114 msg.data.datasave.x = xfersend__mousestr.x;
115 msg.data.datasave.y = xfersend__mousestr.y;
116 msg.data.datasave.type = xfersend__filetype;
117 msg.data.datasave.estsize = xfersend__estsize;
118 {
119 int tail;
120 char name[256];
121 strncpy(name,xfersend__filename, 256);
122 tail = strlen(name); /* point at the zero */
123 while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
124 tail--;
125
126 strncpy(msg.data.datasave.leaf, name + tail, 210);
127 msg.data.dataload.name[211] = 0; /* Avoid boundcheck warning */
128 msg.hdr.size = (48+strlen(msg.data.datasave.leaf)) & ~3;
129 tracef1("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]);
130 };
131 wimpt_noerr(wimp_sendwmessage(
132 wimp_ESENDWANTACK, &msg, xfersend__mousestr.w, xfersend__mousestr.i));
133 xfersend__msgid = msg.hdr.my_ref; /* filled in by wimp. */
134 /* We still get unknown events, so we'll get the reply sometime. */
135 };
136 };
137 return TRUE;
138
139 case wimp_ESEND:
140 case wimp_ESENDWANTACK:
141
142#if TRACE
143 tracef("xfersend msg %x received: %i %i.\n",
144 e->data.msg.hdr.action,e->data.msg.hdr.your_ref,xfersend__msgid);
145#endif
146
147 if (e->data.msg.hdr.your_ref == xfersend__msgid)
148 switch (e->data.msg.hdr.action)
149 {
150 case wimp_MRAMFETCH:
151 if (xfersend__sendproc != 0)
152 {
153 xfersend__fileissafe = FALSE ;
154
155 /* He wants to do an in-core transfer, and we can do this. */
156 /* Note that this can't be other than the first response, as others
157 are grabbed by sendbuf */
158
159 tracef0("ram transfer starting.\n");
160
161 /* Prepare the reply record. */
162 xfersend__msg = e->data.msg;
163 xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
164 xfersend__msg.hdr.action = wimp_MRAMTRANSMIT;
165 xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
166 xfersend__msg.data.ramtransmit.nbyteswritten = 0; /* so far. */
167 rcvbufsize = e->data.msg.data.ramfetch.nbytes;
168
169 xfersend__receiver = e->data.msg.hdr.task ;
170 /* the copy in xfersend__msg.hdr.task is overwritten by the Wimp
171 message sending */
172
173 if (xfersend__sendproc(xfersend__savehandle, &rcvbufsize))
174 {
175 /* See sendbuf for all the real work for this case... */
176 tracef0("The send succeeded; send final RAMTRANSMIT.\n");
177
178 /* We may have transferred some data but not yet told the
179 other end about it. xfersend__msg contains a final RAMTRANSMIT,
180 which does not quite fill his buffer (or we'd have sent it already)
181 thus signalling to him that the transfer is over. */
182
183 wimpt_noerr(wimp_sendmessage(
184 wimp_ESEND,
185 &xfersend__msg,
186 xfersend__receiver));
187 xfersend__finishedXfer=TRUE;
188 if(xfersend__close) xfersend__winclose();
189 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
190 }
191 else
192 {
193 tracef0("the send failed.\n");
194 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
195 xfersend__finishedXfer=TRUE;
196 };
197 return TRUE;
198 }
199 else
200 {
201 if (getenv("Wimp$Scrap")==0)
202 xfersend__finishedXfer=TRUE;
203 /*** The other application reports an error, and I don't get my ***
204 *** no-acknowledgement message to tell me to abort the data ***
205 *** transfer. ***/
206 }
207 break ;
208
209 case wimp_MPrintFile: /* was dropped on a printer application */
210 if (xfersend__printproc != 0)
211 {
212 int res ;
213
214 tracef0("print request acceptable\n");
215 xfersend__fileissafe = FALSE ;
216
217 res = xfersend__printproc(&e->data.msg.data.print.name[0],
218 xfersend__savehandle) ;
219
220 xfersend__msg = e->data.msg;
221 xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
222 xfersend__msg.hdr.action =
223 res >= 0 ? wimp_MDATALOAD : wimp_MWillPrint;
224 xfersend__msg.data.print.type = res ; /* in case it's been saved */
225 wimpt_noerr(wimp_sendmessage(
226 wimp_ESENDWANTACK,
227 &xfersend__msg,
228 xfersend__receiver));
229 xfersend__msgid=xfersend__msg.hdr.my_ref;
230 if (res==xfersend_printPrinted)
231 {
232 xfersend__finishedXfer=TRUE;
233 if(xfersend__close) xfersend__winclose();
234 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
235 }
236 else if (res==xfersend_printFailed)
237 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
238 return TRUE;
239 }
240 break ;
241
242 case wimp_MDATALOADOK:
243 xfersend__finishedXfer=TRUE;
244 if(xfersend__close) xfersend__winclose();
245 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
246 return (TRUE);
247 break;
248
249 case wimp_MDATASAVEOK:
250 {
251 tracef4("datasaveok %i %i %i %i.\n",
252 e->data.msg.hdr.size,
253 e->data.msg.hdr.task,
254 e->data.msg.hdr.your_ref,
255 e->data.msg.hdr.my_ref);
256 tracef4("datasaveok %x %x %x %x.\n",
257 e->data.msg.data.words[0],
258 e->data.msg.data.words[1],
259 e->data.msg.data.words[2],
260 e->data.msg.data.words[3]);
261 tracef1("it's the datasaveok, to file '%s'.\n",
262 (int) &e->data.msg.data.datasaveok.name[0]);
263
264 tracef1("save to filename '%s'.\n",
265 (int) &e->data.msg.data.datasaveok.name[0]);
266
267 xfersend__fileissafe = e->data.msg.data.datasaveok.estsize >= 0 ;
268
269 if (xfersend__saveproc(&e->data.msg.data.datasaveok.name[0],
270 xfersend__savehandle))
271 {
272 tracef0("the save succeeded: send dataload\n");
273
274 xfersend__msg = e->data.msg;
275 /* sets hdr.size, data.w,i,x,y, size, name */
276 xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref;
277 xfersend__msg.hdr.action = wimp_MDATALOAD;
278 xfersend__msg.data.dataload.type = xfersend__filetype ;
279 wimpt_noerr(wimp_sendmessage(
280 wimp_ESENDWANTACK,
281 &xfersend__msg,
282 e->data.msg.hdr.task));
283 xfersend__msgid=xfersend__msg.hdr.my_ref;
284
285 } else
286 {
287 /* he has already reported the error: nothing more to do. */
288 tracef0("save was not successful.\n");
289 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
290 xfersend__finishedXfer=TRUE;
291 };
292 return TRUE;
293 }
294 }
295 return FALSE ; /* unknown not dealt with */
296
297 case wimp_EACK:
298 if (e->data.msg.hdr.my_ref == xfersend__msgid)
299 {
300 switch (e->data.msg.hdr.action)
301 {
302 case wimp_MDATALOAD:
303 {
304 /* It looks as if he hasn't acknowledged my DATALOAD acknowledge:
305 thus it may be a loose scrap file, and must be deleted. */
306 char a[256];
307 tracef0("he hasn't ack'd our data load of temp file, so delete the file.\n");
308 werr(FALSE, msgs_lookup("xfersend1:Bad data transfer, receiver dead."));
309 sprintf(a, "%%delete %s", &xfersend__msg.data.dataload.name[0]);
310 os_cli(a) ;
311 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
312 xfersend__finishedXfer=TRUE;
313 }
314 break;
315 case wimp_MDATASAVE:
316 xfersend__finishedXfer=TRUE;
317 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
318 break;
319 }
320 };
321 return TRUE;
322 default:
323 return FALSE ;
324 };
325}
326
327
328static int sendbuf__state ;
329
330static BOOL sendbuf__unknowns(wimp_eventstr *e, void *h)
331{
332 h = h ;
333
334 tracef4("sendbuf__unknowns %d %d %d %d\n",
335 e->data.msg.hdr.my_ref, e->data.msg.hdr.your_ref,
336 xfersend__msg.hdr.your_ref, xfersend__msg.hdr.my_ref) ;
337
338 if ((e->e == wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
339 e->data.msg.hdr.your_ref == xfersend__msg.hdr.my_ref &&
340 e->data.msg.hdr.action == wimp_MRAMFETCH)
341 {
342 /* Prepare xfersend__msg as the next RAMTRANSMIT. Most of
343 the fields are already set up. */
344
345 xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
346 xfersend__msg.data.ramtransmit.nbyteswritten = 0;
347 xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref ;
348 rcvbufsize = e->data.msg.data.ramfetch.nbytes;
349
350 tracef2("RAMFETCH received: continue with buffer at %x, size %d\n",
351 (int) xfersend__msg.data.ramtransmit.addr, rcvbufsize) ;
352
353 sendbuf__state = 1 ;
354 return TRUE ; /* We've had another RAMFETCH: off we go again */
355 }
356
357 if (e->e == wimp_EACK &&
358 e->data.msg.hdr.my_ref == xfersend__msg.hdr.my_ref)
359 {
360 sendbuf__state = 2 ;
361 tracef0("xfersend RAMTRANSMIT bounced; set failed state\n") ;
362 return TRUE ;/* our message bounced back; give up */
363 }
364
365 return FALSE ; /* we don't want it */
366}
367
368
369BOOL xfersend_sendbuf(char *buffer, int size)
370{
371
372/* Called by his sendproc when sending things in memory. The
373reply record is in xfersend__msg. */
374
375 tracef2("xfersend_sendbuf %i %i\n", (int) buffer, size);
376
377 /* Make the data transfer */
378 tracef3("transfer block of %d from %x to %x\n", size, (int) buffer,
379 (int) (xfersend__msg.data.ramtransmit.addr +
380 xfersend__msg.data.ramtransmit.nbyteswritten)) ;
381
382 wimpt_noerr(wimp_transferblock(
383 wimpt_task(),
384 buffer,
385 xfersend__receiver,
386 xfersend__msg.data.ramtransmit.addr +
387 xfersend__msg.data.ramtransmit.nbyteswritten,
388 size));
389
390 /* record bytes to be sent to the other end */
391 xfersend__msg.data.ramtransmit.nbyteswritten += size;
392 rcvbufsize -= size ;
393
394 /* if size != 0, there are still bytes to send. */
395
396 if (rcvbufsize > 0) return TRUE;
397
398 tracef1("xfersend message has put %d into buffer\n",size) ;
399 /* Tell him that you've done it */
400 wimpt_noerr(wimp_sendmessage(
401 wimp_ESENDWANTACK,
402 &xfersend__msg,
403 xfersend__receiver));
404
405 /* Get his reply. Poll and despatch events until get nack or message */
406
407 sendbuf__state = 0 ;
408
409 win_add_unknown_event_processor(sendbuf__unknowns, 0) ;
410 do { event_process() ; } while (sendbuf__state == 0) ;
411 win_remove_unknown_event_processor(sendbuf__unknowns, 0) ;
412
413 /* This exit happens in the cases where the buffers at each end
414 are of identical size. So, return for another call to sendbuf, or
415 so that the sendbuf procedure can return. */
416
417 return sendbuf__state != 2 ; /* OK unless state = broken */
418}
419
420BOOL xfersend(int filetype, char *filename, int estsize,
421 xfersend_saveproc saver,
422 xfersend_sendproc sender,
423 xfersend_printproc printer,
424 wimp_eventstr *e, void *handle)
425{
426 wimp_dragstr dr;
427 wimp_wstate wstate;
428 wimp_icon icon;
429 wimp_w w = e->data.but.m.w;
430 os_regset r;
431 xfersend__saveproc = saver;
432 xfersend__sendproc = sender;
433 xfersend__printproc = printer;
434 xfersend__filetype = filetype;
435 xfersend__estsize = estsize;
436 xfersend__savehandle = handle;
437 if(filename == 0)
438 strcpy(xfersend__filename, msgs_lookup("xfersend2:Selection"));
439 else
440 strncpy(xfersend__filename,filename,256);
441 if (e->e==wimp_EBUT)
442 {
443 xfersend__w = e->data.but.m.w;
444 xfersend__i = e->data.but.m.i;
445 tracef0("Initiate a drag.\n");
446 r.r[0]=161; /* Read CMOS */
447 r.r[1]=0x1c; /* Support DragASrite? */
448 wimpt_noerr(os_swix(XOS_Byte,&r));
449 wimp_get_wind_state(w, &wstate);
450 wimp_get_icon_info(w, e->data.but.m.i, &icon);
451 dr.box.x0 = wstate.o.box.x0 - wstate.o.x + icon.box.x0;
452 dr.box.y0 = wstate.o.box.y1 - wstate.o.y + icon.box.y0;
453 dr.box.x1 = wstate.o.box.x0 - wstate.o.x + icon.box.x1;
454 dr.box.y1 = wstate.o.box.y1 - wstate.o.y + icon.box.y1;
455 if ((r.r[2] & 2) && wimpt_getVersion()>=300)
456 {
457 r.r[0]=0xC5; /* Centre, whole-screen, drop-shadow */
458 r.r[1]=1;
459 r.r[2]=(int)fileicon_spriteName(filetype,filename);
460 r.r[3]=(int)&dr.box;
461 xfersend__iconDel(xfersend__w,xfersend__i,TRUE);
462 wimpt_noerr(os_swix(XDragASprite_Start,&r));
463 }
464 else
465 {
466 /* Pedestrian drag-box */
467 dr.window = w; /* not relevant. */
468 dr.type = wimp_USER_FIXED;
469 dr.parent.x0 = 0;
470 dr.parent.y0 = 0;
471 dr.parent.x1 = wimpt_scwidth();
472 dr.parent.y1 = wimpt_scheight();
473 wimp_drag_box(&dr);
474 }
475 }
476 win_add_unknown_event_processor(xfersend__unknowns, 0);
477 xfersend__finishedXfer=FALSE;
478 while (xfersend__finishedXfer==FALSE)
479 event_process();
480 win_remove_unknown_event_processor(xfersend__unknowns, 0);
481 xfersend__w=0;
482 return TRUE;
483}
484
485
486BOOL xfersend_file_is_safe()
487{
488 return xfersend__fileissafe ;
489}
490
491void xfersend_set_fileissafe(BOOL value)
492{
493 xfersend__fileissafe = value;
494}
495
496/*
497 * BOOL xfersend_sendBlock(void *block,size_t length,int *maxbuf)
498 *
499 * Use
500 * Sends a block to xfersend_sendbuf() a chunk at a time.
501 *
502 * Parameters
503 * void *block == pointer to the block
504 * size_t length == length of block
505 * int *maxbuf == pointer to the length of the destination task's buffer
506 *
507 * Returns
508 * TRUE if successful, FALSE if it failed. If this returns FALSE, you must
509 * return FALSE immediately.
510 */
511
512BOOL xfersend_sendBlock(void *block,int length,int *maxbuf)
513{
514 char *p=(char *)block;
515 int left=length;
516 int send;
517 while (left)
518 {
519 if (left<=(*maxbuf))
520 send=left;
521 else
522 send=*maxbuf;
523 if (xfersend_sendbuf(p,send)==FALSE)
524 return (FALSE);
525 left-=send;
526 p+=send;
527 }
528 return (TRUE);
529}
530
531/* end xfersend.c */