wine/dlls/twain/dsm_ctrl.c

452 lines
13 KiB
C

/*
* TWAIN32 Source Manager
*
* Copyright 2000 Corel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "twain.h"
#include "twain_i.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(twain);
/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
activeDS *currentDS = NULL, *prevDS = NULL;
TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
{
if (currentDS->identity.Id == pIdentity->Id)
break;
prevDS = currentDS;
}
if (currentDS)
{
/* Only valid to close a data source if it is in state 4 */
if (currentDS->currentState == 4)
{
sane_close (currentDS->deviceHandle);
/* remove the data source from active data source list */
if (prevDS)
prevDS->next = currentDS->next;
else
activeSources = currentDS->next;
HeapFree (GetProcessHeap(), 0, currentDS);
twRC = TWRC_SUCCESS;
DSM_twCC = TWCC_SUCCESS;
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_SEQERROR;
}
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_NODS;
}
return twRC;
#endif
}
/* Sane returns device names that are longer than the 32 bytes allowed
by TWAIN. However, it colon separates them, and the last bit is
the most interesting. So we use the last bit, and add a signature
to ensure uniqueness */
#ifdef HAVE_SANE
static void copy_sane_short_name(const char *in, char *out, size_t outsize)
{
const char *p;
int signature = 0;
if (strlen(in) <= outsize - 1)
{
strcpy(out, in);
return;
}
for (p = in; *p; p++)
signature += *p;
p = strrchr(in, ':');
if (!p)
p = in;
else
p++;
if (strlen(p) > outsize - 7 - 1)
p += strlen(p) - (outsize - 7 - 1);
strcpy(out, p);
sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
}
#endif
/* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
if (!device_list)
{
if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
{
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
}
}
/* FIXME: the default device is not necessarily the first device. *
* Users should be able to choose the default device */
if (device_list && device_list[0])
{
pSourceIdentity->Id = DSM_sourceId ++;
copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
twRC = TWRC_SUCCESS;
DSM_twCC = TWCC_SUCCESS;
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_NODS;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
SANE_Status status;
TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
status = sane_get_devices (&device_list, SANE_FALSE);
if (status == SANE_STATUS_GOOD)
{
if (device_list[0])
{
pSourceIdentity->Id = DSM_sourceId ++;
copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
DSM_currentDevice = 1;
twRC = TWRC_SUCCESS;
DSM_twCC = TWCC_SUCCESS;
}
else
{
TRACE("got empty device list\n");
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_NODS;
}
}
else if (status == SANE_STATUS_NO_MEM)
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_LOWMEMORY;
}
else
{
WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_NODS;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
DSM_twCC = TWCC_SUCCESS;
return TWRC_ENDOFLIST;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
if (device_list && device_list[DSM_currentDevice] &&
device_list[DSM_currentDevice]->name &&
device_list[DSM_currentDevice]->vendor &&
device_list[DSM_currentDevice]->model)
{
pSourceIdentity->Id = DSM_sourceId ++;
copy_sane_short_name(device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
TRACE("got: %s (short [%s]), %s, %s\n", device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, device_list[DSM_currentDevice]->vendor, device_list[DSM_currentDevice]->model);
lstrcpynA (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
lstrcpynA (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
DSM_currentDevice ++;
twRC = TWRC_SUCCESS;
DSM_twCC = TWCC_SUCCESS;
}
else
{
DSM_twCC = TWCC_SUCCESS;
twRC = TWRC_ENDOFLIST;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
TW_STR32 shortname;
activeDS *newSource;
SANE_Status status;
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
if (DSM_currentState != 3)
{
DSM_twCC = TWCC_SEQERROR;
return TWRC_FAILURE;
}
if (!device_list &&
(sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
{
DSM_twCC = TWCC_NODS;
return TWRC_FAILURE;
}
if (pIdentity->ProductName[0] != '\0')
{
/* Make sure the source to be opened exists in the device list */
for (i = 0; device_list[i]; i ++)
{
copy_sane_short_name(device_list[i]->name, shortname, sizeof(shortname) - 1);
if (strcmp (shortname, pIdentity->ProductName) == 0)
break;
}
}
if (device_list[i])
{
/* the source is found in the device list */
newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
if (newSource)
{
status = sane_open(device_list[i]->name,&newSource->deviceHandle);
if (status == SANE_STATUS_GOOD)
{
/* Assign name and id for the opened data source */
lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
pIdentity->Id = DSM_sourceId ++;
/* add the data source to an internal active source list */
newSource->next = activeSources;
newSource->identity.Id = pIdentity->Id;
strcpy (newSource->identity.ProductName, pIdentity->ProductName);
newSource->currentState = 4; /*transition into state 4*/
newSource->twCC = TWCC_SUCCESS;
activeSources = newSource;
twRC = TWRC_SUCCESS;
DSM_twCC = TWCC_SUCCESS;
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_OPERATIONERROR;
}
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_LOWMEMORY;
}
}
else
{
twRC = TWRC_FAILURE;
DSM_twCC = TWCC_NODS;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
return TWRC_SUCCESS;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
/* FIXME: we should replace xscanimage with our own User Select UI */
system("xscanimage");
DSM_twCC = TWCC_SUCCESS;
return twRC;
#endif
}
/* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
activeDS *currentDS = activeSources, *nextDS;
TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
if (DSM_currentState == 3)
{
sane_exit ();
DSM_initialized = FALSE;
DSM_parentHWND = 0;
DSM_currentState = 2;
/* If there are data sources still open, close them now. */
while (currentDS != NULL)
{
nextDS = currentDS->next;
sane_close (currentDS->deviceHandle);
HeapFree (GetProcessHeap(), 0, currentDS);
currentDS = nextDS;
}
activeSources = NULL;
DSM_twCC = TWCC_SUCCESS;
twRC = TWRC_SUCCESS;
}
else
{
DSM_twCC = TWCC_SEQERROR;
twRC = TWRC_FAILURE;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
#ifndef HAVE_SANE
return TWRC_FAILURE;
#else
TW_UINT16 twRC = TWRC_SUCCESS;
SANE_Status status;
SANE_Int version_code;
TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
if (DSM_currentState == 2)
{
if (!DSM_initialized)
{
DSM_initialized = TRUE;
status = sane_init (&version_code, NULL);
device_list = NULL;
DSM_currentDevice = 0;
DSM_sourceId = 0;
}
DSM_parentHWND = *(TW_HANDLE*)pData;
DSM_currentState = 3; /* transition to state 3 */
DSM_twCC = TWCC_SUCCESS;
twRC = TWRC_SUCCESS;
}
else
{
/* operation invoked in invalid state */
DSM_twCC = TWCC_SEQERROR;
twRC = TWRC_FAILURE;
}
return twRC;
#endif
}
/* DG_CONTROL/DAT_STATUS/MSG_GET */
TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
pSourceStatus->ConditionCode = DSM_twCC;
DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
return TWRC_SUCCESS;
}