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 | |
47 | static int rcvbufsize ; |
48 | static int xfersend__msgid; |
49 | static xfersend_saveproc xfersend__saveproc; |
50 | static xfersend_sendproc xfersend__sendproc; |
51 | static xfersend_printproc xfersend__printproc; |
52 | static int xfersend__filetype; |
53 | static void *xfersend__savehandle; |
54 | static int xfersend__estsize; |
55 | static wimp_t xfersend__receiver ; |
56 | static BOOL xfersend__fileissafe ; |
57 | static char xfersend__filename[256]; |
58 | |
59 | static wimp_mousestr xfersend__mousestr; |
60 | static wimp_msgstr xfersend__msg; |
61 | static BOOL xfersend__close; |
62 | static wimp_w xfersend__w; |
63 | static wimp_i xfersend__i; |
64 | |
65 | static BOOL xfersend__finishedXfer; |
66 | |
67 | static 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 | |
78 | void xfersend_close_on_xfer(BOOL do_we_close, wimp_w w) |
79 | { |
80 | xfersend__close = do_we_close; |
81 | xfersend__w = w; |
82 | } |
83 | |
84 | static 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 | |
92 | static 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 | |
328 | static int sendbuf__state ; |
329 | |
330 | static 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 | |
369 | BOOL xfersend_sendbuf(char *buffer, int size) |
370 | { |
371 | |
372 | /* Called by his sendproc when sending things in memory. The |
373 | reply 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 | |
420 | BOOL 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 | |
486 | BOOL xfersend_file_is_safe() |
487 | { |
488 | return xfersend__fileissafe ; |
489 | } |
490 | |
491 | void 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 | |
512 | BOOL 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 */ |