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 | |
47 | typedef enum |
48 | { |
49 | xferrecv_state_Ask, |
50 | xferrecv_state_Talk, |
51 | xferrecv_state_Done, |
52 | xferrecv_state_Broken |
53 | } xferrecv_stateval ; |
54 | |
55 | |
56 | static wimp_t xferrecv_sendertask ; |
57 | static wimp_msgstr xferrecv_ack ; |
58 | |
59 | static xferrecv_buffer_processor xferrecv_processbuff ; |
60 | static char *xferrecv_buffer ; |
61 | static int xferrecv_buffersize ; |
62 | static int xferrecv_state ; |
63 | static int xferrecv_msgid ; |
64 | |
65 | static flex_ptr xferrecv__flex; |
66 | static int xferrecv__returnBlockSize; |
67 | |
68 | static char xferrecv__nameToImport[256]; |
69 | |
70 | static int scrap_ref; |
71 | static int xferrecv__fileissafe ; |
72 | |
73 | int 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 | |
99 | void 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 | |
115 | int 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 | |
138 | void xferrecv_printfileok(int type) |
139 | { |
140 | xferrecv_ack.data.print.type = type ; |
141 | (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask); |
142 | } |
143 | |
144 | int 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 | |
181 | char *xferrecv_nameToImport(void) |
182 | { |
183 | return (xferrecv__nameToImport); |
184 | } |
185 | |
186 | static 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 | |
210 | static 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 | |
286 | void 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 | |
310 | int 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 | |
344 | static 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 | |
374 | int 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 | |
389 | BOOL xferrecv_file_is_safe() |
390 | { |
391 | return xferrecv__fileissafe ; |
392 | } |
393 | |
394 | /* end */ |