Initial revision
[ssr] / StraySrc / Libraries / Steel / c / xferrecv
CommitLineData
2ee739cc 1/* Title: -> c.xferrecv
2 * Purpose: general purpose import of data by dragging icon
3 * Requires:
4 * BOOL
5 */
6
7/*----- Licensing note ----------------------------------------------------*
8 *
9 * This file is part of Straylight's Steel library.
10 *
11 * Steel is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * Steel is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Steel. If not, write to the Free Software Foundation,
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26
27#include <string.h>
28#include <stdio.h>
29#include "trace.h"
30#include "os.h"
31#include "bbc.h"
32#include "wimp.h"
33#include "wimpt.h"
34#include "win.h"
35#include "dbox.h"
36#include "typdat.h"
37#include "xfersend.h"
38#include "fileicon.h"
39#include "werr.h"
40#include "menu.h"
41#include "event.h"
42#include "xferrecv.h"
43#include "msgs.h"
44
45#define XOS_ReadVarVal 0x20023
46
47typedef enum
48{
49 xferrecv_state_Ask,
50 xferrecv_state_Talk,
51 xferrecv_state_Done,
52 xferrecv_state_Broken
53} xferrecv_stateval ;
54
55
56static wimp_t xferrecv_sendertask ;
57static wimp_msgstr xferrecv_ack ;
58
59static xferrecv_buffer_processor xferrecv_processbuff ;
60static char *xferrecv_buffer ;
61static int xferrecv_buffersize ;
62static int xferrecv_state ;
63static int xferrecv_msgid ;
64
65static flex_ptr xferrecv__flex;
66static int xferrecv__returnBlockSize;
67
68static char xferrecv__nameToImport[256];
69
70static int scrap_ref;
71static int xferrecv__fileissafe ;
72
73int xferrecv_checkinsert(char **filename)
74{
75
76 wimp_eventstr *e = wimpt_last_event();
77
78 if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
79 (e->data.msg.hdr.action == wimp_MDATALOAD ||
80 e->data.msg.hdr.action == wimp_MDATAOPEN))
81 {
82 tracef4("xferrecv_checkinsert returning filetype %x: %d %d %d\n",
83 e->data.msg.data.dataload.type,
84 scrap_ref,e->data.msg.hdr.your_ref,e->data.msg.hdr.my_ref) ;
85 xferrecv__fileissafe = e->data.msg.hdr.your_ref != scrap_ref ||
86 scrap_ref==0 ;
87 xferrecv_ack.hdr.action = wimp_MDATALOADOK ;
88 xferrecv_ack.hdr.size = sizeof(wimp_msghdr) ;
89 xferrecv_sendertask = e->data.msg.hdr.task ;
90 xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
91 *filename = e->data.msg.data.dataload.name ;
92 if (xferrecv__fileissafe)
93 strcpy(xferrecv__nameToImport,*filename);
94 return e->data.msg.data.dataload.type ;
95 }
96 else return -1 ;
97}
98
99void xferrecv_insertfileok(void)
100{
101/* An insert has been completed successfully. This sends an acknowledge back
102 to the original application. */
103
104 tracef0("xferrecv_insertfileok\n") ;
105
106 if (!xferrecv__fileissafe)
107 {
108 tracef0("Must delete scrap file\n") ;
109 os_cli("%remove <Wimp$Scrap>") ;
110 }
111 scrap_ref = 0 ;
112 (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
113}
114
115int xferrecv_checkprint(char **filename)
116{
117 wimp_eventstr *e = wimpt_last_event();
118
119 if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
120 (e->data.msg.hdr.action == wimp_MPrintTypeOdd))
121 {
122 tracef4("xferrecv_checkprint returning filetype %x: %d %d %d\n",
123 e->data.msg.data.print.type,
124 scrap_ref,e->data.msg.hdr.your_ref,e->data.msg.hdr.my_ref) ;
125
126 xferrecv__fileissafe = 0 ;
127 xferrecv_ack.hdr.action = wimp_MPrintTypeKnown ;
128 xferrecv_ack.hdr.size = sizeof(wimp_msghdr)+sizeof(wimp_msgprint) ;
129 xferrecv_sendertask = e->data.msg.hdr.task ;
130 xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
131 *filename = e->data.msg.data.print.name ;
132 return e->data.msg.data.print.type ;
133 }
134 else return -1 ;
135}
136
137
138void xferrecv_printfileok(int type)
139{
140 xferrecv_ack.data.print.type = type ;
141 (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
142}
143
144int xferrecv_checkimport(int *estsize)
145{
146 wimp_eventstr *e = wimpt_last_event();
147
148 if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
149 e->data.msg.hdr.action == wimp_MDATASAVE)
150 {
151 xferrecv_ack.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasaveok) ;
152 xferrecv_sendertask = e->data.msg.hdr.task ;
153 xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
154 xferrecv_ack.hdr.action = wimp_MDATASAVEOK ;
155 xferrecv_ack.data.datasaveok.w = e->data.msg.data.datasave.w ;
156 xferrecv_ack.data.datasaveok.i = e->data.msg.data.datasave.i ;
157 xferrecv_ack.data.datasaveok.x = e->data.msg.data.datasave.x ;
158 xferrecv_ack.data.datasaveok.y = e->data.msg.data.datasave.y ;
159 xferrecv_ack.data.datasaveok.type = e->data.msg.data.datasave.type ;
160 *estsize = xferrecv_ack.data.datasaveok.estsize
161 = e->data.msg.data.datasave.estsize ;
162 strcpy(xferrecv__nameToImport,e->data.msg.data.datasave.leaf);
163 tracef2("xferrecv_checkimport returning filetype %x from %d\n",
164 e->data.msg.data.datasave.type,xferrecv_sendertask) ;
165
166 return xferrecv_ack.data.datasaveok.type = e->data.msg.data.datasave.type ;
167 }
168 else return -1 ;
169}
170
171/*
172 * char *xferrecv_nameToImport(void)
173 *
174 * Use
175 * Returns the name of the file to import (full pathname if available).
176 *
177 * Returns
178 * A pointer to a read-only string.
179 */
180
181char *xferrecv_nameToImport(void)
182{
183 return (xferrecv__nameToImport);
184}
185
186static void xferrecv_sendRAMFETCH(void)
187{
188 char *addr = xferrecv_ack.data.ramfetch.addr ;
189 int size = xferrecv_ack.data.ramfetch.nbytes ;
190 int action = xferrecv_ack.hdr.action ;
191
192 tracef2("xferrecv_sendRAMFETCH with buffer %x, size %d :",
193 (int) xferrecv_buffer,xferrecv_buffersize) ;
194
195 xferrecv_ack.hdr.action = wimp_MRAMFETCH ;
196 xferrecv_ack.data.ramfetch.addr = xferrecv_buffer ;
197 xferrecv_ack.data.ramfetch.nbytes = xferrecv_buffersize ;
198 (void) wimp_sendmessage(wimp_ESENDWANTACK,
199 &xferrecv_ack,
200 xferrecv_sendertask);
201 xferrecv_msgid = xferrecv_ack.hdr.my_ref ;
202
203 tracef1(" ramfetch msg id %d\n",xferrecv_msgid) ;
204
205 xferrecv_ack.data.ramfetch.addr=addr ;
206 xferrecv_ack.data.ramfetch.nbytes=size ;
207 xferrecv_ack.hdr.action = action ;
208}
209
210static BOOL xferrecv_unknown_events(wimp_eventstr *e, void *handle)
211{
212 handle = handle ;
213
214#if TRACE
215 tracef("xferrecv_unknown_events %d %d %d %d %d\n",e->e,
216 e->data.msg.hdr.action,e->data.msg.hdr.my_ref,
217 e->data.msg.hdr.your_ref,xferrecv_msgid) ;
218#endif
219
220 if ((e->e == wimp_ESEND || e->e == wimp_ESENDWANTACK) &&
221 e->data.msg.hdr.your_ref == xferrecv_msgid &&
222 e->data.msg.hdr.action == wimp_MRAMTRANSMIT)
223 {
224 tracef2("xferrecv got ramtransmit of %d into %d\n",
225 e->data.msg.data.ramtransmit.nbyteswritten,xferrecv_buffersize) ;
226 if (e->data.msg.data.ramtransmit.nbyteswritten == xferrecv_buffersize)
227 {
228 /* other end has filled our buffer; better try and allocate some more
229 space */
230 if (xferrecv_processbuff(&xferrecv_buffer, &xferrecv_buffersize))
231 {
232 /* can go on */
233 tracef2("users buffer processor set buffer %x, size %d\n",
234 (int) xferrecv_buffer, xferrecv_buffersize) ;
235
236 xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
237 xferrecv_sendRAMFETCH() ;
238 xferrecv_state = xferrecv_state_Talk ;
239 }
240 else
241 {
242 tracef0("users buffer processor failed: break down\n") ;
243 xferrecv_state = xferrecv_state_Broken ;
244 }
245 }
246 else
247 {
248 tracef0("xferrecv had final ramtransmit; set done state\n") ;
249 xferrecv_state = xferrecv_state_Done ;
250 xferrecv_buffersize=e->data.msg.data.ramtransmit.nbyteswritten;
251 if (xferrecv_buffersize!=0)
252 {
253 if (!xferrecv_processbuff(&xferrecv_buffer, &xferrecv_buffersize))
254 xferrecv_state = xferrecv_state_Broken ;
255 }
256 xferrecv_buffersize = e->data.msg.data.ramtransmit.nbyteswritten ;
257 }
258 }
259 else if (e->e == wimp_EACK && e->data.msg.hdr.my_ref == xferrecv_msgid)
260 {
261 tracef0("xferrecv ramfetch bounced: ") ;
262 /* got our message back */
263 if (xferrecv_state == xferrecv_state_Ask)
264 xferrecv_importByScrap();
265 else
266 {
267 tracef0("tell the user the protocol fell down\n") ;
268 werr(0, msgs_lookup("xferrecv2:Data transfer failed.")) ;
269 }
270 xferrecv_state = xferrecv_state_Broken ;
271 }
272 else return FALSE ;
273
274 return TRUE ;
275}
276
277/*
278 * void xferrecv_importByScrap(void)
279 *
280 * Use
281 * Tells xferrecv not to bother with RAM transfer, but to use the
282 * <Wimp$Scrap> file instead. It checks that the system variables and
283 * everything are set up right beforehand.
284 */
285
286void xferrecv_importByScrap(void)
287{
288 os_regset r ;
289 tracef0("ask for Wimp$Scrap transfer\n") ;
290
291 /* first check that variable exists */
292 r.r[0] = (int) "Wimp$Scrap" ;
293 r.r[1] = NULL ;
294 r.r[2] = -1 ;
295 r.r[3] = 0 ;
296 r.r[4] = 3 ;
297 os_swix(XOS_ReadVarVal, &r) ;
298
299 if (r.r[2]==0)
300 werr(0,msgs_lookup("xferrecv1:Can't transfer file (use *Set Wimp$Scrap <filename>)")) ;
301 else
302 {
303 strcpy(xferrecv_ack.data.datasaveok.name, "<Wimp$Scrap>") ;
304 xferrecv_ack.data.datasaveok.estsize = -1 ; /* file is not safe with us */
305 (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
306 scrap_ref = xferrecv_ack.hdr.my_ref ;
307 }
308}
309
310int xferrecv_doimport(char *buf, int size, xferrecv_buffer_processor p)
311{
312
313/* Receives data into the buffer; calls the buffer processor if the buffer
314 given becomes full. Returns TRUE if the transaction completed sucessfully.
315 */
316
317 win_add_unknown_event_processor(xferrecv_unknown_events, 0) ;
318
319 tracef0("xferrecv_doimport entered\n") ;
320 xferrecv_processbuff = p ;
321 xferrecv_buffer = buf ;
322 xferrecv_buffersize = size ;
323 xferrecv_sendRAMFETCH() ;
324 xferrecv_state = xferrecv_state_Ask ;
325 xferrecv__fileissafe = FALSE ;
326
327 do
328 {
329 event_process() ;
330 } while (xferrecv_state < xferrecv_state_Done) ;
331
332 win_remove_unknown_event_processor(xferrecv_unknown_events, 0) ;
333
334 return (xferrecv_state == xferrecv_state_Done ? xferrecv_buffersize : -1 ) ;
335}
336
337/*
338 * BOOL xferrecv__returnBlockBuffProcessor(char **buff,int *size)
339 *
340 * Use
341 * Buffer processor for xferrecv_returnImportedBlock.
342 */
343
344static BOOL xferrecv__returnBlockBuffProcessor(char **buff,int *size)
345{
346 if (!flex_extend(xferrecv__flex,xferrecv__returnBlockSize+8192))
347 return (FALSE);
348 xferrecv__returnBlockSize+=8192;
349 *buff+=*size;
350 *size=8192;
351 return (TRUE);
352}
353
354/*
355 * int xferrecv_returnImportedBlock(flex_ptr p)
356 *
357 * Use
358 * Performs the data import if possible, and returns with the block filled
359 * with *ALL* the imported data i.e. it obviates the need of any work on
360 * your part for the data transfer. This is the life, huh? If anything
361 * went wrong, it returns -1 as for xferrecv_doimport
362 *
363 * Parameters
364 * flex_ptr p == flex pointer to nothing in particular (certainly not a
365 * flex block - one is allocated for you). Remember to free it after
366 * you've read all the data! Also ensure that flex has been initialised.
367 * If there is no data to import (i.e. the import failed) then p is freed
368 * of any data that may have been stored there.
369 *
370 * Returns
371 * -1 for failure, or the total size of the imported data for success
372 */
373
374int xferrecv_returnImportedBlock(flex_ptr p)
375{
376 xferrecv__flex=p;
377 if (!flex_alloc(p,xferrecv_ack.data.datasaveok.estsize))
378 return (-1);
379 xferrecv__returnBlockSize=xferrecv_ack.data.datasaveok.estsize;
380 if (xferrecv_doimport(*p,xferrecv_ack.data.datasaveok.estsize,
381 xferrecv__returnBlockBuffProcessor)==-1)
382 {
383 flex_free(p);
384 return (-1);
385 }
386 return (xferrecv__returnBlockSize);
387}
388
389BOOL xferrecv_file_is_safe()
390{
391 return xferrecv__fileissafe ;
392}
393
394/* end */