/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_prv_data) { struct xio_msg *rsp; if (req->status) printf("**** request completed with error. [%s]\n", xio_strerror(req->status)); /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_set(rsp, 0, test_config.hdr_len, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); } return 0; }
ssize_t parse_response_line(io *s, int *retcode, unsigned char linecpy[512]) { /* 512 is maximum length of response line */ int i, j; unsigned char line[512] = { 0 }; int c; for(i = 0; i < 512; i++) { c = io_getc(s); switch(c) { case EOF: msg_set("Unexpected end of stream in response line"); return -1; case '\n': line[i] = '\0'; /* intentional */ goto ret; default: line[i] = (unsigned char)c; break; } } if(i == 512) { msg_set("Response line exceeding maximum 512 bytes"); return -1; } if(i < 4) { msg_set("Response line too small to contain response code"); return -1; } ret: *retcode = 0; for(j = 0; j < 3; j++) { c = line[j]; if(c < '0' || c > '9') { msg_set("Response line did not contain 3-digit response code"); return -1; } *retcode *= 10; *retcode += c - '0'; } if(linecpy != NULL) memcpy(linecpy, line, sizeof(line)); return i; }
/*---------------------------------------------------------------------------*/ static int on_new_session(struct xio_session *session, struct xio_new_session_req *session_data, void *cb_prv_data) { struct xio_msg *req; int i = 0; printf("**** [%p] on_new_session :%s:%d\n", session, get_ip((struct sockaddr *)&session_data->src_addr), get_port((struct sockaddr *)&session_data->src_addr)); xio_accept(session, NULL, 0, NULL, 0); msg_pool_reset(pool); conn = xio_get_connection(session, ctx); printf("**** starting ...\n"); while (1) { /* create transaction */ req = msg_pool_get(pool); if (req == NULL) break; /* get pointers to internal buffers */ req->in.header.iov_base = NULL; req->in.header.iov_len = 0; req->in.data_iovlen = 1; req->in.data_iov[0].iov_base = NULL; req->in.data_iov[0].iov_len = ONE_MB; req->in.data_iov[0].mr = NULL; /* recycle the message and fill new request */ msg_set(req, 1, test_config.hdr_len, test_config.data_len); /* try to send it */ if (xio_send_request(conn, req) == -1) { printf("**** sent %d messages\n", i); if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, req); return 0; } i++; if (i == 256) break; } return 0; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *rsp, int more_in_batch, void *cb_prv_data) { process_response(rsp); if (rsp->status) printf("**** message completed with error. [%s]\n", xio_strerror(rsp->status)); /* message is no longer needed */ xio_release_response(rsp); /* reset message */ rsp->in.header.iov_base = NULL; rsp->in.header.iov_len = 0; rsp->in.data_iovlen = 1; rsp->in.data_iov[0].iov_base = NULL; rsp->in.data_iov[0].iov_len = ONE_MB; rsp->in.data_iov[0].mr = NULL; rsp->sn = 0; rsp->more_in_batch = 0; do { /* recycle the message and fill new request */ msg_set(rsp, 1, test_config.hdr_len, test_config.data_len); /* try to send it */ if (xio_send_request(conn, rsp) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); return 0; } } while (0); return 0; }
/* ICAP_PIXELFLAVOR */ static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA }; TW_UINT32 val; TW_UINT32 flavor = activeDS.sane_param.depth == 1 ? TWPF_VANILLA : TWPF_CHOCOLATE; TRACE("ICAP_PIXELFLAVOR\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]), TWTY_UINT16, flavor, flavor); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val); } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_UINT16, flavor); break; case MSG_RESET: /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, flavor); break; } #endif return twCC; }
/* ICAP_XFERMECH */ static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action) { static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY }; TW_UINT32 val; TW_UINT16 twCC = TWCC_BADCAP; TRACE("ICAP_XFERMECH\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]), TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { activeDS.capXferMech = (TW_UINT16) val; FIXME("Partial Stub: XFERMECH set to %d, but ignored\n", val); } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE); break; case MSG_RESET: activeDS.capXferMech = TWSX_NATIVE; /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech); FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech); break; } return twCC; }
/* ICAP_UNITS */ static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT32 val; TW_UINT16 twCC = TWCC_BADCAP; TRACE("ICAP_UNITS\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { if (val != TWUN_INCHES) { ERR("Sane supports only SANE_UNIT_DPI\n"); twCC = TWCC_BADVALUE; } } break; case MSG_GETDEFAULT: case MSG_RESET: /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES); break; } return twCC; }
/* ICAP_COMPRESSION */ static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action) { static const TW_UINT32 possible_values[] = { TWCP_NONE }; TW_UINT32 val; TW_UINT16 twCC = TWCC_BADCAP; TRACE("ICAP_COMPRESSION\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]), TWTY_UINT16, TWCP_NONE, TWCP_NONE); FIXME("Partial stub: We don't attempt to support compression\n"); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val); break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE); break; case MSG_RESET: /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE); break; } return twCC; }
/* CAP_XFERCOUNT */ static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT32 val; TW_UINT16 twCC = TWCC_BADCAP; TRACE("CAP_XFERCOUNT\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = set_onevalue(pCapability, TWTY_INT16, -1); FIXME("Partial Stub: Reporting only support for transfer all\n"); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val); break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_INT16, -1); break; case MSG_RESET: /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_INT16, -1); break; } return twCC; }
/* CAP_AUTOFEED */ static TW_UINT16 SANE_CAPAutofeed (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE TW_UINT32 val; SANE_Bool autofeed; SANE_Status status; TRACE("CAP_AUTOFEED\n"); if (sane_option_get_bool(activeDS.deviceHandle, "batch-scan", &autofeed, NULL) != SANE_STATUS_GOOD) return TWCC_BADCAP; switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { if (val) autofeed = SANE_TRUE; else autofeed = SANE_FALSE; status = sane_option_set_bool(activeDS.deviceHandle, "batch-scan", autofeed, NULL); if (status != SANE_STATUS_GOOD) { ERR("Error %s: Could not set batch-scan to %d\n", psane_strstatus(status), autofeed); return sane_status_to_twcc(status); } } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_BOOL, SANE_TRUE); break; case MSG_RESET: autofeed = SANE_TRUE; status = sane_option_set_bool(activeDS.deviceHandle, "batch-scan", autofeed, NULL); if (status != SANE_STATUS_GOOD) { ERR("Error %s: Could not reset batch-scan to SANE_TRUE\n", psane_strstatus(status)); return sane_status_to_twcc(status); } /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed); break; } #endif return twCC; }
/* ICAP_SUPPORTEDSIZES */ static TW_UINT16 SANE_ICAPSupportedSizes (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE static TW_UINT32 possible_values[SUPPORTED_SIZE_COUNT]; unsigned int i; TW_UINT32 val; TW_UINT16 default_size = get_default_paper_size(supported_sizes, SUPPORTED_SIZE_COUNT); TW_UINT16 current_size = get_current_paper_size(supported_sizes, SUPPORTED_SIZE_COUNT); TRACE("ICAP_SUPPORTEDSIZES\n"); switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: for (i = 0; i < sizeof(supported_sizes) / sizeof(supported_sizes[0]); i++) possible_values[i] = supported_sizes[i].size; twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]), TWTY_UINT16, current_size, default_size); WARN("Partial Stub: our supported size selection is a bit thin.\n"); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) for (i = 1; i < SUPPORTED_SIZE_COUNT; i++) if (supported_sizes[i].size == val) return set_width_height(supported_sizes[i].x, supported_sizes[i].y); ERR("Unsupported size %d\n", val); twCC = TWCC_BADCAP; break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_UINT16, default_size); break; case MSG_RESET: twCC = TWCC_BADCAP; for (i = 1; i < SUPPORTED_SIZE_COUNT; i++) if (supported_sizes[i].size == default_size) { twCC = set_width_height(supported_sizes[i].x, supported_sizes[i].y); break; } if (twCC != TWCC_SUCCESS) return twCC; /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, current_size); break; } #undef SUPPORTED_SIZE_COUNT #endif return twCC; }
/* ICAP_XRESOLUTION, ICAP_YRESOLUTION */ static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE TW_UINT32 val; SANE_Int current_resolution; TW_FIX32 *default_res; const char *best_option_name; SANE_Int minval, maxval, quantval; SANE_Status sane_rc; SANE_Int set_status; TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y'); /* Some scanners support 'x-resolution', most seem to just support 'resolution' */ if (cap == ICAP_XRESOLUTION) { best_option_name = "x-resolution"; default_res = &activeDS.defaultXResolution; } else { best_option_name = "y-resolution"; default_res = &activeDS.defaultYResolution; } if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD) { best_option_name = "resolution"; if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD) return TWCC_BADCAP; } /* Sane does not support a concept of 'default' resolution, so we have to * cache the resolution the very first time we load the scanner, and use that * as the default */ if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet) { default_res->Whole = current_resolution; default_res->Frac = 0; activeDS.XResolutionSet = TRUE; } if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet) { default_res->Whole = current_resolution; default_res->Frac = 0; activeDS.YResolutionSet = TRUE; } switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval); if (sane_rc != SANE_STATUS_GOOD) twCC = TWCC_BADCAP; else twCC = msg_get_range(pCapability, TWTY_FIX32, minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { TW_FIX32 f32; memcpy(&f32, &val, sizeof(f32)); sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status); if (sane_rc != SANE_STATUS_GOOD) { FIXME("Status of %d not expected or handled\n", sane_rc); twCC = TWCC_BADCAP; } else if (set_status == SANE_INFO_INEXACT) twCC = TWCC_CHECKSTATUS; } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole); break; case MSG_RESET: sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL); if (sane_rc != SANE_STATUS_GOOD) return TWCC_BADCAP; /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution); break; } #endif return twCC; }
/* ICAP_PIXELTYPE */ static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE TW_UINT32 possible_values[3]; int possible_value_count; TW_UINT32 val; SANE_Status rc; SANE_Int status; SANE_String_Const *choices; char current_mode[64]; TW_UINT16 current_pixeltype = TWPT_BW; SANE_Char mode[64]; TRACE("ICAP_PIXELTYPE\n"); rc = sane_option_probe_mode(activeDS.deviceHandle, &choices, current_mode, sizeof(current_mode)); if (rc != SANE_STATUS_GOOD) { ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n"); return twCC; } sane_mode_to_pixeltype(current_mode, ¤t_pixeltype); /* Sane does not support a concept of a default mode, so we simply cache * the first mode we find */ if (! activeDS.PixelTypeSet) { activeDS.PixelTypeSet = TRUE; activeDS.defaultPixelType = current_pixeltype; } switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: for (possible_value_count = 0; choices && *choices && possible_value_count < 3; choices++) { TW_UINT16 pix; if (sane_mode_to_pixeltype(*choices, &pix)) possible_values[possible_value_count++] = pix; } twCC = msg_get_enum(pCapability, possible_values, possible_value_count, TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { TRACE("Setting pixeltype to %d\n", val); if (! pixeltype_to_sane_mode(val, mode, sizeof(mode))) return TWCC_BADVALUE; status = 0; rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status); /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */ if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) { strcpy(mode, "Grayscale"); rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status); } if (rc != SANE_STATUS_GOOD) return sane_status_to_twcc(rc); if (status & SANE_INFO_RELOAD_PARAMS) psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param); } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.defaultPixelType); break; case MSG_RESET: current_pixeltype = activeDS.defaultPixelType; if (! pixeltype_to_sane_mode(current_pixeltype, mode, sizeof(mode))) return TWCC_BADVALUE; status = 0; rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status); /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */ if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) { strcpy(mode, "Grayscale"); rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status); } if (rc != SANE_STATUS_GOOD) return sane_status_to_twcc(rc); if (status & SANE_INFO_RELOAD_PARAMS) psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param); /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_UINT16, current_pixeltype); TRACE("Returning current pixeltype of %d\n", current_pixeltype); break; } #endif return twCC; }
/* CAP_FEEDERENABLED */ static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; #ifdef SONAME_LIBSANE TW_UINT32 val; TW_BOOL enabled; SANE_Status status; SANE_Char source[64]; TRACE("CAP_FEEDERENABLED\n"); if (sane_option_get_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, sizeof(source), NULL) != SANE_STATUS_GOOD) return TWCC_BADCAP; if (strcmp(source, "Auto") == 0 || strcmp(source, "ADF") == 0) enabled = TRUE; else enabled = FALSE; switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET ); break; case MSG_GET: twCC = set_onevalue(pCapability, TWTY_BOOL, enabled); break; case MSG_SET: twCC = msg_set(pCapability, &val); if (twCC == TWCC_SUCCESS) { if (val) enabled = TRUE; else enabled = FALSE; strcpy(source, "ADF"); status = sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL); if (status != SANE_STATUS_GOOD) { strcpy(source, "Auto"); status = sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL); } if (status != SANE_STATUS_GOOD) { ERR("Error %s: Could not set source to either ADF or Auto\n", psane_strstatus(status)); return sane_status_to_twcc(status); } } break; case MSG_GETDEFAULT: twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE); break; case MSG_RESET: strcpy(source, "Auto"); if (sane_option_set_str(activeDS.deviceHandle, SANE_NAME_SCAN_SOURCE, source, NULL) == SANE_STATUS_GOOD) enabled = TRUE; twCC = TWCC_SUCCESS; /* .. fall through intentional .. */ case MSG_GETCURRENT: twCC = set_onevalue(pCapability, TWTY_BOOL, enabled); break; } #endif return twCC; }
static ssize_t message_store_helper(const char *buf, size_t count, struct msg_group_t *group) { char *cp = (char *) buf; char *end = cp + count; char *linefeed = NULL; char *temp = NULL; ssize_t msg_stored = 0; ssize_t retval = count; size_t desc_length = 0; unsigned long index = 0; int received = 0; int used = 0; int rejected = 0; int reset = 0; enum msg_index_t firstmessage = group->start; enum msg_index_t lastmessage = group->end; enum msg_index_t curmessage; while (cp < end) { while ((cp < end) && (*cp == ' ' || *cp == '\t')) cp++; if (cp == end) break; if (strchr("dDrR", *cp)) { reset = 1; break; } received++; linefeed = strchr(cp, '\n'); if (!linefeed) { rejected++; break; } if (!isdigit(*cp)) { rejected++; cp = linefeed + 1; continue; } index = simple_strtoul(cp, &temp, 10); while ((temp < linefeed) && (*temp == ' ' || *temp == '\t')) temp++; desc_length = linefeed - temp; curmessage = firstmessage + index; /* * Note the check (curmessage < firstmessage). It is not * redundant. Suppose that the user gave us an index * equal to ULONG_MAX - 1. If firstmessage > 1, then * firstmessage + index < firstmessage! */ if ((curmessage < firstmessage) || (curmessage > lastmessage)) { rejected++; cp = linefeed + 1; continue; } msg_stored = msg_set(curmessage, temp, desc_length); if (msg_stored < 0) { retval = msg_stored; if (msg_stored == -ENOMEM) reset = 1; break; } else { used++; } cp = linefeed + 1; } if (reset) reset_msg_group(group); report_msg_status(reset, received, used, rejected, group->name); return retval; }
ssize_t parse_response_block(io *s, io *buf) { int c; enum { meat, line, dot, dot_r, } state; size_t sz = 0; state = line; while((c = io_getc(s)) != EOF) { sz += 1; switch(state) { case meat: switch(c) { case '\n': io_putc(buf, '\n'); state = line; break; default: io_putc(buf, c); break; } break; case line: switch(c) { case '.': state = dot; break; case '\n': io_putc(buf, '\n'); break; default: state = meat; io_putc(buf, c); break; } break; case dot: switch(c) { case '\r': state = dot_r; break; case '\n': goto ret; case '.': state = meat; io_putc(buf, '.'); break; default: state = meat; io_putc(buf, '.'); io_putc(buf, c); break; } break; case dot_r: switch(c) { case '\n': goto ret; default: state = meat; io_putc(buf, '.'); io_putc(buf, '\r'); io_putc(buf, c); break; } } } if(c == EOF) { msg_set("Unexpected end of stream in response block"); return -1; } ret: return sz; }