diff --git a/include/h.h b/include/h.h index 9df1bb04d..3d8a0b43c 100644 --- a/include/h.h +++ b/include/h.h @@ -701,6 +701,7 @@ extern MODVAR int (*tkl_hash)(unsigned int c); extern MODVAR char (*tkl_typetochar)(int type); extern MODVAR int (*tkl_chartotype)(char c); extern MODVAR char *(*tkl_type_string)(TKL *tk); +extern MODVAR char *(*tkl_type_config_string)(TKL *tk); extern MODVAR TKL *(*tkl_add_serverban)(int type, char *usermask, char *hostmask, char *reason, char *setby, time_t expire_at, time_t set_at, int soft, int flags); extern MODVAR TKL *(*tkl_add_banexception)(int type, char *usermask, char *hostmask, char *reason, char *set_by, @@ -776,6 +777,7 @@ extern MODVAR void *(*labeled_response_save_context)(void); extern MODVAR void (*labeled_response_set_context)(void *ctx); extern MODVAR void (*labeled_response_force_end)(void); extern MODVAR void (*kick_user)(MessageTag *mtags, Channel *channel, Client *client, Client *victim, char *comment); +extern MODVAR char *(*tkl_uhost)(TKL *tkl, char *buf, size_t buflen, int options); /* /Efuncs */ /* SSL/TLS functions */ @@ -1098,9 +1100,11 @@ extern char *log_type_valtostring(LogType v); extern void do_unreal_log(LogLevel loglevel, char *subsystem, char *event_id, Client *client, char *msg, ...) __attribute__((format(printf,5,0))); extern void do_unreal_log_raw(LogLevel loglevel, char *subsystem, char *event_id, Client *client, char *msg, ...); extern LogData *log_data_string(const char *key, const char *str); +extern LogData *log_data_char(const char *key, const char c); extern LogData *log_data_integer(const char *key, int64_t integer); extern LogData *log_data_client(const char *key, Client *client); extern LogData *log_data_source(const char *file, int line, const char *function); extern LogData *log_data_socket_error(int fd); extern LogData *log_data_link_block(ConfigItem_link *link); +extern LogData *log_data_tkl(const char *key, TKL *tkl); /* end of logging */ diff --git a/include/modules.h b/include/modules.h index c4c1caa14..725681fdd 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2311,6 +2311,7 @@ enum EfunctionType { EFUNC_MTAGS_TO_STRING, EFUNC_TKL_CHARTOTYPE, EFUNC_TKL_TYPE_STRING, + EFUNC_TKL_TYPE_CONFIG_STRING, EFUNC_CAN_SEND_TO_CHANNEL, EFUNC_CAN_SEND_TO_USER, EFUNC_BROADCAST_MD_GLOBALVAR, @@ -2335,6 +2336,7 @@ enum EfunctionType { EFUNC_LABELED_RESPONSE_SET_CONTEXT, EFUNC_LABELED_RESPONSE_FORCE_END, EFUNC_KICK_USER, + EFUNC_TKL_UHOST, }; /* Module flags */ diff --git a/src/api-efunctions.c b/src/api-efunctions.c index 4412af13d..290c410a2 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -46,6 +46,8 @@ int (*tkl_hash)(unsigned int c); char (*tkl_typetochar)(int type); int (*tkl_chartotype)(char c); char *(*tkl_type_string)(TKL *tk); +char *(*tkl_type_config_string)(TKL *tk); +char *(*tkl_uhost)(TKL *tkl, char *buf, size_t buflen, int options); TKL *(*tkl_add_serverban)(int type, char *usermask, char *hostmask, char *reason, char *setby, time_t expire_at, time_t set_at, int soft, int flags); TKL *(*tkl_add_nameban)(int type, char *name, int hold, char *reason, char *setby, @@ -343,6 +345,7 @@ void efunctions_init(void) efunc_init_function(EFUNC_MTAGS_TO_STRING, mtags_to_string, &mtags_to_string_default_handler); efunc_init_function(EFUNC_TKL_CHARTOTYPE, tkl_chartotype, NULL); efunc_init_function(EFUNC_TKL_TYPE_STRING, tkl_type_string, NULL); + efunc_init_function(EFUNC_TKL_TYPE_CONFIG_STRING, tkl_type_config_string, NULL); efunc_init_function(EFUNC_CAN_SEND_TO_CHANNEL, can_send_to_channel, NULL); efunc_init_function(EFUNC_BROADCAST_MD_GLOBALVAR, broadcast_md_globalvar, NULL); efunc_init_function(EFUNC_BROADCAST_MD_GLOBALVAR_CMD, broadcast_md_globalvar_cmd, NULL); @@ -365,4 +368,5 @@ void efunctions_init(void) efunc_init_function(EFUNC_LABELED_RESPONSE_SET_CONTEXT, labeled_response_set_context, labeled_response_set_context_default_handler); efunc_init_function(EFUNC_LABELED_RESPONSE_FORCE_END, labeled_response_force_end, labeled_response_force_end_default_handler); efunc_init_function(EFUNC_KICK_USER, kick_user, NULL); + efunc_init_function(EFUNC_TKL_UHOST, tkl_uhost, NULL); } diff --git a/src/log.c b/src/log.c index 565b570e6..435c00667 100644 --- a/src/log.c +++ b/src/log.c @@ -268,6 +268,17 @@ LogData *log_data_string(const char *key, const char *str) return d; } +LogData *log_data_char(const char *key, const char c) +{ + LogData *d = safe_alloc(sizeof(LogData)); + d->type = LOG_FIELD_STRING; + safe_strdup(d->key, key); + d->value.string = safe_alloc(2); + d->value.string[0] = c; + d->value.string[1] = '\0'; + return d; +} + LogData *log_data_integer(const char *key, int64_t integer) { LogData *d = safe_alloc(sizeof(LogData)); @@ -356,6 +367,63 @@ LogData *log_data_link_block(ConfigItem_link *link) } +LogData *log_data_tkl(const char *key, TKL *tkl) +{ + char buf[BUFSIZE]; + LogData *d = safe_alloc(sizeof(LogData)); + json_t *j; + + d->type = LOG_FIELD_OBJECT; + safe_strdup(d->key, key); + d->value.object = j = json_object(); + + json_object_set_new(j, "type", json_string(tkl_type_config_string(tkl))); // Eg 'kline' + json_object_set_new(j, "type_string", json_string(tkl_type_string(tkl))); // Eg 'Soft K-Line' + json_object_set_new(j, "set_by", json_string(tkl->set_by)); + json_object_set_new(j, "set_at", json_integer(tkl->set_at)); + json_object_set_new(j, "expire_at", json_integer(tkl->expire_at)); + *buf = '\0'; + short_date(tkl->set_at, buf); + strlcat(buf, " GMT", sizeof(buf)); + json_object_set_new(j, "set_at_string", json_string(buf)); + if (tkl->expire_at <= 0) + { + json_object_set_new(j, "expire_at_string", json_string("Never")); + } else { + *buf = '\0'; + short_date(tkl->expire_at, buf); + strlcat(buf, " GMT", sizeof(buf)); + json_object_set_new(j, "expire_at_string", json_string(buf)); + } + json_object_set_new(j, "set_at_delta", json_integer(TStime() - tkl->set_at)); + if (TKLIsServerBan(tkl)) + { + json_object_set_new(j, "name", json_string(tkl_uhost(tkl, buf, sizeof(buf), 0))); + json_object_set_new(j, "reason", json_string(tkl->ptr.serverban->reason)); + } else + if (TKLIsNameBan(tkl)) + { + json_object_set_new(j, "name", json_string(tkl->ptr.nameban->name)); + json_object_set_new(j, "reason", json_string(tkl->ptr.nameban->reason)); + } else + if (TKLIsBanException(tkl)) + { + json_object_set_new(j, "name", json_string(tkl_uhost(tkl, buf, sizeof(buf), 0))); + json_object_set_new(j, "reason", json_string(tkl->ptr.banexception->reason)); + json_object_set_new(j, "exception_types", json_string(tkl->ptr.banexception->bantypes)); + } else + if (TKLIsSpamfilter(tkl)) + { + json_object_set_new(j, "name", json_string(tkl->ptr.spamfilter->match->str)); + json_object_set_new(j, "match_type", json_string(unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type))); + json_object_set_new(j, "ban_action", json_string(banact_valtostring(tkl->ptr.spamfilter->action))); + json_object_set_new(j, "spamfilter_targets", json_string(spamfilter_target_inttostring(tkl->ptr.spamfilter->target))); + json_object_set_new(j, "reason", json_string(tkl->ptr.spamfilter->tkl_reason)); + } + + return d; +} + void log_data_free(LogData *d) { if (d->type == LOG_FIELD_STRING) diff --git a/src/modules/tkl.c b/src/modules/tkl.c index 1e3ce21fd..fc2b25f4d 100644 --- a/src/modules/tkl.c +++ b/src/modules/tkl.c @@ -55,6 +55,7 @@ char _tkl_typetochar(int type); int _tkl_chartotype(char c); int tkl_banexception_chartotype(char c); char *_tkl_type_string(TKL *tk); +char *_tkl_type_config_string(TKL *tk); char *tkl_banexception_configname_to_chars(char *name); TKL *_tkl_add_serverban(int type, char *usermask, char *hostmask, char *reason, char *set_by, time_t expire_at, time_t set_at, int soft, int flags); @@ -71,6 +72,7 @@ void _sendnotice_tkl_add(TKL *tkl); void _free_tkl(TKL *tkl); void _tkl_del_line(TKL *tkl); static void _tkl_check_local_remove_shun(TKL *tmp); +char *_tkl_uhost(TKL *tkl, char *buf, size_t buflen, int options); void tkl_expire_entry(TKL * tmp); EVENT(tkl_check_expire); int _find_tkline_match(Client *client, int skip_soft); @@ -161,6 +163,7 @@ MOD_TEST() EfunctionAdd(modinfo->handle, EFUNC_TKL_TYPETOCHAR, TO_INTFUNC(_tkl_typetochar)); EfunctionAdd(modinfo->handle, EFUNC_TKL_CHARTOTYPE, TO_INTFUNC(_tkl_chartotype)); EfunctionAddPChar(modinfo->handle, EFUNC_TKL_TYPE_STRING, _tkl_type_string); + EfunctionAddPChar(modinfo->handle, EFUNC_TKL_TYPE_CONFIG_STRING, _tkl_type_config_string); EfunctionAddPVoid(modinfo->handle, EFUNC_TKL_ADD_SERVERBAN, TO_PVOIDFUNC(_tkl_add_serverban)); EfunctionAddPVoid(modinfo->handle, EFUNC_TKL_ADD_BANEXCEPTION, TO_PVOIDFUNC(_tkl_add_banexception)); EfunctionAddPVoid(modinfo->handle, EFUNC_TKL_ADD_NAMEBAN, TO_PVOIDFUNC(_tkl_add_nameban)); @@ -191,6 +194,7 @@ MOD_TEST() EfunctionAddVoid(modinfo->handle, EFUNC_SENDNOTICE_TKL_ADD, _sendnotice_tkl_add); EfunctionAddVoid(modinfo->handle, EFUNC_SENDNOTICE_TKL_DEL, _sendnotice_tkl_del); EfunctionAdd(modinfo->handle, EFUNC_FIND_TKL_EXCEPTION, _find_tkl_exception); + EfunctionAddPChar(modinfo->handle, EFUNC_TKL_UHOST, _tkl_uhost); return MOD_SUCCESS; } @@ -2123,8 +2127,9 @@ int _tkl_hash(unsigned int c) else if ((c >= 'A') && (c <= 'Z')) return c-'A'; else { - sendto_realops("[BUG] tkl_hash() called with out of range parameter (c = '%c') !!!", c); - ircd_log(LOG_ERROR, "[BUG] tkl_hash() called with out of range parameter (c = '%c') !!!", c); + unreal_log(ULOG_ERROR, "bug", "TKL_HASH_INVALID", NULL, + "tkl_hash() called with out of range parameter (c = '$tkl_char') !!!", + log_data_char("tkl_char", c)); return 0; } #else @@ -2141,8 +2146,9 @@ char _tkl_typetochar(int type) for (i=0; tkl_types[i].config_name; i++) if ((tkl_types[i].type == type) && tkl_types[i].tkltype) return tkl_types[i].letter; - sendto_realops("[BUG]: tkl_typetochar(): unknown type 0x%x !!!", type); - ircd_log(LOG_ERROR, "[BUG] tkl_typetochar(): unknown type 0x%x !!!", type); + unreal_log(ULOG_ERROR, "bug", "TKL_TYPETOCHAR_INVALID", NULL, + "tkl_typetochar(): unknown type $tkl_type!!!", + log_data_integer("tkl_type", type)); return 0; } @@ -2201,13 +2207,13 @@ char *tkl_banexception_configname_to_chars(char *name) char *_tkl_type_string(TKL *tkl) { static char txt[256]; + int i; *txt = '\0'; if (TKLIsServerBan(tkl) && (tkl->ptr.serverban->subtype == TKL_SUBTYPE_SOFT)) strlcpy(txt, "Soft ", sizeof(txt)); - int i; for (i=0; tkl_types[i].config_name; i++) { if ((tkl_types[i].type == tkl->type) && tkl_types[i].tkltype) @@ -2221,6 +2227,18 @@ char *_tkl_type_string(TKL *tkl) return txt; } +/** Short config string, lowercase alnum with possibly hyphens (eg: 'kline') */ +char *_tkl_type_config_string(TKL *tkl) +{ + int i; + + for (i=0; tkl_types[i].config_name; i++) + if ((tkl_types[i].type == tkl->type) && tkl_types[i].tkltype) + return tkl_types[i].config_name; + + return "???"; +} + int tkl_banexception_matches_type(TKL *except, int bantype) { char *p; @@ -2746,7 +2764,7 @@ void _tkl_check_local_remove_shun(TKL *tmp) * that can be used in oper notices like expiring kline, added kline, etc. */ #define NO_SOFT_PREFIX 1 -char *tkl_uhost(TKL *tkl, char *buf, size_t buflen, int options) +char *_tkl_uhost(TKL *tkl, char *buf, size_t buflen, int options) { if (TKLIsServerBan(tkl)) { @@ -2784,56 +2802,29 @@ char *tkl_uhost(TKL *tkl, char *buf, size_t buflen, int options) */ void tkl_expire_entry(TKL *tkl) { - char *whattype = tkl_type_string(tkl); - - if (!tkl) - return; - - if (tkl->type & TKL_SPAMF) - { - /* Impossible */ - } else if (TKLIsServerBan(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - sendto_snomask(SNO_TKL, - "*** Expiring %s (%s) made by %s (Reason: %s) set %lld seconds ago", - whattype, uhost, tkl->set_by, tkl->ptr.serverban->reason, - (long long)(TStime() - tkl->set_at)); - ircd_log - (LOG_TKL, "Expiring %s (%s) made by %s (Reason: %s) set %lld seconds ago", - whattype, uhost, tkl->set_by, tkl->ptr.serverban->reason, - (long long)(TStime() - tkl->set_at)); + unreal_log(ULOG_INFO, "tkl", "TKL_EXPIRE", NULL, + "Expiring $tkl.type_string '$tkl' [reason: $tkl.reason] [by: $tkl.set_by] set $tkl.set_at_delta seconds ago", + log_data_tkl("tkl", tkl)); } else if (TKLIsNameBan(tkl)) { if (!tkl->ptr.nameban->hold) { - sendto_snomask(SNO_TKL, - "*** Expiring %s (%s) made by %s (Reason: %s) set %lld seconds ago", - whattype, tkl->ptr.nameban->name, tkl->set_by, tkl->ptr.nameban->reason, - (long long)(TStime() - tkl->set_at)); - ircd_log - (LOG_TKL, "Expiring %s (%s) made by %s (Reason: %s) set %lld seconds ago", - whattype, tkl->ptr.nameban->name, tkl->set_by, tkl->ptr.nameban->reason, - (long long)(TStime() - tkl->set_at)); + unreal_log(ULOG_INFO, "tkl", "TKL_EXPIRE", NULL, + "Expiring $tkl.type_string '$tkl' [reason: $tkl.reason] [by: $tkl.set_by] set $tkl.set_at_delta seconds ago", + log_data_tkl("tkl", tkl)); } } else if (TKLIsBanException(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - sendto_snomask(SNO_TKL, - "*** Expiring %s (%s) for types '%s' made by %s (Reason: %s) set %lld seconds ago", - whattype, uhost, tkl->ptr.banexception->bantypes, tkl->set_by, tkl->ptr.banexception->reason, - (long long)(TStime() - tkl->set_at)); - ircd_log - (LOG_TKL, "Expiring %s (%s) for types '%s' made by %s (Reason: %s) set %lld seconds ago", - whattype, uhost, tkl->ptr.banexception->bantypes, tkl->set_by, tkl->ptr.banexception->reason, - (long long)(TStime() - tkl->set_at)); + unreal_log(ULOG_INFO, "tkl", "TKL_EXPIRE", NULL, + "Expiring $tkl.type_string '$tkl' [type: $tkl.exception_types] [reason: $tkl.reason] [by: $tkl.set_by] set $tkl.set_at_delta seconds ago", + log_data_tkl("tkl", tkl)); } + // FIXME: so.. this isn't logged? or what? if (tkl->type & TKL_SHUN) tkl_check_local_remove_shun(tkl); @@ -3827,66 +3818,32 @@ void _sendnotice_tkl_add(TKL *tkl) if (TKLIsServerBan(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - if (tkl->expire_at != 0) - { - ircsnprintf(buf, sizeof(buf), "%s added for %s on %s GMT (from %s to expire at %s GMT: %s)", - tkl_type_str, uhost, - set_at, tkl->set_by, expire_at, tkl->ptr.serverban->reason); - } else { - ircsnprintf(buf, sizeof(buf), "Permanent %s added for %s on %s GMT (from %s: %s)", - tkl_type_str, uhost, - set_at, tkl->set_by, tkl->ptr.serverban->reason); - } + unreal_log(ULOG_INFO, "tkl", "TKL_ADD", NULL, + "$tkl.type_string added: '$tkl' [reason: $tkl.reason] [by: $tkl.set_by] [expires: $tkl.expire_at_string]", + log_data_tkl("tkl", tkl)); } else if (TKLIsNameBan(tkl)) { - if (tkl->expire_at > 0) - { - ircsnprintf(buf, sizeof(buf), "%s added for %s on %s GMT (from %s to expire at %s GMT: %s)", - tkl_type_str, tkl->ptr.nameban->name, set_at, tkl->set_by, expire_at, tkl->ptr.nameban->reason); - } else { - ircsnprintf(buf, sizeof(buf), "Permanent %s added for %s on %s GMT (from %s: %s)", - tkl_type_str, tkl->ptr.nameban->name, set_at, tkl->set_by, tkl->ptr.nameban->reason); - } + unreal_log(ULOG_INFO, "tkl", "TKL_ADD", NULL, + "$tkl.type_string added: '$tkl' [reason: $tkl.reason] [by: $tkl.set_by] [expires: $tkl.expire_at_string]", + log_data_tkl("tkl", tkl)); } else if (TKLIsSpamfilter(tkl)) { - /* Spamfilter */ - ircsnprintf(buf, sizeof(buf), - "Spamfilter added: '%s' [type: %s] [target: %s] [action: %s] [reason: %s] on %s GMT (from %s)", - tkl->ptr.spamfilter->match->str, - unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type), - spamfilter_target_inttostring(tkl->ptr.spamfilter->target), - banact_valtostring(tkl->ptr.spamfilter->action), - unreal_decodespace(tkl->ptr.spamfilter->tkl_reason), - set_at, - tkl->set_by); + unreal_log(ULOG_INFO, "tkl", "TKL_ADD", NULL, + "Spamfilter added: '$tkl' [type: $tkl.match_type] [targets: $tkl.spamfilter_targets] " + "[action: $tkl.ban_action] [reason: $tkl.reason] [by: $tkl.set_by]", + log_data_tkl("tkl", tkl)); } else if (TKLIsBanException(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - if (tkl->expire_at != 0) - { - ircsnprintf(buf, sizeof(buf), "%s added for %s for types '%s' on %s GMT (from %s to expire at %s GMT: %s)", - tkl_type_str, uhost, - tkl->ptr.banexception->bantypes, - set_at, tkl->set_by, expire_at, tkl->ptr.banexception->reason); - } else { - ircsnprintf(buf, sizeof(buf), "Permanent %s added for %s for types '%s' on %s GMT (from %s: %s)", - tkl_type_str, uhost, - tkl->ptr.banexception->bantypes, - set_at, tkl->set_by, tkl->ptr.banexception->reason); - } + unreal_log(ULOG_INFO, "tkl", "TKL_ADD", NULL, + "$tkl.type_string added: '$tkl' [types: $tkl.exception_types] [by: $tkl.set_by] [expires: $tkl.expire_at_string]", + log_data_tkl("tkl", tkl)); } else { ircsnprintf(buf, sizeof(buf), "[BUG] %s added but type unhandled in sendnotice_tkl_add()!!!", tkl_type_str); } - - sendto_snomask(SNO_TKL, "*** %s", buf); - ircd_log(LOG_TKL, "%s", buf); } /** Send a notice to opers about the TKL that is being deleted */ @@ -3907,40 +3864,36 @@ void _sendnotice_tkl_del(char *removed_by, TKL *tkl) if (TKLIsServerBan(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - ircsnprintf(buf, sizeof(buf), - "%s removed %s %s (set at %s - reason: %s)", - removed_by, tkl_type_str, uhost, - set_at, tkl->ptr.serverban->reason); + unreal_log(ULOG_INFO, "tkl", "TKL_DEL", NULL, + "$tkl.type_string removed: '$tkl' [reason: $tkl.reason] [by: $removed_by] [set at: $tkl.set_at_string]", + log_data_tkl("tkl", tkl), + log_data_string("removed_by", removed_by)); } else if (TKLIsNameBan(tkl)) { - ircsnprintf(buf, sizeof(buf), - "%s removed %s %s (set at %s - reason: %s)", - removed_by, tkl_type_str, tkl->ptr.nameban->name, set_at, tkl->ptr.nameban->reason); + unreal_log(ULOG_INFO, "tkl", "TKL_DEL", NULL, + "$tkl.type_string removed: '$tkl' [reason: $tkl.reason] [by: $removed_by] [set at: $tkl.set_at_string]", + log_data_tkl("tkl", tkl), + log_data_string("removed_by", removed_by)); } else if (TKLIsSpamfilter(tkl)) { - ircsnprintf(buf, sizeof(buf), - "%s removed Spamfilter '%s' (set at %s)", - removed_by, tkl->ptr.spamfilter->match->str, set_at); + unreal_log(ULOG_INFO, "tkl", "TKL_DEL", NULL, + "Spamfilter removed: '$tkl' [type: $tkl.match_type] [targets: $tkl.spamfilter_targets] " + "[action: $tkl.ban_action] [reason: $tkl.reason] [by: $removed_by] [set at: $tkl.set_at_string]", + log_data_tkl("tkl", tkl), + log_data_string("removed_by", removed_by)); } else if (TKLIsBanException(tkl)) { - char uhostbuf[BUFSIZE]; - char *uhost = tkl_uhost(tkl, uhostbuf, sizeof(uhostbuf), 0); - ircsnprintf(buf, sizeof(buf), - "%s removed exception on %s (set at %s - reason: %s)", - removed_by, uhost, - set_at, tkl->ptr.banexception->reason); + unreal_log(ULOG_INFO, "tkl", "TKL_DEL", NULL, + "$tkl.type_string removed: '$tkl' [types: $tkl.exception_types] [by: $removed_by] [set at: $tkl.set_at_string]", + log_data_tkl("tkl", tkl), + log_data_string("removed_by", removed_by)); } else { ircsnprintf(buf, sizeof(buf), "[BUG] %s added but type unhandled in sendnotice_tkl_del()!!!!!", tkl_type_str); } - - sendto_snomask(SNO_TKL, "*** %s", buf); - ircd_log(LOG_TKL, "%s", buf); } /** Add a TKL using the TKL layer. See cmd_tkl for parv[] and protocol documentation. */