Commit 7c34046a authored by Touboul Nathane's avatar Touboul Nathane Committed by Olaf Meeuwissen

Add escl backend

parent fdcb2fa5
......@@ -12,3 +12,7 @@ root = true ; look no further
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[backend/escl/*]
indent_size = 4
indent_style = space
......@@ -6,7 +6,7 @@
variables:
REGISTRY_HUB: "registry.gitlab.com/sane-project/ci-envs"
CONFIGURE_MINI: "--enable-silent-rules"
CONFIGURE_FULL: "--with-usb --enable-avahi --enable-pnm-backend"
CONFIGURE_FULL: "--with-usb --enable-avahi --enable-pnm-backend --with-libcurl"
stages:
- tarball
......
......@@ -32,6 +32,7 @@ Backends:
epson: Karl Heinz Kremer
epson2: Alessandro Zummo
epsonds: Alessandro Zummo
escl: Touboul Nathane, Thierry HUCHARD (*)
fujitsu: Randolph Bentson, Frederik Ramm, Oliver Schirrmeister,
m. allan noah (*)
genesys: Henning Geinitz, Gerhard Jaeger (*), Stéphane Voltz,
......@@ -248,9 +249,11 @@ Sergey Vlasov <[email protected]>
Simon Krix <[email protected]>
Simon Munton <[email protected]>
Stéphane Voltz <[email protected]>
Thierry HUCHARD <[email protected]>
Thomas Soumarmon <[email protected]>
Tom Martone <[email protected]>
Tom Wang <[email protected]>
Touboul Nathane <[email protected]>
Tristan Tarrant <[email protected]>
Troy Rollo <[email protected]e>
Ullrich Sigwanz <[email protected]>
......
......@@ -611,6 +611,26 @@ for be in ${BACKENDS}; do
fi
;;
escl)
if test "x${enable_avahi}" != "xyes"; then
echo "*** $be backend requires AVAHI library - $DISABLE_MSG"
backend_supported="no"
fi
if test "x${with_libcurl}" != "xyes"; then
echo "*** $be backend requires cURL library - $DISABLE_MSG"
backend_supported="no"
fi
if test "x${have_libxml}" != "xyes"; then
echo "*** $be backend requires XML library - $DISABLE_MSG"
backend_supported="no"
fi
# FIXME: Remove when PNG and/or PDF support have been added.
if test "x${sane_cv_use_libjpeg}" != "xyes"; then
echo "*** $be backend currently requires JPEG library - $DISABLE_MSG"
backend_supported="no"
fi
;;
gphoto2)
if test "${HAVE_GPHOTO2}" != "true" \
|| test "${sane_cv_use_libjpeg}" != "yes"; then
......
......@@ -68,8 +68,8 @@ BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \
canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \
coolscan.conf dc210.conf dc240.conf dc25.conf \
dell1600n_net.conf dmc.conf epjitsu.conf epson2.conf \
epson.conf epsonds.conf fujitsu.conf genesys.conf gphoto2.conf \
gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \
epson.conf epsonds.conf escl.conf fujitsu.conf genesys.conf \
gphoto2.conf gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \
hp.conf hpsj5s.conf hs2p.conf ibm.conf kodak.conf kodakaio.conf\
kvs1025.conf \
leo.conf lexmark.conf ma1509.conf magicolor.conf \
......@@ -161,7 +161,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \
libcoolscan2.la libcoolscan3.la libdc25.la \
libdc210.la libdc240.la libdell1600n_net.la \
libdmc.la libdll.la libdll_preload.la libepjitsu.la libepson.la \
libepson2.la libepsonds.la libfujitsu.la libgenesys.la \
libepson2.la libepsonds.la libescl.la libfujitsu.la libgenesys.la \
libgphoto2_i.la libgt68xx.la libhp.la \
libhp3500.la libhp3900.la libhp4200.la \
libhp5400.la libhp5590.la libhpljm1005.la \
......@@ -194,8 +194,8 @@ be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \
libsane-coolscan2.la libsane-coolscan3.la libsane-dc25.la \
libsane-dc210.la libsane-dc240.la libsane-dell1600n_net.la \
libsane-dmc.la libsane-epjitsu.la libsane-epson.la \
libsane-epson2.la libsane-epsonds.la libsane-fujitsu.la libsane-genesys.la \
libsane-gphoto2.la libsane-gt68xx.la libsane-hp.la \
libsane-epson2.la libsane-epsonds.la libsane-escl.la libsane-fujitsu.la \
libsane-genesys.la libsane-gphoto2.la libsane-gt68xx.la libsane-hp.la \
libsane-hp3500.la libsane-hp3900.la libsane-hp4200.la \
libsane-hp5400.la libsane-hp5590.la libsane-hpljm1005.la \
libsane-hpsj5s.la libsane-hs2p.la libsane-ibm.la libsane-kodak.la libsane-kodakaio.la\
......@@ -434,6 +434,21 @@ libsane_dmc_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_dmc_la_LIBADD = $(COMMON_LIBS) libdmc.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += dmc.conf.in
if have_libavahi
if have_libcurl
if have_libxml2
libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c
libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
nodist_libsane_escl_la_SOURCES = escl-s.c
libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS)
endif
endif
endif
EXTRA_DIST += escl.conf.in
libepjitsu_la_SOURCES = epjitsu.c epjitsu.h epjitsu-cmd.h
libepjitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epjitsu
......
# escl.conf -- ESCL configuration
# Lines starting with a # or a ; are comments. Comments must be on a
# line of their own. End-of-line comments are not supported.
# Explanation : if you can't detect your device but it's an eSCL device, modify this escl conf' file to use your device.
# -> uncomment the lines below, from '[device]' to 'port'.
# -> put your device name instead of 'EPSON X'.
# -> put your type of protocol instead of 'https' : http or https.
# -> put your device ip instead of '123.456.789.10'.
# -> put the port that you use instead of '88'.
# For example, the lines below are for one device, but if you have several devices to use, you can duplicate the lines below as many times as you have devices.
#[device]
#model EPSON X
#type https
#ip 123.456.789.10
#port 88
This diff is collapsed.
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <[email protected]>
This file is part of the SANE package.
SANE is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
SANE 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#ifndef __ESCL_H__
#define __ESCL_H__
#include "../include/sane/config.h"
#if !(HAVE_LIBCURL && defined(WITH_AVAHI) && defined(HAVE_LIBXML2))
#error "The escl backend requires libcurl, libavahi and libxml2"
#endif
#ifndef HAVE_LIBJPEG
/* FIXME: Make JPEG support optional.
Support for PNG and PDF is to be added later but currently only
JPEG is supported. Absence of JPEG support makes the backend a
no-op at present.
*/
#error "The escl backend currently requires libjpeg"
#endif
#include "../include/sane/sane.h"
#include <stdio.h>
#ifndef BACKEND_NAME
#define BACKEND_NAME escl
#endif
#define ESCL_CONFIG_FILE "escl.conf"
typedef struct {
int p1_0;
int p2_0;
int p3_3;
int DocumentType;
int p4_0;
int p5_0;
int p6_1;
int reserve[11];
} ESCL_SCANOPTS;
typedef struct ESCL_Device {
struct ESCL_Device *next;
char *model_name;
int port_nb;
char *ip_address;
char *type;
} ESCL_Device;
typedef struct capabilities
{
int height;
int width;
int pos_x;
int pos_y;
SANE_String default_color;
SANE_String_Const default_format;
SANE_Int default_resolution;
int MinWidth;
int MaxWidth;
int MinHeight;
int MaxHeight;
int MaxScanRegions;
SANE_String_Const *ColorModes;
int ColorModesSize;
SANE_String_Const *ContentTypes;
int ContentTypesSize;
SANE_String_Const *DocumentFormats;
int DocumentFormatsSize;
SANE_Int *SupportedResolutions;
int SupportedResolutionsSize;
SANE_String_Const *SupportedIntents;
int SupportedIntentsSize;
SANE_String_Const SupportedIntentDefault;
int MaxOpticalXResolution;
int RiskyLeftMargin;
int RiskyRightMargin;
int RiskyTopMargin;
int RiskyBottomMargin;
FILE *tmp;
int format_ext;
} capabilities_t;
typedef struct {
int XRes;
int YRes;
int Left;
int Top;
int Right;
int Bottom;
int ScanMode;
int ScanMethod;
ESCL_SCANOPTS opts;
} ESCL_ScanParam;
enum
{
OPT_NUM_OPTS = 0,
OPT_MODE_GROUP,
OPT_MODE,
OPT_RESOLUTION,
OPT_PREVIEW,
OPT_GRAY_PREVIEW,
OPT_GEOMETRY_GROUP,
OPT_TL_X,
OPT_TL_Y,
OPT_BR_X,
OPT_BR_Y,
NUM_OPTIONS
};
ESCL_Device *escl_devices(SANE_Status *status);
SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type);
SANE_Status escl_status(SANE_String_Const name);
capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, SANE_String_Const name, SANE_Status *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result);
void escl_scanner(SANE_String_Const name, char *result);
#endif
This diff is collapsed.
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <[email protected]>
This file is part of the SANE package.
SANE is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
SANE 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#include "escl.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avahi-client/lookup.h>
#include <avahi-common/error.h>
#include <avahi-common/simple-watch.h>
#include "../include/sane/sanei.h"
static AvahiSimplePoll *simple_poll = NULL;
/**
* \fn static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
* const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata)
* \brief Callback function that will check if the selected scanner follows the escl protocol or not.
*/
static void
resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
const char __sane_unused__ *type, const char __sane_unused__ *domain, const char __sane_unused__ *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags __sane_unused__ flags, void __sane_unused__ *userdata)
{
char a[AVAHI_ADDRESS_STR_MAX], *t;
assert(r);
switch (event) {
case AVAHI_RESOLVER_FAILURE:
break;
case AVAHI_RESOLVER_FOUND:
avahi_address_snprint(a, sizeof(a), address);
t = avahi_string_list_to_string(txt);
if (strstr(t, "\"rs=eSCL\""))
escl_device_add(port, name, a, (char*)type);
}
}
/**
* \fn static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
* AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata)
* \brief Callback function that will browse tanks to 'avahi' the scanners connected in network.
*/
static void
browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata)
{
AvahiClient *c = userdata;
assert(b);
switch (event) {
case AVAHI_BROWSER_FAILURE:
avahi_simple_poll_quit(simple_poll);
return;
case AVAHI_BROWSER_NEW:
if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
break;
case AVAHI_BROWSER_REMOVE:
break;
case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
if (event != AVAHI_BROWSER_CACHE_EXHAUSTED)
avahi_simple_poll_quit(simple_poll);
break;
}
}
/**
* \fn static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *userdata)
* \brief Callback Function that quit if it doesn't find a connected scanner, possible thanks the "Hello Protocol".
* --> Waiting for a answer by the scanner to continue the avahi process.
*/
static void
client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *userdata)
{
assert(c);
if (state == AVAHI_CLIENT_FAILURE)
avahi_simple_poll_quit(simple_poll);
}
/**
* \fn ESCL_Device *escl_devices(SANE_Status *status)
* \brief Function that calls all the avahi functions and then, recovers the connected eSCL devices.
* This function is called in the 'sane_get_devices' function.
*
* \return NULL (the eSCL devices found)
*/
ESCL_Device *
escl_devices(SANE_Status *status)
{
AvahiClient *client = NULL;
AvahiServiceBrowser *sb = NULL;
int error;
*status = SANE_STATUS_GOOD;
if (!(simple_poll = avahi_simple_poll_new())) {
fprintf(stderr, "Failed to create simple poll object.\n");
*status = SANE_STATUS_INVAL;
goto fail;
}
client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error);
if (!client) {
fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
*status = SANE_STATUS_INVAL;
goto fail;
}
if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_uscan._tcp", NULL, 0, browse_callback, client))) {
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
*status = SANE_STATUS_INVAL;
goto fail;
}
if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_uscans._tcp", NULL, 0, browse_callback, client))) {
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
*status = SANE_STATUS_INVAL;
goto fail;
}
avahi_simple_poll_loop(simple_poll);
fail:
if (sb)
avahi_service_browser_free(sb);
if (client)
avahi_client_free(client);
if (simple_poll)
avahi_simple_poll_free(simple_poll);
return (NULL);
}
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <[email protected]>
This file is part of the SANE package.
SANE is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
SANE 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#include "escl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct uploading
{
const char *read_data;
size_t size;
};
struct downloading
{
char *memory;
size_t size;
};
static const char settings[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
"<scan:ScanSettings xmlns:pwg=\"http://www.pwg.org/schemas/2010/12/sm\" xmlns:scan=\"http://schemas.hp.com/imaging/escl/2011/05/03\">" \
" <pwg:Version>2.0</pwg:Version>" \
" <pwg:ScanRegions>" \
" <pwg:ScanRegion>" \
" <pwg:ContentRegionUnits>escl:ThreeHundredthsOfInches</pwg:ContentRegionUnits>" \
" <pwg:Height>%d</pwg:Height>" \
" <pwg:Width>%d</pwg:Width>" \
" <pwg:XOffset>%d</pwg:XOffset>" \
" <pwg:YOffset>%d</pwg:YOffset>" \
" </pwg:ScanRegion>" \
" </pwg:ScanRegions>" \
" <pwg:DocumentFormat>image/jpeg</pwg:DocumentFormat>" \
"%s" \
" <scan:ColorMode>%s</scan:ColorMode>" \
" <scan:XResolution>%d</scan:XResolution>" \
" <scan:YResolution>%d</scan:YResolution>" \
" <pwg:InputSource>Platen</pwg:InputSource>" \
"</scan:ScanSettings>";
static const char formatExt[] =
" <scan:DocumentFormatExt>image/jpeg</scan:DocumentFormatExt>";
/**
* \fn static size_t download_callback(void *str, size_t size, size_t nmemb, void *userp)
* \brief Callback function that stocks in memory the content of the 'job'. Example below :
* "Trying 192.168.14.150...
* TCP_NODELAY set
* Connected to 192.168.14.150 (192.168.14.150) port 80
* POST /eSCL/ScanJobs HTTP/1.1
* Host: 192.168.14.150
* User-Agent: curl/7.55.1
* Accept: /
* Content-Length: 605
* Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 605 out of 605 bytes
* < HTTP/1.1 201 Created
* < MIME-Version: 1.0
* < Location: http://192.168.14.150/eSCL/ScanJobs/22b54fd0-027b-1000-9bd0-f4a99726e2fa
* < Content-Length: 0
* < Connection: close
* <
* Closing connection 0"
*
* \return realsize (size of the content needed -> the 'job')
*/
static size_t
download_callback(void *str, size_t size, size_t nmemb, void *userp)
{
struct downloading *download = (struct downloading *)userp;
size_t realsize = size * nmemb;
char *content = realloc(download->memory, download->size + realsize + 1);
if (content == NULL) {
fprintf(stderr, "not enough memory (realloc returned NULL)\n");
return (0);
}
download->memory = content;
memcpy(&(download->memory[download->size]), str, realsize);
download->size = download->size + realsize;
download->memory[download->size] = 0;
return (realsize);
}
/**
* \fn char *escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
* \brief Function that, using curl, uploads the data (composed by the scanner capabilities) to the
* server to download the 'job' and recover the 'new job' (char *result), in LOCATION.
* This function is called in the 'sane_start' function and it's the equivalent of the
* following curl command : "curl -v POST -d cap.xml http(s)://'ip':'port'/eSCL/ScanJobs".
*
* \return result (the 'new job', situated in LOCATION)
*/
char *
escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
{
CURL *curl_handle = NULL;
struct uploading *upload = NULL;
struct downloading *download = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
char cap_data[PATH_MAX] = { 0 };
char job_cmd[PATH_MAX] = { 0 };
char *location = NULL;
char *result = NULL;
char *temporary = NULL;
*status = SANE_STATUS_GOOD;
if (name == NULL || scanner == NULL) {
*status = SANE_STATUS_NO_MEM;
return (NULL);
}
upload = (struct uploading *)calloc(1, sizeof(struct uploading));
if (upload == NULL) {
*status = SANE_STATUS_NO_MEM;
return (NULL);
}
download = (struct downloading *)calloc(1, sizeof(struct downloading));
if (download == NULL) {
free(upload);
*status = SANE_STATUS_NO_MEM;
return (NULL);
}
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0,
(scanner->format_ext == 1 ? formatExt : ""),
scanner->default_color, scanner->default_resolution, scanner->default_resolution);
//fprintf(stderr, "CAP_DATA = %s\n", cap_data);
upload->read_data = strdup(cap_data);
upload->size = strlen(cap_data);
download->memory = malloc(1);
download->size = 0;
strcpy(job_cmd, name);
strcat(job_cmd, scan_jobs);
curl_easy_setopt(curl_handle, CURLOPT_URL, job_cmd);
if (strncmp(name, "https", 5) == 0) {
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, upload->read_data);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, upload->size);
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, download_callback);
curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)download);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
fprintf(stderr, "THERE IS NO SCANNER\n");
*status = SANE_STATUS_INVAL;
}
else {
if (download->memory != NULL) {
if (strstr(download->memory, "Location:")) {
temporary = strrchr(download->memory, '/');
if (temporary != NULL) {
location = strchr(temporary, '\r');
if (location == NULL)
location = strchr(temporary, '\n');
else {
*location = '\0';
result = strdup(temporary);
}
}
free(download->memory);
}
else {
fprintf(stderr, "THERE IS NO LOCATION\n");
*status = SANE_STATUS_INVAL;
}
}
else {
*status = SANE_STATUS_NO_MEM;
return (NULL);
}
}
curl_easy_cleanup(curl_handle);
}
curl_global_cleanup();
if (upload != NULL)
free(upload);
if (download != NULL)
free(download);
return (result);
}
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Touboul Nathane
Copyright (C) 2019 Thierry HUCHARD <[email protected]>
This file is part of the SANE package.
SANE is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
SANE 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#include "escl.h"