chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / xferrecv
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 */