diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:45:34 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:45:34 +0200 |
commit | 2b3e02411ecc09e7d41741b5587655c9b2f955b7 (patch) | |
tree | d839746371ecb8ed64ac81d2e37c11fcd25a00ac /backend/escl/escl.c | |
parent | 787fb1d54ec9ee5fb941ae897fb201feb9cb2fd1 (diff) | |
parent | ad38bc6ecb80ddeb562841b33258dd53659b1da6 (diff) |
Update upstream source from tag 'upstream/1.0.31'
Update to upstream version '1.0.31'
with Debian dir aa7a39fe56343f5e164eec83783f4c923a394865
Diffstat (limited to 'backend/escl/escl.c')
-rw-r--r-- | backend/escl/escl.c | 893 |
1 files changed, 693 insertions, 200 deletions
diff --git a/backend/escl/escl.c b/backend/escl/escl.c index 8df6c5c..c40fd98 100644 --- a/backend/escl/escl.c +++ b/backend/escl/escl.c @@ -46,14 +46,16 @@ static int num_devices = 0; typedef struct Handled { struct Handled *next; - SANE_String_Const name; + ESCL_Device *device; char *result; ESCL_ScanParam param; SANE_Option_Descriptor opt[NUM_OPTIONS]; Option_Value val[NUM_OPTIONS]; capabilities_t *scanner; - SANE_Range x_range; - SANE_Range y_range; + SANE_Range x_range1; + SANE_Range x_range2; + SANE_Range y_range1; + SANE_Range y_range2; SANE_Bool cancel; SANE_Bool write_scan_data; SANE_Bool decompress_scan_data; @@ -61,6 +63,59 @@ typedef struct Handled { SANE_Parameters ps; } escl_sane_t; +static ESCL_Device * +escl_free_device(ESCL_Device *current) +{ + if (!current) return NULL; + free((void*)current->ip_address); + free((void*)current->model_name); + free((void*)current->type); + free(current->unix_socket); + free(current); + return NULL; +} + +void +escl_free_handler(escl_sane_t *handler) +{ + if (handler == NULL) + return; + + escl_free_device(handler->device); + free(handler); +} + +SANE_Status escl_parse_name(SANE_String_Const name, ESCL_Device *device); + +static SANE_Status +escl_check_and_add_device(ESCL_Device *current) +{ + if(!current) { + DBG (10, "ESCL_Device *current us null.\n"); + return (SANE_STATUS_NO_MEM); + } + if (!current->ip_address) { + DBG (10, "Ip Address allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + if (current->port_nb == 0) { + DBG (10, "No port defined.\n"); + return (SANE_STATUS_NO_MEM); + } + if (!current->model_name) { + DBG (10, "Modele Name allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + if (!current->type) { + DBG (10, "Scanner Type allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + ++num_devices; + current->next = list_devices_primary; + list_devices_primary = current; + return (SANE_STATUS_GOOD); +} + /** * \fn static SANE_Status escl_add_in_list(ESCL_Device *current) * \brief Function that adds all the element needed to my list : @@ -72,10 +127,18 @@ typedef struct Handled { static SANE_Status escl_add_in_list(ESCL_Device *current) { - ++num_devices; - current->next = list_devices_primary; - list_devices_primary = current; - return (SANE_STATUS_GOOD); + if(!current) { + DBG (10, "ESCL_Device *current us null.\n"); + return (SANE_STATUS_NO_MEM); + } + + if (SANE_STATUS_GOOD == + escl_check_and_add_device(current)) { + list_devices_primary = current; + return (SANE_STATUS_GOOD); + } + current = escl_free_device(current); + return (SANE_STATUS_NO_MEM); } /** @@ -89,19 +152,44 @@ escl_add_in_list(ESCL_Device *current) SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type) { + char tmp[PATH_MAX] = { 0 }; + char *model = NULL; ESCL_Device *current = NULL; DBG (10, "escl_device_add\n"); for (current = list_devices_primary; current; current = current->next) { - if (strcmp(current->ip_address, ip_address) == 0 && current->port_nb == port_nb - && strcmp(current->type, type) == 0) - return (SANE_STATUS_GOOD); + if (strcmp(current->ip_address, ip_address) == 0) + { + if (strcmp(current->type, type)) + { + if(!strcmp(type, "_uscans._tcp") || + !strcmp(type, "https")) + { + free (current->type); + current->type = strdup(type); + current->port_nb = port_nb; + current->https = SANE_TRUE; + } + return (SANE_STATUS_GOOD); + } + else if (current->port_nb == port_nb) + return (SANE_STATUS_GOOD); + } + } + current = (ESCL_Device*)calloc(1, sizeof(*current)); + if (current == NULL) { + DBG (10, "New device allocation failure.\n"); + return (SANE_STATUS_NO_MEM); } - current = malloc(sizeof(*current)); - if (current == NULL) - return (SANE_STATUS_NO_MEM); - memset(current, 0, sizeof(*current)); current->port_nb = port_nb; - current->model_name = strdup(model_name); + + if (strcmp(type, "_uscan._tcp") != 0 && strcmp(type, "http") != 0) { + snprintf(tmp, sizeof(tmp), "%s SSL", model_name); + current->https = SANE_TRUE; + } else { + current->https = SANE_FALSE; + } + model = (char*)(tmp[0] != 0 ? tmp : model_name); + current->model_name = strdup(model); current->ip_address = strdup(ip_address); current->type = strdup(type); return escl_add_in_list(current); @@ -121,13 +209,51 @@ max_string_size(const SANE_String_Const strings[]) int i = 0; for (i = 0; strings[i]; ++i) { - size_t size = strlen (strings[i]); - if (size > max_size) - max_size = size; + size_t size = strlen (strings[i]); + if (size > max_size) + max_size = size; } return (max_size + 1); } +static char * +get_vendor(char *search) +{ + if(strcasestr(search, "Epson")) + return strdup("Epson"); + else if(strcasestr(search, "Fujitsu")) + return strdup("Fujitsu"); + else if(strcasestr(search, "HP")) + return strdup("HP"); + else if(strcasestr(search, "Canon")) + return strdup("Canon"); + else if(strcasestr(search, "Lexmark")) + return strdup("Lexmark"); + else if(strcasestr(search, "Samsung")) + return strdup("Samsung"); + else if(strcasestr(search, "Xerox")) + return strdup("Xerox"); + else if(strcasestr(search, "OKI")) + return strdup("OKI"); + else if(strcasestr(search, "Hewlett Packard")) + return strdup("Hewlett Packard"); + else if(strcasestr(search, "IBM")) + return strdup("IBM"); + else if(strcasestr(search, "Mustek")) + return strdup("Mustek"); + else if(strcasestr(search, "Ricoh")) + return strdup("Ricoh"); + else if(strcasestr(search, "Sharp")) + return strdup("Sharp"); + else if(strcasestr(search, "UMAX")) + return strdup("UMAX"); + else if(strcasestr(search, "PINT")) + return strdup("PINT"); + else if(strcasestr(search, "Brother")) + return strdup("Brother"); + return NULL; +} + /** * \fn static SANE_Device *convertFromESCLDev(ESCL_Device *cdev) * \brief Function that checks if the url of the received scanner is secured or not (http / https). @@ -142,19 +268,61 @@ max_string_size(const SANE_String_Const strings[]) static SANE_Device * convertFromESCLDev(ESCL_Device *cdev) { + char *tmp; + int len, lv = 0; + char unix_path[PATH_MAX+7] = { 0 }; SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device)); - char tmp[PATH_MAX] = { 0 }; + if (!sdev) { + DBG (10, "Sane_Device allocation failure.\n"); + return NULL; + } + + if (cdev->unix_socket && strlen(cdev->unix_socket)) { + snprintf(unix_path, sizeof(unix_path), "unix:%s:", cdev->unix_socket); + } + len = snprintf(NULL, 0, "%shttp%s://%s:%d", + unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb); + len++; + tmp = (char *)malloc(len); + if (!tmp) { + DBG (10, "Name allocation failure.\n"); + goto freedev; + } + snprintf(tmp, len, "%shttp%s://%s:%d", + unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb); + sdev->name = tmp; - if (strcmp(cdev->type, "_uscan._tcp") == 0 || strcmp(cdev->type, "http") == 0) - snprintf(tmp, sizeof(tmp), "http://%s:%d", cdev->ip_address, cdev->port_nb); - else - snprintf(tmp, sizeof(tmp), "https://%s:%d", cdev->ip_address, cdev->port_nb); DBG( 1, "Escl add device : %s\n", tmp); - sdev->name = strdup(tmp); - sdev->model = strdup(cdev->model_name); - sdev->vendor = strdup("ESCL"); + sdev->vendor = get_vendor(cdev->model_name); + + if (!sdev->vendor) + sdev->vendor = strdup("ESCL"); + else + lv = strlen(sdev->vendor) + 1; + if (!sdev->vendor) { + DBG (10, "Vendor allocation failure.\n"); + goto freemodel; + } + sdev->model = strdup(lv + cdev->model_name); + if (!sdev->model) { + DBG (10, "Model allocation failure.\n"); + goto freename; + } sdev->type = strdup("flatbed scanner"); + if (!sdev->type) { + DBG (10, "Scanner Type allocation failure.\n"); + goto freevendor; + } return (sdev); +freevendor: + free((void*)sdev->vendor); +freemodel: + free((void*)sdev->model); +freename: + free((void*)sdev->name); +freedev: + free((void*)sdev); + return NULL; } /** @@ -174,9 +342,9 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) SANE_Status status = SANE_STATUS_GOOD; curl_global_init(CURL_GLOBAL_ALL); if (version_code != NULL) - *version_code = SANE_VERSION_CODE(1, 0, 0); + *version_code = SANE_VERSION_CODE(1, 0, 0); if (status != SANE_STATUS_GOOD) - return (status); + return (status); return (SANE_STATUS_GOOD); } @@ -194,12 +362,12 @@ sane_exit(void) ESCL_Device *next = NULL; while (list_devices_primary != NULL) { - next = list_devices_primary->next; - free(list_devices_primary); - list_devices_primary = next; + next = list_devices_primary->next; + free(list_devices_primary); + list_devices_primary = next; } if (devlist) - free (devlist); + free (devlist); list_devices_primary = NULL; devlist = NULL; curl_global_cleanup(); @@ -218,44 +386,85 @@ static SANE_Status attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) { int port = 0; - static int count = 0; + SANE_Status status; static ESCL_Device *escl_device = NULL; - if (strncmp(line, "[device]", 8) == 0) { - count = 0; + if (strncmp(line, "device", 6) == 0) { + char *name_str = NULL; + char *opt_model = NULL; + + line = sanei_config_get_string(line + 6, &name_str); + DBG (10, "New Escl_Device URL [%s].\n", (name_str ? name_str : "VIDE")); + if (!name_str || !*name_str) { + DBG (1, "Escl_Device URL missing.\n"); + return SANE_STATUS_INVAL; + } + if (*line) { + line = sanei_config_get_string(line, &opt_model); + DBG (10, "New Escl_Device model [%s].\n", opt_model); + } + + escl_free_device(escl_device); escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device)); + if (!escl_device) { + DBG (10, "New Escl_Device allocation failure.\n"); + free(name_str); + return (SANE_STATUS_NO_MEM); + } + status = escl_parse_name(name_str, escl_device); + free(name_str); + if (status != SANE_STATUS_GOOD) { + escl_free_device(escl_device); + escl_device = NULL; + return status; + } + escl_device->model_name = opt_model ? opt_model : strdup("Unknown model"); + escl_device->type = strdup("flatbed scanner"); + } + + if (strncmp(line, "[device]", 8) == 0) { + escl_device = escl_free_device(escl_device); + escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device)); + if (!escl_device) { + DBG (10, "New Escl_Device allocation failure."); + return (SANE_STATUS_NO_MEM); + } } if (strncmp(line, "ip", 2) == 0) { - const char *ip_space = sanei_config_skip_whitespace(line + 2); - if (escl_device != NULL && ip_space != NULL) { - count++; - escl_device->ip_address = strdup(ip_space); - } + const char *ip_space = sanei_config_skip_whitespace(line + 2); + DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE")); + if (escl_device != NULL && ip_space != NULL) { + DBG (10, "New Escl_Device IP Affected."); + escl_device->ip_address = strdup(ip_space); + } } if (sscanf(line, "port %i", &port) == 1 && port != 0) { - const char *port_space = sanei_config_skip_whitespace(line + 4); - if (escl_device != NULL && port_space != NULL) { - count++; - escl_device->port_nb = port; - } + DBG (10, "New Escl_Device PORT [%d].", port); + if (escl_device != NULL) { + DBG (10, "New Escl_Device PORT Affected."); + escl_device->port_nb = port; + } } if (strncmp(line, "model", 5) == 0) { - const char *model_space = sanei_config_skip_whitespace(line + 5); - if (escl_device != NULL && model_space != NULL) { - count++; - escl_device->model_name = strdup(model_space); - } + const char *model_space = sanei_config_skip_whitespace(line + 5); + DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE")); + if (escl_device != NULL && model_space != NULL) { + DBG (10, "New Escl_Device MODEL Affected."); + escl_device->model_name = strdup(model_space); + } } if (strncmp(line, "type", 4) == 0) { - const char *type_space = sanei_config_skip_whitespace(line + 4); - if (escl_device != NULL && type_space != NULL) { - count++; - escl_device->type = strdup(type_space); - } + const char *type_space = sanei_config_skip_whitespace(line + 4); + DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE")); + if (escl_device != NULL && type_space != NULL) { + DBG (10, "New Escl_Device TYPE Affected."); + escl_device->type = strdup(type_space); + } } - if (count == 4) - return (escl_add_in_list(escl_device)); - return (SANE_STATUS_GOOD); + status = escl_check_and_add_device(escl_device); + if (status == SANE_STATUS_GOOD) + escl_device = NULL; + return status; } /** @@ -269,7 +478,7 @@ SANE_Status sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) { if (local_only) /* eSCL is a network-only protocol */ - return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL); + return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL); DBG (10, "escl sane_get_devices\n"); ESCL_Device *dev = NULL; @@ -277,29 +486,46 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) SANE_Status status; if (device_list == NULL) - return (SANE_STATUS_INVAL); + return (SANE_STATUS_INVAL); status = sanei_configure_attach(ESCL_CONFIG_FILE, NULL, attach_one_config); if (status != SANE_STATUS_GOOD) - return (status); + return (status); escl_devices(&status); if (status != SANE_STATUS_GOOD) - return (status); + return (status); if (devlist) - free(devlist); + free(devlist); devlist = (const SANE_Device **) calloc (num_devices + 1, sizeof (devlist[0])); if (devlist == NULL) - return (SANE_STATUS_NO_MEM); + return (SANE_STATUS_NO_MEM); int i = 0; for (dev = list_devices_primary; i < num_devices; dev = dev->next) { - SANE_Device *s_dev = convertFromESCLDev(dev); - devlist[i] = s_dev; - i++; + SANE_Device *s_dev = convertFromESCLDev(dev); + devlist[i] = s_dev; + i++; } devlist[i] = 0; *device_list = devlist; return (devlist) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM; } +/* Returns the length of the longest string, including the terminating + * character. */ +static size_t +_source_size_max (SANE_String_Const * sources) +{ + size_t size = 0; + + while(*sources) + { + size_t t = strlen (*sources) + 1; + if (t > size) + size = t; + sources++; + } + return size; +} + /** * \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s) * \brief Function thzt initializes all the needed options of the received scanner @@ -309,26 +535,51 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) * \return status (if everything is OK, status = SANE_STATUS_GOOD) */ static SANE_Status -init_options(SANE_String_Const name, escl_sane_t *s) +init_options(SANE_String_Const name_source, escl_sane_t *s) { DBG (10, "escl init_options\n"); + SANE_Status status = SANE_STATUS_GOOD; int i = 0; - - if (name == NULL) - return (SANE_STATUS_INVAL); + if (!s->scanner) return SANE_STATUS_INVAL; + if (name_source) { + int source = s->scanner->source; + DBG (10, "escl init_options name [%s]\n", name_source); + if (!strcmp(name_source, SANE_I18N ("ADF Duplex"))) + s->scanner->source = ADFDUPLEX; + else if (!strncmp(name_source, "A", 1) || + !strcmp(name_source, SANE_I18N ("ADF"))) + s->scanner->source = ADFSIMPLEX; + else + s->scanner->source = PLATEN; + if (source == s->scanner->source) return status; + } + else + s->scanner->source = PLATEN; memset (s->opt, 0, sizeof (s->opt)); memset (s->val, 0, sizeof (s->val)); for (i = 0; i < NUM_OPTIONS; ++i) { - s->opt[i].size = sizeof (SANE_Word); - s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - } - s->x_range.min = 0; - s->x_range.max = s->scanner->MaxWidth - s->scanner->MinWidth; - s->x_range.quant = 1; - s->y_range.min = 0; - s->y_range.max = s->scanner->MaxHeight - s->scanner->MinHeight; - s->y_range.quant = 1; + s->opt[i].size = sizeof (SANE_Word); + s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + s->x_range1.min = 0; + s->x_range1.max = + PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxWidth - + s->scanner->caps[s->scanner->source].MinWidth), + 300.0); + s->x_range1.quant = 0; + s->x_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinWidth, 300.0); + s->x_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxWidth, 300.0); + s->x_range2.quant = 0; + s->y_range1.min = 0; + s->y_range1.max = + PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxHeight - + s->scanner->caps[s->scanner->source].MinHeight), + 300.0); + s->y_range1.quant = 0; + s->y_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinHeight, 300.0); + s->y_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxHeight, 300.0); + s->y_range2.quant = 0; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; @@ -347,10 +598,18 @@ init_options(SANE_String_Const name, escl_sane_t *s) s->opt[OPT_MODE].type = SANE_TYPE_STRING; s->opt[OPT_MODE].unit = SANE_UNIT_NONE; s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_MODE].constraint.string_list = s->scanner->ColorModes; - s->val[OPT_MODE].s = (char *)strdup(s->scanner->ColorModes[0]); - s->opt[OPT_MODE].size = max_string_size(s->scanner->ColorModes); - s->scanner->default_color = (char *)strdup(s->scanner->ColorModes[0]); + s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes; + s->val[OPT_MODE].s = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]); + if (!s->val[OPT_MODE].s) { + DBG (10, "Color Mode Default allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + s->opt[OPT_MODE].size = max_string_size(s->scanner->caps[s->scanner->source].ColorModes); + s->scanner->caps[s->scanner->source].default_color = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]); + if (!s->scanner->caps[s->scanner->source].default_color) { + DBG (10, "Color Mode Default allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; @@ -358,9 +617,9 @@ init_options(SANE_String_Const name, escl_sane_t *s) s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; - s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->SupportedResolutions; - s->val[OPT_RESOLUTION].w = s->scanner->SupportedResolutions[1]; - s->scanner->default_resolution = s->scanner->SupportedResolutions[1]; + s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->caps[s->scanner->source].SupportedResolutions; + s->val[OPT_RESOLUTION].w = s->scanner->caps[s->scanner->source].SupportedResolutions[1]; + s->scanner->caps[s->scanner->source].default_resolution = s->scanner->caps[s->scanner->source].SupportedResolutions[1]; s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; @@ -376,7 +635,7 @@ init_options(SANE_String_Const name, escl_sane_t *s) s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE; s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY; - s->opt[OPT_GEOMETRY_GROUP].desc = ""; + s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY; s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; @@ -385,40 +644,107 @@ init_options(SANE_String_Const name, escl_sane_t *s) s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_X].size = sizeof(SANE_Fixed); + s->opt[OPT_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->opt[OPT_TL_X].unit = SANE_UNIT_MM; s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_X].constraint.range = &s->x_range; - s->val[OPT_TL_X].w = s->scanner->RiskyLeftMargin; + s->opt[OPT_TL_X].constraint.range = &s->x_range1; + s->val[OPT_TL_X].w = s->x_range1.min; s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_Y].size = sizeof(SANE_Fixed); + s->opt[OPT_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_Y].constraint.range = &s->y_range; - s->val[OPT_TL_Y].w = s->scanner->RiskyTopMargin; + s->opt[OPT_TL_Y].constraint.range = &s->y_range1; + s->val[OPT_TL_Y].w = s->y_range1.min; s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_X].size = sizeof(SANE_Fixed); + s->opt[OPT_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->opt[OPT_BR_X].unit = SANE_UNIT_MM; s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_X].constraint.range = &s->x_range; - s->val[OPT_BR_X].w = s->scanner->MaxWidth; + s->opt[OPT_BR_X].constraint.range = &s->x_range2; + s->val[OPT_BR_X].w = s->x_range2.max; s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_Y].size = sizeof(SANE_Fixed); + s->opt[OPT_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_Y].constraint.range = &s->y_range; - s->val[OPT_BR_Y].w = s->scanner->MaxHeight; + s->opt[OPT_BR_Y].constraint.range = &s->y_range2; + s->val[OPT_BR_Y].w = s->y_range2.max; + + /* OPT_SCAN_SOURCE */ + s->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE; + s->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE; + s->opt[OPT_SCAN_SOURCE].desc = SANE_DESC_SCAN_SOURCE; + s->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING; + s->opt[OPT_SCAN_SOURCE].size = _source_size_max(s->scanner->Sources); + s->opt[OPT_SCAN_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_SCAN_SOURCE].constraint.string_list = s->scanner->Sources; + if (s->val[OPT_SCAN_SOURCE].s) + free (s->val[OPT_SCAN_SOURCE].s); + s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]); return (status); } +SANE_Status +escl_parse_name(SANE_String_Const name, ESCL_Device *device) +{ + SANE_String_Const host = NULL; + SANE_String_Const port_str = NULL; + DBG(10, "escl_parse_name\n"); + if (name == NULL || device == NULL) { + return SANE_STATUS_INVAL; + } + + if (strncmp(name, "unix:", 5) == 0) { + SANE_String_Const socket = name + 5; + name = strchr(socket, ':'); + if (name == NULL) + return SANE_STATUS_INVAL; + device->unix_socket = strndup(socket, name - socket); + name++; + } + + if (strncmp(name, "https://", 8) == 0) { + device->https = SANE_TRUE; + host = name + 8; + } else if (strncmp(name, "http://", 7) == 0) { + device->https = SANE_FALSE; + host = name + 7; + } else { + DBG(1, "Unknown URL scheme in %s", name); + return SANE_STATUS_INVAL; + } + + port_str = strchr(host, ':'); + if (port_str == NULL) { + DBG(1, "Port missing from URL: %s", name); + return SANE_STATUS_INVAL; + } + port_str++; + device->port_nb = atoi(port_str); + if (device->port_nb < 1 || device->port_nb > 65535) { + DBG(1, "Invalid port number in URL: %s", name); + return SANE_STATUS_INVAL; + } + + device->ip_address = strndup(host, port_str - host - 1); + return SANE_STATUS_GOOD; +} + /** * \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h) * \brief Function that establishes a connection with the device named by 'name', @@ -437,28 +763,45 @@ sane_open(SANE_String_Const name, SANE_Handle *h) if (name == NULL) return (SANE_STATUS_INVAL); - status = escl_status(name); - if (status != SANE_STATUS_GOOD) - return (status); + + ESCL_Device *device = calloc(1, sizeof(ESCL_Device)); + if (device == NULL) { + DBG (10, "Handle device allocation failure.\n"); + return SANE_STATUS_NO_MEM; + } + status = escl_parse_name(name, device); + if (status != SANE_STATUS_GOOD) { + escl_free_device(device); + return status; + } + handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t)); - if (handler == NULL) + if (handler == NULL) { + escl_free_device(device); return (SANE_STATUS_NO_MEM); - handler->name = strdup(name); - handler->scanner = escl_capabilities(name, &status); - if (status != SANE_STATUS_GOOD) + } + handler->device = device; // Handler owns device now. + handler->scanner = escl_capabilities(device, &status); + if (status != SANE_STATUS_GOOD) { + escl_free_handler(handler); return (status); - status = init_options(name, handler); - if (status != SANE_STATUS_GOOD) + } + status = init_options(NULL, handler); + if (status != SANE_STATUS_GOOD) { + escl_free_handler(handler); return (status); + } handler->ps.depth = 8; handler->ps.last_frame = SANE_TRUE; handler->ps.format = SANE_FRAME_RGB; - handler->ps.pixels_per_line = handler->val[OPT_BR_X].w; - handler->ps.lines = handler->val[OPT_BR_Y].w; + handler->ps.pixels_per_line = MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0); + handler->ps.lines = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0); handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3; status = sane_get_parameters(handler, 0); - if (status != SANE_STATUS_GOOD) + if (status != SANE_STATUS_GOOD) { + escl_free_handler(handler); return (status); + } handler->cancel = SANE_FALSE; handler->write_scan_data = SANE_FALSE; handler->decompress_scan_data = SANE_FALSE; @@ -483,8 +826,11 @@ sane_cancel(SANE_Handle h) fclose(handler->scanner->tmp); handler->scanner->tmp = NULL; } + handler->scanner->work = SANE_FALSE; handler->cancel = SANE_TRUE; - escl_scanner(handler->name, handler->result); + escl_scanner(handler->device, handler->result); + free(handler->result); + handler->result = NULL; } /** @@ -497,7 +843,7 @@ sane_close(SANE_Handle h) { DBG (10, "escl sane_close\n"); if (h != NULL) { - free(h); + escl_free_handler(h); h = NULL; } } @@ -517,8 +863,8 @@ sane_get_option_descriptor(SANE_Handle h, SANE_Int n) escl_sane_t *s = h; if ((unsigned) n >= NUM_OPTIONS || n < 0) - return (0); - return (s->opt + n); + return (0); + return (&s->opt[n]); } /** @@ -541,62 +887,92 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int escl_sane_t *handler = h; if (i) - *i = 0; + *i = 0; if (n >= NUM_OPTIONS || n < 0) - return (SANE_STATUS_INVAL); + return (SANE_STATUS_INVAL); if (a == SANE_ACTION_GET_VALUE) { - switch (n) { - case OPT_NUM_OPTS: - case OPT_RESOLUTION: - case OPT_TL_X: - case OPT_TL_Y: - case OPT_BR_X: - case OPT_BR_Y: - case OPT_PREVIEW: - case OPT_GRAY_PREVIEW: - *(SANE_Word *) v = handler->val[n].w; - break; - case OPT_MODE: - strcpy (v, handler->val[n].s); - break; - case OPT_MODE_GROUP: - default: - break; - } - return (SANE_STATUS_GOOD); + switch (n) { + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_NUM_OPTS: + case OPT_RESOLUTION: + case OPT_PREVIEW: + case OPT_GRAY_PREVIEW: + *(SANE_Word *) v = handler->val[n].w; + break; + case OPT_SCAN_SOURCE: + case OPT_MODE: + strcpy (v, handler->val[n].s); + break; + case OPT_MODE_GROUP: + default: + break; + } + return (SANE_STATUS_GOOD); } if (a == SANE_ACTION_SET_VALUE) { - switch (n) { - case OPT_TL_X: - case OPT_TL_Y: - case OPT_BR_X: - case OPT_BR_Y: - case OPT_PREVIEW: - case OPT_GRAY_PREVIEW: - handler->val[n].w = *(SANE_Word *) v; - if (i && handler->val[n].w != *(SANE_Word *) v) - *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; - handler->val[n].w = *(SANE_Word *) v; - break; - case OPT_RESOLUTION: - handler->val[n].w = *(SANE_Word *) v; - if (i) - *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; - break; - case OPT_MODE: - if (handler->val[n].s) - free (handler->val[n].s); - handler->val[n].s = strdup (v); - if (i) - *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; - break; - default: - break; - } + switch (n) { + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_NUM_OPTS: + case OPT_RESOLUTION: + case OPT_PREVIEW: + case OPT_GRAY_PREVIEW: + handler->val[n].w = *(SANE_Word *) v; + if (i) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + break; + case OPT_SCAN_SOURCE: + DBG(10, "SET OPT_SCAN_SOURCE(%s)\n", (SANE_String_Const)v); + init_options((SANE_String_Const)v, handler); + if (i) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + break; + case OPT_MODE: + if (handler->val[n].s) + free (handler->val[n].s); + handler->val[n].s = strdup (v); + if (!handler->val[n].s) { + DBG (10, "OPT_MODE allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + if (i) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + break; + default: + break; + } } return (SANE_STATUS_GOOD); } +static SANE_Bool +_go_next_page(SANE_Status status, + SANE_Status job) +{ + // Thank's Alexander Pevzner (pzz@apevzner.com) + SANE_Status st = SANE_STATUS_NO_DOCS; + switch (status) { + case SANE_STATUS_GOOD: + case SANE_STATUS_UNSUPPORTED: + case SANE_STATUS_DEVICE_BUSY: { + DBG(10, "eSCL : Test next page\n"); + if (job != SANE_STATUS_GOOD) { + DBG(10, "eSCL : Go next page\n"); + st = SANE_STATUS_GOOD; + } + break; + } + default: + DBG(10, "eSCL : No next page\n"); + } + return st; +} + /** * \fn SANE_Status sane_start(SANE_Handle h) * \brief Function that initiates aquisition of an image from the device represented by handle 'h'. @@ -614,70 +990,137 @@ sane_start(SANE_Handle h) int he = 0; int bps = 0; - if (handler->name == NULL) + if (handler->device == NULL) { + DBG(1, "Missing handler device.\n"); return (SANE_STATUS_INVAL); + } handler->cancel = SANE_FALSE; handler->write_scan_data = SANE_FALSE; handler->decompress_scan_data = SANE_FALSE; handler->end_read = SANE_FALSE; - handler->scanner->height = handler->val[OPT_BR_Y].w; - handler->scanner->width = handler->val[OPT_BR_X].w; - handler->scanner->pos_x = handler->val[OPT_TL_X].w; - handler->scanner->pos_y = handler->val[OPT_TL_Y].w; - if(handler->scanner->default_color) - free(handler->scanner->default_color); - if (handler->val[OPT_PREVIEW].w == SANE_TRUE) - { - int i = 0, val = 9999;; - if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE || - !strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3)) - handler->scanner->default_color = strdup("Grayscale8"); + if (handler->scanner->work == SANE_FALSE) { + SANE_Status st = escl_status(handler->device, + handler->scanner->source, + NULL, + NULL); + if (st != SANE_STATUS_GOOD) + return st; + if(handler->scanner->caps[handler->scanner->source].default_color) + free(handler->scanner->caps[handler->scanner->source].default_color); + if (handler->val[OPT_PREVIEW].w == SANE_TRUE) + { + int i = 0, val = 9999;; + if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE || + !strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) + handler->scanner->caps[handler->scanner->source].default_color = + strdup("Grayscale8"); + else + handler->scanner->caps[handler->scanner->source].default_color = + strdup("RGB24"); + if (!handler->scanner->caps[handler->scanner->source].default_color) { + DBG (10, "Default Color allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + for (i = 1; i < handler->scanner->caps[handler->scanner->source].SupportedResolutionsSize; i++) + { + if (val > handler->scanner->caps[handler->scanner->source].SupportedResolutions[i]) + val = handler->scanner->caps[handler->scanner->source].SupportedResolutions[i]; + } + handler->scanner->caps[handler->scanner->source].default_resolution = val; + } else - handler->scanner->default_color = strdup("RGB24"); - for (i = 1; i < handler->scanner->SupportedResolutionsSize; i++) { - if (val > handler->scanner->SupportedResolutions[i]) - val = handler->scanner->SupportedResolutions[i]; + handler->scanner->caps[handler->scanner->source].default_resolution = + handler->val[OPT_RESOLUTION].w; + if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) + handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8"); + else if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) + handler->scanner->caps[handler->scanner->source].default_color = + strdup("BlackAndWhite1"); + else + handler->scanner->caps[handler->scanner->source].default_color = + strdup("RGB24"); } - handler->scanner->default_resolution = val; + handler->scanner->caps[handler->scanner->source].height = + MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0); + handler->scanner->caps[handler->scanner->source].width = + MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);; + if (handler->x_range1.min == handler->val[OPT_TL_X].w) + handler->scanner->caps[handler->scanner->source].pos_x = 0; + else + handler->scanner->caps[handler->scanner->source].pos_x = + MM_TO_PIXEL((handler->val[OPT_TL_X].w - handler->x_range1.min), + 300.0); + if (handler->y_range1.min == handler->val[OPT_TL_X].w) + handler->scanner->caps[handler->scanner->source].pos_y = 0; + else + handler->scanner->caps[handler->scanner->source].pos_y = + MM_TO_PIXEL((handler->val[OPT_TL_Y].w - handler->y_range1.min), + 300.0); + DBG(10, "Calculate Size Image [%dx%d|%dx%d]\n", + handler->scanner->caps[handler->scanner->source].pos_x, + handler->scanner->caps[handler->scanner->source].pos_y, + handler->scanner->caps[handler->scanner->source].width, + handler->scanner->caps[handler->scanner->source].height); + if (!handler->scanner->caps[handler->scanner->source].default_color) { + DBG (10, "Default Color allocation failure.\n"); + return (SANE_STATUS_NO_MEM); + } + handler->result = escl_newjob(handler->scanner, handler->device, &status); + if (status != SANE_STATUS_GOOD) + return (status); } else { - handler->scanner->default_resolution = handler->val[OPT_RESOLUTION].w; - if (!strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3)) - handler->scanner->default_color = strdup("Grayscale8"); - else - handler->scanner->default_color = strdup("RGB24"); + SANE_Status job = SANE_STATUS_UNSUPPORTED; + SANE_Status st = escl_status(handler->device, + handler->scanner->source, + handler->result, + &job); + DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st)); + if (_go_next_page(st, job) != SANE_STATUS_GOOD) + { + handler->scanner->work = SANE_FALSE; + return SANE_STATUS_NO_DOCS; + } } - handler->result = escl_newjob(handler->scanner, handler->name, &status); + status = escl_scan(handler->scanner, handler->device, handler->result); if (status != SANE_STATUS_GOOD) - return (status); - status = escl_scan(handler->scanner, handler->name, handler->result); - if (status != SANE_STATUS_GOOD) - return (status); - if (!strcmp(handler->scanner->default_format, "image/jpeg")) + return (status); + if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/jpeg")) { status = get_JPEG_data(handler->scanner, &w, &he, &bps); } - else if (!strcmp(handler->scanner->default_format, "image/png")) + else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/png")) { status = get_PNG_data(handler->scanner, &w, &he, &bps); } - else if (!strcmp(handler->scanner->default_format, "image/tiff")) + else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/tiff")) { status = get_TIFF_data(handler->scanner, &w, &he, &bps); } - else - return SANE_STATUS_INVAL; + else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "application/pdf")) + { + status = get_PDF_data(handler->scanner, &w, &he, &bps); + } + else { + DBG(10, "Unknow image format\n"); + return SANE_STATUS_INVAL; + } + + DBG(10, "2-Size Image (%ld)[%dx%d|%dx%d]\n", handler->scanner->img_size, 0, 0, w, he); if (status != SANE_STATUS_GOOD) - return (status); + return (status); handler->ps.depth = 8; handler->ps.pixels_per_line = w; handler->ps.lines = he; handler->ps.bytes_per_line = w * bps; handler->ps.last_frame = SANE_TRUE; handler->ps.format = SANE_FRAME_RGB; + handler->scanner->work = SANE_FALSE; +// DBG(10, "NEXT Frame [%s]\n", (handler->ps.last_frame ? "Non" : "Oui")); + DBG(10, "Real Size Image [%dx%d|%dx%d]\n", 0, 0, w, he); return (status); } @@ -700,7 +1143,7 @@ sane_get_parameters(SANE_Handle h, SANE_Parameters *p) return (status); if (p != NULL) { p->depth = 8; - p->last_frame = SANE_TRUE; + p->last_frame = handler->ps.last_frame; p->format = SANE_FRAME_RGB; p->pixels_per_line = handler->ps.pixels_per_line; p->lines = handler->ps.lines; @@ -729,6 +1172,7 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) if (!handler | !buf | !len) return (SANE_STATUS_INVAL); + if (handler->cancel) return (SANE_STATUS_CANCELLED); if (!handler->write_scan_data) @@ -756,10 +1200,23 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) } } else { + SANE_Status job = SANE_STATUS_UNSUPPORTED; *len = 0; free(handler->scanner->img_data); handler->scanner->img_data = NULL; - return (SANE_STATUS_EOF); + if (handler->scanner->source != PLATEN) { + SANE_Bool next_page = SANE_FALSE; + SANE_Status st = escl_status(handler->device, + handler->scanner->source, + handler->result, + &job); + DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st)); + if (_go_next_page(st, job) == SANE_STATUS_GOOD) + next_page = SANE_TRUE; + handler->scanner->work = SANE_TRUE; + handler->ps.last_frame = !next_page; + } + return SANE_STATUS_EOF; } return (SANE_STATUS_GOOD); } @@ -775,3 +1232,39 @@ sane_set_io_mode(SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ n { return (SANE_STATUS_UNSUPPORTED); } + +/** + * \fn void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path) + * \brief Uses the device info in 'device' and the path from 'path' to construct + * a full URL. Sets this URL and any necessary connection options into + * 'handle'. + */ +void +escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path) +{ + int url_len; + char *url; + + url_len = snprintf(NULL, 0, "%s://%s:%d%s", + (device->https ? "https" : "http"), device->ip_address, + device->port_nb, path); + url_len++; + url = (char *)malloc(url_len); + snprintf(url, url_len, "%s://%s:%d%s", + (device->https ? "https" : "http"), device->ip_address, + device->port_nb, path); + + DBG( 1, "escl_curl_url: URL: %s\n", url ); + curl_easy_setopt(handle, CURLOPT_URL, url); + free(url); + if (device->https) { + DBG( 1, "Ignoring safety certificates, use https\n"); + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + if (device->unix_socket != NULL) { + DBG( 1, "Using local socket %s\n", device->unix_socket ); + curl_easy_setopt(handle, CURLOPT_UNIX_SOCKET_PATH, + device->unix_socket); + } +} |