Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / twain / dsm_ctrl.c
1 /*
2  * TWAIN32 Source Manager
3  *
4  * Copyright 2000 Corel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "winbase.h"
28 #include "twain.h"
29 #include "twain_i.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33
34 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
35 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
36 {
37 #ifndef HAVE_SANE
38     DSM_twCC = TWCC_NODS;
39     return TWRC_FAILURE;
40 #else
41     TW_UINT16 twRC = TWRC_SUCCESS;
42     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
43     activeDS *currentDS = NULL, *prevDS = NULL;
44
45     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
46
47     for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
48     {
49         if (currentDS->identity.Id == pIdentity->Id)
50             break;
51         prevDS = currentDS;
52     }
53     if (currentDS)
54     {
55         /* Only valid to close a data source if it is in state 4 */
56         if (currentDS->currentState == 4)
57         {
58             sane_close (currentDS->deviceHandle);
59             /* remove the data source from active data source list */
60             if (prevDS)
61                 prevDS->next = currentDS->next;
62             else
63                 activeSources = currentDS->next;
64             HeapFree (GetProcessHeap(), 0, currentDS);
65             twRC = TWRC_SUCCESS;
66             DSM_twCC = TWCC_SUCCESS;
67         }
68         else
69         {
70             twRC = TWRC_FAILURE;
71             DSM_twCC = TWCC_SEQERROR;
72         }
73     }
74     else
75     {
76         twRC = TWRC_FAILURE;
77         DSM_twCC = TWCC_NODS;
78     }
79
80     return twRC;
81 #endif
82 }
83
84 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
85 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
86 {
87 #ifndef HAVE_SANE
88     DSM_twCC = TWCC_NODS;
89     return TWRC_FAILURE;
90 #else
91     TW_UINT16 twRC = TWRC_SUCCESS;
92     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
93
94     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
95
96     if (!device_list)
97     {
98         if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
99         {
100             DSM_twCC = TWCC_NODS;
101             return TWRC_FAILURE;
102         }
103     }
104
105     /* FIXME: the default device is not necessarily the first device.  *
106      * Users should be able to choose the default device               */
107     if (device_list && device_list[0])
108     {
109         pSourceIdentity->Id = DSM_sourceId ++;
110         strcpy (pSourceIdentity->ProductName, device_list[0]->name);
111         strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
112         strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
113         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
114         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
115
116         twRC = TWRC_SUCCESS;
117         DSM_twCC = TWCC_SUCCESS;
118     }
119     else
120     {
121         twRC = TWRC_FAILURE;
122         DSM_twCC = TWCC_NODS;
123     }
124
125     return twRC;
126 #endif
127 }
128
129 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
130 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
131 {
132 #ifndef HAVE_SANE
133     DSM_twCC = TWCC_NODS;
134     return TWRC_FAILURE;
135 #else
136     TW_UINT16 twRC = TWRC_SUCCESS;
137     pTW_IDENTITY pSourceIdentity;/* = (pTW_IDENTITY) pData;*/
138     SANE_Status status;
139
140     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
141
142     status = sane_get_devices (&device_list, SANE_FALSE);
143     if (status == SANE_STATUS_GOOD)
144     {
145         if (device_list[0])
146         {
147             pSourceIdentity->Id = DSM_sourceId ++;
148             strcpy (pSourceIdentity->ProductName, device_list[0]->name);
149             strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
150             strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
151             pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
152             pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
153         }
154         DSM_currentDevice = 1;
155         twRC = TWRC_SUCCESS;
156         DSM_twCC = TWCC_SUCCESS;
157     }
158     else if (status == SANE_STATUS_NO_MEM)
159     {
160         twRC = TWRC_FAILURE;
161         DSM_twCC = TWCC_LOWMEMORY;
162     }
163     else
164     {
165         WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
166         twRC = TWRC_FAILURE;
167         DSM_twCC = TWCC_NODS;
168     }
169
170     return twRC;
171 #endif
172 }
173
174 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
175 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
176 {
177 #ifndef HAVE_SANE
178     DSM_twCC = TWCC_SUCCESS;
179     return TWRC_ENDOFLIST;
180 #else
181     TW_UINT16 twRC = TWRC_SUCCESS;
182     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
183
184     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
185
186     if (device_list && device_list[DSM_currentDevice])
187     {
188         pSourceIdentity->Id = DSM_sourceId ++;
189         strcpy (pSourceIdentity->ProductName, device_list[DSM_currentDevice]->name);
190         strcpy (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor);
191         strcpy (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model);
192         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
193         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
194         DSM_currentDevice ++;
195
196         twRC = TWRC_SUCCESS;
197         DSM_twCC = TWCC_SUCCESS;
198     }
199     else
200     {
201         DSM_twCC = TWCC_SUCCESS;
202         twRC = TWRC_ENDOFLIST;
203     }
204
205     return twRC;
206 #endif
207 }
208
209 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
210 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
211 {
212 #ifndef HAVE_SANE
213     DSM_twCC = TWCC_NODS;
214     return TWRC_FAILURE;
215 #else
216     TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
217     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
218     activeDS *newSource;
219     SANE_Status status;
220
221     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
222
223     if (DSM_currentState != 3)
224     {
225         DSM_twCC = TWCC_SEQERROR;
226         return TWRC_FAILURE;
227     }
228
229     if (!device_list &&
230        (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
231     {
232         DSM_twCC = TWCC_NODS;
233         return TWRC_FAILURE;
234     }
235
236     if (pIdentity->ProductName[0] != '\0')
237     {
238         /* Make sure the source to be open exists in the device list */
239         for (i = 0; device_list[i]; i ++)
240         {
241             if (strcmp (device_list[i]->name, pIdentity->ProductName) == 0)
242                 break;
243         }
244     }
245
246     if (device_list[i])
247     {
248         /* the source is found in the device list */
249         newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
250         if (newSource)
251         {
252             status = sane_open(device_list[i]->name,&newSource->deviceHandle);
253             if (status == SANE_STATUS_GOOD)
254             {
255                 /* Assign name and id for the opened data source */
256                 strcpy (pIdentity->ProductName, device_list[i]->name);
257                 pIdentity->Id = DSM_sourceId ++;
258                 /* add the data source to an internal active source list */
259                 newSource->next = activeSources;
260                 newSource->identity.Id = pIdentity->Id;
261                 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
262                 newSource->currentState = 4; /*transition into state 4*/
263                 newSource->twCC = TWCC_SUCCESS;
264                 activeSources = newSource;
265                 twRC = TWRC_SUCCESS;
266                 DSM_twCC = TWCC_SUCCESS;
267             }
268             else
269             {
270                 twRC = TWRC_FAILURE;
271                 DSM_twCC = TWCC_OPERATIONERROR;
272             }
273         }
274         else
275         {
276             twRC = TWRC_FAILURE;
277             DSM_twCC = TWCC_LOWMEMORY;
278         }
279     }
280     else
281     {
282         twRC = TWRC_FAILURE;
283         DSM_twCC = TWCC_NODS;
284     }
285
286     return twRC;
287 #endif
288 }
289
290 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
291 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
292 {
293 #ifndef HAVE_SANE
294     return TWRC_SUCCESS;
295 #else
296     TW_UINT16 twRC = TWRC_SUCCESS;
297
298     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
299
300     /* FIXME: we should replace xscanimage with our own  User Select UI */
301     system("xscanimage");
302
303     DSM_twCC = TWCC_SUCCESS;
304     return twRC;
305 #endif
306 }
307
308 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
309 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
310 {
311 #ifndef HAVE_SANE
312     return TWRC_FAILURE;
313 #else
314     TW_UINT16 twRC = TWRC_SUCCESS;
315     activeDS *currentDS = activeSources, *nextDS;
316
317     TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
318
319     if (DSM_currentState == 3)
320     {
321         sane_exit ();
322         DSM_initialized = FALSE;
323         DSM_parentHWND = 0;
324         DSM_currentState = 2;
325
326         /* If there are data sources still open, close them now. */
327         while (currentDS != NULL)
328         {
329             nextDS = currentDS->next;
330             sane_close (currentDS->deviceHandle);
331             HeapFree (GetProcessHeap(), 0, currentDS);
332             currentDS = nextDS;
333         }
334         activeSources = NULL;
335         DSM_twCC = TWCC_SUCCESS;
336         twRC = TWRC_SUCCESS;
337     }
338     else
339     {
340         DSM_twCC = TWCC_SEQERROR;
341         twRC = TWRC_FAILURE;
342     }
343
344     return twRC;
345 #endif
346 }
347
348 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
349 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
350 {
351 #ifndef HAVE_SANE
352     return TWRC_FAILURE;
353 #else
354     TW_UINT16 twRC = TWRC_SUCCESS;
355     SANE_Status status;
356     SANE_Int version_code;
357
358     TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
359
360     if (DSM_currentState == 2)
361     {
362         if (!DSM_initialized)
363         {
364             DSM_initialized = TRUE;
365             status = sane_init (&version_code, NULL);
366             device_list = NULL;
367             DSM_currentDevice = 0;
368             DSM_sourceId = 0;
369         }
370         DSM_parentHWND = *(TW_HANDLE*)pData;
371         DSM_currentState = 3; /* transition to state 3 */
372         DSM_twCC = TWCC_SUCCESS;
373         twRC = TWRC_SUCCESS;
374     }
375     else
376     {
377         /* operation invoked in invalid state */
378         DSM_twCC = TWCC_SEQERROR;
379         twRC = TWRC_FAILURE;
380     }
381
382     return twRC;
383 #endif
384 }
385
386 /* DG_CONTROL/DAT_STATUS/MSG_GET */
387 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
388 {
389     pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
390
391     TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
392
393     pSourceStatus->ConditionCode = DSM_twCC;
394     DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
395
396     return TWRC_SUCCESS;
397 }