1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-05 11:13:13 +02:00

Update TKL code to use new logging system. Make the TKL add/del/expiry

messages more consistent at the same time.
This commit is contained in:
Bram Matthys
2021-08-05 10:19:05 +02:00
parent 952cb121c2
commit dbdfb7c656
5 changed files with 142 additions and 111 deletions
+4
View File
@@ -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 */
+2
View File
@@ -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 */
+4
View File
@@ -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);
}
+68
View File
@@ -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)
+64 -111
View File
@@ -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. */