From 302276dc1b90cfc972fb726ca94a23b18f4b0088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Tue, 1 Feb 2022 15:24:35 +0100 Subject: New upstream version 1.1.1 --- backend/escl/escl.c | 45 ++++++++++++++-- backend/escl/escl.h | 4 ++ backend/escl/escl_capabilities.c | 111 +++++++++++++++++++++++++++++++++++++-- backend/escl/escl_devices.c | 10 +++- backend/escl/escl_jpeg.c | 53 +++++++++++-------- backend/escl/escl_newjob.c | 12 +++++ backend/escl/escl_reset.c | 10 ++-- backend/escl/escl_scan.c | 10 ++-- backend/escl/escl_status.c | 2 + 9 files changed, 216 insertions(+), 41 deletions(-) (limited to 'backend/escl') diff --git a/backend/escl/escl.c b/backend/escl/escl.c index bb62219..5f02ec8 100644 --- a/backend/escl/escl.c +++ b/backend/escl/escl.c @@ -432,7 +432,8 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line, int port = 0; SANE_Status status; static ESCL_Device *escl_device = NULL; - + if (*line == '#') return SANE_STATUS_GOOD; + if (!strncmp(line, "pdfblacklist", 12)) return SANE_STATUS_GOOD; if (strncmp(line, "device", 6) == 0) { char *name_str = NULL; char *opt_model = NULL; @@ -1135,6 +1136,37 @@ finish_hack: fclose(fp); } +static char* +_get_blacklist_pdf(void) +{ + FILE *fp; + char *blacklist = NULL; + SANE_Char line[PATH_MAX]; + + /* open configuration file */ + fp = sanei_config_open (ESCL_CONFIG_FILE); + if (!fp) + { + DBG (2, "_get_blacklit: couldn't access %s\n", ESCL_CONFIG_FILE); + DBG (3, "_get_blacklist: exit\n"); + } + + /* loop reading the configuration file, all line beginning by "option " are + * parsed for value to store in configuration structure, other line are + * used are device to try to attach + */ + while (sanei_config_read (line, PATH_MAX, fp)) + { + if (!strncmp(line, "pdfblacklist", 12)) { + blacklist = strdup(line); + goto finish_; + } + } +finish_: + DBG (3, "_get_blacklist_pdf: finish\n"); + fclose(fp); + return blacklist; +} /** @@ -1149,6 +1181,7 @@ finish_hack: SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h) { + char *blacklist = NULL; DBG (10, "escl sane_open\n"); SANE_Status status; escl_sane_t *handler = NULL; @@ -1173,7 +1206,8 @@ sane_open(SANE_String_Const name, SANE_Handle *h) return (SANE_STATUS_NO_MEM); } handler->device = device; // Handler owns device now. - handler->scanner = escl_capabilities(device, &status); + blacklist = _get_blacklist_pdf(); + handler->scanner = escl_capabilities(device, blacklist, &status); if (status != SANE_STATUS_GOOD) { escl_free_handler(handler); return (status); @@ -1222,9 +1256,11 @@ sane_cancel(SANE_Handle h) } handler->scanner->work = SANE_FALSE; handler->cancel = SANE_TRUE; - escl_scanner(handler->device, handler->result); + escl_scanner(handler->device, handler->scanner->scanJob, handler->result); free(handler->result); handler->result = NULL; + free(handler->scanner->scanJob); + handler->scanner->scanJob = NULL; } /** @@ -1381,6 +1417,7 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int break; case OPT_RESOLUTION: handler->val[n].w = _get_resolution(handler, (int)(*(SANE_Word *) v)); + handler->scanner->caps[handler->scanner->source].default_resolution = handler->val[n].w; if (i) *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; break; @@ -1591,7 +1628,7 @@ sane_start(SANE_Handle h) return SANE_STATUS_NO_DOCS; } } - status = escl_scan(handler->scanner, handler->device, handler->result); + status = escl_scan(handler->scanner, handler->device, handler->scanner->scanJob, handler->result); if (status != SANE_STATUS_GOOD) return (status); if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/jpeg")) diff --git a/backend/escl/escl.h b/backend/escl/escl.h index 67b11c7..142b4b4 100644 --- a/backend/escl/escl.h +++ b/backend/escl/escl.h @@ -156,6 +156,7 @@ typedef struct capabilities SANE_String_Const *Sources; int SourcesSize; FILE *tmp; + char *scanJob; unsigned char *img_data; long img_size; long img_read; @@ -230,6 +231,7 @@ SANE_Status escl_status(const ESCL_Device *device, SANE_Status *job); capabilities_t *escl_capabilities(ESCL_Device *device, + char *blacklist, SANE_Status *status); char *escl_newjob(capabilities_t *scanner, @@ -238,9 +240,11 @@ char *escl_newjob(capabilities_t *scanner, SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device, + char *scanJob, char *result); void escl_scanner(const ESCL_Device *device, + char *scanJob, char *result); typedef void CURL; diff --git a/backend/escl/escl_capabilities.c b/backend/escl/escl_capabilities.c index db194f9..7422896 100644 --- a/backend/escl/escl_capabilities.c +++ b/backend/escl/escl_capabilities.c @@ -40,6 +40,25 @@ struct cap size_t size; }; +static size_t +header_callback(void *str, size_t size, size_t nmemb, void *userp) +{ + struct cap *header = (struct cap *)userp; + size_t realsize = size * nmemb; + char *content = realloc(header->memory, header->size + realsize + 1); + + if (content == NULL) { + DBG( 1, "Not enough memory (realloc returned NULL)\n"); + return (0); + } + header->memory = content; + memcpy(&(header->memory[header->size]), str, realsize); + header->size = header->size + realsize; + header->memory[header->size] = 0; + return (realsize); +} + + /** * \fn static SANE_String_Const convert_elements(SANE_String_Const str) * \brief Function that converts the 'color modes' of the scanner (color/gray) to be understood by SANE. @@ -182,10 +201,10 @@ find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner, int type) { const char *name = (const char *)node->name; if (strcmp(name, "ColorMode") == 0) { - const char *color = (SANE_String_Const)xmlNodeGetContent(node); - if (type == PLATEN || strcmp(color, "BlackAndWhite1")) + const char *color = (SANE_String_Const)xmlNodeGetContent(node); + if (type == PLATEN || strcmp(color, "BlackAndWhite1")) scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, &scanner->caps[type].ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1); - } + } else if (strcmp(name, "ContentType") == 0) scanner->caps[type].ContentTypes = char_to_array(scanner->caps[type].ContentTypes, &scanner->caps[type].ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0); else if (strcmp(name, "DocumentFormat") == 0) @@ -385,6 +404,16 @@ find_true_variables(xmlNode *node, capabilities_t *scanner, int type) return (0); } +static char* +replace_char(char* str, char find, char replace){ + char *current_pos = strchr(str,find); + while (current_pos) { + *current_pos = replace; + current_pos = strchr(current_pos,find); + } + return str; +} + /** * \fn static int print_xml_c(xmlNode *node, capabilities_t *scanner) * \brief Function that browses the xml file, node by node. @@ -454,6 +483,37 @@ _reduce_color_modes(capabilities_t *scanner) } } +static void +_delete_pdf(capabilities_t *scanner) +{ + int type = 0; + for (type = 0; type < 3; type++) { + if (scanner->caps[type].ColorModesSize) { + if (scanner->caps[type].default_format) { + scanner->caps[type].have_pdf = -1; + if (!strcmp(scanner->caps[type].default_format, "application/pdf")) { + free(scanner->caps[type].default_format); + if (scanner->caps[type].have_tiff > -1) + scanner->caps[type].default_format = strdup("image/tiff"); + else if (scanner->caps[type].have_png > -1) + scanner->caps[type].default_format = strdup("image/png"); + else if (scanner->caps[type].have_jpeg > -1) + scanner->caps[type].default_format = strdup("image/jpeg"); + } + free(scanner->caps[type].ColorModes); + scanner->caps[type].ColorModes = NULL; + scanner->caps[type].ColorModesSize = 0; + scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, + &scanner->caps[type].ColorModesSize, + (SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0); + scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, + &scanner->caps[type].ColorModesSize, + (SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0); + } + } + } +} + /** * \fn capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status) * \brief Function that finally recovers all the capabilities of the scanner, using curl. @@ -463,15 +523,17 @@ _reduce_color_modes(capabilities_t *scanner) * \return scanner (the structure that stocks all the capabilities elements) */ capabilities_t * -escl_capabilities(ESCL_Device *device, SANE_Status *status) +escl_capabilities(ESCL_Device *device, char *blacklist, SANE_Status *status) { capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t)); CURL *curl_handle = NULL; struct cap *var = NULL; + struct cap *header = NULL; xmlDoc *data = NULL; xmlNode *node = NULL; int i = 0; const char *scanner_capabilities = "/eSCL/ScannerCapabilities"; + SANE_Bool use_pdf = SANE_TRUE; *status = SANE_STATUS_GOOD; if (device == NULL) @@ -481,11 +543,22 @@ escl_capabilities(ESCL_Device *device, SANE_Status *status) *status = SANE_STATUS_NO_MEM; var->memory = malloc(1); var->size = 0; + header = (struct cap *)calloc(1, sizeof(struct cap)); + if (header == NULL) + *status = SANE_STATUS_NO_MEM; + header->memory = malloc(1); + header->size = 0; curl_handle = curl_easy_init(); escl_curl_url(curl_handle, device, scanner_capabilities); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)header); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); CURLcode res = curl_easy_perform(curl_handle); + if (res == CURLE_OK) + DBG( 1, "Create NewJob : the scanner header responded : [%s]\n", header->memory); if (res != CURLE_OK) { DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res)); *status = SANE_STATUS_INVAL; @@ -503,18 +576,46 @@ escl_capabilities(ESCL_Device *device, SANE_Status *status) goto clean; } + if (device->hack && + header && + header->memory && + strstr(header->memory, "Server: HP_Compact_Server")) + device->hack = curl_slist_append(NULL, "Host: localhost"); + scanner->source = 0; scanner->Sources = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * 4); for (i = 0; i < 4; i++) scanner->Sources[i] = NULL; print_xml_c(node, device, scanner, -1); - _reduce_color_modes(scanner); + DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") ); + if (device->model_name != NULL) { + if (strcasestr(device->model_name, "MFC-J985DW")) { + DBG (3, "blacklist_pdf: device not support PDF\n"); + use_pdf = SANE_FALSE; + } + else if (blacklist) { + char *model = strdup(device->model_name); + replace_char(model, ' ', '_'); + if (strcasestr(blacklist, model)) { + use_pdf = SANE_FALSE; + } + free(model); + } + } + DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") ); + if (use_pdf) + _reduce_color_modes(scanner); + else + _delete_pdf(scanner); clean: xmlFreeDoc(data); clean_data: xmlCleanupParser(); xmlMemoryDump(); curl_easy_cleanup(curl_handle); + if (header) + free(header->memory); + free(header); if (var) free(var->memory); free(var); diff --git a/backend/escl/escl_devices.c b/backend/escl/escl_devices.c index 3ca28de..92e064b 100644 --- a/backend/escl/escl_devices.c +++ b/backend/escl/escl_devices.c @@ -74,6 +74,7 @@ resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interfac avahi_address_snprint(a, sizeof(a), address); t = avahi_string_list_to_string(txt); if (strstr(t, "\"rs=eSCL\"") || strstr(t, "\"rs=/eSCL\"")) { + char ip_add[PATH_MAX] = {0}; s = avahi_string_list_find(txt, "is"); if (s && s->size > 3) is = (const char*)s->text + 3; @@ -84,7 +85,14 @@ resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interfac uuid = (const char*)s->text + 5; else uuid = (const char*)NULL; - escl_device_add(port, name, a, is, uuid, (char*)type); + DBG (10, "resolve_callback [%s]\n", a); + if (strstr(a, "127.0.0.1") != NULL) { + snprintf(ip_add, sizeof(ip_add), "%s", "localhost"); + DBG (10,"resolve_callback fix redirect [localhost]\n"); + } + else + snprintf(ip_add, sizeof(ip_add), "%s", a); + escl_device_add(port, name, ip_add, is, uuid, (char*)type); } } } diff --git a/backend/escl/escl_jpeg.c b/backend/escl/escl_jpeg.c index 651e7c5..1dd3ec9 100644 --- a/backend/escl/escl_jpeg.c +++ b/backend/escl/escl_jpeg.c @@ -192,34 +192,41 @@ get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps) cinfo.out_color_space = JCS_RGB; cinfo.quantize_colors = FALSE; jpeg_calc_output_dimensions(&cinfo); - if (cinfo.output_width < (unsigned int)scanner->caps[scanner->source].width) - scanner->caps[scanner->source].width = cinfo.output_width; - if (scanner->caps[scanner->source].pos_x < 0) - scanner->caps[scanner->source].pos_x = 0; - - if (cinfo.output_height < (unsigned int)scanner->caps[scanner->source].height) - scanner->caps[scanner->source].height = cinfo.output_height; - if (scanner->caps[scanner->source].pos_y < 0) - scanner->caps[scanner->source].pos_y = 0; + double ratio = (double)cinfo.output_width / (double)scanner->caps[scanner->source].width; + int rw = (int)((double)scanner->caps[scanner->source].width * ratio); + int rh = (int)((double)scanner->caps[scanner->source].height * ratio); + int rx = (int)((double)scanner->caps[scanner->source].pos_x * ratio); + int ry = (int)((double)scanner->caps[scanner->source].pos_y * ratio); + + + if (cinfo.output_width < (unsigned int)rw) + rw = cinfo.output_width; + if (rx < 0) + rx = 0; + + if (cinfo.output_height < (unsigned int)rh) + rh = cinfo.output_height; + if (ry < 0) + ry = 0; DBG(10, "1-JPEF Geometry [%dx%d|%dx%d]\n", - scanner->caps[scanner->source].pos_x, - scanner->caps[scanner->source].pos_y, - scanner->caps[scanner->source].width, - scanner->caps[scanner->source].height); - x_off = scanner->caps[scanner->source].pos_x; - if (x_off > (unsigned int)scanner->caps[scanner->source].width) { - w = scanner->caps[scanner->source].width; + rx, + ry, + rw, + rh); + x_off = rx; + if (x_off > (unsigned int)rw) { + w = rw; x_off = 0; } else - w = scanner->caps[scanner->source].width - x_off; - y_off = scanner->caps[scanner->source].pos_y; - if(y_off > (unsigned int)scanner->caps[scanner->source].height) { - h = scanner->caps[scanner->source].height; + w = rw - x_off; + y_off = ry; + if(y_off > (unsigned int)rh) { + h = rh; y_off = 0; } else - h = scanner->caps[scanner->source].height - y_off; + h = rh - y_off; DBG(10, "2-JPEF Geometry [%dx%d|%dx%d]\n", x_off, y_off, @@ -242,7 +249,7 @@ get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps) if (y_off > 0) jpeg_skip_scanlines(&cinfo, y_off); pos = 0; - while (cinfo.output_scanline < (unsigned int)scanner->caps[scanner->source].height) { + while (cinfo.output_scanline < (unsigned int)rh) { rowptr[0] = (JSAMPROW)surface + (lineSize * pos); // ..cinfo.output_scanline); jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); pos++; @@ -253,7 +260,7 @@ get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps) *width = w; *height = h; *bps = cinfo.output_components; - jpeg_finish_decompress(&cinfo); + // jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(scanner->tmp); scanner->tmp = NULL; diff --git a/backend/escl/escl_newjob.c b/backend/escl/escl_newjob.c index 24bfbc9..98a953f 100644 --- a/backend/escl/escl_newjob.c +++ b/backend/escl/escl_newjob.c @@ -277,6 +277,8 @@ wake_up_device: 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); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); CURLcode res = curl_easy_perform(curl_handle); if (res != CURLE_OK) { DBG( 1, "Create NewJob : the scanner responded incorrectly: %s\n", curl_easy_strerror(res)); @@ -296,7 +298,17 @@ wake_up_device: result = strdup(location); DBG( 1, "Create NewJob : %s\n", result); *temporary = '\n'; + *location = '\0'; + location = strrchr(tmp_location,'/'); wakup_count = 0; + if (location) { + location++; + scanner->scanJob = strdup(location); + DBG( 1, "Full location header [%s]\n", scanner->scanJob); + } + else + scanner->scanJob = strdup("ScanJobs"); + *location = '/'; } } if (result == NULL) { diff --git a/backend/escl/escl_reset.c b/backend/escl/escl_reset.c index 7494dda..95e3f2d 100644 --- a/backend/escl/escl_reset.c +++ b/backend/escl/escl_reset.c @@ -44,10 +44,10 @@ write_callback(void __sane_unused__*str, * This function is called in the 'sane_cancel' function. */ void -escl_scanner(const ESCL_Device *device, char *result) +escl_scanner(const ESCL_Device *device, char *scanJob, char *result) { CURL *curl_handle = NULL; - const char *scan_jobs = "/eSCL/ScanJobs"; + const char *scan_jobs = "/eSCL/"; const char *scanner_start = "/NextDocument"; char scan_cmd[PATH_MAX] = { 0 }; int i = 0; @@ -58,10 +58,12 @@ escl_scanner(const ESCL_Device *device, char *result) CURL_CALL: curl_handle = curl_easy_init(); if (curl_handle != NULL) { - snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s", - scan_jobs, result, scanner_start); + snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s%s", + scan_jobs, scanJob, result, scanner_start); escl_curl_url(curl_handle, device, scan_cmd); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); if (curl_easy_perform(curl_handle) == CURLE_OK) { curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &answer); i++; diff --git a/backend/escl/escl_scan.c b/backend/escl/escl_scan.c index 53bd438..3350c83 100644 --- a/backend/escl/escl_scan.c +++ b/backend/escl/escl_scan.c @@ -57,10 +57,10 @@ write_callback(void *str, size_t size, size_t nmemb, void *userp) * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) */ SANE_Status -escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result) +escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *scanJob, char *result) { CURL *curl_handle = NULL; - const char *scan_jobs = "/eSCL/ScanJobs"; + const char *scan_jobs = "/eSCL/"; const char *scanner_start = "/NextDocument"; char scan_cmd[PATH_MAX] = { 0 }; SANE_Status status = SANE_STATUS_GOOD; @@ -70,10 +70,12 @@ escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result) scanner->real_read = 0; curl_handle = curl_easy_init(); if (curl_handle != NULL) { - snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s", - scan_jobs, result, scanner_start); + snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s%s", + scan_jobs, scanJob, result, scanner_start); escl_curl_url(curl_handle, device, scan_cmd); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); if (scanner->tmp) fclose(scanner->tmp); scanner->tmp = tmpfile(); diff --git a/backend/escl/escl_status.c b/backend/escl/escl_status.c index a68f6ea..1f848a2 100644 --- a/backend/escl/escl_status.c +++ b/backend/escl/escl_status.c @@ -220,6 +220,8 @@ reload: escl_curl_url(curl_handle, device, scanner_status); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); CURLcode res = curl_easy_perform(curl_handle); if (res != CURLE_OK) { DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res)); -- cgit v1.2.3