SANE_Status tcp_dev_open (struct device *dev) { SANE_Status status; char* strhost; char* strport; int port; struct servent *sp; struct timeval tv; SANE_String_Const devname; devname = dev->sane.name; DBG (3, "%s: open %s\n", __FUNCTION__, devname); if (strncmp (devname, "tcp", 3) != 0) return SANE_STATUS_INVAL; devname += 3; devname = sanei_config_skip_whitespace (devname); if (!*devname) return SANE_STATUS_INVAL; devname = sanei_config_get_string (devname, &strhost); devname = sanei_config_skip_whitespace (devname); if (*devname) devname = sanei_config_get_string (devname, &strport); else strport = "9400"; if (isdigit(*strport)) { port = atoi(strport); } else { if ((sp = getservbyname(strport, "tcp"))) { port = ntohs(sp->s_port); } else { DBG (1, "%s: unknown TCP service %s\n", __FUNCTION__, strport); return SANE_STATUS_IO_ERROR; } } status = sanei_tcp_open(strhost, port, &dev->dn); if (status == SANE_STATUS_GOOD) { tv.tv_sec = RECV_TIMEOUT; tv.tv_usec = 0; if (setsockopt (dev->dn, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { DBG(1, "%s: setsockopts %s", __FUNCTION__, strerror(errno)); } } return status; }
const char * sanei_config_get_string (const char *str, char **string_const) { const char *start; size_t len; str = sanei_config_skip_whitespace (str); if (*str == '"') { start = ++str; while (*str && *str != '"') ++str; len = str - start; if (*str == '"') ++str; else start = 0; /* final double quote is missing */ } else { start = str; while (*str && !isspace (*str)) ++str; len = str - start; } if (start) *string_const = strndup (start, len); else *string_const = 0; return str; }
SANE_Status sane_init( SANE_Int *versionP, SANE_Auth_Callback authorize ) { FILE *fp; SANE_Status status; DBG_INIT(); DBG(DCODE, "sane_init: version %s null, authorize %s null\n", (versionP) ? "!=" : "==", (authorize) ? "!=" : "=="); if( versionP != NULL ) *versionP = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, V_MINOR, 0); status = SANE_STATUS_GOOD; if( (fp = sanei_config_open(ST400_CONFIG_FILE)) != NULL ) { char line[PATH_MAX], *str; size_t len, linenum; linenum = 0; DBG(DCODE, "sane_init: reading config file\n"); while( sanei_config_read(line, sizeof(line), fp) ) { ++linenum; str = line; if( str[0] == '#' ) continue; /* ignore comments */ str = (char *)sanei_config_skip_whitespace(str); len = strlen(str); if( !len ) continue; /* ignore empty lines */ if( strncmp(str, "option", 6) == 0 && isspace(str[6]) ) { DBG(DCODE, "sane_init: config line <%s>\n", line); status = st400_config_do_option(str+7, linenum); } else { DBG(DCODE, "sane_init: attaching device <%s>\n", line); sanei_config_attach_matching_devices(line, st400_attach_one); } if( status != SANE_STATUS_GOOD ) break; } DBG(DCODE, "sane_init: closing config file\n"); fclose(fp); } if( status == SANE_STATUS_GOOD && st400_devices == NULL ) { DBG(DCODE, "sane_init: attaching default device <%s>\n", ST400_DEFAULT_DEVICE); sanei_config_attach_matching_devices(ST400_DEFAULT_DEVICE, st400_attach_one); } return status; }
static SANE_Status st400_config_get_arg(char **optP, unsigned long *argP, size_t linenum) { int n; linenum = linenum; /* silence compilation warnings */ if( sscanf(*optP, "%lu%n", argP, &n) == 1 ) { *optP += n; *optP = (char *)sanei_config_skip_whitespace(*optP); return SANE_STATUS_GOOD; } return SANE_STATUS_INVAL; }
static SANE_Status st400_config_get_single_arg(char *opt, unsigned long *argP, size_t linenum) { int n; if( sscanf(opt, "%lu%n", argP, &n) == 1 ) { opt += n; opt = (char *)sanei_config_skip_whitespace(opt); if( *opt == '\0' ) return SANE_STATUS_GOOD; else { DBG(DERR, "extraneous arguments at line %lu: %s\n", (u_long)linenum, opt); return SANE_STATUS_INVAL; } } DBG(DERR, "invalid option argument at line %lu: %s\n", (u_long)linenum, opt); return SANE_STATUS_INVAL; }
/* * Called by SANE to find out about supported devices. * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a * pointer to a NULL terminated array of pointers to SANE_Device * structures in *device_list. The returned list is guaranteed to * remain unchanged and valid until (a) another call to this function * is performed or (b) a call to sane_exit() is performed. This * function can be called repeatedly to detect when new devices become * available. If argument local_only is true, only local devices are * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and * undesirable to call this function first. * * Read the config file, find scanners with help from sanei_* * store in global device structs */ SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) { struct scanner *dev; char line[PATH_MAX]; const char *lp; FILE *fp; int num_devices=0; int i=0; local_only = local_only; /* get rid of compiler warning */ DBG (10, "sane_get_devices: start\n"); global_has_cal_buffer = 1; global_lines_per_block = 16; fp = sanei_config_open (CONFIG_FILE); if (fp) { DBG (15, "sane_get_devices: reading config file %s\n", CONFIG_FILE); while (sanei_config_read (line, PATH_MAX, fp)) { lp = line; /* ignore comments */ if (*lp == '#') continue; /* skip empty lines */ if (*lp == 0) continue; if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { DBG (15, "sane_get_devices: looking for '%s'\n", lp); sanei_usb_attach_matching_devices(lp, attach_one); } else if (!strncmp(lp, "has_cal_buffer", 14) && isspace (lp[14])) { int buf; lp += 14; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); if(buf){ global_has_cal_buffer = 1; } else{ global_has_cal_buffer = 0; } DBG (15, "sane_get_devices: setting \"has_cal_buffer\" to %d\n", global_has_cal_buffer); } else if (!strncmp(lp, "lines_per_block", 15) && isspace (lp[15])) { int buf; lp += 15; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); if(buf < 1 || buf > 32){ DBG (15, "sane_get_devices: \"lines_per_block\"=%d\n out of range", buf ); continue; } DBG (15, "sane_get_devices: \"lines_per_block\" is %d\n", buf); global_lines_per_block = buf; } else{ DBG (5, "sane_get_devices: config line \"%s\" ignored.\n", lp); } } fclose (fp); } else { DBG (5, "sane_get_devices: no config file '%s', using defaults\n", CONFIG_FILE); DBG (15, "sane_get_devices: looking for 'usb 0x08F0 0x0005'\n"); sanei_usb_attach_matching_devices("usb 0x08F0 0x0005", attach_one); } for (dev = scanner_devList; dev; dev=dev->next) { DBG (15, "sane_get_devices: found scanner %s\n",dev->device_name); num_devices++; } DBG (15, "sane_get_devices: found %d scanner(s)\n",num_devices); sane_devArray = calloc (num_devices + 1, sizeof (SANE_Device*)); if (!sane_devArray) return SANE_STATUS_NO_MEM; for (dev = scanner_devList; dev; dev=dev->next) { sane_devArray[i++] = (SANE_Device *)&dev->sane; } sane_devArray[i] = 0; *device_list = sane_devArray; DBG (10, "sane_get_devices: finish\n"); return SANE_STATUS_GOOD; }
static SANE_Status st400_config_do_option(char *opt, size_t linenum) { unsigned long arg; SANE_Status status; int i; status = SANE_STATUS_GOOD; opt = (char *)sanei_config_skip_whitespace(opt); if( strncmp(opt, "maxread", 7) == 0 && isspace(opt[7]) ) { opt += 8; status = st400_config_get_single_arg(opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) { if( arg == 0 ) st400_maxread = sanei_scsi_max_request_size; else st400_maxread = (size_t)arg; } } else if( strncmp(opt, "delay", 5) == 0 && isspace(opt[5]) ) { opt += 6; status = st400_config_get_single_arg(opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) st400_light_delay = (size_t)arg; } else if( strncmp(opt, "scanner_bufsize", 15) == 0 && isspace(opt[15]) ) { opt += 16; status = st400_config_get_single_arg(opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) if( st400_devices ) st400_devices->model->bufsize = arg; /* FIXME: changes bufsize for all scanners of this model! */ } else if( strncmp(opt, "scanner_bits", 12) == 0 && isspace(opt[12]) ) { opt += 13; status = st400_config_get_single_arg(opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) if( st400_devices ) st400_devices->model->bits = arg; /* FIXME */ } else if( strncmp(opt, "scanner_maxread", 15) == 0 && isspace(opt[15]) ) { opt += 16; status = st400_config_get_single_arg(opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) if( st400_devices ) st400_devices->model->maxread = arg; /* FIXME */ } else if( strncmp(opt, "scanner_resolutions", 19) == 0 && isspace(opt[19]) ) { opt += 20; st400_devices->model->dpi_list = malloc(16 * sizeof(SANE_Int)); i = 0; do { status = st400_config_get_arg(&opt, &arg, linenum); if( status == SANE_STATUS_GOOD ) { ++i; st400_devices->model->dpi_list[i] = (SANE_Int)arg; } } while( status == SANE_STATUS_GOOD && i < 15 ); st400_devices->model->dpi_list[0] = i; DBG(DINFO, "%d entries for resolution\n", i); status = SANE_STATUS_GOOD; } else if( strncmp(opt, "dump_inquiry", 12) == 0 ) { st400_dump_data = 1; } if( st400_devices ) st400_reset_options(st400_devices); return status; }
static void add_alias (char *line) { const char *command; enum { CMD_ALIAS, CMD_HIDE } cmd; const char *oldname, *oldend, *newname, *newend; size_t oldlen, newlen; struct alias *alias; command = sanei_config_skip_whitespace(line); if( !*command ) return; line = strpbrk(command, " \t"); if( !line ) return; *line++ = '\0'; if( strcmp(command, "alias") == 0 ) cmd = CMD_ALIAS; else if( strcmp(command, "hide") == 0 ) cmd = CMD_HIDE; else return; newlen = 0; newname = NULL; if( cmd == CMD_ALIAS ) { newname = sanei_config_skip_whitespace(line); if( !*newname ) return; if( *newname == '\"' ) { ++newname; newend = strchr(newname, '\"'); } else newend = strpbrk(newname, " \t"); if( !newend ) return; newlen = newend - newname; line = (char*)(newend+1); } oldname = sanei_config_skip_whitespace(line); if( !*oldname ) return; oldend = oldname + strcspn(oldname, " \t"); oldlen = oldend - oldname; alias = malloc(sizeof(struct alias)); if( alias ) { alias->oldname = malloc(oldlen + newlen + 2); if( alias->oldname ) { strncpy(alias->oldname, oldname, oldlen); alias->oldname[oldlen] = '\0'; if( cmd == CMD_ALIAS ) { alias->newname = alias->oldname + oldlen + 1; strncpy(alias->newname, newname, newlen); alias->newname[newlen] = '\0'; } else alias->newname = NULL; alias->next = first_alias; first_alias = alias; return; } free(alias); } return; }
SANE_Status sanei_configure_attach (const char *config_file, SANEI_Config * config, SANE_Status (*attach) (SANEI_Config * config, const char *devname)) { SANE_Char line[PATH_MAX]; SANE_Char *token, *string; SANE_Int len; const char *lp, *lp2; FILE *fp; SANE_Status status = SANE_STATUS_GOOD; int i, j, count; void *value = NULL; int size=0; SANE_Bool found; SANE_Word *wa; SANE_Bool *ba; DBG (3, "sanei_configure_attach: start\n"); /* open configuration file */ fp = sanei_config_open (config_file); if (!fp) { DBG (2, "sanei_configure_attach: couldn't access %s\n", config_file); DBG (3, "sanei_configure_attach: exit\n"); return SANE_STATUS_ACCESS_DENIED; } /* 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) && status == SANE_STATUS_GOOD) { /* skip white spaces at beginning of line */ lp = sanei_config_skip_whitespace (line); /* skip empty lines */ if (*lp == 0) continue; /* skip comment line */ if (line[0] == '#') continue; len = strlen (line); /* delete newline characters at end */ if (line[len - 1] == '\n') line[--len] = '\0'; lp2 = lp; /* to ensure maximum compatibility, we accept line like: * option "option_name" "option_value" * "option_name" "option_value" * So we parse the line 2 time to find an option */ /* check if it is an option */ lp = sanei_config_get_string (lp, &token); if (strncmp (token, "option", 6) == 0) { /* skip the "option" token */ free (token); lp = sanei_config_get_string (lp, &token); } /* search for a matching descriptor */ i = 0; found = SANE_FALSE; while (config!=NULL && i < config->count && !found) { if (strcmp (config->descriptors[i]->name, token) == 0) { found = SANE_TRUE; switch (config->descriptors[i]->type) { case SANE_TYPE_INT: size=config->descriptors[i]->size; value = malloc (size); wa = (SANE_Word *) value; count = config->descriptors[i]->size / sizeof (SANE_Word); for (j = 0; j < count; j++) { lp = sanei_config_get_string (lp, &string); if (string == NULL) { DBG (2, "sanei_configure_attach: couldn't find a string to parse"); return SANE_STATUS_INVAL; } wa[j] = strtol (string, NULL, 0); free (string); } break; case SANE_TYPE_BOOL: size=config->descriptors[i]->size; value = malloc (size); ba = (SANE_Bool *) value; count = config->descriptors[i]->size / sizeof (SANE_Bool); for (j = 0; j < count; j++) { lp = sanei_config_get_string (lp, &string); if (string == NULL) { DBG (2, "sanei_configure_attach: couldn't find a string to parse"); return SANE_STATUS_INVAL; } if ((strcmp (string, "1") == 0) || (strcmp (string, "true") == 0)) { ba[j] = SANE_TRUE; } else { if ((strcmp (string, "0") == 0) || (strcmp (string, "false") == 0)) ba[j] = SANE_FALSE; else { DBG (2, "sanei_configure_attach: couldn't find a valid boolean value"); return SANE_STATUS_INVAL; } } free (string); } break; case SANE_TYPE_FIXED: size=config->descriptors[i]->size; value = malloc (size); wa = (SANE_Word *) value; count = config->descriptors[i]->size / sizeof (SANE_Word); for (j = 0; j < count; j++) { lp = sanei_config_get_string (lp, &string); if (string == NULL) { DBG (2, "sanei_configure_attach: couldn't find a string to parse"); return SANE_STATUS_INVAL; } wa[j] = SANE_FIX(strtod (string, NULL)); free (string); } break; case SANE_TYPE_STRING: sanei_config_get_string (lp, &string); if (string == NULL) { DBG (2, "sanei_configure_attach: couldn't find a string value to parse"); return SANE_STATUS_INVAL; } value = string; size=strlen(string)+1; if(size>config->descriptors[i]->size) { size=config->descriptors[i]->size-1; string[size]=0; } break; default: DBG (1, "sanei_configure_attach: incorrect type %d for option %s, skipping option ...\n", config->descriptors[i]->type, config->descriptors[i]->name); } /* check decoded value */ status = sanei_check_value (config->descriptors[i], value); /* if value OK, copy it in configuration struct */ if (status == SANE_STATUS_GOOD) { memcpy (config->values[i], value, size); } if (value != NULL) { free (value); value = NULL; } } if (status != SANE_STATUS_GOOD) { DBG (1, "sanei_configure_attach: failed to parse option '%s', line '%s'\n", token, line); } i++; } free (token); /* not detected as an option, so we call the attach function * with it */ if (!found && status == SANE_STATUS_GOOD) { /* if not an option, try to attach */ /* to avoid every backend to depend on scsi and usb functions * we call back the backend for attach. In turn it will call * sanei_usb_attach_matching_devices, sanei_config_attach_matching_devices * or other. This means 2 callback functions per backend using this * function. */ DBG (3, "sanei_configure_attach: trying to attach with '%s'\n", lp2); if(attach!=NULL) attach (config, lp2); } } fclose (fp); DBG (3, "sanei_configure_attach: exit\n"); return status; }