mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-01 06:35:27 +00:00
snapshot-20000511
This commit is contained in:
@@ -3916,3 +3916,31 @@ Apologies for any names omitted.
|
|||||||
IP address for SMTP client connections. Specify in master.cf
|
IP address for SMTP client connections. Specify in master.cf
|
||||||
as "smtp -o smtp_bind_address=x.x.x.x" in order to give
|
as "smtp -o smtp_bind_address=x.x.x.x" in order to give
|
||||||
different delivery agents different source addresses.
|
different delivery agents different source addresses.
|
||||||
|
|
||||||
|
20000510
|
||||||
|
|
||||||
|
Cleanup: mailbox_transport did not work with the lmtp
|
||||||
|
delivery agent. This dates back to when Postfix used empty
|
||||||
|
nexthop information to indicate that a destination was
|
||||||
|
local. File: global/deliver_pass.c.
|
||||||
|
|
||||||
|
Bugfix: configuration parameters for one mysql dictionary
|
||||||
|
would become default settings for the next one. File:
|
||||||
|
dict_mysql.c. This patch was merged into Postfix a while
|
||||||
|
back but apparently that Postfix version was nuked when
|
||||||
|
other parts were redesigned. Update by Scott Cotton.
|
||||||
|
|
||||||
|
Bugfix: some Postfix delivery agents would abort on addresses
|
||||||
|
of the form `stuff@.' which could be generated only locally.
|
||||||
|
Found by Patrik Rak. File: trivial-rewrite/resolve.c.
|
||||||
|
|
||||||
|
Third-party Berkeley DB support for HP-UX by Lamont Jones.
|
||||||
|
File: makedefs.
|
||||||
|
|
||||||
|
20000511
|
||||||
|
|
||||||
|
Bugfix: Postfix would incorrectly reject domain names with
|
||||||
|
adjacent - characters. File: util/valid_hostname.c.
|
||||||
|
|
||||||
|
The 20000505 pipeline tarpit delay flush was wrong and
|
||||||
|
caused SMTP protocol errors.
|
||||||
|
@@ -90,7 +90,7 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
|
|||||||
mail_print(stream, "%s %s %ld %ld %s %s %s %s %ld %ld %s %s",
|
mail_print(stream, "%s %s %ld %ld %s %s %s %s %ld %ld %s %s",
|
||||||
request->queue_name, request->queue_id,
|
request->queue_name, request->queue_id,
|
||||||
request->data_offset, request->data_size,
|
request->data_offset, request->data_size,
|
||||||
addr, request->sender,
|
request->nexthop, request->sender,
|
||||||
request->errors_to, request->return_receipt,
|
request->errors_to, request->return_receipt,
|
||||||
request->arrival_time,
|
request->arrival_time,
|
||||||
offs, addr, "0");
|
offs, addr, "0");
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-20000507"
|
#define DEF_MAIL_VERSION "Snapshot-20000511"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -186,6 +186,9 @@ HP-UX.A.09.*) SYSTYPE=HPUX9
|
|||||||
CCARGS="$CCARGS -DHAS_DB"
|
CCARGS="$CCARGS -DHAS_DB"
|
||||||
SYSLIBS="$SYSLIBS -ldb"
|
SYSLIBS="$SYSLIBS -ldb"
|
||||||
fi
|
fi
|
||||||
|
if [ -f /usr/include/db_185.h ]; then
|
||||||
|
CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
HP-UX.B.10.*) SYSTYPE=HPUX10
|
HP-UX.B.10.*) SYSTYPE=HPUX10
|
||||||
CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null |
|
CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null |
|
||||||
@@ -194,6 +197,9 @@ HP-UX.B.10.*) SYSTYPE=HPUX10
|
|||||||
CCARGS="$CCARGS -DHAS_DB"
|
CCARGS="$CCARGS -DHAS_DB"
|
||||||
SYSLIBS=-ldb
|
SYSLIBS=-ldb
|
||||||
fi
|
fi
|
||||||
|
if [ -f /usr/include/db_185.h ]; then
|
||||||
|
CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
HP-UX.B.11.*) SYSTYPE=HPUX11
|
HP-UX.B.11.*) SYSTYPE=HPUX11
|
||||||
SYSLIBS=-lnsl
|
SYSLIBS=-lnsl
|
||||||
@@ -201,6 +207,9 @@ HP-UX.B.11.*) SYSTYPE=HPUX11
|
|||||||
CCARGS="$CCARGS -DHAS_DB"
|
CCARGS="$CCARGS -DHAS_DB"
|
||||||
SYSLIBS="$SYSLIBS -ldb"
|
SYSLIBS="$SYSLIBS -ldb"
|
||||||
fi
|
fi
|
||||||
|
if [ -f /usr/include/db_185.h ]; then
|
||||||
|
CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
|
ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
|
||||||
RANLIB=echo
|
RANLIB=echo
|
||||||
|
@@ -133,6 +133,7 @@ void smtpd_chat_query(SMTPD_STATE *state)
|
|||||||
void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
int slept = 0;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vstring_vsprintf(state->buffer, format, ap);
|
vstring_vsprintf(state->buffer, format, ap);
|
||||||
@@ -147,16 +148,21 @@ void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
|||||||
* that abort the connection and go into a connect-error-disconnect loop;
|
* that abort the connection and go into a connect-error-disconnect loop;
|
||||||
* sleep-on-anything slows down clients that make an excessive number of
|
* sleep-on-anything slows down clients that make an excessive number of
|
||||||
* errors within a session.
|
* errors within a session.
|
||||||
*
|
|
||||||
* Flush unsent output before sleeping. Pipelined error responses could
|
|
||||||
* result in client-side timeouts.
|
|
||||||
*/
|
*/
|
||||||
if (state->error_count > var_smtpd_soft_erlim)
|
if (state->error_count > var_smtpd_soft_erlim)
|
||||||
vstream_fflush(state->client), sleep(state->error_count);
|
sleep(slept = state->error_count);
|
||||||
else if (STR(state->buffer)[0] == '4' || STR(state->buffer)[0] == '5')
|
else if (STR(state->buffer)[0] == '4' || STR(state->buffer)[0] == '5')
|
||||||
vstream_fflush(state->client), sleep(var_smtpd_err_sleep);
|
sleep(slept = var_smtpd_err_sleep);
|
||||||
|
|
||||||
smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
|
smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush unsent output AFTER writing instead of before sleeping (so that
|
||||||
|
* vstream_fflush() flushes the output half of a bidirectional stream).
|
||||||
|
* Pipelined error responses could result in client-side timeouts.
|
||||||
|
*/
|
||||||
|
if (slept)
|
||||||
|
(vstream_fflush(state->client));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print_line - line_wrap callback */
|
/* print_line - line_wrap callback */
|
||||||
|
@@ -110,10 +110,12 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
|
|||||||
while (tree->head) {
|
while (tree->head) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Strip trailing dot.
|
* Strip trailing dot or @.
|
||||||
*/
|
*/
|
||||||
if (tree->tail->type == '.')
|
if (tree->tail->type == '.' || tree->tail->type == '@') {
|
||||||
tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
|
tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A lone empty string becomes the postmaster.
|
* A lone empty string becomes the postmaster.
|
||||||
|
@@ -201,9 +201,9 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* plmysql_query - process a MySQL query. Return MYSQL_RES* on success.
|
* plmysql_query - process a MySQL query. Return MYSQL_RES* on success.
|
||||||
* On failure, log failure and try other db instances.
|
* On failure, log failure and try other db instances.
|
||||||
* on failure of all db instances, return 0;
|
* on failure of all db instances, return 0;
|
||||||
* close unnecessary active connections
|
* close unnecessary active connections
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
||||||
@@ -361,20 +361,29 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
int i;
|
int i;
|
||||||
char *nameval;
|
char *nameval;
|
||||||
char *hosts;
|
char *hosts;
|
||||||
/* the name of the dict for processing the mysql options file */
|
|
||||||
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||||
ARGV *hosts_argv;
|
ARGV *hosts_argv;
|
||||||
|
VSTRING *opt_dict_name;
|
||||||
dict_load_file(mysqlcf_path, mysqlcf_path);
|
|
||||||
|
/*
|
||||||
|
* setup a dict containing info in the mysql cf file. the dict has a
|
||||||
|
* name, and a path. The name must be distinct from the path, or the
|
||||||
|
* dict interface gets confused. The name must be distinct for two
|
||||||
|
* different paths, or the configuration info will cache across different
|
||||||
|
* mysql maps, which can be confusing.
|
||||||
|
*/
|
||||||
|
opt_dict_name = vstring_alloc(64);
|
||||||
|
vstring_sprintf(opt_dict_name, "mysql opt dict %s", mysqlcf_path);
|
||||||
|
dict_load_file(vstring_str(opt_dict_name), mysqlcf_path);
|
||||||
/* mysql username lookup */
|
/* mysql username lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "user")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "user")) == NULL)
|
||||||
name->username = mystrdup("");
|
name->username = mystrdup("");
|
||||||
else
|
else
|
||||||
name->username = mystrdup(nameval);
|
name->username = mystrdup(nameval);
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("mysqlname_parse(): set username to '%s'", name->username);
|
msg_info("mysqlname_parse(): set username to '%s'", name->username);
|
||||||
/* password lookup */
|
/* password lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "password")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "password")) == NULL)
|
||||||
name->password = mystrdup("");
|
name->password = mystrdup("");
|
||||||
else
|
else
|
||||||
name->password = mystrdup(nameval);
|
name->password = mystrdup(nameval);
|
||||||
@@ -382,7 +391,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set password to '%s'", name->password);
|
msg_info("mysqlname_parse(): set password to '%s'", name->password);
|
||||||
|
|
||||||
/* database name lookup */
|
/* database name lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "dbname")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "dbname")) == NULL)
|
||||||
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
||||||
else
|
else
|
||||||
name->dbname = mystrdup(nameval);
|
name->dbname = mystrdup(nameval);
|
||||||
@@ -390,7 +399,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set database name to '%s'", name->dbname);
|
msg_info("mysqlname_parse(): set database name to '%s'", name->dbname);
|
||||||
|
|
||||||
/* table lookup */
|
/* table lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "table")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "table")) == NULL)
|
||||||
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
||||||
else
|
else
|
||||||
name->table = mystrdup(nameval);
|
name->table = mystrdup(nameval);
|
||||||
@@ -398,7 +407,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set table name to '%s'", name->table);
|
msg_info("mysqlname_parse(): set table name to '%s'", name->table);
|
||||||
|
|
||||||
/* select field lookup */
|
/* select field lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "select_field")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "select_field")) == NULL)
|
||||||
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
||||||
else
|
else
|
||||||
name->select_field = mystrdup(nameval);
|
name->select_field = mystrdup(nameval);
|
||||||
@@ -406,7 +415,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set select_field to '%s'", name->select_field);
|
msg_info("mysqlname_parse(): set select_field to '%s'", name->select_field);
|
||||||
|
|
||||||
/* where field lookup */
|
/* where field lookup */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "where_field")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "where_field")) == NULL)
|
||||||
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
||||||
else
|
else
|
||||||
name->where_field = mystrdup(nameval);
|
name->where_field = mystrdup(nameval);
|
||||||
@@ -414,7 +423,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set where_field to '%s'", name->where_field);
|
msg_info("mysqlname_parse(): set where_field to '%s'", name->where_field);
|
||||||
|
|
||||||
/* additional conditions */
|
/* additional conditions */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "additional_conditions")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "additional_conditions")) == NULL)
|
||||||
name->additional_conditions = mystrdup("");
|
name->additional_conditions = mystrdup("");
|
||||||
else
|
else
|
||||||
name->additional_conditions = mystrdup(nameval);
|
name->additional_conditions = mystrdup(nameval);
|
||||||
@@ -422,7 +431,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
msg_info("mysqlname_parse(): set additional_conditions to '%s'", name->additional_conditions);
|
msg_info("mysqlname_parse(): set additional_conditions to '%s'", name->additional_conditions);
|
||||||
|
|
||||||
/* mysql server hosts */
|
/* mysql server hosts */
|
||||||
if ((nameval = (char *) dict_lookup(mysqlcf_path, "hosts")) == NULL)
|
if ((nameval = (char *) dict_lookup(vstring_str(opt_dict_name), "hosts")) == NULL)
|
||||||
hosts = mystrdup("");
|
hosts = mystrdup("");
|
||||||
else
|
else
|
||||||
hosts = mystrdup(nameval);
|
hosts = mystrdup(nameval);
|
||||||
@@ -448,6 +457,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
myfree(hosts);
|
myfree(hosts);
|
||||||
|
vstring_free(opt_dict_name);
|
||||||
argv_free(hosts_argv);
|
argv_free(hosts_argv);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -455,7 +465,7 @@ static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* plmysql_init - initalize a MYSQL database.
|
* plmysql_init - initalize a MYSQL database.
|
||||||
* Return NULL on failure, or a PLMYSQL * on success.
|
* Return NULL on failure, or a PLMYSQL * on success.
|
||||||
*/
|
*/
|
||||||
static PLMYSQL *plmysql_init(char *hostnames[],
|
static PLMYSQL *plmysql_init(char *hostnames[],
|
||||||
int len_hosts)
|
int len_hosts)
|
||||||
|
@@ -81,12 +81,18 @@ int valid_hostname(const char *name)
|
|||||||
}
|
}
|
||||||
if (!ISDIGIT(ch))
|
if (!ISDIGIT(ch))
|
||||||
non_numeric = 1;
|
non_numeric = 1;
|
||||||
} else if (ch == '.' || ch == '-') {
|
} else if (ch == '.') {
|
||||||
if (label_length == 0 || cp[1] == 0) {
|
if (label_length == 0 || cp[1] == 0) {
|
||||||
msg_warn("%s: misplaced delimiter: %.100s", myname, name);
|
msg_warn("%s: misplaced delimiter: %.100s", myname, name);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
label_length = 0;
|
label_length = 0;
|
||||||
|
} else if (ch == '-') {
|
||||||
|
label_length++;
|
||||||
|
if (label_length == 1 || cp[1] == 0 || cp[1] == '.') {
|
||||||
|
msg_warn("%s: misplaced hyphen: %.100s", myname, name);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msg_warn("%s: invalid character %d(decimal): %.100s",
|
msg_warn("%s: invalid character %d(decimal): %.100s",
|
||||||
myname, ch, name);
|
myname, ch, name);
|
||||||
|
@@ -26,3 +26,13 @@ f1.2.3.4
|
|||||||
1.2.3.4f
|
1.2.3.4f
|
||||||
1.2.3.f4
|
1.2.3.f4
|
||||||
1.2.3.f
|
1.2.3.f
|
||||||
|
-.a.b
|
||||||
|
a.-.b
|
||||||
|
a.b.-
|
||||||
|
-aa.b.b
|
||||||
|
aa-.b.b
|
||||||
|
a.-bb.b
|
||||||
|
a.bb-.b
|
||||||
|
a.b.-bb
|
||||||
|
a.b.bb-
|
||||||
|
a-a.b-b
|
||||||
|
@@ -70,3 +70,32 @@
|
|||||||
./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f4
|
./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f4
|
||||||
./valid_hostname: testing: "1.2.3.f"
|
./valid_hostname: testing: "1.2.3.f"
|
||||||
./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f
|
./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f
|
||||||
|
./valid_hostname: testing: "-.a.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: -.a.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -.a.b
|
||||||
|
./valid_hostname: testing: "a.-.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-.b
|
||||||
|
./valid_hostname: testing: "a.b.-"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-
|
||||||
|
./valid_hostname: testing: "-aa.b.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: -aa.b.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -aa.b.b
|
||||||
|
./valid_hostname: testing: "aa-.b.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: aa-.b.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): aa-.b.b
|
||||||
|
./valid_hostname: testing: "a.-bb.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-bb.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-bb.b
|
||||||
|
./valid_hostname: testing: "a.bb-.b"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.bb-.b
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.bb-.b
|
||||||
|
./valid_hostname: testing: "a.b.-bb"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-bb
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-bb
|
||||||
|
./valid_hostname: testing: "a.b.bb-"
|
||||||
|
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.bb-
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.bb-
|
||||||
|
./valid_hostname: testing: "a-a.b-b"
|
||||||
|
./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a-a.b-b
|
||||||
|
Reference in New Issue
Block a user