diff --git a/include/h.h b/include/h.h index 8f54b8550..b01b2e893 100644 --- a/include/h.h +++ b/include/h.h @@ -937,6 +937,8 @@ extern MODVAR void (*exit_client_ex)(Client *client, Client *origin, MessageTag extern MODVAR void (*banned_client)(Client *client, const char *bantype, const char *reason, int global, int noexit); extern MODVAR char *(*unreal_expand_string)(const char *str, char *buf, size_t buflen, NameValuePrioList *nvp, int buildvarstring_options, Client *client); extern MODVAR char *(*utf8_convert_confusables)(const char *i, char *obuf, int olen); +extern MODVAR const char *(*utf8_get_block_name)(int i); +extern MODVAR int (*utf8_get_block_number)(const char *name); /* /Efuncs */ /* TLS functions */ @@ -998,6 +1000,8 @@ extern void sasl_succeeded_default_handler(Client *client); extern void sasl_failed_default_handler(Client *client); extern int decode_authenticate_plain_default_handler(const char *param, char **authorization_id, char **authentication_id, char **passwd); extern char *utf8_convert_confusables_default_handler(const char *i, char *obuf, int olen); +extern const char *utf8_get_block_name_default_handler(int i); +extern int utf8_get_block_number_default_handler(const char *name); /* End of default handlers for efunctions */ extern MODVAR MOTDFile opermotd, svsmotd, motd, botmotd, smotd, rules; diff --git a/include/modules.h b/include/modules.h index fd4d06704..6e804c376 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2751,6 +2751,8 @@ enum EfunctionType { EFUNC_UNREAL_EXPAND_STRING, EFUNC_UTF8_CONVERT_CONFUSABLES, EFUNC_UTF8_ANALYZE_TEXT, + EFUNC_UTF8_GET_BLOCK_NAME, + EFUNC_UTF8_GET_BLOCK_NUMBER, }; /* Module flags */ diff --git a/src/api-efunctions.c b/src/api-efunctions.c index 7615d0477..83d344de7 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -186,6 +186,8 @@ void (*exit_client_ex)(Client *client, Client *origin, MessageTag *recv_mtags, c void (*banned_client)(Client *client, const char *bantype, const char *reason, int global, int noexit); char *(*unreal_expand_string)(const char *str, char *buf, size_t buflen, NameValuePrioList *nvp, int buildvarstring_options, Client *client); char *(*utf8_convert_confusables)(const char *i, char *obuf, int olen); +const char *(*utf8_get_block_name)(int i); +int (*utf8_get_block_number)(const char *name); Efunction *EfunctionAddMain(Module *module, EfunctionType eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)()) { @@ -514,4 +516,6 @@ void efunctions_init(void) efunc_init_function(EFUNC_BANNED_CLIENT, banned_client, NULL, 0); efunc_init_function(EFUNC_UNREAL_EXPAND_STRING, unreal_expand_string, NULL, 0); efunc_init_function(EFUNC_UTF8_CONVERT_CONFUSABLES, utf8_convert_confusables, utf8_convert_confusables_default_handler, 0); + efunc_init_function(EFUNC_UTF8_GET_BLOCK_NAME, utf8_get_block_name, utf8_get_block_name, 0); + efunc_init_function(EFUNC_UTF8_GET_BLOCK_NUMBER, utf8_get_block_number, utf8_get_block_number, 0); } diff --git a/src/misc.c b/src/misc.c index 323ffd243..8c1300e48 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1542,6 +1542,16 @@ char *utf8_convert_confusables_default_handler(const char *i, char *obuf, int ol return obuf; } +const char *utf8_get_block_name_default_handler(int i) +{ + return NULL; +} + +int utf8_get_block_number_default_handler(const char *name) +{ + return -1; +} + /** my_timegm: mktime()-like function which will use GMT/UTC. * Strangely enough there is no standard function for this. * On some *NIX OS's timegm() may be available, sometimes only diff --git a/src/modules/tkl.c b/src/modules/tkl.c index 87f27d506..53e77e06a 100644 --- a/src/modules/tkl.c +++ b/src/modules/tkl.c @@ -255,7 +255,7 @@ MOD_INIT() CommandAdd(modinfo->handle, "SPAMFILTER", cmd_spamfilter, 7, CMD_OPER); CommandAdd(modinfo->handle, "ELINE", cmd_eline, 4, CMD_OPER); CommandAdd(modinfo->handle, "TKL", _cmd_tkl, MAXPARA, CMD_OPER|CMD_SERVER); - CommandAdd(modinfo->handle, "SPAMINFO", cmd_spaminfo, 1, CMD_OPER); + CommandAdd(modinfo->handle, "SPAMINFO", cmd_spaminfo, 1, CMD_OPER|CMD_TEXTANALYSIS); add_default_exempts(); return MOD_SUCCESS; } @@ -6199,7 +6199,7 @@ int spamfilter_pre_command(Client *from, MessageTag *mtags, const char *buf) CMD_FUNC(cmd_spaminfo) { const char *line; - char deconfused[512], *s; + int i, cnt; if (!IsOper(client)) { @@ -6213,14 +6213,36 @@ CMD_FUNC(cmd_spaminfo) return; } + if (!clictx->textanalysis) + { + sendnotice(client, "ERROR: Text analysis is not available. Maybe the utf8functions module is not loaded?"); + return; + } + sendnotice(client, "*** SPAMINFO ***"); sendnotice(client, "This will show the original text and the deconfused text which can be used in a spamfilter block with input-conversion deconfused;"); line = parv[1]; sendnotice(client, "Original spam text: %s", line); - - s = utf8_convert_confusables(line, deconfused, sizeof(deconfused)); - if (s) - sendnotice(client, "Deconfused spam text: %s", s); + sendnotice(client, "Deconfused spam text: %s", clictx->textanalysis->deconfused); + sendnotice(client, "AntiMixedUTF8 points: %d", clictx->textanalysis->antimixedutf8_points); + sendnotice(client, "Number of Unicode characters in total: %d", clictx->textanalysis->num_unicode_characters); + sendnotice(client, "Number of different Unicode blocks used: %d", clictx->textanalysis->unicode_blocks); + sendnotice(client, "Unicode Block breakdown (name: bytes [capped at 255]):"); + for (i = 0, cnt = 0; i < UNICODE_BLOCK_COUNT; i++) + { + if (clictx->textanalysis->unicode_blockmap[i]) + { + cnt += clictx->textanalysis->unicode_blockmap[i]; + sendnotice(client, "- %s: %d", + utf8_get_block_name(i), + (int)clictx->textanalysis->unicode_blockmap[i]); + } + } + if (clictx->textanalysis->num_unicode_characters != cnt) + { + sendnotice(client, "- Non-alpha ASCII characters (digits/spaces/etc.): %d", + clictx->textanalysis->num_unicode_characters - cnt); + } } diff --git a/src/modules/utf8functions.c b/src/modules/utf8functions.c index 8c299dc7b..486a2e696 100644 --- a/src/modules/utf8functions.c +++ b/src/modules/utf8functions.c @@ -5550,11 +5550,15 @@ ConfusablesConversionTable confusables_table[] = /* Forward declarations */ char *_utf8_convert_confusables(const char *i, char *obuf, int olen); int utf8_text_analysis(Client *client, const char *text, TextAnalysis *e); +const char *_utf8_get_block_name(int i); +int _utf8_get_block_number(const char *name); MOD_TEST() { MARK_AS_OFFICIAL_MODULE(modinfo); EfunctionAddString(modinfo->handle, EFUNC_UTF8_CONVERT_CONFUSABLES, _utf8_convert_confusables); + EfunctionAddConstString(modinfo->handle, EFUNC_UTF8_GET_BLOCK_NAME, _utf8_get_block_name); + EfunctionAdd(modinfo->handle, EFUNC_UTF8_GET_BLOCK_NUMBER, _utf8_get_block_number); return MOD_SUCCESS; } @@ -5937,3 +5941,21 @@ char *_utf8_convert_confusables(const char *i, char *obuf, int olen) *o = '\0'; return obuf; } + +/** Get UTF8 name for a block number (eg 0 returns "Basic Latin") */ +const char *_utf8_get_block_name(int i) +{ + if ((i < 0) || (i > ARRAY_SIZEOF(unicode_blocks)-1)) + return NULL; + return unicode_blocks[i].name; +} + +/** Get UTF8 block number by name (eg "Basic Latin" returns 0) */ +int _utf8_get_block_number(const char *name) +{ + int i; + for (i = 0; i < ARRAY_SIZEOF(unicode_blocks); i++) + if (!strcasecmp(unicode_blocks[i].name, name)) + return i; + return -1; +}