diff options
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); +    } +}  | 
