From: Wietse Venema Date: Fri, 1 Apr 2005 05:00:00 +0000 (-0500) Subject: postfix-2.2.2 X-Git-Tag: v2.2.2^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4c9849b42cca520774e1667d54dd45a3a4a1c101;p=thirdparty%2Fpostfix.git postfix-2.2.2 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 926f0b027..8af435734 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -10485,3 +10485,30 @@ Apologies for any names omitted. Bugfix: when is included, read is a reserved identifier. File: smtpstone/smtp-source.c. +20050317 + + Cleanup: change wording of error message when an IPv6 address + is mistaken for maptype:mapname. File: util/dict_open.c. + +20050321 + + Robustness: don't look for SMTP status code when there was + none. File: smtp/smtp_chat.c, lmtp/lmtp_chat.c. + + Portability: missing netinet/in.h include, so that ntohs() + was not defined on HP-UX. File: smtp/smtp_proto.c. + +20050327 + + Bugfix: the SMTP and LMTP clients did not ask the queue + manager to reduce destination concurrency when "lost + connection" or "connection timed out" happened AFTER Postfix + received the server greeting. Files: smtp/smtp_trouble.c, + lmtp/lmtp-trouble.c. + +20050328 + + Cleanup: the REPLACE action is no longer implemented as + PREPEND+IGNORE. The result remains in the input stream, and + is subject to address rewriting and other processing where + applicable. File: cleanup/cleanup_message.c. diff --git a/postfix/conf/header_checks b/postfix/conf/header_checks index 14b7d6f3c..038470778 100644 --- a/postfix/conf/header_checks +++ b/postfix/conf/header_checks @@ -1,4 +1,4 @@ -# HEADER_CHECKS(5) HEADER_CHECKS(5) +# HEADER_CHECKS(5) HEADER_CHECKS(5) # # NAME # header_checks - Postfix built-in header/body inspection @@ -202,6 +202,12 @@ # line, immediately before the input that # triggered the PREPEND action. # +# o The prepended text is not considered part of +# the input stream: it is not subject to +# header/body checks or address rewriting, and +# it does not affect the way that Postfix adds +# missing message headers. +# # o When prepending text before a message header # line, the prepended text must begin with a # valid message header label. @@ -228,11 +234,22 @@ # Replace the current line with the specified text # and inspect the next input line. # -# Note: when replacing a message header line, the -# replacement text must begin with a valid header -# label. -# # This feature is available in Postfix 2.2 and later. +# The description below applies to Postfix 2.2.2 and +# later. +# +# Notes: +# +# o When replacing a message header line, the +# replacement text must begin with a valid +# header label. +# +# o The replaced text remains part of the input +# stream. Unlike the result from the PREPEND +# action, a replaced message header may be +# subject to address rewriting and may affect +# the way that Postfix adds missing message +# headers. # # REJECT optional text... # Reject the entire message. Reply with optional @@ -359,4 +376,4 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# HEADER_CHECKS(5) +# HEADER_CHECKS(5) diff --git a/postfix/conf/virtual b/postfix/conf/virtual index 668332f9e..6aa789bc9 100644 --- a/postfix/conf/virtual +++ b/postfix/conf/virtual @@ -1,4 +1,4 @@ -# VIRTUAL(5) VIRTUAL(5) +# VIRTUAL(5) VIRTUAL(5) # # NAME # virtual - Postfix virtual alias table format @@ -11,10 +11,12 @@ # postmap -q - /etc/postfix/virtual PREPEND action. + o The prepended text is not considered part of + the input stream: it is not subject to + header/body checks or address rewriting, and + it does not affect the way that Postfix adds + missing message headers. + o When prepending text before a message header line, the prepended text must begin with a valid message header label. @@ -234,11 +240,22 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) Replace the current line with the specified text and inspect the next input line. - Note: when replacing a message header line, the - replacement text must begin with a valid header - label. - This feature is available in Postfix 2.2 and later. + The description below applies to Postfix 2.2.2 and + later. + + Notes: + + o When replacing a message header line, the + replacement text must begin with a valid + header label. + + o The replaced text remains part of the input + stream. Unlike the result from the PREPEND + action, a replaced message header may be + subject to address rewriting and may affect + the way that Postfix adds missing message + headers. REJECT optional text... Reject the entire message. Reply with optional diff --git a/postfix/html/virtual.5.html b/postfix/html/virtual.5.html index 2d6681c0f..937d3ed1f 100644 --- a/postfix/html/virtual.5.html +++ b/postfix/html/virtual.5.html @@ -17,10 +17,12 @@ VIRTUAL(5) VIRTUAL(5) postmap -q - /etc/postfix/virtual <inputfile DESCRIPTION - The optional virtual(5) alias table specifies address - aliasing for arbitrary local or non-local recipient - addresses. Virtual aliasing is recursive, and is done by - the Postfix cleanup(8) daemon. + The optional virtual(5) alias table rewrites recipient + addresses for all local, virtual and remote mail destina- + tions. This is unlike the aliases(5) table which is used + only for local(8) delivery. Virtual aliasing is recur- + sive, and is implemented by the Postfix cleanup(8) daemon + before mail is queued. The main applications of virtual aliasing are: diff --git a/postfix/man/man5/header_checks.5 b/postfix/man/man5/header_checks.5 index 71a48372d..3475ea3bf 100644 --- a/postfix/man/man5/header_checks.5 +++ b/postfix/man/man5/header_checks.5 @@ -194,6 +194,11 @@ Notes: The prepended text is output on a separate line, immediately before the input that triggered the \fBPREPEND\fR action. .IP \(bu +The prepended text is not considered part of the input +stream: it is not subject to header/body checks or address +rewriting, and it does not affect the way that Postfix adds +missing message headers. +.IP \(bu When prepending text before a message header line, the prepended text must begin with a valid message header label. .IP \(bu @@ -216,10 +221,20 @@ This feature is available in Postfix 2.1 and later. Replace the current line with the specified text and inspect the next input line. .sp -Note: when replacing a message header line, the replacement text -must begin with a valid header label. +This feature is available in Postfix 2.2 and later. The +description below applies to Postfix 2.2.2 and later. .sp -This feature is available in Postfix 2.2 and later. +Notes: +.RS +.IP \(bu +When replacing a message header line, the replacement text +must begin with a valid header label. +.IP \(bu +The replaced text remains part of the input stream. Unlike +the result from the \fBPREPEND\fR action, a replaced message +header may be subject to address rewriting and may affect +the way that Postfix adds missing message headers. +.RE .IP "\fBREJECT \fIoptional text...\fR Reject the entire message. Reply with \fIoptional text...\fR when the optional text is specified, otherwise reply with a generic error diff --git a/postfix/man/man5/virtual.5 b/postfix/man/man5/virtual.5 index c2851b8b2..9250663fc 100644 --- a/postfix/man/man5/virtual.5 +++ b/postfix/man/man5/virtual.5 @@ -16,9 +16,12 @@ Postfix virtual alias table format .SH DESCRIPTION .ad .fi -The optional \fBvirtual\fR(5) alias table specifies address aliasing -for arbitrary local or non-local recipient addresses. Virtual aliasing -is recursive, and is done by the Postfix \fBcleanup\fR(8) daemon. +The optional \fBvirtual\fR(5) alias table rewrites recipient +addresses for all local, virtual and remote mail destinations. +This is unlike the \fBaliases\fR(5) table which is used +only for \fBlocal\fR(8) delivery. Virtual aliasing is +recursive, and is implemented by the Postfix \fBcleanup\fR(8) +daemon before mail is queued. The main applications of virtual aliasing are: .IP \(bu diff --git a/postfix/proto/header_checks b/postfix/proto/header_checks index 289acac25..6fc1965d3 100644 --- a/postfix/proto/header_checks +++ b/postfix/proto/header_checks @@ -180,6 +180,11 @@ # The prepended text is output on a separate line, immediately # before the input that triggered the \fBPREPEND\fR action. # .IP \(bu +# The prepended text is not considered part of the input +# stream: it is not subject to header/body checks or address +# rewriting, and it does not affect the way that Postfix adds +# missing message headers. +# .IP \(bu # When prepending text before a message header line, the prepended # text must begin with a valid message header label. # .IP \(bu @@ -202,10 +207,20 @@ # Replace the current line with the specified text and inspect the next # input line. # .sp -# Note: when replacing a message header line, the replacement text -# must begin with a valid header label. +# This feature is available in Postfix 2.2 and later. The +# description below applies to Postfix 2.2.2 and later. # .sp -# This feature is available in Postfix 2.2 and later. +# Notes: +# .RS +# .IP \(bu +# When replacing a message header line, the replacement text +# must begin with a valid header label. +# .IP \(bu +# The replaced text remains part of the input stream. Unlike +# the result from the \fBPREPEND\fR action, a replaced message +# header may be subject to address rewriting and may affect +# the way that Postfix adds missing message headers. +# .RE # .IP "\fBREJECT \fIoptional text...\fR # Reject the entire message. Reply with \fIoptional text...\fR when # the optional text is specified, otherwise reply with a generic error diff --git a/postfix/proto/virtual b/postfix/proto/virtual index cf28b83d4..8a2a0b1f2 100644 --- a/postfix/proto/virtual +++ b/postfix/proto/virtual @@ -10,9 +10,12 @@ # # \fBpostmap -q - /etc/postfix/virtual <\fIinputfile\fR # DESCRIPTION -# The optional \fBvirtual\fR(5) alias table specifies address aliasing -# for arbitrary local or non-local recipient addresses. Virtual aliasing -# is recursive, and is done by the Postfix \fBcleanup\fR(8) daemon. +# The optional \fBvirtual\fR(5) alias table rewrites recipient +# addresses for all local, virtual and remote mail destinations. +# This is unlike the \fBaliases\fR(5) table which is used +# only for \fBlocal\fR(8) delivery. Virtual aliasing is +# recursive, and is implemented by the Postfix \fBcleanup\fR(8) +# daemon before mail is queued. # # The main applications of virtual aliasing are: # .IP \(bu diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 0a77d4f3d..029f70688 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -295,18 +295,17 @@ static void cleanup_act_log(CLEANUP_STATE *state, /* cleanup_act - act upon a header/body match */ -static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, - const char *value, const char *map_class) +static const char *cleanup_act(CLEANUP_STATE *state, char *context, + const char *buf, const char *value, + const char *map_class) { const char *optional_text = value + strcspn(value, " \t"); int command_len = optional_text - value; - VSTRING *bp; while (*optional_text && ISSPACE(*optional_text)) optional_text++; #define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0) -#define CLEANUP_ACT_KEEP 1 #define CLEANUP_ACT_DROP 0 if (STREQUAL(value, "REJECT", command_len)) { @@ -316,17 +315,18 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, state->errs |= CLEANUP_STAT_CONT; state->flags &= ~CLEANUP_FLAG_FILTER; cleanup_act_log(state, "reject", context, buf, state->reason); - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "WARN", command_len)) { cleanup_act_log(state, "warning", context, buf, optional_text); - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "FILTER", command_len)) { if (*optional_text == 0) { msg_warn("missing FILTER command argument in %s map", map_class); } else if (strchr(optional_text, ':') == 0) { - msg_warn("bad FILTER command %s in %s, need transport:destination", + msg_warn("bad FILTER command %s in %s -- " + "need transport:destination", optional_text, map_class); } else { if (state->filter) @@ -334,57 +334,52 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, state->filter = mystrdup(optional_text); cleanup_act_log(state, "filter", context, buf, optional_text); } - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "DISCARD", command_len)) { cleanup_act_log(state, "discard", context, buf, optional_text); state->flags |= CLEANUP_FLAG_DISCARD; state->flags &= ~CLEANUP_FLAG_FILTER; - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "HOLD", command_len)) { cleanup_act_log(state, "hold", context, buf, optional_text); state->flags |= CLEANUP_FLAG_HOLD; - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "PREPEND", command_len)) { if (*optional_text == 0) { msg_warn("PREPEND action without text in %s map", map_class); } else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0 && !is_header(optional_text)) { - msg_warn("bad PREPEND header text \"%s\" in %s map, " + msg_warn("bad PREPEND header text \"%s\" in %s map -- " "need \"headername: headervalue\"", optional_text, map_class); } else { cleanup_act_log(state, "prepend", context, buf, optional_text); cleanup_out_string(state, REC_TYPE_NORM, optional_text); } - return (CLEANUP_ACT_KEEP); + return (buf); } if (STREQUAL(value, "REPLACE", command_len)) { if (*optional_text == 0) { msg_warn("REPLACE action without text in %s map", map_class); - return (CLEANUP_ACT_KEEP); - } else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0) { - if (!is_header(optional_text)) { - msg_warn("bad REPLACE header text \"%s\" in %s map, " - "need \"headername: headervalue\"", - optional_text, map_class); - return (CLEANUP_ACT_KEEP); - } - /* XXX Impedance mismatch. */ - bp = vstring_strcpy(vstring_alloc(100), optional_text); - cleanup_out_header(state, bp); - vstring_free(bp); + return (buf); + } else if (strcmp(context, CLEANUP_ACT_CTXT_HEADER) == 0 + && !is_header(optional_text)) { + msg_warn("bad REPLACE header text \"%s\" in %s map -- " + "need \"headername: headervalue\"", + optional_text, map_class); + return (buf); } else { - cleanup_out_string(state, REC_TYPE_NORM, optional_text); + cleanup_act_log(state, "replace", context, buf, optional_text); + return (mystrdup(optional_text)); } - cleanup_act_log(state, "replace", context, buf, optional_text); - return (CLEANUP_ACT_DROP); } if (STREQUAL(value, "REDIRECT", command_len)) { if (strchr(optional_text, '@') == 0) { - msg_warn("bad REDIRECT target \"%s\" in %s map, need user@domain", + msg_warn("bad REDIRECT target \"%s\" in %s map -- " + "need user@domain", optional_text, map_class); } else { if (state->redirect) @@ -393,7 +388,7 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, cleanup_act_log(state, "redirect", context, buf, optional_text); state->flags &= ~CLEANUP_FLAG_FILTER; } - return (CLEANUP_ACT_KEEP); + return (buf); } /* Allow and ignore optional text after the action. */ @@ -401,13 +396,13 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, return (CLEANUP_ACT_DROP); if (STREQUAL(value, "DUNNO", command_len)) /* preferred */ - return (CLEANUP_ACT_KEEP); + return (buf); if (STREQUAL(value, "OK", command_len)) /* compat */ - return (CLEANUP_ACT_KEEP); + return (buf); msg_warn("unknown command in %s map: %s", map_class, value); - return (CLEANUP_ACT_KEEP); + return (buf); } /* cleanup_header_callback - process one complete header line */ @@ -456,10 +451,17 @@ static void cleanup_header_callback(void *context, int header_class, const char *value; if ((value = maps_find(checks, header, 0)) != 0) { - if (cleanup_act(state, CLEANUP_ACT_CTXT_HEADER, - header, value, map_class) - == CLEANUP_ACT_DROP) + const char *result; + + if ((result = cleanup_act(state, CLEANUP_ACT_CTXT_HEADER, + header, value, map_class)) + == CLEANUP_ACT_DROP) { return; + } else if (result != header) { + vstring_strcpy(header_buf, result); + hdr_opts = header_opts_find(result); + myfree((char *) result); + } } } @@ -665,10 +667,17 @@ static void cleanup_body_callback(void *context, int type, const char *value; if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) { - if (cleanup_act(state, CLEANUP_ACT_CTXT_BODY, - buf, value, VAR_BODY_CHECKS) - == CLEANUP_ACT_DROP) + const char *result; + + if ((result = cleanup_act(state, CLEANUP_ACT_CTXT_BODY, + buf, value, VAR_BODY_CHECKS)) + == CLEANUP_ACT_DROP) { return; + } else if (result != buf) { + cleanup_out(state, type, result, strlen(result)); + myfree((char *) result); + return; + } } } cleanup_out(state, type, buf, len); diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 8c1a6f86d..d35191193 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,8 +20,8 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only. */ -#define MAIL_RELEASE_DATE "20050315" -#define MAIL_VERSION_NUMBER "2.2.1" +#define MAIL_RELEASE_DATE "20050401" +#define MAIL_VERSION_NUMBER "2.2.2" #define VAR_MAIL_VERSION "mail_version" #ifdef SNAPSHOT diff --git a/postfix/src/lmtp/lmtp_chat.c b/postfix/src/lmtp/lmtp_chat.c index 43379a753..b06377138 100644 --- a/postfix/src/lmtp/lmtp_chat.c +++ b/postfix/src/lmtp/lmtp_chat.c @@ -175,6 +175,7 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state) static LMTP_RESP rdata; char *cp; int last_char; + int three_digs = 0; /* * Initialize the response data buffer. @@ -215,7 +216,7 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state) */ for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++) /* void */ ; - if (cp - STR(state->buffer) == 3) { + if ((three_digs = (cp - STR(state->buffer) == 3)) != 0) { if (*cp == '-') continue; if (*cp == ' ' || *cp == 0) @@ -223,7 +224,10 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state) } state->error_mask |= MAIL_ERROR_PROTOCOL; } - rdata.code = atoi(STR(state->buffer)); + if (three_digs != 0) + rdata.code = atoi(STR(state->buffer)); + else + rdata.code = 0; VSTRING_TERMINATE(rdata.buf); rdata.str = STR(rdata.buf); return (&rdata); diff --git a/postfix/src/lmtp/lmtp_trouble.c b/postfix/src/lmtp/lmtp_trouble.c index 84ce001e1..b9d1ce500 100644 --- a/postfix/src/lmtp/lmtp_trouble.c +++ b/postfix/src/lmtp/lmtp_trouble.c @@ -313,6 +313,8 @@ int lmtp_stream_except(LMTP_STATE *state, int code, char *description) request->arrival_time, "%s", vstring_str(why)); } + if (request->hop_status == 0) + request->hop_status = mystrdup(vstring_str(why)); /* * Cleanup. diff --git a/postfix/src/smtp/smtp_addr.c b/postfix/src/smtp/smtp_addr.c index 24f08902a..49980a415 100644 --- a/postfix/src/smtp/smtp_addr.c +++ b/postfix/src/smtp/smtp_addr.c @@ -209,7 +209,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRI freeaddrinfo(res0); if (found == 0) { vstring_sprintf(why, "%s: host not found", host); - smtp_errno = SMTP_ERR_FAIL; + if (smtp_errno != SMTP_ERR_RETRY) + smtp_errno = SMTP_ERR_FAIL; } return (addr_list); } diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 4cb579498..2270f7741 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -198,6 +198,7 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session) static SMTP_RESP rdata; char *cp; int last_char; + int three_digs = 0; /* * Initialize the response data buffer. @@ -238,7 +239,7 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session) */ for (cp = STR(session->buffer); *cp && ISDIGIT(*cp); cp++) /* void */ ; - if (cp - STR(session->buffer) == 3) { + if ((three_digs = (cp - STR(session->buffer) == 3)) != 0) { if (*cp == '-') continue; if (*cp == ' ' || *cp == 0) @@ -246,7 +247,10 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session) } session->error_mask |= MAIL_ERROR_PROTOCOL; } - rdata.code = atoi(STR(session->buffer)); + if (three_digs != 0) + rdata.code = atoi(STR(session->buffer)); + else + rdata.code = 0; VSTRING_TERMINATE(rdata.buf); rdata.str = STR(rdata.buf); return (&rdata); diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index ebbe53f1a..398a951c7 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -91,6 +91,7 @@ #include #include #include /* shutdown(2) */ +#include /* ntohs() */ #include #include #include /* 44BSD stdarg.h uses abort() */ diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 64cb7f273..453cc9e69 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -129,13 +129,6 @@ /* * Per-site policies can override main.cf settings. - * - * XXX 200412 This does not work as some people may expect. A policy that - * specifies "use TLS" in a policy file while TLS is turned off in main.cf - * cannot work, because there is no OpenSSL context for creating sessions - * (that context exists only if TLS is enabled via main.cf settings; the - * OpenSSL context is created at process initialization time and cannot be - * created on the fly). */ typedef struct { int dont_use; /* don't use TLS */ diff --git a/postfix/src/smtp/smtp_trouble.c b/postfix/src/smtp/smtp_trouble.c index 435a1ae35..1d8ba27e3 100644 --- a/postfix/src/smtp/smtp_trouble.c +++ b/postfix/src/smtp/smtp_trouble.c @@ -420,6 +420,9 @@ int smtp_stream_except(SMTP_STATE *state, int code, char *description) "%s", vstring_str(why)); SMTP_RCPT_DROP(state, rcpt); } + /* XXX This assumes no fall-back relay. */ + if (request->hop_status == 0) + request->hop_status = mystrdup(vstring_str(why)); } /* diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index 079c51ee3..c89911f54 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -266,7 +266,7 @@ DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags) DICT *dict; if ((dict_name = split_at(saved_dict_spec, ':')) == 0) - msg_fatal("open dictionary: need \"type:name\" form instead of: \"%s\"", + msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s\"", dict_spec); dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags); @@ -284,6 +284,9 @@ DICT *dict_open3(const char *dict_type, const char *dict_name, DICT_OPEN_INFO *dp; DICT *dict; + if (*dict_type == 0 || *dict_name == 0) + msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s:%s\"", + dict_type, dict_name); if (dict_open_hash == 0) dict_open_init(); if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0)