diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/HISTORY ./HISTORY *** /var/tmp/postfix-2.10-20120308/HISTORY Thu Mar 8 09:01:53 2012 --- ./HISTORY Sun Mar 18 11:22:48 2012 *************** *** 17684,17686 **** --- 17684,17692 ---- postconf -X option to exclude parameters from main.cf (require two-finger action, because this is irreversible). Files: postconf/postconf.[hc], postconf/postconf_edit.c. + + 20120317 + + Feature: Sendmail-style socketmap. Files: util/dict_sockmap.[hc], + util/netstring.[hc], proto/DATABASE_README.html, + postconf/postconf.c. diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/README_FILES/DATABASE_README ./README_FILES/DATABASE_README *** /var/tmp/postfix-2.10-20120308/README_FILES/DATABASE_README Thu Jan 19 13:56:15 2012 --- ./README_FILES/DATABASE_README Sun Mar 18 11:06:51 2012 *************** *** 246,251 **** --- 246,256 ---- with the postmap(1) or postalias(1) command. The lookup table name as used in "sdbm:table" is the database file name without the ".dir" or ".pag" suffix. + ssoocckkeettmmaapp (read-only) + Query a Sendmail-style socketmap server. The name of the table + specifies iinneett:host:port:socketmap-name for a TCP-based server, or + uunniixx:pathname:socketmap-name for a UNIX-domain server. In both cases + socketmap-name is the name of the socketmap. ssqqlliittee (read-only) Perform SQLite database lookups. Configuration details are given in sqlite_table(5). diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/html/DATABASE_README.html ./html/DATABASE_README.html *** /var/tmp/postfix-2.10-20120308/html/DATABASE_README.html Thu Jan 19 13:56:15 2012 --- ./html/DATABASE_README.html Sun Mar 18 11:06:51 2012 *************** *** 370,375 **** --- 370,384 ---- table name as used in "sdbm:table" is the database file name without the ".dir" or ".pag" suffix. +
socketmap (read-only)
+ +
Query a Sendmail-style socketmap server. The name of the table + specifies inet:host:port:socketmap-name + for a TCP-based server, or + unix:pathname:socketmap-name for a UNIX-domain + server. In both cases socketmap-name is the name of the + socketmap.
+
sqlite (read-only)
Perform SQLite database lookups. Configuration details are given diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/html/postconf.1.html ./html/postconf.1.html *** /var/tmp/postfix-2.10-20120308/html/postconf.1.html Thu Mar 8 08:44:07 2012 --- ./html/postconf.1.html Sun Mar 18 11:05:31 2012 *************** *** 228,233 **** --- 228,242 ---- is available on systems with support for SDBM databases. + socketmap (read-only) + Query a Sendmail-style socketmap server. The + name of the table specifies + inet:host:port:socketmap-name for a TCP- + based server, or unix:pathname:socketmap- + name for a UNIX-domain server. In both + cases, socketmap-name is the name of the + socketmap. + sqlite (read-only) Perform lookups from SQLite database files. This is described in sqlite_table(5). diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/man/man1/postconf.1 ./man/man1/postconf.1 *** /var/tmp/postfix-2.10-20120308/man/man1/postconf.1 Thu Mar 8 08:44:07 2012 --- ./man/man1/postconf.1 Sun Mar 18 11:05:31 2012 *************** *** 207,212 **** --- 207,220 ---- .IP \fBsdbm\fR An indexed file type based on hashing. This is available on systems with support for SDBM databases. + .IP "\fBsocketmap\fR (read-only)" + Query a Sendmail-style socketmap server. The name of the + table specifies + \fBinet\fR:\fIhost\fR:\fIport\fR:\fIsocketmap-name\fR for + a TCP-based server, or + \fBunix\fR:\fIpathname\fR:\fIsocketmap-name\fR for a + UNIX-domain server. In both cases, \fIsocketmap-name\fR is + the name of the socketmap. .IP "\fBsqlite\fR (read-only)" Perform lookups from SQLite database files. This is described in \fBsqlite_table\fR(5). diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/proto/DATABASE_README.html ./proto/DATABASE_README.html *** /var/tmp/postfix-2.10-20120308/proto/DATABASE_README.html Thu Jan 19 13:56:12 2012 --- ./proto/DATABASE_README.html Sun Mar 18 11:06:50 2012 *************** *** 370,375 **** --- 370,384 ---- table name as used in "sdbm:table" is the database file name without the ".dir" or ".pag" suffix.
+
socketmap (read-only)
+ +
Query a Sendmail-style socketmap server. The name of the table + specifies inet:host:port:socketmap-name + for a TCP-based server, or + unix:pathname:socketmap-name for a UNIX-domain + server. In both cases socketmap-name is the name of the + socketmap.
+
sqlite (read-only)
Perform SQLite database lookups. Configuration details are given diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/postconf/postconf.c ./src/postconf/postconf.c *** /var/tmp/postfix-2.10-20120308/src/postconf/postconf.c Thu Mar 8 08:34:30 2012 --- ./src/postconf/postconf.c Sun Mar 18 11:05:30 2012 *************** *** 201,206 **** --- 201,214 ---- /* .IP \fBsdbm\fR /* An indexed file type based on hashing. /* This is available on systems with support for SDBM databases. + /* .IP "\fBsocketmap\fR (read-only)" + /* Query a Sendmail-style socketmap server. The name of the + /* table specifies + /* \fBinet\fR:\fIhost\fR:\fIport\fR:\fIsocketmap-name\fR for + /* a TCP-based server, or + /* \fBunix\fR:\fIpathname\fR:\fIsocketmap-name\fR for a + /* UNIX-domain server. In both cases, \fIsocketmap-name\fR is + /* the name of the socketmap. /* .IP "\fBsqlite\fR (read-only)" /* Perform lookups from SQLite database files. This is described /* in \fBsqlite_table\fR(5). diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/Makefile.in ./src/util/Makefile.in *** /var/tmp/postfix-2.10-20120308/src/util/Makefile.in Sun Jan 22 10:55:11 2012 --- ./src/util/Makefile.in Sun Mar 25 10:12:15 2012 *************** *** 34,40 **** unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \ unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \ ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \ ! dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ --- 34,41 ---- unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \ unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \ ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \ ! dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \ ! dict_sockmap.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ *************** *** 70,76 **** unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \ unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \ ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \ ! dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ --- 71,78 ---- unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \ unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \ ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \ ! dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \ ! dict_sockmap.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ *************** *** 91,97 **** username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \ vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \ edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \ ! dict_fail.h warn_stat.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) --- 93,99 ---- username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \ vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \ edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \ ! dict_fail.h warn_stat.h dict_sockmap.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) *************** *** 1001,1006 **** --- 1003,1009 ---- dict_open.o: dict_pcre.h dict_open.o: dict_regexp.h dict_open.o: dict_sdbm.h + dict_open.o: dict_sockmap.h dict_open.o: dict_static.h dict_open.o: dict_tcp.h dict_open.o: dict_thash.h *************** *** 1060,1065 **** --- 1063,1082 ---- dict_sdbm.o: vstream.h dict_sdbm.o: vstring.h dict_sdbm.o: warn_stat.h + dict_sockmap.o: argv.h + dict_sockmap.o: auto_clnt.h + dict_sockmap.o: dict.h + dict_sockmap.o: dict_sockmap.c + dict_sockmap.o: dict_sockmap.h + dict_sockmap.o: msg.h + dict_sockmap.o: mymalloc.h + dict_sockmap.o: netstring.h + dict_sockmap.o: split_at.h + dict_sockmap.o: stringops.h + dict_sockmap.o: sys_defs.h + dict_sockmap.o: vbuf.h + dict_sockmap.o: vstream.h + dict_sockmap.o: vstring.h dict_static.o: argv.h dict_static.o: dict.h dict_static.o: dict_static.c diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/dict_open.c ./src/util/dict_open.c *** /var/tmp/postfix-2.10-20120308/src/util/dict_open.c Sun Jan 15 11:27:10 2012 --- ./src/util/dict_open.c Sat Mar 17 19:05:48 2012 *************** *** 235,240 **** --- 235,241 ---- #include #include #include + #include #include #include #include *************** *** 285,290 **** --- 286,292 ---- DICT_TYPE_STATIC, dict_static_open, DICT_TYPE_CIDR, dict_cidr_open, DICT_TYPE_THASH, dict_thash_open, + DICT_TYPE_SOCKMAP, dict_sockmap_open, DICT_TYPE_FAIL, dict_fail_open, 0, }; diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/dict_sockmap.c ./src/util/dict_sockmap.c *** /var/tmp/postfix-2.10-20120308/src/util/dict_sockmap.c Wed Dec 31 19:00:00 1969 --- ./src/util/dict_sockmap.c Sun Mar 25 09:47:48 2012 *************** *** 0 **** --- 1,338 ---- + /*++ + /* NAME + /* dict_sockmap 3 + /* SUMMARY + /* dictionary manager interface to Sendmail-style socketmap server + /* SYNOPSIS + /* #include + /* + /* DICT *dict_sockmap_open(map, open_flags, dict_flags) + /* const char *map; + /* int open_flags; + /* int dict_flags; + /* DESCRIPTION + /* dict_sockmap_open() makes a Sendmail-style socketmap server + /* accessible via the generic dictionary operations described + /* in dict_open(3). The only implemented operation is dictionary + /* lookup. This map type can be useful for simulating a dynamic + /* lookup table. + /* + /* Postfix socketmap names have the form inet:host:port:socketmap-name + /* or unix:pathname:socketmap-name, where socketmap-name + /* specifies the socketmap name that the socketmap server uses. + /* PROTOCOL + /* .ad + /* .fi + /* The socketmap class implements a simple protocol: the client + /* sends one request, and the server sends one reply. + /* ENCODING + /* .ad + /* .fi + /* Each request and reply are sent as one netstring object. + /* REQUEST FORMAT + /* .ad + /* .fi + /* .IP " " + /* Search the specified socketmap under the specified key. + /* REPLY FORMAT + /* .ad + /* .fi + /* Replies must be no longer than 100000 characters (not including + /* the netstring encapsulation), and must have the following + /* form: + /* .IP "OK " + /* The requested data was found. + /* .IP "NOTFOUND " + /* The requested data was not found. + /* .IP "TEMP " + /* .IP "TIMEOUT " + /* .IP "PERM " + /* The request failed. The reason, if non-empty, is descriptive + /* text. + /* SECURITY + /* This map cannot be used for security-sensitive information, + /* because neither the connection nor the server are authenticated. + /* SEE ALSO + /* dict(3) generic dictionary manager + /* netstring(3) netstring stream I/O support + /* DIAGNOSTICS + /* Fatal errors: out of memory, unknown host or service name, + /* attempt to update or iterate over map. + /* BUGS + /* The protocol limits are not yet configurable. + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + /* + * System library. + */ + #include + #include + #include + #include + + /* + * Utility library. + */ + #include + #include + #include + #include + #include + #include + #include + #include + + /* + * Socket map data structure. + */ + typedef struct { + DICT dict; /* parent class */ + char *sockmap_name; /* on-the-wire socketmap name */ + VSTRING *rdwr_buf; /* read/write buffer */ + } DICT_SOCKMAP; + + /* + * Default limits. + */ + #define DICT_SOCKMAP_DEF_TIMEOUT 100 /* connect/read/write timeout */ + #define DICT_SOCKMAP_DEF_MAX_REPLY 100000 /* reply size limit */ + #define DICT_SOCKMAP_DEF_MAX_IDLE 10 /* close idle socket */ + #define DICT_SOCKMAP_DEF_MAX_TTL 100 /* close old socket */ + + /* + * Class variables. + */ + static AUTO_CLNT *dict_sockmap_clnt; /* auto_clnt handle */ + static int dict_sockmap_refcount; /* handle reference count */ + static int dict_sockmap_timeout = DICT_SOCKMAP_DEF_TIMEOUT; + static int dict_sockmap_max_reply = DICT_SOCKMAP_DEF_MAX_REPLY; + static int dict_sockmap_max_idle = DICT_SOCKMAP_DEF_MAX_IDLE; + static int dict_sockmap_max_ttl = DICT_SOCKMAP_DEF_MAX_TTL; + + /* + * Socketmap protocol elements. + */ + #define DICT_SOCKMAP_PROT_OK "OK" + #define DICT_SOCKMAP_PROT_NOTFOUND "NOTFOUND" + #define DICT_SOCKMAP_PROT_TEMP "TEMP" + #define DICT_SOCKMAP_PROT_TIMEOUT "TIMEOUT" + #define DICT_SOCKMAP_PROT_PERM "PERM" + + /* + * SLMs. + */ + #define STR(x) vstring_str(x) + #define LEN(x) VSTRING_LEN(x) + + /* dict_sockmap_lookup - socket map lookup */ + + static const char *dict_sockmap_lookup(DICT *dict, const char *key) + { + const char *myname = "dict_sockmap_lookup"; + DICT_SOCKMAP *dp = (DICT_SOCKMAP *) dict; + VSTREAM *fp; + int netstring_err; + char *reply_payload; + int except_count; + const char *error_class; + + if (msg_verbose) + msg_info("%s: key %s", myname, key); + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_MUL) { + if (dict->fold_buf == 0) + dict->fold_buf = vstring_alloc(100); + vstring_strcpy(dict->fold_buf, key); + key = lowercase(STR(dict->fold_buf)); + } + + /* + * We retry connection-level errors once, to make server restarts + * transparent. + */ + for (except_count = 0; /* see below */ ; except_count++) { + + /* + * Look up the stream. + */ + if ((fp = auto_clnt_access(dict_sockmap_clnt)) == 0) { + msg_warn("table %s:%s lookup error: %m", dict->type, dict->name); + dict->error = DICT_ERR_RETRY; + return (0); + } + + /* + * Set up an exception handler. + */ + netstring_setup(fp, dict_sockmap_timeout); + if ((netstring_err = vstream_setjmp(fp)) == 0) { + + /* + * Send the query. This may raise an exception. + */ + vstring_sprintf(dp->rdwr_buf, "%s %s", dp->sockmap_name, key); + NETSTRING_PUT_BUF(fp, dp->rdwr_buf); + + /* + * Receive the response. This may raise an exception. + */ + netstring_get(fp, dp->rdwr_buf, dict_sockmap_max_reply); + + /* + * If we got here, then no exception was raised. + */ + break; + } + + /* + * Handle exceptions. + */ + else { + + /* + * We retry a broken connection only once. + */ + if (except_count == 0 && netstring_err == NETSTRING_ERR_EOF + && errno != ETIMEDOUT) { + auto_clnt_recover(dict_sockmap_clnt); + continue; + } + + /* + * We do not retry other errors. + */ + else { + msg_warn("table %s:%s lookup error: %s", + dict->type, dict->name, + netstring_strerror(netstring_err)); + dict->error = DICT_ERR_RETRY; + return (0); + } + } + } + + /* + * Parse the reply. + */ + VSTRING_TERMINATE(dp->rdwr_buf); + reply_payload = split_at(STR(dp->rdwr_buf), ' '); + if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_OK) == 0) { + dict->error = 0; + return (reply_payload); + } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_NOTFOUND) == 0) { + dict->error = 0; + return (0); + } + /* We got no definitive reply. */ + if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_TEMP) == 0) { + error_class = "temporary"; + dict->error = DICT_ERR_RETRY; + } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_TIMEOUT) == 0) { + error_class = "timeout"; + dict->error = DICT_ERR_RETRY; + } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_PERM) == 0) { + error_class = "permanent"; + dict->error = DICT_ERR_CONFIG; + } else { + error_class = "unknown"; + dict->error = DICT_ERR_RETRY; + } + while (reply_payload && ISSPACE(*reply_payload)) + reply_payload++; + msg_warn("%s:%s socketmap server %s error%s%.200s", + dict->type, dict->name, error_class, + reply_payload && *reply_payload ? ": " : "", + reply_payload && *reply_payload ? + printable(reply_payload, '?') : ""); + return (0); + } + + /* dict_sockmap_close - close socket map */ + + static void dict_sockmap_close(DICT *dict) + { + DICT_SOCKMAP *dp = (DICT_SOCKMAP *) dict; + + vstring_free(dp->rdwr_buf); + myfree(dp->sockmap_name); + if (--dict_sockmap_refcount == 0) { + auto_clnt_free(dict_sockmap_clnt); + dict_sockmap_clnt = 0; + } + if (dict->fold_buf) + vstring_free(dict->fold_buf); + myfree((char *) dp); + } + + /* dict_sockmap_open - open socket map */ + + DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags) + { + DICT_SOCKMAP *dp; + char *saved_name; + char *sockmap; + + /* + * Sanity checks. + */ + if (open_flags != O_RDONLY) + return (dict_surrogate(DICT_TYPE_SOCKMAP, mapname, + open_flags, dict_flags, + "%s:%s map requires O_RDONLY access mode", + DICT_TYPE_SOCKMAP, mapname)); + if (dict_flags & DICT_FLAG_NO_UNAUTH) + return (dict_surrogate(DICT_TYPE_SOCKMAP, mapname, + open_flags, dict_flags, + "%s:%s map is not allowed for security-sensitive data", + DICT_TYPE_SOCKMAP, mapname)); + + /* + * Split the socketmap name off the Postfix mapname. + */ + saved_name = mystrdup(mapname); + if ((sockmap = split_at_right(saved_name, ':')) == 0) + return (dict_surrogate(DICT_TYPE_SOCKMAP, mapname, + open_flags, dict_flags, + "%s requires server:socketmap argument", + DICT_TYPE_SOCKMAP)); + + /* + * Instantiate the shared client handle. + * + * XXX Todo: graceful degradation after endpoint syntax error. + */ + if (dict_sockmap_refcount == 0) + dict_sockmap_clnt = auto_clnt_create(saved_name, dict_sockmap_timeout, + dict_sockmap_max_idle, dict_sockmap_max_ttl); + dict_sockmap_refcount += 1; + + /* + * Instantiate a socket map handle. + */ + dp = (DICT_SOCKMAP *) dict_alloc(DICT_TYPE_SOCKMAP, mapname, sizeof(*dp)); + dp->rdwr_buf = vstring_alloc(100); + dp->sockmap_name = mystrdup(sockmap); + dp->dict.lookup = dict_sockmap_lookup; + dp->dict.close = dict_sockmap_close; + /* Don't look up parent domains or network superblocks. */ + dp->dict.flags = dict_flags | DICT_FLAG_PATTERN; + + /* + * Clean up. + */ + myfree(saved_name); + + return (DICT_DEBUG (&dp->dict)); + } diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/dict_sockmap.h ./src/util/dict_sockmap.h *** /var/tmp/postfix-2.10-20120308/src/util/dict_sockmap.h Wed Dec 31 19:00:00 1969 --- ./src/util/dict_sockmap.h Sun Mar 18 11:38:48 2012 *************** *** 0 **** --- 1,37 ---- + #ifndef _DICT_SOCKMAP_H_INCLUDED_ + #define _DICT_SOCKMAP_H_INCLUDED_ + + /*++ + /* NAME + /* dict_sockmap 3h + /* SUMMARY + /* dictionary manager interface to Sendmail-stye socketmap. + /* SYNOPSIS + /* #include + /* DESCRIPTION + /* .nf + + /* + * Utility library. + */ + #include + + /* + * External interface. + */ + #define DICT_TYPE_SOCKMAP "socketmap" + + extern DICT *dict_sockmap_open(const char *, int, int); + + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + #endif diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/netstring.c ./src/util/netstring.c *** /var/tmp/postfix-2.10-20120308/src/util/netstring.c Fri Feb 3 17:41:03 2012 --- ./src/util/netstring.c Sun Mar 25 10:08:32 2012 *************** *** 14,19 **** --- 14,22 ---- /* VSTREAM *stream; /* int exception; /* + /* const char *netstring_strerror(err) + /* int err; + /* /* VSTRING *netstring_get(stream, buf, limit) /* VSTREAM *stream; /* VSTRING *buf; *************** *** 72,77 **** --- 75,82 ---- /* netstring_except() raises the specified exception on the /* named stream. See the DIAGNOSTICS section below. /* + /* netstring_strerror() converts an exception number to string. + /* /* netstring_get() reads a netstring from the specified stream /* and extracts its content. The limit specifies a maximal size. /* Specify zero to disable the size limit. The result is not null *************** *** 352,354 **** --- 357,377 ---- VSTRING_ADDCH(buf, ','); return (buf); } + + /* netstring_strerror - convert error number to string */ + + const char *netstring_strerror(int err) + { + switch (err) { + case NETSTRING_ERR_EOF: + return ("unexpected disconnect"); + case NETSTRING_ERR_TIME: + return ("time limit exceeded"); + case NETSTRING_ERR_FORMAT: + return ("input format error"); + case NETSTRING_ERR_SIZE: + return ("input exceeds size limit"); + default: + return ("unknown netstring error"); + } + } diff -cr --exclude=.indent.pro --new-file /var/tmp/postfix-2.10-20120308/src/util/netstring.h ./src/util/netstring.h *** /var/tmp/postfix-2.10-20120308/src/util/netstring.h Sun Jul 10 16:37:49 2005 --- ./src/util/netstring.h Sun Mar 18 11:38:48 2012 *************** *** 36,41 **** --- 36,42 ---- extern void netstring_fflush(VSTREAM *); extern VSTRING *netstring_memcpy(VSTRING *, const char *, ssize_t); extern VSTRING *netstring_memcat(VSTRING *, const char *, ssize_t); + extern const char *netstring_strerror(int); #define NETSTRING_PUT_BUF(str, buf) \ netstring_put((str), vstring_str(buf), VSTRING_LEN(buf))