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