tests: Make some variables static.
[wine] / dlls / gphoto2.ds / gphoto2_main.c
1 /*
2  * SANE.DS functions
3  *
4  * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
5  * Copyright 2006 Marcus Meissner
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <stdlib.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "twain.h"
34 #include "gphoto2_i.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(twain);
38
39
40 #ifdef HAVE_GPHOTO2
41 static char* GPHOTO2_StrDup(const char* str)
42 {
43     char* dst = HeapAlloc(GetProcessHeap(), 0, strlen(str)+1);
44     strcpy(dst, str);
45     return dst;
46 }
47 #endif
48
49 static void
50 load_filesystem(const char *folder) {
51 #ifdef HAVE_GPHOTO2
52     int         i, count, ret;
53     CameraList  *list;
54
55     ret = gp_list_new (&list);
56     if (ret < GP_OK)
57         return;
58     ret = gp_camera_folder_list_files (activeDS.camera, folder, list, activeDS.context);
59     if (ret < GP_OK) {
60         gp_list_free (list);
61         return;
62     }
63     count = gp_list_count (list);
64     if (count < GP_OK) {
65         gp_list_free (list);
66         return;
67     }
68     for (i = 0; i < count; i++) {
69         const char *name;
70         struct gphoto2_file *gpfile;
71
72         ret = gp_list_get_name (list, i, &name);
73         if (ret < GP_OK)
74             continue;
75         gpfile = HeapAlloc(GetProcessHeap(), 0, sizeof(struct gphoto2_file)); /* FIXME: Leaked */
76         if (!gpfile)
77             continue;
78         TRACE("adding %s/%s\n", folder, name);
79         gpfile->folder = GPHOTO2_StrDup(folder);
80         gpfile->filename = GPHOTO2_StrDup(name);
81         gpfile->download = FALSE;
82         list_add_tail( &activeDS.files, &gpfile->entry );
83     }
84     gp_list_reset (list);
85
86     ret = gp_camera_folder_list_folders (activeDS.camera, folder, list, activeDS.context);
87     if (ret < GP_OK) {
88         FIXME("list_folders failed\n");
89         gp_list_free (list);
90         return;
91     }
92     count = gp_list_count (list);
93     if (count < GP_OK) {
94         FIXME("list_folders failed\n");
95         gp_list_free (list);
96         return;
97     }
98     for (i = 0; i < count; i++) {
99         const char *name;
100         char *newfolder;
101         ret = gp_list_get_name (list, i, &name);
102         if (ret < GP_OK)
103             continue;
104         TRACE("recursing into %s\n", name);
105         newfolder = HeapAlloc(GetProcessHeap(), 0, strlen(folder)+1+strlen(name)+1);
106         if (!strcmp(folder,"/"))
107             sprintf (newfolder, "/%s", name);
108         else
109             sprintf (newfolder, "%s/%s", folder, name);
110         load_filesystem (newfolder); /* recurse ... happily */
111     }
112     gp_list_free (list);
113 #endif
114 }
115
116 /* DG_CONTROL/DAT_CAPABILITY/MSG_GET */
117 static TW_UINT16 GPHOTO2_CapabilityGet (pTW_IDENTITY pOrigin, TW_MEMREF pData)
118 {
119     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
120
121     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GET\n");
122     if (activeDS.currentState < 4 || activeDS.currentState > 7) {
123         activeDS.twCC = TWCC_SEQERROR;
124         return TWRC_FAILURE;
125     }
126     activeDS.twCC = GPHOTO2_SaneCapability (pCapability, MSG_GET);
127     return (activeDS.twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
128 }
129
130 /* DG_CONTROL/DAT_CAPABILITY/MSG_GETCURRENT */
131 static TW_UINT16 GPHOTO2_CapabilityGetCurrent (pTW_IDENTITY pOrigin, TW_MEMREF pData)
132 {
133     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
134
135     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GETCURRENT\n");
136
137     if (activeDS.currentState < 4 || activeDS.currentState > 7) {
138         activeDS.twCC = TWCC_SEQERROR;
139         return TWRC_FAILURE;
140     }
141     activeDS.twCC = GPHOTO2_SaneCapability (pCapability, MSG_GETCURRENT);
142     return (activeDS.twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
143 }
144
145 /* DG_CONTROL/DAT_CAPABILITY/MSG_GETDEFAULT */
146 static TW_UINT16 GPHOTO2_CapabilityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
147 {
148     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
149
150     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GETDEFAULT\n");
151     if (activeDS.currentState < 4 || activeDS.currentState > 7) {
152         activeDS.twCC = TWCC_SEQERROR;
153         return TWRC_FAILURE;
154     }
155     activeDS.twCC = GPHOTO2_SaneCapability (pCapability, MSG_GETDEFAULT);
156     return (activeDS.twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
157 }
158
159 /* DG_CONTROL/DAT_CAPABILITY/MSG_QUERYSUPPORT */
160 static TW_UINT16 GPHOTO2_CapabilityQuerySupport (pTW_IDENTITY pOrigin,
161                                         TW_MEMREF pData)
162 {
163     FIXME ("stub!\n");
164
165     return TWRC_FAILURE;
166 }
167
168 /* DG_CONTROL/DAT_CAPABILITY/MSG_RESET */
169 static TW_UINT16 GPHOTO2_CapabilityReset (pTW_IDENTITY pOrigin,
170                                  TW_MEMREF pData)
171 {
172     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
173
174     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_RESET\n");
175
176     if (activeDS.currentState < 4 || activeDS.currentState > 7) {
177         activeDS.twCC = TWCC_SEQERROR;
178         return TWRC_FAILURE;
179     }
180     activeDS.twCC = GPHOTO2_SaneCapability (pCapability, MSG_RESET);
181     return (activeDS.twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
182 }
183
184 /* DG_CONTROL/DAT_CAPABILITY/MSG_SET */
185 static TW_UINT16 GPHOTO2_CapabilitySet (pTW_IDENTITY pOrigin,
186                                TW_MEMREF pData)
187 {
188     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
189
190     TRACE ("DG_CONTROL/DAT_CAPABILITY/MSG_SET\n");
191
192     if (activeDS.currentState != 4) {
193         activeDS.twCC = TWCC_SEQERROR;
194         return TWRC_FAILURE;
195     }
196     activeDS.twCC = GPHOTO2_SaneCapability (pCapability, MSG_SET);
197     return (activeDS.twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
198 }
199
200 /* DG_CONTROL/DAT_CUSTOMDSDATA/MSG_GET */
201 static TW_UINT16 GPHOTO2_CustomDSDataGet (pTW_IDENTITY pOrigin,
202                                 TW_MEMREF pData)
203 {
204     FIXME ("stub!\n");
205
206     return TWRC_FAILURE;
207 }
208
209 /* DG_CONTROL/DAT_CUSTOMDSDATA/MSG_SET */
210 static TW_UINT16 GPHOTO2_CustomDSDataSet (pTW_IDENTITY pOrigin,
211                                  TW_MEMREF pData)
212 {
213     FIXME ("stub!\n");
214
215     return TWRC_FAILURE;
216 }
217
218 /* DG_CONTROL/DAT_FILESYSTEM/MSG_CHANGEDIRECTORY */
219 static TW_UINT16 GPHOTO2_ChangeDirectory (pTW_IDENTITY pOrigin,
220                                  TW_MEMREF pData)
221 {
222     FIXME ("stub!\n");
223
224     return TWRC_FAILURE;
225 }
226
227 /* DG_CONTROL/DAT_FILESYSTEM/MSG_CREATEDIRECTORY */
228 static TW_UINT16 GPHOTO2_CreateDirectory (pTW_IDENTITY pOrigin,
229                                  TW_MEMREF pData)
230 {
231     FIXME ("stub!\n");
232
233     return TWRC_FAILURE;
234 }
235
236 /* DG_CONTROL/DAT_FILESYSTEM/MSG_DELETE */
237 static TW_UINT16 GPHOTO2_FileSystemDelete (pTW_IDENTITY pOrigin,
238                                   TW_MEMREF pData)
239 {
240     FIXME ("stub!\n");
241
242     return TWRC_FAILURE;
243 }
244
245 /* DG_CONTROL/DAT_FILESYSTEM/MSG_FORMATMEDIA */
246 static TW_UINT16 GPHOTO2_FormatMedia (pTW_IDENTITY pOrigin,
247                              TW_MEMREF pData)
248 {
249     FIXME ("stub!\n");
250
251     return TWRC_FAILURE;
252 }
253
254 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETCLOSE */
255 static TW_UINT16 GPHOTO2_FileSystemGetClose (pTW_IDENTITY pOrigin,
256                                     TW_MEMREF pData)
257 {
258     FIXME ("stub!\n");
259
260     return TWRC_FAILURE;
261 }
262
263 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETFIRSTFILE */
264 static TW_UINT16 GPHOTO2_FileSystemGetFirstFile (pTW_IDENTITY pOrigin,
265
266                                         TW_MEMREF pData)
267 {
268     FIXME ("stub!\n");
269
270     return TWRC_FAILURE;
271 }
272
273 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETINFO */
274 static TW_UINT16 GPHOTO2_FileSystemGetInfo (pTW_IDENTITY pOrigin,
275                                    TW_MEMREF pData)
276 {
277     FIXME ("stub!\n");
278
279     return TWRC_FAILURE;
280 }
281
282 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETNEXTFILE */
283 static TW_UINT16 GPHOTO2_FileSystemGetNextFile (pTW_IDENTITY pOrigin,
284
285                                        TW_MEMREF pData)
286 {
287     FIXME ("stub!\n");
288
289     return TWRC_FAILURE;
290 }
291
292 /* DG_CONTROL/DAT_FILESYSTEM/MSG_RENAME */
293 static TW_UINT16 GPHOTO2_FileSystemRename (pTW_IDENTITY pOrigin,
294                                   TW_MEMREF pData)
295 {
296     FIXME ("stub!\n");
297
298     return TWRC_FAILURE;
299 }
300
301 /* DG_CONTROL/DAT_EVENT/MSG_PROCESSEVENT */
302 static TW_UINT16 GPHOTO2_ProcessEvent (pTW_IDENTITY pOrigin,
303                               TW_MEMREF pData)
304 {
305     TW_UINT16 twRC = TWRC_SUCCESS;
306     pTW_EVENT pEvent = (pTW_EVENT) pData;
307
308     TRACE("DG_CONTROL/DAT_EVENT/MSG_PROCESSEVENT\n");
309
310     if (activeDS.currentState < 5 || activeDS.currentState > 7) {
311         activeDS.twCC = TWCC_SEQERROR;
312         return TWRC_FAILURE;
313     }
314
315     if (activeDS.pendingEvent.TWMessage != MSG_NULL) {
316         pEvent->TWMessage = activeDS.pendingEvent.TWMessage;
317         activeDS.pendingEvent.TWMessage = MSG_NULL;
318         twRC = TWRC_SUCCESS;
319     } else {
320         pEvent->TWMessage = MSG_NULL;  /* no message to the application */
321         twRC = TWRC_NOTDSEVENT;
322     }
323     activeDS.twCC = TWCC_SUCCESS;
324     return twRC;
325 }
326
327 /* DG_CONTROL/DAT_PASSTHRU/MSG_PASSTHRU */
328 static TW_UINT16 GPHOTO2_PassThrough (pTW_IDENTITY pOrigin,
329                              TW_MEMREF pData)
330 {
331     FIXME ("stub!\n");
332
333     return TWRC_FAILURE;
334 }
335
336 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_ENDXFER */
337 static TW_UINT16 GPHOTO2_PendingXfersEndXfer (pTW_IDENTITY pOrigin,
338                                      TW_MEMREF pData)
339 {
340     TW_UINT32 count;
341     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
342     struct gphoto2_file *file;
343
344     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_ENDXFER\n");
345
346     if (activeDS.currentState != 6 && activeDS.currentState != 7) {
347         activeDS.twCC = TWCC_SEQERROR;
348         return TWRC_FAILURE;
349     }
350     count = 0;
351     LIST_FOR_EACH_ENTRY( file, &activeDS.files, struct gphoto2_file, entry ) {
352         if (file->download)
353             count++;
354     }
355     TRACE("count = %d\n", count);
356     pPendingXfers->Count = count;
357     if (pPendingXfers->Count != 0) {
358         activeDS.currentState = 6;
359     } else {
360         activeDS.currentState = 5;
361         /* Notify the application that it can close the data source */
362         activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
363         /* close any Transferring dialog */
364         TransferringDialogBox(activeDS.progressWnd,-1);
365         activeDS.progressWnd = 0;
366     }
367     activeDS.twCC = TWCC_SUCCESS;
368     return TWRC_SUCCESS;
369 }
370
371 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_GET */
372 static TW_UINT16 GPHOTO2_PendingXfersGet (pTW_IDENTITY pOrigin,
373                                  TW_MEMREF pData)
374 {
375     TW_UINT32 count;
376     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
377     struct gphoto2_file *file;
378
379     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_GET\n");
380
381     if (activeDS.currentState < 4 || activeDS.currentState > 7) {
382         activeDS.twCC = TWCC_SEQERROR;
383         return TWRC_FAILURE;
384     }
385
386     count = 0;
387     LIST_FOR_EACH_ENTRY( file, &activeDS.files, struct gphoto2_file, entry ) {
388         if (file->download)
389             count++;
390     }
391     TRACE("count = %d\n", count);
392     pPendingXfers->Count = count;
393     activeDS.twCC = TWCC_SUCCESS;
394     return TWRC_SUCCESS;
395 }
396
397 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_RESET */
398 static TW_UINT16 GPHOTO2_PendingXfersReset (pTW_IDENTITY pOrigin,
399                                    TW_MEMREF pData)
400 {
401     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
402
403     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_RESET\n");
404
405     if (activeDS.currentState != 6) {
406         activeDS.twCC = TWCC_SEQERROR;
407         return TWRC_FAILURE;
408     }
409     pPendingXfers->Count = 0;
410     activeDS.currentState = 5;
411     activeDS.twCC = TWCC_SUCCESS;
412     return TWRC_SUCCESS;
413 }
414
415 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_GET */
416 static TW_UINT16 GPHOTO2_SetupFileXferGet (pTW_IDENTITY pOrigin,
417                                   TW_MEMREF pData)
418 {
419     FIXME ("stub!\n");
420
421     return TWRC_FAILURE;
422 }
423
424 /* DG_CONTROL/DAT_SETUPXFER/MSG_GETDEFAULT */
425 static TW_UINT16 GPHOTO2_SetupFileXferGetDefault (pTW_IDENTITY pOrigin,
426                                          TW_MEMREF pData)
427 {
428     FIXME ("stub!\n");
429
430     return TWRC_FAILURE;
431 }
432
433
434 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_RESET */
435 static TW_UINT16 GPHOTO2_SetupFileXferReset (pTW_IDENTITY pOrigin,
436                                     TW_MEMREF pData)
437 {
438     FIXME ("stub!\n");
439
440     return TWRC_FAILURE;
441 }
442
443 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_SET */
444 static TW_UINT16 GPHOTO2_SetupFileXferSet (pTW_IDENTITY pOrigin,
445                                   TW_MEMREF pData)
446 {
447     FIXME ("stub!\n");
448
449     return TWRC_FAILURE;
450 }
451
452 /* DG_CONTROL/DAT_SETUPMEMXFER/MSG_GET */
453 static TW_UINT16 GPHOTO2_SetupMemXferGet (pTW_IDENTITY pOrigin,
454                                   TW_MEMREF pData)
455 {
456     pTW_SETUPMEMXFER  pSetupMemXfer = (pTW_SETUPMEMXFER)pData;
457
458     TRACE("DG_CONTROL/DAT_SETUPMEMXFER/MSG_GET\n");
459     /* Guessing */
460     pSetupMemXfer->MinBufSize = 20000;
461     pSetupMemXfer->MaxBufSize = 80000;
462     pSetupMemXfer->Preferred = 40000;
463     return TWRC_SUCCESS;
464 }
465
466 /* DG_CONTROL/DAT_STATUS/MSG_GET */
467 static TW_UINT16 GPHOTO2_GetDSStatus (pTW_IDENTITY pOrigin,
468                              TW_MEMREF pData)
469 {
470     pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
471
472     TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
473     pSourceStatus->ConditionCode = activeDS.twCC;
474     /* Reset the condition code */
475     activeDS.twCC = TWCC_SUCCESS;
476     return TWRC_SUCCESS;
477 }
478
479 /* DG_CONTROL/DAT_USERINTERFACE/MSG_DISABLEDS */
480 static TW_UINT16 GPHOTO2_DisableDSUserInterface (pTW_IDENTITY pOrigin,
481                                         TW_MEMREF pData)
482 {
483     TRACE ("DG_CONTROL/DAT_USERINTERFACE/MSG_DISABLEDS\n");
484
485     if (activeDS.currentState != 5) {
486         activeDS.twCC = TWCC_SEQERROR;
487         return TWRC_FAILURE;
488     }
489     activeDS.currentState = 4;
490     activeDS.twCC = TWCC_SUCCESS;
491     return TWRC_SUCCESS;
492 }
493
494 /* DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDS */
495 static TW_UINT16 GPHOTO2_EnableDSUserInterface (pTW_IDENTITY pOrigin,
496                                        TW_MEMREF pData)
497 {
498     pTW_USERINTERFACE pUserInterface = (pTW_USERINTERFACE) pData;
499
500     load_filesystem("/");
501
502     TRACE ("DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDS\n");
503     if (activeDS.currentState != 4) {
504         FIXME("Sequence error %d\n", activeDS.currentState);
505         activeDS.twCC = TWCC_SEQERROR;
506         return TWRC_FAILURE;
507     }
508     activeDS.hwndOwner = pUserInterface->hParent;
509     if (pUserInterface->ShowUI)
510     {
511         BOOL rc;
512         activeDS.currentState = 5; /* Transitions to state 5 */
513         rc = DoCameraUI();
514         if (!rc) {
515             activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
516         } else {
517             /* FIXME: The GUI should have marked the files to download... */
518             activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
519             activeDS.currentState = 6; /* Transitions to state 6 directly */
520         }
521     } else {
522         /* no UI will be displayed, so source is ready to transfer data */
523         activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
524         activeDS.currentState = 6; /* Transitions to state 6 directly */
525     }
526     activeDS.hwndOwner = pUserInterface->hParent;
527     activeDS.twCC = TWCC_SUCCESS;
528     return TWRC_SUCCESS;
529 }
530
531 /* DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDSUIONLY */
532 static TW_UINT16 GPHOTO2_EnableDSUIOnly (pTW_IDENTITY pOrigin,
533                                 TW_MEMREF pData)
534 {
535     TRACE("DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDSUIONLY\n");
536
537     if (activeDS.currentState != 4) {
538         activeDS.twCC = TWCC_SEQERROR;
539         return TWRC_FAILURE;
540     }
541     /* FIXME: we should replace xscanimage with our own UI */
542     FIXME ("not implemented!\n");
543     activeDS.currentState = 5;
544     activeDS.twCC = TWCC_SUCCESS;
545     return TWRC_SUCCESS;
546 }
547
548 /* DG_CONTROL/DAT_XFERGROUP/MSG_GET */
549 static TW_UINT16 GPHOTO2_XferGroupGet (pTW_IDENTITY pOrigin,
550                               TW_MEMREF pData)
551 {
552     FIXME ("stub!\n");
553     return TWRC_FAILURE;
554 }
555
556 /* DG_CONTROL/DAT_XFERGROUP/MSG_SET */
557 static TW_UINT16 GPHOTO2_XferGroupSet (pTW_IDENTITY pOrigin,
558                                   TW_MEMREF pData)
559 {
560     FIXME ("stub!\n");
561     return TWRC_FAILURE;
562 }
563
564 HINSTANCE GPHOTO2_instance;
565
566 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
567 {
568     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
569
570     switch (fdwReason)
571     {
572         case DLL_PROCESS_ATTACH:
573             GPHOTO2_instance = hinstDLL;
574             DisableThreadLibraryCalls(hinstDLL);
575 #ifdef HAVE_GPHOTO2
576             activeDS.context = gp_context_new ();
577 #endif
578             break;
579
580         case DLL_PROCESS_DETACH:
581             GPHOTO2_instance = NULL;
582             break;
583     }
584
585     return TRUE;
586 }
587
588 #ifdef HAVE_GPHOTO2
589 static TW_UINT16 GPHOTO2_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
590 static TW_UINT16 GPHOTO2_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
591 #endif
592
593 static TW_UINT16 GPHOTO2_SourceControlHandler (
594    pTW_IDENTITY pOrigin,
595    TW_UINT16    DAT,
596    TW_UINT16    MSG,
597    TW_MEMREF    pData)
598 {
599     TW_UINT16 twRC = TWRC_SUCCESS;
600
601     switch (DAT)
602     {
603         case DAT_IDENTITY:
604             switch (MSG)
605             {
606                 case MSG_CLOSEDS:
607 #ifdef HAVE_GPHOTO2
608                      if (activeDS.camera) {
609                         gp_camera_free (activeDS.camera);
610                         activeDS.camera = NULL;
611                      }
612 #endif
613                      break;
614                 case MSG_GET:
615 #ifdef HAVE_GPHOTO2
616                      twRC = GPHOTO2_GetIdentity(pOrigin,(pTW_IDENTITY)pData);
617 #else
618                      twRC = TWRC_FAILURE;
619 #endif
620                      break;
621                 case MSG_OPENDS:
622 #ifdef HAVE_GPHOTO2
623                      twRC = GPHOTO2_OpenDS(pOrigin,(pTW_IDENTITY)pData);
624 #else
625                      twRC = TWRC_FAILURE;
626 #endif
627                      break;
628             }
629             break;
630         case DAT_CAPABILITY:
631             switch (MSG)
632             {
633                 case MSG_GET:
634                     twRC = GPHOTO2_CapabilityGet (pOrigin, pData);
635                     break;
636                 case MSG_GETCURRENT:
637                     twRC = GPHOTO2_CapabilityGetCurrent (pOrigin, pData);
638                     break;
639                 case MSG_GETDEFAULT:
640                     twRC = GPHOTO2_CapabilityGetDefault (pOrigin, pData);
641                     break;
642                 case MSG_QUERYSUPPORT:
643                     twRC = GPHOTO2_CapabilityQuerySupport (pOrigin, pData);
644                     break;
645                 case MSG_RESET:
646                     twRC = GPHOTO2_CapabilityReset (pOrigin, pData);
647                     break;
648                 case MSG_SET:
649                     twRC = GPHOTO2_CapabilitySet (pOrigin, pData);
650                     break;
651                 default:
652                     twRC = TWRC_FAILURE;
653                     FIXME("unrecognized opertion triplet\n");
654             }
655             break;
656
657         case DAT_CUSTOMDSDATA:
658             switch (MSG)
659             {
660                 case MSG_GET:
661                     twRC = GPHOTO2_CustomDSDataGet (pOrigin, pData);
662                     break;
663                 case MSG_SET:
664                     twRC = GPHOTO2_CustomDSDataSet (pOrigin, pData);
665                     break;
666                 default:
667                     break;
668             }
669             break;
670
671         case DAT_FILESYSTEM:
672             switch (MSG)
673             {
674                 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
675                     twRC = GPHOTO2_AutomaticCaptureDirectory
676                                (pOrigin, pData);
677                     break;*/
678                 case MSG_CHANGEDIRECTORY:
679                     twRC = GPHOTO2_ChangeDirectory (pOrigin, pData);
680                     break;
681                 /*case MSG_COPY:
682                     twRC = GPHOTO2_FileSystemCopy (pOrigin, pData);
683                     break;*/
684                 case MSG_CREATEDIRECTORY:
685                     twRC = GPHOTO2_CreateDirectory (pOrigin, pData);
686                     break;
687                 case MSG_DELETE:
688                     twRC = GPHOTO2_FileSystemDelete (pOrigin, pData);
689                     break;
690                 case MSG_FORMATMEDIA:
691                     twRC = GPHOTO2_FormatMedia (pOrigin, pData);
692                     break;
693                 case MSG_GETCLOSE:
694                     twRC = GPHOTO2_FileSystemGetClose (pOrigin, pData);
695                     break;
696                 case MSG_GETFIRSTFILE:
697                     twRC = GPHOTO2_FileSystemGetFirstFile (pOrigin, pData);
698                     break;
699                 case MSG_GETINFO:
700                     twRC = GPHOTO2_FileSystemGetInfo (pOrigin, pData);
701                     break;
702                 case MSG_GETNEXTFILE:
703                     twRC = GPHOTO2_FileSystemGetNextFile (pOrigin, pData);
704                     break;
705                 case MSG_RENAME:
706                     twRC = GPHOTO2_FileSystemRename (pOrigin, pData);
707                     break;
708                 default:
709                     twRC = TWRC_FAILURE;
710                     break;
711             }
712             break;
713
714         case DAT_EVENT:
715             if (MSG == MSG_PROCESSEVENT)
716                 twRC = GPHOTO2_ProcessEvent (pOrigin, pData);
717             else
718                 twRC = TWRC_FAILURE;
719             break;
720
721         case DAT_PASSTHRU:
722             if (MSG == MSG_PASSTHRU)
723                 twRC = GPHOTO2_PassThrough (pOrigin, pData);
724             else
725                 twRC = TWRC_FAILURE;
726             break;
727
728         case DAT_PENDINGXFERS:
729             switch (MSG)
730             {
731                 case MSG_ENDXFER:
732                     twRC = GPHOTO2_PendingXfersEndXfer (pOrigin, pData);
733                     break;
734                 case MSG_GET:
735                     twRC = GPHOTO2_PendingXfersGet (pOrigin, pData);
736                     break;
737                 case MSG_RESET:
738                     twRC = GPHOTO2_PendingXfersReset (pOrigin, pData);
739                     break;
740                 /*case MSG_STOPFEEDER:
741                     twRC = GPHOTO2_PendingXfersStopFeeder (pOrigin, pData);
742                     break;*/
743                 default:
744                     twRC = TWRC_FAILURE;
745             }
746             break;
747
748         case DAT_SETUPFILEXFER:
749             switch (MSG)
750             {
751                 case MSG_GET:
752                     twRC = GPHOTO2_SetupFileXferGet (pOrigin, pData);
753                     break;
754                 case MSG_GETDEFAULT:
755                     twRC = GPHOTO2_SetupFileXferGetDefault (pOrigin, pData);
756                     break;
757                 case MSG_RESET:
758                     twRC = GPHOTO2_SetupFileXferReset (pOrigin, pData);
759                     break;
760                 case MSG_SET:
761                     twRC = GPHOTO2_SetupFileXferSet (pOrigin, pData);
762                     break;
763                 default:
764                     twRC = TWRC_FAILURE;
765                     break;
766             }
767             break;
768
769         /*case DAT_SETUPFILEXFER2:
770             switch (MSG)
771             {
772                 case MSG_GET:
773                     twRC = GPHOTO2_SetupFileXfer2Get (pOrigin, pData);
774                     break;
775                 case MSG_GETDEFAULT:
776                     twRC = GPHOTO2_SetupFileXfer2GetDefault (pOrigin, pData);
777                     break;
778                 case MSG_RESET:
779                     twRC = GPHOTO2_SetupFileXfer2Reset (pOrigin, pData);
780                     break;
781                 case MSG_SET:
782                     twRC = GPHOTO2_SetupFileXfer2Set (pOrigin, pData);
783                     break;
784             }
785             break;*/
786         case DAT_SETUPMEMXFER:
787             if (MSG == MSG_GET)
788                 twRC = GPHOTO2_SetupMemXferGet (pOrigin, pData);
789             else
790                 twRC = TWRC_FAILURE;
791             break;
792
793         case DAT_STATUS:
794             if (MSG == MSG_GET)
795                 twRC = GPHOTO2_GetDSStatus (pOrigin, pData);
796             else
797                 twRC = TWRC_FAILURE;
798             break;
799
800         case DAT_USERINTERFACE:
801             switch (MSG)
802             {
803                 case MSG_DISABLEDS:
804                     twRC = GPHOTO2_DisableDSUserInterface (pOrigin, pData);
805                     break;
806                 case MSG_ENABLEDS:
807                     twRC = GPHOTO2_EnableDSUserInterface (pOrigin, pData);
808                     break;
809                 case MSG_ENABLEDSUIONLY:
810                     twRC = GPHOTO2_EnableDSUIOnly (pOrigin, pData);
811                     break;
812                 default:
813                     twRC = TWRC_FAILURE;
814                     break;
815             }
816             break;
817
818         case DAT_XFERGROUP:
819             switch (MSG)
820             {
821                 case MSG_GET:
822                     twRC = GPHOTO2_XferGroupGet (pOrigin, pData);
823                     break;
824                 case MSG_SET:
825                     twRC = GPHOTO2_XferGroupSet (pOrigin, pData);
826                     break;
827                 default:
828                     twRC = TWRC_FAILURE;
829                     break;
830             }
831             break;
832
833         default:
834             FIXME("code unknown: %d\n", DAT);
835             twRC = TWRC_FAILURE;
836             break;
837     }
838
839     return twRC;
840 }
841
842
843 static TW_UINT16 GPHOTO2_ImageGroupHandler (
844            pTW_IDENTITY pOrigin,
845            TW_UINT16    DAT,
846            TW_UINT16    MSG,
847            TW_MEMREF    pData)
848 {
849     TW_UINT16 twRC = TWRC_SUCCESS;
850
851     switch (DAT)
852     {
853         case DAT_CIECOLOR:
854             if (MSG == MSG_GET)
855                 twRC = GPHOTO2_CIEColorGet (pOrigin, pData);
856             else
857                 twRC = TWRC_FAILURE;
858             break;
859
860         case DAT_EXTIMAGEINFO:
861             if (MSG == MSG_GET)
862                 twRC = GPHOTO2_ExtImageInfoGet (pOrigin, pData);
863             else
864                 twRC = TWRC_FAILURE;
865             break;
866
867         case DAT_GRAYRESPONSE:
868             switch (MSG)
869             {
870                 case MSG_RESET:
871                     twRC = GPHOTO2_GrayResponseReset (pOrigin, pData);
872                     break;
873                 case MSG_SET:
874                     twRC = GPHOTO2_GrayResponseSet (pOrigin, pData);
875                     break;
876                 default:
877                     twRC = TWRC_FAILURE;
878                     activeDS.twCC = TWCC_BADPROTOCOL;
879                     FIXME("unrecognized operation triplet\n");
880                     break;
881             }
882             break;
883         case DAT_IMAGEFILEXFER:
884             if (MSG == MSG_GET)
885                 twRC = GPHOTO2_ImageFileXferGet (pOrigin, pData);
886             else
887                 twRC = TWRC_FAILURE;
888             break;
889
890         case DAT_IMAGEINFO:
891             if (MSG == MSG_GET)
892                 twRC = GPHOTO2_ImageInfoGet (pOrigin, pData);
893             else
894                 twRC = TWRC_FAILURE;
895             break;
896
897         case DAT_IMAGELAYOUT:
898             switch (MSG)
899             {
900                 case MSG_GET:
901                     twRC = GPHOTO2_ImageLayoutGet (pOrigin, pData);
902                     break;
903                 case MSG_GETDEFAULT:
904                     twRC = GPHOTO2_ImageLayoutGetDefault (pOrigin, pData);
905                     break;
906                 case MSG_RESET:
907                     twRC = GPHOTO2_ImageLayoutReset (pOrigin, pData);
908                     break;
909                 case MSG_SET:
910                     twRC = GPHOTO2_ImageLayoutSet (pOrigin, pData);
911                     break;
912                 default:
913                     twRC = TWRC_FAILURE;
914                     activeDS.twCC = TWCC_BADPROTOCOL;
915                     ERR("unrecognized operation triplet\n");
916                     break;
917             }
918             break;
919
920         case DAT_IMAGEMEMXFER:
921             if (MSG == MSG_GET)
922                 twRC = GPHOTO2_ImageMemXferGet (pOrigin, pData);
923             else
924                 twRC = TWRC_FAILURE;
925             break;
926
927         case DAT_IMAGENATIVEXFER:
928             if (MSG == MSG_GET)
929                 twRC = GPHOTO2_ImageNativeXferGet (pOrigin, pData);
930             else
931                 twRC = TWRC_FAILURE;
932             break;
933
934         case DAT_JPEGCOMPRESSION:
935             switch (MSG)
936             {
937                 case MSG_GET:
938                     twRC = GPHOTO2_JPEGCompressionGet (pOrigin, pData);
939                     break;
940                 case MSG_GETDEFAULT:
941                     twRC = GPHOTO2_JPEGCompressionGetDefault (pOrigin, pData);
942                     break;
943                 case MSG_RESET:
944                     twRC = GPHOTO2_JPEGCompressionReset (pOrigin, pData);
945                     break;
946                 case MSG_SET:
947                     twRC = GPHOTO2_JPEGCompressionSet (pOrigin, pData);
948                     break;
949                 default:
950                     twRC = TWRC_FAILURE;
951                     activeDS.twCC = TWCC_BADPROTOCOL;
952                     WARN("unrecognized operation triplet\n");
953                     break;
954             }
955             break;
956
957         case DAT_PALETTE8:
958             switch (MSG)
959             {
960                 case MSG_GET:
961                     twRC = GPHOTO2_Palette8Get (pOrigin, pData);
962                     break;
963                 case MSG_GETDEFAULT:
964                     twRC = GPHOTO2_Palette8GetDefault (pOrigin, pData);
965                     break;
966                 case MSG_RESET:
967                     twRC = GPHOTO2_Palette8Reset (pOrigin, pData);
968                     break;
969                 case MSG_SET:
970                     twRC = GPHOTO2_Palette8Set (pOrigin, pData);
971                     break;
972                 default:
973                     twRC = TWRC_FAILURE;
974                     activeDS.twCC = TWCC_BADPROTOCOL;
975                     WARN("unrecognized operation triplet\n");
976             }
977             break;
978
979         case DAT_RGBRESPONSE:
980             switch (MSG)
981             {
982                 case MSG_RESET:
983                     twRC = GPHOTO2_RGBResponseReset (pOrigin, pData);
984                     break;
985                 case MSG_SET:
986                     twRC = GPHOTO2_RGBResponseSet (pOrigin, pData);
987                     break;
988                 default:
989                     twRC = TWRC_FAILURE;
990                     activeDS.twCC = TWCC_BADPROTOCOL;
991                     WARN("unrecognized operation triplet\n");
992                     break;
993             }
994             break;
995
996         default:
997             twRC = TWRC_FAILURE;
998             activeDS.twCC = TWCC_BADPROTOCOL;
999             FIXME("unrecognized DG type %d\n", DAT);
1000     }
1001     return twRC;
1002 }
1003
1004 /* Main entry point for the TWAIN library */
1005 TW_UINT16 WINAPI
1006 DS_Entry ( pTW_IDENTITY pOrigin,
1007            TW_UINT32    DG,
1008            TW_UINT16    DAT,
1009            TW_UINT16    MSG,
1010            TW_MEMREF    pData)
1011 {
1012     TW_UINT16 twRC = TWRC_SUCCESS;  /* Return Code */
1013
1014     TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
1015
1016     switch (DG)
1017     {
1018         case DG_CONTROL:
1019             twRC = GPHOTO2_SourceControlHandler (pOrigin,DAT,MSG,pData);
1020             break;
1021         case DG_IMAGE:
1022             twRC = GPHOTO2_ImageGroupHandler (pOrigin,DAT,MSG,pData);
1023             break;
1024         case DG_AUDIO:
1025             FIXME("The audio group of entry codes is not implemented.\n");
1026         default:
1027             activeDS.twCC = TWCC_BADPROTOCOL;
1028             twRC = TWRC_FAILURE;
1029     }
1030
1031     return twRC;
1032 }
1033
1034 #ifdef HAVE_GPHOTO2
1035 static GPPortInfoList *port_list;
1036 static int curcamera;
1037 static CameraList *detected_cameras;
1038 static CameraAbilitiesList *abilities_list;
1039
1040 static TW_UINT16
1041 gphoto2_auto_detect(void) {
1042     int result, count;
1043
1044     if (detected_cameras && (gp_list_count (detected_cameras) == 0)) {
1045         /* Reload if previously no cameras, we might detect new ones. */
1046         TRACE("Reloading portlist trying to detect cameras.\n");
1047         if (port_list) {
1048             gp_port_info_list_free (port_list);
1049             port_list = NULL;
1050         }
1051     }
1052     if (!port_list) {
1053         TRACE("Auto detecting gphoto cameras.\n");
1054         TRACE("Loading ports...\n");
1055         if (gp_port_info_list_new (&port_list) < GP_OK)
1056             return TWRC_FAILURE;
1057         result = gp_port_info_list_load (port_list);
1058         if (result < 0) {
1059             gp_port_info_list_free (port_list);
1060             return TWRC_FAILURE;
1061         }
1062         count = gp_port_info_list_count (port_list);
1063         if (count <= 0)
1064             return TWRC_FAILURE;
1065         if (gp_list_new (&detected_cameras) < GP_OK)
1066             return TWRC_FAILURE;
1067         if (!abilities_list) { /* Load only once per program start */
1068             gp_abilities_list_new (&abilities_list);
1069             TRACE("Loading cameras...\n");
1070             gp_abilities_list_load (abilities_list, NULL);
1071         }
1072         TRACE("Detecting cameras...\n");
1073         gp_abilities_list_detect (abilities_list, port_list, detected_cameras, NULL);
1074         curcamera = 0;
1075         TRACE("%d cameras detected\n", gp_list_count(detected_cameras));
1076     }
1077     return TWRC_SUCCESS;
1078 }
1079
1080 static TW_UINT16
1081 GPHOTO2_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
1082     int count;
1083     const char *cname, *pname;
1084
1085     if (TWRC_SUCCESS != gphoto2_auto_detect())
1086         return TWRC_FAILURE;
1087
1088     count = gp_list_count (detected_cameras);
1089     if (count < GP_OK) {
1090         gp_list_free (detected_cameras);
1091         return TWRC_FAILURE;
1092     }
1093     TRACE("%d cameras detected.\n", count);
1094     self->ProtocolMajor = TWON_PROTOCOLMAJOR;
1095     self->ProtocolMinor = TWON_PROTOCOLMINOR;
1096     lstrcpynA (self->Manufacturer, "The Wine Team", sizeof(self->Manufacturer) - 1);
1097     lstrcpynA (self->ProductFamily, "GPhoto2 Camera", sizeof(self->ProductFamily) - 1);
1098
1099     if (!count) { /* No camera detected. But we need to return an IDENTITY anyway. */
1100         lstrcpynA (self->ProductName, "GPhoto2 Camera", sizeof(self->ProductName) - 1);
1101         return TWRC_SUCCESS;
1102     }
1103     gp_list_get_name  (detected_cameras, curcamera, &cname);
1104     gp_list_get_value (detected_cameras, curcamera, &pname);
1105     if (count == 1) /* Normal case, only one camera. */
1106         snprintf (self->ProductName, sizeof(self->ProductName), "%s", cname);
1107     else
1108         snprintf (self->ProductName, sizeof(self->ProductName), "%s@%s", cname, pname);
1109     curcamera = (curcamera+1) % count;
1110     return TWRC_SUCCESS;
1111 }
1112
1113 static TW_UINT16
1114 GPHOTO2_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
1115     int ret, m, p, count, i;
1116     CameraAbilities a;
1117     GPPortInfo info;
1118     const char  *model, *port;
1119
1120     if (TWRC_SUCCESS != gphoto2_auto_detect())
1121         return TWRC_FAILURE;
1122
1123     if (lstrcmpA(self->ProductFamily,"GPhoto2 Camera")) {
1124         FIXME("identity passed is not a gphoto camera, but %s!?!\n", self->ProductFamily);
1125         return TWRC_FAILURE;
1126     }
1127     count = gp_list_count (detected_cameras);
1128     if (!count) {
1129         ERR("No camera found by autodetection. Returning failure.\n");
1130         return TWRC_FAILURE;
1131     }
1132
1133     if (!lstrcmpA (self->ProductName, "GPhoto2 Camera")) {
1134         TRACE("Potential undetected camera. Just using the first autodetected one.\n");
1135         i = 0;
1136     } else {
1137         for (i=0;i<count;i++) {
1138             const char *cname, *pname;
1139             TW_STR32    name;
1140
1141             gp_list_get_name  (detected_cameras, i, &cname);
1142             gp_list_get_value (detected_cameras, i, &pname);
1143             if (!lstrcmpA(self->ProductName,cname))
1144                 break;
1145             snprintf(name, sizeof(name), "%s", cname);
1146             if (!lstrcmpA(self->ProductName,name))
1147                 break;
1148             snprintf(name, sizeof(name), "%s@%s", cname, pname);
1149             if (!lstrcmpA(self->ProductName,name))
1150                 break;
1151         }
1152         if (i == count) {
1153             TRACE("Camera %s not found in autodetected list. Using first entry.\n", self->ProductName);
1154             i=0;
1155         }
1156     }
1157     gp_list_get_name  (detected_cameras, i, &model);
1158     gp_list_get_value  (detected_cameras, i, &port);
1159     TRACE("model %s, port %s\n", model, port);
1160     ret = gp_camera_new (&activeDS.camera);
1161     if (ret < GP_OK) {
1162         ERR("gp_camera_new: %d\n", ret);
1163         return TWRC_FAILURE;
1164     }
1165     m = gp_abilities_list_lookup_model (abilities_list, model);
1166     if (m < GP_OK) {
1167         FIXME("Model %s not found, %d!\n", model, m);
1168         return TWRC_FAILURE;
1169     }
1170     ret = gp_abilities_list_get_abilities (abilities_list, m, &a);
1171     if (ret < GP_OK) {
1172         FIXME("gp_camera_list_get_abilities failed? %d\n", ret);
1173         return TWRC_FAILURE;
1174     }
1175     ret = gp_camera_set_abilities (activeDS.camera, a);
1176     if (ret < GP_OK) {
1177         FIXME("gp_camera_set_abilities failed? %d\n", ret);
1178         return TWRC_FAILURE;
1179     }
1180
1181     p = gp_port_info_list_lookup_path (port_list, port);
1182     if (p < GP_OK) {
1183         FIXME("port %s not in portlist?\n", port);
1184         return TWRC_FAILURE;
1185     }
1186     ret = gp_port_info_list_get_info (port_list, p, &info);
1187     if (ret < GP_OK) {
1188         FIXME("could not get portinfo for port %s?\n", port);
1189         return TWRC_FAILURE;
1190     }
1191     ret = gp_camera_set_port_info (activeDS.camera, info);
1192     if (ret < GP_OK) {
1193         FIXME("could not set portinfo for port %s to camera?\n", port);
1194         return TWRC_FAILURE;
1195     }
1196     list_init( &(activeDS.files) );
1197     activeDS.currentState = 4;
1198     activeDS.twCC               = TWRC_SUCCESS;
1199     activeDS.pixelflavor        = TWPF_CHOCOLATE;
1200     activeDS.pixeltype          = TWPT_RGB;
1201     activeDS.capXferMech        = TWSX_MEMORY;
1202     TRACE("OK!\n");
1203     return TWRC_SUCCESS;
1204 }
1205 #endif