static void mime_state_downgrade(MIME_STATE *state, int rec_type, const char *text, int len) { static char hexchars[] = "0123456789ABCDEF"; const unsigned char *cp; int ch; #define QP_ENCODE(buffer, ch) { \ VSTRING_ADDCH(buffer, '='); \ VSTRING_ADDCH(buffer, hexchars[(ch >> 4) & 0xff]); \ VSTRING_ADDCH(buffer, hexchars[ch & 0xf]); \ } /* * Insert a soft line break when the output reaches a critical length * before we reach a hard line break. */ for (cp = CU_CHAR_PTR(text); cp < CU_CHAR_PTR(text + len); cp++) { /* Critical length before hard line break. */ if (LEN(state->output_buffer) > 72) { VSTRING_ADDCH(state->output_buffer, '='); VSTRING_TERMINATE(state->output_buffer); BODY_OUT(state, REC_TYPE_NORM, STR(state->output_buffer), LEN(state->output_buffer)); VSTRING_RESET(state->output_buffer); } /* Append the next character. */ ch = *cp; if ((ch < 32 && ch != '\t') || ch == '=' || ch > 126) { QP_ENCODE(state->output_buffer, ch); } else { VSTRING_ADDCH(state->output_buffer, ch); } } /* * Flush output after a hard line break (i.e. the end of a REC_TYPE_NORM * record). Fix trailing whitespace as per the RFC: in the worst case, * the output length will grow from 73 characters to 75 characters. */ if (rec_type == REC_TYPE_NORM) { if (LEN(state->output_buffer) > 0 && ((ch = END(state->output_buffer)[-1]) == ' ' || ch == '\t')) { vstring_truncate(state->output_buffer, LEN(state->output_buffer) - 1); QP_ENCODE(state->output_buffer, ch); } VSTRING_TERMINATE(state->output_buffer); BODY_OUT(state, REC_TYPE_NORM, STR(state->output_buffer), LEN(state->output_buffer)); VSTRING_RESET(state->output_buffer); } }
VSTRING *off_cvt_number(VSTRING *buf, off_t offset) { static char digs[] = "0123456789"; char *start; char *last; int i; /* * Sanity checks */ if (offset < 0) msg_panic("off_cvt_number: negative offset -%s", STR(off_cvt_number(buf, -offset))); /* * First accumulate the result, backwards. */ VSTRING_RESET(buf); while (offset != 0) { VSTRING_ADDCH(buf, digs[offset % 10]); offset /= 10; } VSTRING_TERMINATE(buf); /* * Then, reverse the result. */ start = STR(buf); last = END(buf) - 1; for (i = 0; i < VSTRING_LEN(buf) / 2; i++) SWAP(int, start[i], last[-i]); return (buf); }
VSTRING *unquote_822_local(VSTRING *dst, const char *mbox) { const char *start; /* first byte of localpart */ const char *end; /* first byte after localpart */ const char *colon; const char *cp; if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) { start = colon + 1; vstring_strncpy(dst, mbox, start - mbox); } else { start = mbox; VSTRING_RESET(dst); } if ((end = strrchr(start, '@')) == 0) end = start + strlen(start); for (cp = start; cp < end; cp++) { if (*cp == '"') continue; if (*cp == '\\') { if (cp[1] == 0) continue; cp++; } VSTRING_ADDCH(dst, *cp); } if (*end) vstring_strcat(dst, end); else VSTRING_TERMINATE(dst); return (dst); }
VSTRING *quote_822_local_flags(VSTRING *dst, const char *mbox, int flags) { const char *start; /* first byte of localpart */ const char *end; /* first byte after localpart */ const char *colon; /* * According to RFC 822, a local-part is a dot-string or a quoted-string. * We first see if the local-part is a dot-string. If it is not, we turn * it into a quoted-string. Anything else would be too painful. But * first, skip over any source route that precedes the local-part. */ if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) start = colon + 1; else start = mbox; if ((end = strrchr(start, '@')) == 0) end = start + strlen(start); if ((flags & QUOTE_FLAG_APPEND) == 0) VSTRING_RESET(dst); if (is_822_dot_string(start, end, flags)) { return (vstring_strcat(dst, mbox)); } else { vstring_strncat(dst, mbox, start - mbox); make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN); return (vstring_strcat(dst, end)); } }
VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted) { const char *cp; int ch; VSTRING_RESET(unquoted); for (cp = quoted; (ch = *cp) != 0; cp++) { if (ch == '+') { if (ISDIGIT(cp[1])) ch = (cp[1] - '0') << 4; else if (cp[1] >= 'a' && cp[1] <= 'f') ch = (cp[1] - 'a' + 10) << 4; else if (cp[1] >= 'A' && cp[1] <= 'F') ch = (cp[1] - 'A' + 10) << 4; else return (0); if (ISDIGIT(cp[2])) ch |= (cp[2] - '0'); else if (cp[2] >= 'a' && cp[2] <= 'f') ch |= (cp[2] - 'a' + 10); else if (cp[2] >= 'A' && cp[2] <= 'F') ch |= (cp[2] - 'A' + 10); else return (0); cp += 2; } VSTRING_ADDCH(unquoted, ch); } VSTRING_TERMINATE(unquoted); return (unquoted); }
static void qmqpd_reply(QMQPD_STATE *state, int log_message, int status_code, const char *fmt,...) { va_list ap; /* * Optionally change hard errors into retryable ones. Send the reply and * optionally log it. Always insert a delay before reporting a problem. * This slows down software run-away conditions. */ if (status_code == QMQPD_STAT_HARD && var_soft_bounce) status_code = QMQPD_STAT_RETRY; VSTRING_RESET(state->buf); VSTRING_ADDCH(state->buf, status_code); va_start(ap, fmt); vstring_vsprintf_append(state->buf, fmt, ap); va_end(ap); NETSTRING_PUT_BUF(state->client, state->buf); if (log_message) (status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s", state->queue_id, state->namaddr, STR(state->buf) + 1); if (status_code != QMQPD_STAT_OK) sleep(var_qmqpd_err_sleep); netstring_fflush(state->client); }
VSTRING *hex_decode(VSTRING *result, const char *in, ssize_t len) { const unsigned char *cp; ssize_t count; unsigned int hex; unsigned int bin; VSTRING_RESET(result); for (cp = UCHAR_PTR(in), count = len; count > 0; cp += 2, count -= 2) { if (count < 2) return (0); hex = cp[0]; if (hex >= '0' && hex <= '9') bin = (hex - '0') << 4; else if (hex >= 'A' && hex <= 'F') bin = (hex - 'A' + 10) << 4; else if (hex >= 'a' && hex <= 'f') bin = (hex - 'a' + 10) << 4; else return (0); hex = cp[1]; if (hex >= '0' && hex <= '9') bin |= (hex - '0'); else if (hex >= 'A' && hex <= 'F') bin |= (hex - 'A' + 10); else if (hex >= 'a' && hex <= 'f') bin |= (hex - 'a' + 10); else return (0); VSTRING_ADDCH(result, bin); } VSTRING_TERMINATE(result); return (result); }
SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags) { SMTP_SESSION *session; int fd; /* * Don't look up an existing plaintext connection when a new connection * would (try to) use TLS. */ #ifdef USE_TLS if (state->tls->level > TLS_LEV_NONE) return (0); #endif /* * Look up the session by its IP address. This means that we have no * destination-to-address binding properties. */ smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA, state->iterator, endp_key_flags); if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label), state->endp_prop)) < 0) return (0); VSTRING_RESET(state->dest_prop); VSTRING_TERMINATE(state->dest_prop); /* * Re-activate the SMTP_SESSION object, and verify that the session is * still good. */ session = smtp_reuse_common(state, fd, STR(state->endp_label)); return (session); }
static const char *dict_union_lookup(DICT *dict, const char *query) { static const char myname[] = "dict_union_lookup"; DICT_UNION *dict_union = (DICT_UNION *) dict; DICT *map; char **cpp; char *dict_type_name; const char *result = 0; /* * After Roel van Meer, postfix-users mailing list, Sept 2014. */ VSTRING_RESET(dict_union->re_buf); for (cpp = dict_union->map_union->argv; (dict_type_name = *cpp) != 0; cpp++) { if ((map = dict_handle(dict_type_name)) == 0) msg_panic("%s: dictionary \"%s\" not found", myname, dict_type_name); if ((result = dict_get(map, query)) == 0) continue; if (VSTRING_LEN(dict_union->re_buf) > 0) VSTRING_ADDCH(dict_union->re_buf, ','); vstring_strcat(dict_union->re_buf, result); } DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, VSTRING_LEN(dict_union->re_buf) > 0 ? STR(dict_union->re_buf) : 0); }
VSTRING *hex_unquote(VSTRING *raw, const char *hex) { const char *cp; int ch; VSTRING_RESET(raw); for (cp = hex; (ch = *cp) != 0; cp++) { if (ch == '%') { if (ISDIGIT(cp[1])) ch = (cp[1] - '0') << 4; else if (cp[1] >= 'a' && cp[1] <= 'f') ch = (cp[1] - 'a' + 10) << 4; else if (cp[1] >= 'A' && cp[1] <= 'F') ch = (cp[1] - 'A' + 10) << 4; else return (0); if (ISDIGIT(cp[2])) ch |= (cp[2] - '0'); else if (cp[2] >= 'a' && cp[2] <= 'f') ch |= (cp[2] - 'a' + 10); else if (cp[2] >= 'A' && cp[2] <= 'F') ch |= (cp[2] - 'A' + 10); else return (0); cp += 2; } VSTRING_ADDCH(raw, ch); } VSTRING_TERMINATE(raw); return (raw); }
const char *cleanup_strflags(unsigned flags) { static VSTRING *result; unsigned i; if (flags == 0) return ("none"); if (result == 0) result = vstring_alloc(20); else VSTRING_RESET(result); for (i = 0; i < sizeof(cleanup_flag_map) / sizeof(cleanup_flag_map[0]); i++) { if (cleanup_flag_map[i].flag & flags) { vstring_sprintf_append(result, "%s ", cleanup_flag_map[i].text); flags &= ~cleanup_flag_map[i].flag; } } if (flags != 0 || VSTRING_LEN(result) == 0) msg_panic("cleanup_strflags: unrecognized flag value(s) 0x%x", flags); vstring_truncate(result, VSTRING_LEN(result) - 1); VSTRING_TERMINATE(result); return (vstring_str(result)); }
char *safe_ultostr(VSTRING *buf, unsigned long ulval, int base, int padlen, int padchar) { const char *myname = "safe_ultostr"; char *start; char *last; int i; /* * Sanity check. */ if (base < SAFE_MIN_BASE || base > SAFE_MAX_BASE) msg_panic("%s: bad base: %d", myname, base); /* * First accumulate the result, backwards. */ VSTRING_RESET(buf); while (ulval != 0) { VSTRING_ADDCH(buf, safe_chars[ulval % base]); ulval /= base; } while (VSTRING_LEN(buf) < padlen) VSTRING_ADDCH(buf, padchar); VSTRING_TERMINATE(buf); /* * Then, reverse the result. */ start = STR(buf); last = END(buf) - 1; for (i = 0; i < VSTRING_LEN(buf) / 2; i++) SWAP(int, start[i], last[-i]); return (STR(buf)); }
int mac_expand(VSTRING *result, const char *pattern, int flags, const char *filter, MAC_EXP_LOOKUP_FN lookup, char *context) { MAC_EXP mc; int status; /* * Bundle up the request and do the substitutions. */ mc.result = result; mc.flags = flags; mc.filter = filter; mc.lookup = lookup; mc.context = context; mc.status = 0; mc.level = 0; if ((flags & (MAC_EXP_FLAG_APPEND | MAC_EXP_FLAG_SCAN)) == 0) VSTRING_RESET(result); status = mac_parse(pattern, mac_expand_callback, (char *) &mc); if ((flags & MAC_EXP_FLAG_SCAN) == 0) VSTRING_TERMINATE(result); return (status); }
VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, ssize_t len) { const char *myname = "netstring_get_data"; /* * Allocate buffer space. */ VSTRING_RESET(buf); VSTRING_SPACE(buf, len); /* * Read the payload and absorb the terminator. */ if (vstream_fread(stream, STR(buf), len) != len) netstring_except(stream, vstream_ftimeout(stream) ? NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); if (msg_verbose > 1) msg_info("%s: read netstring data %.*s", myname, (int) (len < 30 ? len : 30), STR(buf)); netstring_get_terminator(stream); /* * Position the buffer. */ VSTRING_AT_OFFSET(buf, len); return (buf); }
int main(int argc, char **argv) { VSTRING *in = vstring_alloc(10); VSTRING *out = vstring_alloc(10); double tval; int sec; int usec; int sig_dig; int max_dig; while (vstring_get_nonl(in, VSTREAM_IN) > 0) { vstream_printf(">> %s\n", vstring_str(in)); if (vstring_str(in)[0] == 0 || vstring_str(in)[0] == '#') continue; if (sscanf(vstring_str(in), "%lf %d %d", &tval, &sig_dig, &max_dig) != 3) msg_fatal("bad input: %s", vstring_str(in)); sec = (int) tval; /* raw seconds */ usec = (tval - sec) * MILLION; /* raw microseconds */ VSTRING_RESET(out); format_tv(out, sec, usec, sig_dig, max_dig); vstream_printf("%s\n", vstring_str(out)); vstream_fflush(VSTREAM_OUT); } vstring_free(in); vstring_free(out); return (0); }
static int attr_scan_plain_string(VSTREAM *fp, VSTRING *plain_buf, int terminator, const char *context) { #if 0 extern int var_line_limit; /* XXX */ int limit = var_line_limit * 4; #endif int ch; VSTRING_RESET(plain_buf); while ((ch = VSTREAM_GETC(fp)) != '\n' && (terminator == 0 || ch != terminator)) { if (ch == VSTREAM_EOF) { msg_warn("%s on %s while reading %s", vstream_ftimeout(fp) ? "timeout" : "premature end-of-input", VSTREAM_PATH(fp), context); return (-1); } VSTRING_ADDCH(plain_buf, ch); #if 0 if (LEN(plain_buf) > limit) { msg_warn("string length > %d characters from %s while reading %s", limit, VSTREAM_PATH(fp), context); return (-1); } #endif } VSTRING_TERMINATE(plain_buf); if (msg_verbose) msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)"); return (ch); }
VSTRING *vstring_vsprintf(VSTRING *vp, const char *format, va_list ap) { VSTRING_RESET(vp); vbuf_print(&vp->vbuf, format, ap); VSTRING_TERMINATE(vp); return (vp); }
static void scache_single_free_endp(SCACHE_SINGLE *sp) { const char *myname = "scache_single_free_endp"; if (msg_verbose) msg_info("%s: %s", myname, STR(sp->endp.endp_label)); event_cancel_timer(scache_single_expire_endp, (char *) sp); if (sp->endp.fd >= 0 && close(sp->endp.fd) < 0) msg_warn("close session endpoint %s: %m", STR(sp->endp.endp_label)); VSTRING_RESET(sp->endp.endp_label); VSTRING_TERMINATE(sp->endp.endp_label); VSTRING_RESET(sp->endp.endp_prop); VSTRING_TERMINATE(sp->endp.endp_prop); sp->endp.fd = -1; }
static void scache_single_free_dest(SCACHE_SINGLE *sp) { const char *myname = "scache_single_free_dest"; if (msg_verbose) msg_info("%s: %s -> %s", myname, STR(sp->dest.dest_label), STR(sp->dest.endp_label)); event_cancel_timer(scache_single_expire_dest, (char *) sp); VSTRING_RESET(sp->dest.dest_label); VSTRING_TERMINATE(sp->dest.dest_label); VSTRING_RESET(sp->dest.dest_prop); VSTRING_TERMINATE(sp->dest.dest_prop); VSTRING_RESET(sp->dest.endp_label); VSTRING_TERMINATE(sp->dest.endp_label); }
VSTRING *vstring_memcpy(VSTRING *vp, const char *src, ssize_t len) { VSTRING_RESET(vp); VSTRING_SPACE(vp, len); memcpy(vstring_str(vp), src, len); VSTRING_AT_OFFSET(vp, len); return (vp); }
int xsasl_cyrus_server_first(XSASL_SERVER *xp, const char *sasl_method, const char *init_response, VSTRING *reply) { const char *myname = "xsasl_cyrus_server_first"; XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; char *dec_buffer; unsigned dec_length; unsigned reply_len; unsigned serveroutlen; int sasl_status; SERVEROUT_TYPE serverout = 0; int xsasl_status; #if SASL_VERSION_MAJOR < 2 const char *errstr = 0; #endif #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) if (msg_verbose) msg_info("%s: sasl_method %s%s%s", myname, sasl_method, IFELSE(init_response, ", init_response ", ""), IFELSE(init_response, init_response, "")); /* * SASL authentication protocol start-up. Process any initial client * response that was sent along in the AUTH command. */ if (init_response) { reply_len = strlen(init_response); VSTRING_RESET(server->decoded); /* Fix 200512 */ VSTRING_SPACE(server->decoded, reply_len); if ((sasl_status = SASL_DECODE64(init_response, reply_len, dec_buffer = STR(server->decoded), vstring_avail(server->decoded), &dec_length)) != SASL_OK) { vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FORM); } if (msg_verbose) msg_info("%s: decoded initial response %s", myname, dec_buffer); } else { dec_buffer = 0; dec_length = 0; } sasl_status = SASL_SERVER_START(server->sasl_conn, sasl_method, dec_buffer, dec_length, &serverout, &serveroutlen, &errstr); xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout, serveroutlen, reply); #if SASL_VERSION_MAJOR < 2 /* SASL version 1 doesn't free memory that it allocates. */ free(serverout); #endif return (xsasl_status); }
static ssize_t read_buf(VSTREAM *fp, VSTRING *buf) { ssize_t len; VSTRING_RESET(buf); len = vstream_fread(fp, STR(buf), vstring_avail(buf)); VSTRING_AT_OFFSET(buf, len); /* XXX */ VSTRING_TERMINATE(buf); return (len); }
int vstring_get_null(VSTRING *vp, VSTREAM *fp) { int c; VSTRING_RESET(vp); while ((c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0) VSTRING_ADDCH(vp, c); VSTRING_TERMINATE(vp); return (c == 0 ? c : VSTRING_GET_RESULT(vp)); }
VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno) { int ch; int next; int start; char *cp; VSTRING_RESET(buf); /* * Ignore comment lines, all whitespace lines, and empty lines. Terminate * at EOF or at the beginning of the next logical line. */ for (;;) { /* Read one line, possibly not newline terminated. */ start = LEN(buf); while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n') VSTRING_ADDCH(buf, ch); if (ch == '\n' && lineno != 0) *lineno += 1; /* Ignore comment line, all whitespace line, or empty line. */ for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++) /* void */ ; if (cp == END(buf) || *cp == '#') vstring_truncate(buf, start); /* Terminate at EOF or at the beginning of the next logical line. */ if (ch == VSTREAM_EOF) break; if (LEN(buf) > 0) { if ((next = VSTREAM_GETC(fp)) != VSTREAM_EOF) vstream_ungetc(fp, next); if (next != '#' && !ISSPACE(next)) break; } } VSTRING_TERMINATE(buf); /* * Invalid input: continuing text without preceding text. Allowing this * would complicate "postconf -e", which implements its own multi-line * parsing routine. Do not abort, just warn, so that critical programs * like postmap do not leave behind a truncated table. */ if (LEN(buf) > 0 && ISSPACE(*STR(buf))) { msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"", VSTREAM_PATH(fp), STR(buf), LEN(buf) > 30 ? "..." : ""); return (readlline(buf, fp, lineno)); } /* * Done. */ return (LEN(buf) > 0 ? buf : 0); }
VSTRING *vstring_strncpy(VSTRING *vp, const char *src, ssize_t len) { VSTRING_RESET(vp); while (len-- > 0 && *src) { VSTRING_ADDCH(vp, *src); src++; } VSTRING_TERMINATE(vp); return (vp); }
char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, SMTP_ITERATOR *iter, int flags) { static const char myname[] = "smtp_key_prefix"; SMTP_STATE *state = iter->parent; /* private member */ /* * Sanity checks. */ if (state == 0) msg_panic("%s: no parent state", myname); if (flags & ~SMTP_KEY_MASK_ALL) msg_panic("%s: unknown key flags 0x%x", myname, flags & ~SMTP_KEY_MASK_ALL); if (flags == 0) msg_panic("%s: zero flags", myname); /* * Initialize. */ VSTRING_RESET(buffer); /* * Per-service and per-request context. */ if (flags & SMTP_KEY_FLAG_SERVICE) smtp_key_append_str(buffer, state->service, delim_na); if (flags & SMTP_KEY_FLAG_SENDER) smtp_key_append_str(buffer, state->request->sender, delim_na); /* * Per-destination context, non-canonicalized form. */ if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP) smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na); if (flags & SMTP_KEY_FLAG_NEXTHOP) smtp_key_append_str(buffer, STR(iter->dest), delim_na); /* * Per-host context, canonicalized form. */ if (flags & SMTP_KEY_FLAG_HOSTNAME) smtp_key_append_str(buffer, STR(iter->host), delim_na); if (flags & SMTP_KEY_FLAG_ADDR) smtp_key_append_str(buffer, STR(iter->addr), delim_na); if (flags & SMTP_KEY_FLAG_PORT) smtp_key_append_uint(buffer, ntohs(iter->port), delim_na); /* Similarly, provide unique TLS fingerprint when applicable. */ VSTRING_TERMINATE(buffer); return STR(buffer); }
int main(int unused_argc, char **unused_argv) { VSTRING *buf = vstring_alloc(100); VSTRING *result = vstring_alloc(100); char *cp; char *name; char *value; HTABLE *table; int stat; while (!vstream_feof(VSTREAM_IN)) { table = htable_create(0); /* * Read a block of definitions, terminated with an empty line. */ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { vstream_printf("<< %s\n", vstring_str(buf)); vstream_fflush(VSTREAM_OUT); if (VSTRING_LEN(buf) == 0) break; cp = vstring_str(buf); name = mystrtok(&cp, " \t\r\n="); value = mystrtok(&cp, " \t\r\n="); htable_enter(table, name, value ? mystrdup(value) : 0); } /* * Read a block of patterns, terminated with an empty line or EOF. */ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { vstream_printf("<< %s\n", vstring_str(buf)); vstream_fflush(VSTREAM_OUT); if (VSTRING_LEN(buf) == 0) break; cp = vstring_str(buf); VSTRING_RESET(result); stat = mac_expand(result, vstring_str(buf), MAC_EXP_FLAG_NONE, (char *) 0, lookup, (char *) table); vstream_printf("stat=%d result=%s\n", stat, vstring_str(result)); vstream_fflush(VSTREAM_OUT); } htable_free(table, myfree); vstream_printf("\n"); } /* * Clean up. */ vstring_free(buf); vstring_free(result); exit(0); }
static void encode_utf8(VSTRING *buffer, int codepoint) { const char myname[] = "encode_utf8"; VSTRING_RESET(buffer); if (codepoint < 0x80) { VSTRING_ADDCH(buffer, codepoint); } else if (codepoint < 0x800) { VSTRING_ADDCH(buffer, 0xc0 | (codepoint >> 6)); VSTRING_ADDCH(buffer, 0x80 | (codepoint & 0x3f)); } else if (codepoint < 0x10000) {
VSTRING *vstring_strcpy(VSTRING *vp, const char *src) { VSTRING_RESET(vp); while (*src) { VSTRING_ADDCH(vp, *src); src++; } VSTRING_TERMINATE(vp); return (vp); }
static int smtpd_proxy_xforward_flush(SMTPD_STATE *state, VSTRING *buf) { int ret; if (VSTRING_LEN(buf) > 0) { ret = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, XFORWARD_CMD "%s", STR(buf)); VSTRING_RESET(buf); return (ret); } return (0); }