static void verify_update_service(VSTREAM *client_stream) { VSTRING *buf = vstring_alloc(10); VSTRING *addr = vstring_alloc(10); int addr_status; VSTRING *text = vstring_alloc(10); const char *status_name; const char *raw_data; long probed; long updated; if (attr_scan(client_stream, ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_ADDR, addr), RECV_ATTR_INT(MAIL_ATTR_ADDR_STATUS, &addr_status), RECV_ATTR_STR(MAIL_ATTR_WHY, text), ATTR_TYPE_END) == 3) { /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */ translit(STR(addr), ":", "_"); if ((status_name = verify_stat2name(addr_status)) == 0) { msg_warn("bad recipient status %d for recipient %s", addr_status, STR(addr)); attr_print(client_stream, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD), ATTR_TYPE_END); } else { /* * Robustness: don't allow a failed probe to clobber an OK * address before it expires. The failed probe is ignored so that * the address will be re-probed upon the next query. As long as * some probes succeed the address will remain cached as OK. */ if (addr_status == DEL_RCPT_STAT_OK || (raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0 || STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) { probed = 0; updated = (long) time((time_t *) 0); verify_make_entry(buf, addr_status, probed, updated, STR(text)); if (msg_verbose) msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s", STR(addr), addr_status, probed, updated, STR(text)); dict_cache_update(verify_map, STR(addr), STR(buf)); } attr_print(client_stream, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK), ATTR_TYPE_END); } } vstring_free(buf); vstring_free(addr); vstring_free(text); }
static NORETURN PRINTFLIKE(1, 2) pcf_fix_fatal(const char *fmt,...) { VSTRING *buf = vstring_alloc(100); va_list ap; /* * Replace newline with whitespace. */ va_start(ap, fmt); vstring_vsprintf(buf, fmt, ap); va_end(ap); translit(STR(buf), "\n", " "); msg_fatal("%s", STR(buf)); /* NOTREACHED */ }
int main(void) { int c, paren = 0; const char *px = ""; while((c = getchar()) != EOF) { char b = translit(c); if(b) printf("%s%s%c", px, paren ? "(" : "", b), paren = 0, px = " "; else if(c == ']') printf(paren ? "L R" : ")"), paren = 0, px = " "; else if(c == '[') printf("%s%s", px, paren ? "(" : ""), paren = 1, px = ""; else if(isspace(c)) putchar(c), px = ""; } if(paren) printf("L\n"); return 0; }
static void verify_query_service(VSTREAM *client_stream) { VSTRING *addr = vstring_alloc(10); VSTRING *get_buf = 0; VSTRING *put_buf = 0; const char *raw_data; int addr_status; long probed; long updated; char *text; if (attr_scan(client_stream, ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_ADDR, addr), ATTR_TYPE_END) == 1) { long now = (long) time((time_t *) 0); /* * Produce a default record when no usable record exists. * * If negative caching is disabled, purge an expired record from the * database. * * XXX Assume that a probe is lost if no response is received in 1000 * seconds. If this number is too small the queue will slowly fill up * with delayed probes. * * XXX Maintain a moving average for the probe turnaround time, and * allow probe "retransmission" when a probe is outstanding for, say * some minimal amount of time (1000 sec) plus several times the * observed probe turnaround time. This causes probing to back off * when the mail system becomes congested. */ #define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \ (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now) #define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \ (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now) #define PROBE_TTL 1000 /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */ translit(STR(addr), ":", "_"); if ((raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0 /* not found */ || ((get_buf = vstring_alloc(10)), vstring_strcpy(get_buf, raw_data), /* malformed */ verify_parse_entry(STR(get_buf), &addr_status, &probed, &updated, &text) < 0) || (now - probed > PROBE_TTL /* safe to probe */ && (POSITIVE_ENTRY_EXPIRED(addr_status, updated) || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) { addr_status = DEL_RCPT_STAT_TODO; probed = 0; updated = 0; text = "Address verification in progress"; if (raw_data != 0 && var_verify_neg_cache == 0) dict_cache_delete(verify_map, STR(addr)); } if (msg_verbose) msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s", STR(addr), addr_status, probed, updated, text); /* * Respond to the client. */ attr_print(client_stream, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK), SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status), SEND_ATTR_STR(MAIL_ATTR_WHY, text), ATTR_TYPE_END); /* * Send a new probe when the information needs to be refreshed. * * XXX For an initial proof of concept implementation, use synchronous * mail submission. This needs to be made async for high-volume * sites, which makes it even more interesting to eliminate duplicate * queries while a probe is being built. * * If negative caching is turned off, update the database only when * refreshing an existing entry. */ #define POSITIVE_REFRESH_NEEDED(addr_status, updated) \ (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now) #define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \ (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now) if (now - probed > PROBE_TTL && (POSITIVE_REFRESH_NEEDED(addr_status, updated) || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) { if (msg_verbose) msg_info("PROBE %s status=%d probed=%ld updated=%ld", STR(addr), addr_status, now, updated); post_mail_fopen_async(make_verify_sender_addr(), STR(addr), MAIL_SRC_MASK_VERIFY, DEL_REQ_FLAG_MTA_VRFY, SMTPUTF8_FLAG_NONE, (VSTRING *) 0, verify_post_mail_action, (void *) 0); if (updated != 0 || var_verify_neg_cache != 0) { put_buf = vstring_alloc(10); verify_make_entry(put_buf, addr_status, now, updated, text); if (msg_verbose) msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s", STR(addr), addr_status, now, updated, text); dict_cache_update(verify_map, STR(addr), STR(put_buf)); } } } vstring_free(addr); if (get_buf) vstring_free(get_buf); if (put_buf) vstring_free(put_buf); }