1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2019 Touboul Nathane
4141cc406Sopenharmony_ci   Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   SANE is free software; you can redistribute it and/or modify it under
9141cc406Sopenharmony_ci   the terms of the GNU General Public License as published by the Free
10141cc406Sopenharmony_ci   Software Foundation; either version 3 of the License, or (at your
11141cc406Sopenharmony_ci   option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   SANE is distributed in the hope that it will be useful, but WITHOUT
14141cc406Sopenharmony_ci   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15141cc406Sopenharmony_ci   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16141cc406Sopenharmony_ci   for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with sane; see the file COPYING.
20141cc406Sopenharmony_ci   If not, see <https://www.gnu.org/licenses/>.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   This file implements a SANE backend for eSCL scanners.  */
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
25141cc406Sopenharmony_ci#include "../include/sane/config.h"
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci#include "escl.h"
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci#include <stdio.h>
30141cc406Sopenharmony_ci#include <stdlib.h>
31141cc406Sopenharmony_ci#include <string.h>
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci/**
36141cc406Sopenharmony_ci * \fn static size_t write_callback(void *str, size_t size, size_t nmemb, void *userp)
37141cc406Sopenharmony_ci * \brief Callback function that writes the image scanned into the temporary file.
38141cc406Sopenharmony_ci *
39141cc406Sopenharmony_ci * \return to_write (the result of the fwrite function)
40141cc406Sopenharmony_ci */
41141cc406Sopenharmony_cistatic size_t
42141cc406Sopenharmony_ciwrite_callback(void *str, size_t size, size_t nmemb, void *userp)
43141cc406Sopenharmony_ci{
44141cc406Sopenharmony_ci    capabilities_t *scanner = (capabilities_t *)userp;
45141cc406Sopenharmony_ci    size_t to_write = fwrite(str, size, nmemb, scanner->tmp);
46141cc406Sopenharmony_ci    scanner->real_read += to_write;
47141cc406Sopenharmony_ci    return (to_write);
48141cc406Sopenharmony_ci}
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci/**
51141cc406Sopenharmony_ci * \fn SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result)
52141cc406Sopenharmony_ci * \brief Function that, after recovering the 'new job', scans the image writed in the
53141cc406Sopenharmony_ci *        temporary file, using curl.
54141cc406Sopenharmony_ci *        This function is called in the 'sane_start' function and it's the equivalent of
55141cc406Sopenharmony_ci *        the following curl command : "curl -s http(s)://'ip:'port'/eSCL/ScanJobs/'new job'/NextDocument > image.jpg".
56141cc406Sopenharmony_ci *
57141cc406Sopenharmony_ci * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
58141cc406Sopenharmony_ci */
59141cc406Sopenharmony_ciSANE_Status
60141cc406Sopenharmony_ciescl_scan(capabilities_t *scanner, const ESCL_Device *device, char *scanJob, char *result)
61141cc406Sopenharmony_ci{
62141cc406Sopenharmony_ci    CURL *curl_handle = NULL;
63141cc406Sopenharmony_ci    const char *scan_jobs = "/eSCL/";
64141cc406Sopenharmony_ci    const char *scanner_start = "/NextDocument";
65141cc406Sopenharmony_ci    char scan_cmd[PATH_MAX] = { 0 };
66141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci    if (device == NULL)
69141cc406Sopenharmony_ci        return (SANE_STATUS_NO_MEM);
70141cc406Sopenharmony_ci    scanner->real_read = 0;
71141cc406Sopenharmony_ci    curl_handle = curl_easy_init();
72141cc406Sopenharmony_ci    if (curl_handle != NULL) {
73141cc406Sopenharmony_ci        snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s%s",
74141cc406Sopenharmony_ci                 scan_jobs, scanJob, result, scanner_start);
75141cc406Sopenharmony_ci        escl_curl_url(curl_handle, device, scan_cmd);
76141cc406Sopenharmony_ci        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
77141cc406Sopenharmony_ci        curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
78141cc406Sopenharmony_ci        curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L);
79141cc406Sopenharmony_ci        if (scanner->tmp)
80141cc406Sopenharmony_ci            fclose(scanner->tmp);
81141cc406Sopenharmony_ci        scanner->tmp = tmpfile();
82141cc406Sopenharmony_ci        if (scanner->tmp != NULL) {
83141cc406Sopenharmony_ci            curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, scanner);
84141cc406Sopenharmony_ci            CURLcode res = curl_easy_perform(curl_handle);
85141cc406Sopenharmony_ci            if (res != CURLE_OK) {
86141cc406Sopenharmony_ci                DBG( 1, "Unable to scan: %s\n", curl_easy_strerror(res));
87141cc406Sopenharmony_ci                scanner->real_read = 0;
88141cc406Sopenharmony_ci                fclose(scanner->tmp);
89141cc406Sopenharmony_ci                scanner->tmp = NULL;
90141cc406Sopenharmony_ci                status = SANE_STATUS_INVAL;
91141cc406Sopenharmony_ci		goto cleanup;
92141cc406Sopenharmony_ci            }
93141cc406Sopenharmony_ci            fseek(scanner->tmp, 0, SEEK_SET);
94141cc406Sopenharmony_ci        }
95141cc406Sopenharmony_ci        else
96141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
97141cc406Sopenharmony_cicleanup:
98141cc406Sopenharmony_ci        curl_easy_cleanup(curl_handle);
99141cc406Sopenharmony_ci    }
100141cc406Sopenharmony_ci    DBG(10, "eSCL scan : [%s]\treal read (%ld)\n", sane_strstatus(status), scanner->real_read);
101141cc406Sopenharmony_ci    if (scanner->real_read == 0)
102141cc406Sopenharmony_ci    {
103141cc406Sopenharmony_ci       fclose(scanner->tmp);
104141cc406Sopenharmony_ci       scanner->tmp = NULL;
105141cc406Sopenharmony_ci       return SANE_STATUS_NO_DOCS;
106141cc406Sopenharmony_ci    }
107141cc406Sopenharmony_ci    return (status);
108141cc406Sopenharmony_ci}
109