849 lines
19 KiB
C
849 lines
19 KiB
C
|
/*
|
||
|
* Copyright (c) 2005 William Pitcock
|
||
|
* Rights to this code are as documented in doc/LICENSE.
|
||
|
*
|
||
|
* Allows setting multiple marks on nicknames using nickserv mark
|
||
|
* Do NOT use this in combination with nickserv/mark!
|
||
|
*/
|
||
|
|
||
|
#include "atheme.h"
|
||
|
#include "../nickserv/list.h"
|
||
|
|
||
|
DECLARE_MODULE_V1
|
||
|
(
|
||
|
"contrib/multimark", false, _modinit, _moddeinit,
|
||
|
PACKAGE_STRING,
|
||
|
"Atheme Development Group <http://www.atheme.org>"
|
||
|
);
|
||
|
|
||
|
static void ns_cmd_multimark(sourceinfo_t *si, int parc, char *parv[]);
|
||
|
|
||
|
static void write_multimark_db(database_handle_t *db);
|
||
|
static void db_h_mm(database_handle_t *db, const char *type);
|
||
|
static void db_h_rm(database_handle_t *db, const char *type);
|
||
|
|
||
|
static void show_multimark(hook_user_req_t *hdata);
|
||
|
static void show_multimark_noexist(hook_info_noexist_req_t *hdata);
|
||
|
|
||
|
static void account_drop_hook(myuser_t *mu);
|
||
|
|
||
|
static void nick_group_hook(hook_user_req_t *hdata);
|
||
|
static void nick_ungroup_hook(hook_user_req_t *hdata);
|
||
|
static void account_register_hook(myuser_t *mu);
|
||
|
|
||
|
static inline mowgli_list_t *multimark_list(myuser_t *mu);
|
||
|
|
||
|
static mowgli_patricia_t *restored_marks;
|
||
|
|
||
|
command_t ns_multimark = { "MARK", N_("Adds a note to a user."), PRIV_MARK, 3, ns_cmd_multimark, { .path = "contrib/multimark" } };
|
||
|
|
||
|
struct multimark {
|
||
|
char *setter_uid;
|
||
|
char *setter_name;
|
||
|
char *restored_from_uid;
|
||
|
time_t time;
|
||
|
int number;
|
||
|
char *mark;
|
||
|
mowgli_node_t node;
|
||
|
};
|
||
|
|
||
|
struct restored_mark {
|
||
|
char *account_uid;
|
||
|
char *account_name;
|
||
|
char *setter_uid;
|
||
|
char *setter_name;
|
||
|
time_t time;
|
||
|
char *mark;
|
||
|
mowgli_node_t node;
|
||
|
};
|
||
|
|
||
|
typedef struct multimark multimark_t;
|
||
|
typedef struct restored_mark restored_mark_t;
|
||
|
|
||
|
static bool multimark_match(const mynick_t *mn, const void *arg) {
|
||
|
const char *markpattern = (const char*)arg;
|
||
|
myuser_t *mu = mn->owner;
|
||
|
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
|
||
|
if (!match(markpattern, mm->mark)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool is_marked(const mynick_t *mn, const void *arg) {
|
||
|
myuser_t *mu = mn->owner;
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
return MOWGLI_LIST_LENGTH(l) != 0;
|
||
|
}
|
||
|
|
||
|
void _modinit(module_t *m)
|
||
|
{
|
||
|
if (!module_find_published("backend/opensex"))
|
||
|
{
|
||
|
slog(LG_INFO, "Module %s requires use of the OpenSEX database backend, refusing to load.", m->name);
|
||
|
m->mflags = MODTYPE_FAIL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
restored_marks = mowgli_patricia_create(strcasecanon);
|
||
|
|
||
|
hook_add_db_write(write_multimark_db);
|
||
|
db_register_type_handler("MM", db_h_mm);
|
||
|
db_register_type_handler("RM", db_h_rm);
|
||
|
|
||
|
hook_add_event("user_info");
|
||
|
hook_add_user_info(show_multimark);
|
||
|
|
||
|
hook_add_event("user_info_noexist");
|
||
|
hook_add_user_info_noexist(show_multimark_noexist);
|
||
|
|
||
|
hook_add_event("user_drop");
|
||
|
hook_add_user_drop(account_drop_hook);
|
||
|
|
||
|
hook_add_event("nick_ungroup");
|
||
|
hook_add_nick_ungroup(nick_ungroup_hook);
|
||
|
|
||
|
hook_add_event("nick_group");
|
||
|
hook_add_nick_group(nick_group_hook);
|
||
|
|
||
|
hook_add_event("user_register");
|
||
|
hook_add_user_register(account_register_hook);
|
||
|
|
||
|
service_named_bind_command("nickserv", &ns_multimark);
|
||
|
|
||
|
use_nslist_main_symbols(m);
|
||
|
|
||
|
static list_param_t mark;
|
||
|
mark.opttype = OPT_STRING;
|
||
|
mark.is_match = multimark_match;
|
||
|
|
||
|
list_register("mark-reason", &mark);
|
||
|
|
||
|
static list_param_t mark_check;
|
||
|
mark_check.opttype = OPT_BOOL;
|
||
|
mark_check.is_match = is_marked;
|
||
|
|
||
|
list_register("marked", &mark_check);
|
||
|
|
||
|
}
|
||
|
|
||
|
void _moddeinit(module_unload_intent_t intent)
|
||
|
{
|
||
|
hook_del_db_write(write_multimark_db);
|
||
|
db_unregister_type_handler("MM");
|
||
|
|
||
|
hook_del_user_info(show_multimark);
|
||
|
hook_del_user_info_noexist(show_multimark_noexist);
|
||
|
hook_del_user_drop(account_drop_hook);
|
||
|
hook_del_nick_ungroup(nick_ungroup_hook);
|
||
|
hook_del_nick_group(nick_group_hook);
|
||
|
hook_del_user_register(account_register_hook);
|
||
|
|
||
|
service_named_unbind_command("nickserv", &ns_multimark);
|
||
|
|
||
|
list_unregister("mark-reason");
|
||
|
list_unregister("marked");
|
||
|
}
|
||
|
|
||
|
static inline mowgli_list_t *multimark_list(myuser_t *mu)
|
||
|
{
|
||
|
mowgli_list_t *l;
|
||
|
|
||
|
return_val_if_fail(mu != NULL, NULL);
|
||
|
|
||
|
l = privatedata_get(mu, "mark:list");
|
||
|
|
||
|
if (l != NULL)
|
||
|
return l;
|
||
|
|
||
|
l = mowgli_list_create();
|
||
|
privatedata_set(mu, "mark:list", l);
|
||
|
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
mowgli_list_t *restored_mark_list(const char *nick)
|
||
|
{
|
||
|
mowgli_list_t *l = mowgli_patricia_retrieve(restored_marks, nick);
|
||
|
|
||
|
if (l == NULL) {
|
||
|
l = mowgli_list_create();
|
||
|
mowgli_patricia_add(restored_marks, nick, l);
|
||
|
}
|
||
|
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
static void write_multimark_db(database_handle_t *db)
|
||
|
{
|
||
|
mowgli_node_t *n;
|
||
|
mynick_t *mn;
|
||
|
myuser_t *mu;
|
||
|
myentity_iteration_state_t state;
|
||
|
mowgli_list_t *l;
|
||
|
myentity_t *mt;
|
||
|
|
||
|
mowgli_patricia_iteration_state_t state2;
|
||
|
mowgli_list_t *rml;
|
||
|
restored_mark_t *rm;
|
||
|
|
||
|
MYENTITY_FOREACH_T(mt, &state, ENT_USER)
|
||
|
{
|
||
|
mu = user(mt);
|
||
|
l = multimark_list(mu);
|
||
|
|
||
|
if (l == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head)
|
||
|
{
|
||
|
multimark_t *mm = n->data;
|
||
|
db_start_row(db, "MM");
|
||
|
db_write_word(db, entity(mu)->id);
|
||
|
db_write_word(db, mm->setter_uid);
|
||
|
db_write_word(db, mm->setter_name);
|
||
|
|
||
|
if (mm->restored_from_uid == NULL) {
|
||
|
db_write_word(db, "NULL");
|
||
|
} else {
|
||
|
db_write_word(db, mm->restored_from_uid);
|
||
|
}
|
||
|
|
||
|
db_write_uint(db, mm->time);
|
||
|
db_write_int(db, mm->number);
|
||
|
db_write_str(db, mm->mark);
|
||
|
db_commit_row(db);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MOWGLI_PATRICIA_FOREACH(rml, &state2, restored_marks)
|
||
|
{
|
||
|
MOWGLI_ITER_FOREACH(n, rml->head)
|
||
|
{
|
||
|
rm = n->data;
|
||
|
db_start_row(db, "RM");
|
||
|
db_write_word(db, rm->account_uid);
|
||
|
db_write_word(db, rm->account_name);
|
||
|
db_write_word(db, rm->setter_uid);
|
||
|
db_write_word(db, rm->setter_name);
|
||
|
db_write_uint(db, rm->time);
|
||
|
db_write_str(db, rm->mark);
|
||
|
db_commit_row(db);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void db_h_mm(database_handle_t *db, const char *type)
|
||
|
{
|
||
|
myuser_t *mu;
|
||
|
mowgli_patricia_iteration_state_t state;
|
||
|
mowgli_list_t *l;
|
||
|
|
||
|
const char *account_uid = db_sread_word(db);
|
||
|
const char *setter_uid = db_sread_word(db);
|
||
|
const char *setter_name = db_sread_word(db);
|
||
|
const char *restored_from_uid = db_sread_word(db);
|
||
|
time_t time = db_sread_uint(db);
|
||
|
int number = db_sread_int(db);
|
||
|
const char *mark = db_sread_str(db);
|
||
|
|
||
|
mu = myuser_find_uid(account_uid);
|
||
|
|
||
|
l = multimark_list(mu);
|
||
|
|
||
|
multimark_t *mm = smalloc(sizeof(multimark_t));
|
||
|
|
||
|
mm->setter_uid = sstrdup(setter_uid);
|
||
|
mm->setter_name = sstrdup(setter_name);
|
||
|
mm->restored_from_uid = sstrdup(restored_from_uid);
|
||
|
|
||
|
if (!strcasecmp (mm->restored_from_uid, "NULL")) {
|
||
|
mm->restored_from_uid = NULL;
|
||
|
}
|
||
|
|
||
|
mm->time = time;
|
||
|
mm->number = number;
|
||
|
mm->mark = sstrdup(mark);
|
||
|
|
||
|
mowgli_node_add(mm, &mm->node, l);
|
||
|
}
|
||
|
|
||
|
static void db_h_rm(database_handle_t *db, const char *type)
|
||
|
{
|
||
|
myuser_t *mu;
|
||
|
mowgli_patricia_iteration_state_t state;
|
||
|
|
||
|
const char *account_uid = db_sread_word(db);
|
||
|
const char *account_name = db_sread_word(db);
|
||
|
const char *setter_uid = db_sread_word(db);
|
||
|
const char *setter_name = db_sread_word(db);
|
||
|
time_t time = db_sread_uint(db);
|
||
|
const char *mark = db_sread_str(db);
|
||
|
|
||
|
mowgli_list_t *l = restored_mark_list(account_name);
|
||
|
|
||
|
restored_mark_t *rm = smalloc(sizeof(restored_mark_t));
|
||
|
|
||
|
rm->account_uid = sstrdup(account_uid);
|
||
|
rm->account_name = sstrdup(account_name);
|
||
|
rm->setter_uid = sstrdup(setter_uid);
|
||
|
rm->setter_name = sstrdup(setter_name);
|
||
|
rm->time = time;
|
||
|
rm->mark = sstrdup(mark);
|
||
|
|
||
|
mowgli_node_add(rm, &rm->node, l);
|
||
|
|
||
|
mowgli_patricia_add(restored_marks, account_name, l);
|
||
|
}
|
||
|
|
||
|
|
||
|
int get_multimark_max(myuser_t *mu) {
|
||
|
int max = 0;
|
||
|
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
if (mm->number > max) {
|
||
|
max = mm->number;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return max+1;
|
||
|
}
|
||
|
|
||
|
static void nick_ungroup_hook(hook_user_req_t *hdata) {
|
||
|
myuser_t *mu = hdata->mu;
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
|
||
|
char *uid = entity(mu)->id;
|
||
|
const char *name = hdata->mn->nick;
|
||
|
|
||
|
mowgli_list_t *rml = restored_mark_list(name);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
|
||
|
restored_mark_t *rm = smalloc(sizeof(restored_mark_t));
|
||
|
rm->account_uid = sstrdup(uid);
|
||
|
rm->account_name = sstrdup(name);
|
||
|
rm->setter_uid = sstrdup(mm->setter_uid);
|
||
|
rm->setter_name = sstrdup(mm->setter_name);
|
||
|
rm->time = mm->time;
|
||
|
rm->mark = sstrdup(mm->mark);
|
||
|
|
||
|
mowgli_node_add(rm, &rm->node, rml);
|
||
|
}
|
||
|
|
||
|
mowgli_patricia_add(restored_marks, name, rml);
|
||
|
}
|
||
|
|
||
|
static void account_drop_hook(myuser_t *mu) {
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
|
||
|
char *uid = entity(mu)->id;
|
||
|
const char *name = entity(mu)->name;
|
||
|
mowgli_list_t *rml = restored_mark_list(name);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
|
||
|
restored_mark_t *rm = smalloc(sizeof(restored_mark_t));
|
||
|
rm->account_uid = sstrdup(uid);
|
||
|
rm->account_name = sstrdup(name);
|
||
|
rm->setter_uid = sstrdup(mm->setter_uid);
|
||
|
rm->setter_name = sstrdup(mm->setter_name);
|
||
|
rm->time = mm->time;
|
||
|
rm->mark = sstrdup(mm->mark);
|
||
|
|
||
|
mowgli_node_add(rm, &rm->node, rml);
|
||
|
}
|
||
|
|
||
|
mowgli_patricia_add(restored_marks, name, rml);
|
||
|
}
|
||
|
|
||
|
static void account_register_hook(myuser_t *mu) {
|
||
|
mowgli_list_t *l = multimark_list(mu);
|
||
|
|
||
|
mowgli_node_t *n, *tn;
|
||
|
restored_mark_t *rm;
|
||
|
|
||
|
const char *name = entity(mu)->name;
|
||
|
|
||
|
char *setter_name;
|
||
|
myuser_t *setter;
|
||
|
|
||
|
mowgli_list_t *rml = restored_mark_list(name);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH_SAFE(n, tn, rml->head) {
|
||
|
rm = n->data;
|
||
|
|
||
|
multimark_t *mm = smalloc(sizeof(multimark_t));
|
||
|
|
||
|
mm->setter_uid = sstrdup(rm->setter_uid);
|
||
|
mm->setter_name = sstrdup(rm->setter_name);
|
||
|
mm->restored_from_uid = rm->account_uid;
|
||
|
mm->time = rm->time;
|
||
|
mm->number = get_multimark_max(mu);
|
||
|
mm->mark = sstrdup(rm->mark);
|
||
|
|
||
|
mowgli_node_add(mm, &mm->node, l);
|
||
|
|
||
|
mowgli_node_delete(&rm->node, rml);
|
||
|
//mowgli_node_free(n);
|
||
|
}
|
||
|
|
||
|
mowgli_patricia_add(restored_marks, name, rml);
|
||
|
}
|
||
|
|
||
|
static void nick_group_hook(hook_user_req_t *hdata) {
|
||
|
myuser_t *smu = hdata->si->smu;
|
||
|
mowgli_list_t *l = multimark_list(smu);
|
||
|
|
||
|
mowgli_node_t *n, *tn, *n2;
|
||
|
multimark_t *mm2;
|
||
|
restored_mark_t *rm;
|
||
|
|
||
|
char *uid = entity(smu)->id;
|
||
|
const char *name = hdata->mn->nick;
|
||
|
|
||
|
mowgli_list_t *rml = restored_mark_list(name);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH_SAFE(n, tn, rml->head) {
|
||
|
rm = n->data;
|
||
|
bool stop = false;
|
||
|
|
||
|
MOWGLI_ITER_FOREACH (n2, l->head) {
|
||
|
mm2 = n2->data;
|
||
|
|
||
|
if (!strcasecmp (mm2->mark, rm->mark)) {
|
||
|
stop = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mowgli_node_delete(&rm->node, rml);
|
||
|
|
||
|
if (stop) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
multimark_t *mm = smalloc(sizeof(multimark_t));
|
||
|
|
||
|
mm->setter_uid = sstrdup(rm->setter_uid);
|
||
|
mm->setter_name = sstrdup(rm->setter_name);
|
||
|
mm->restored_from_uid = rm->account_uid;
|
||
|
mm->time = rm->time;
|
||
|
mm->number = get_multimark_max(smu);
|
||
|
mm->mark = sstrdup(rm->mark);
|
||
|
|
||
|
mowgli_node_add(mm, &mm->node, l);
|
||
|
|
||
|
//mowgli_node_free(n);
|
||
|
}
|
||
|
|
||
|
mowgli_patricia_add(restored_marks, name, rml);
|
||
|
}
|
||
|
|
||
|
static void show_multimark(hook_user_req_t *hdata) {
|
||
|
mowgli_list_t *l = multimark_list(hdata->mu);
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
struct tm tm;
|
||
|
char time[BUFSIZE];
|
||
|
|
||
|
myuser_t *setter;
|
||
|
char *setter_name;
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
tm = *localtime(&mm->time);
|
||
|
|
||
|
strftime(time, sizeof time, TIME_FORMAT, &tm);
|
||
|
|
||
|
if ( setter = myuser_find_uid(mm->setter_uid) ) {
|
||
|
setter_name = entity(setter)->name;
|
||
|
} else {
|
||
|
setter_name = mm->setter_name;
|
||
|
}
|
||
|
|
||
|
if ( mm->restored_from_uid == NULL ) {
|
||
|
if ( strcasecmp (setter_name, mm->setter_name) ) {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("Mark \2%d\2 set by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("Mark \2%d\2 set by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
if ( strcasecmp (setter_name, mm->setter_name) ) {
|
||
|
myuser_t *user;
|
||
|
if (user = myuser_find_uid(mm->restored_from_uid)) {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 (\2%s\2) by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
entity(user)->name,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
myuser_t *user;
|
||
|
if (user = myuser_find_uid(mm->restored_from_uid)) {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 (\2%s\2) by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
entity(user)->name,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void show_multimark_noexist(hook_info_noexist_req_t *hdata)
|
||
|
{
|
||
|
const char *nick = hdata->nick;
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
restored_mark_t *rm;
|
||
|
struct tm tm;
|
||
|
char time[BUFSIZE];
|
||
|
|
||
|
myuser_t *setter;
|
||
|
char *setter_name;
|
||
|
|
||
|
mowgli_list_t *l = restored_mark_list(nick);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
rm = n->data;
|
||
|
tm = *localtime(&rm->time);
|
||
|
|
||
|
strftime(time, sizeof time, TIME_FORMAT, &tm);
|
||
|
|
||
|
if ( setter = myuser_find_uid(rm->setter_uid) ) {
|
||
|
setter_name = entity(setter)->name;
|
||
|
} else {
|
||
|
setter_name = rm->setter_name;
|
||
|
}
|
||
|
|
||
|
if ( strcasecmp (setter_name, rm->setter_name) ) {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2%s\2 is not registered anymore but was \2marked\2 by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
nick,
|
||
|
setter_name,
|
||
|
rm->setter_name,
|
||
|
time,
|
||
|
rm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
hdata->si,
|
||
|
_("\2%s\2 is not registered anymore but was \2marked\2 by \2%s\2 on \2%s\2: %s"),
|
||
|
nick,
|
||
|
setter_name,
|
||
|
time,
|
||
|
rm->mark
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ns_cmd_multimark(sourceinfo_t *si, int parc, char *parv[])
|
||
|
{
|
||
|
char *target = parv[0];
|
||
|
char *action = parv[1];
|
||
|
char *info = parv[2];
|
||
|
myuser_t *mu;
|
||
|
myuser_name_t *mun;
|
||
|
mowgli_list_t *l;
|
||
|
multimark_t *mm;
|
||
|
|
||
|
if (!target || !action)
|
||
|
{
|
||
|
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "MARK");
|
||
|
command_fail(si, fault_needmoreparams, _("Usage: MARK <target> <ADD|DEL|LIST> [note]"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!(mu = myuser_find_ext(target)) && strcasecmp(action, "LIST"))
|
||
|
{
|
||
|
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), target);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
l = multimark_list(mu);
|
||
|
|
||
|
if (!strcasecmp(action, "ADD"))
|
||
|
{
|
||
|
if (!info)
|
||
|
{
|
||
|
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "MARK");
|
||
|
command_fail(si, fault_needmoreparams, _("Usage: MARK <target> ADD <note>"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mm = smalloc(sizeof(multimark_t));
|
||
|
mm->setter_uid = sstrdup(entity(si->smu)->id);
|
||
|
mm->setter_name = sstrdup(entity(si->smu)->name);
|
||
|
mm->restored_from_uid = NULL;
|
||
|
mm->time = CURRTIME;
|
||
|
mm->number = get_multimark_max(mu);
|
||
|
mm->mark = sstrdup(info);
|
||
|
mowgli_node_add(mm, &mm->node, l);
|
||
|
|
||
|
command_success_nodata(si, _("\2%s\2 has been marked."), target);
|
||
|
logcommand(si, CMDLOG_ADMIN, "MARK:ADD: \2%s\2 \2%s\2", target, info);
|
||
|
} else if (!strcasecmp(action, "LIST")) {
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
struct tm tm;
|
||
|
char time[BUFSIZE];
|
||
|
|
||
|
myuser_t *setter;
|
||
|
char *setter_name;
|
||
|
|
||
|
if (!mu) {
|
||
|
mowgli_list_t *rl = restored_mark_list(target);
|
||
|
restored_mark_t *rm;
|
||
|
|
||
|
if (rl->count == 0) {
|
||
|
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered, and was not marked."), target);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, rl->head) {
|
||
|
rm = n->data;
|
||
|
tm = *localtime(&rm->time);
|
||
|
|
||
|
strftime(time, sizeof time, TIME_FORMAT, &tm);
|
||
|
|
||
|
if ( setter = myuser_find_uid(rm->setter_uid) ) {
|
||
|
setter_name = entity(setter)->name;
|
||
|
} else {
|
||
|
setter_name = rm->setter_name;
|
||
|
}
|
||
|
|
||
|
if ( strcasecmp (setter_name, rm->setter_name) ) {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2%s\2 is not registered anymore but was \2marked\2 by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
target,
|
||
|
setter_name,
|
||
|
rm->setter_name,
|
||
|
time,
|
||
|
rm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2%s\2 is not registered anymore but was \2marked\2 by \2%s\2 on \2%s\2: %s"),
|
||
|
target,
|
||
|
setter_name,
|
||
|
time,
|
||
|
rm->mark
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
command_success_nodata(si, _("\2%s\2's marks:"), target);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
tm = *localtime(&mm->time);
|
||
|
|
||
|
strftime(time, sizeof time, TIME_FORMAT, &tm);
|
||
|
|
||
|
if ( setter = myuser_find_uid(mm->setter_uid) ) {
|
||
|
setter_name = entity(setter)->name;
|
||
|
} else {
|
||
|
setter_name = mm->setter_name;
|
||
|
}
|
||
|
|
||
|
if ( mm->restored_from_uid == NULL ) {
|
||
|
if ( strcasecmp (setter_name, mm->setter_name) ) {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("Mark \2%d\2 set by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("Mark \2%d\2 set by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
if ( strcasecmp (setter_name, mm->setter_name) ) {
|
||
|
myuser_t *user;
|
||
|
if (user = myuser_find_uid(mm->restored_from_uid)) {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 (\2%s\2) by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
entity(user)->name,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 by \2%s\2 (%s) on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
setter_name,
|
||
|
mm->setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
myuser_t *user;
|
||
|
if (user = myuser_find_uid(mm->restored_from_uid)) {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 (\2%s\2) by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
entity(user)->name,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
} else {
|
||
|
command_success_nodata(
|
||
|
si,
|
||
|
_("\2(Restored)\2 Mark \2%d\2 originally set on \2%s\2 by \2%s\2 on \2%s\2: %s"),
|
||
|
mm->number,
|
||
|
mm->restored_from_uid,
|
||
|
setter_name,
|
||
|
time,
|
||
|
mm->mark
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
command_success_nodata(si, _("End of list."));
|
||
|
} else if (!strcasecmp(action, "DEL") || !strcasecmp(action, "DELETE")) {
|
||
|
if (!info)
|
||
|
{
|
||
|
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "MARK");
|
||
|
command_fail(si, fault_needmoreparams, _("Usage: MARK <target> DEL <number>"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mowgli_node_t *n;
|
||
|
multimark_t *mm;
|
||
|
int found = 0;
|
||
|
int num = atoi(info);
|
||
|
|
||
|
MOWGLI_ITER_FOREACH(n, l->head) {
|
||
|
mm = n->data;
|
||
|
|
||
|
if ( mm->number == num ) {
|
||
|
mowgli_node_delete(&mm->node, l);
|
||
|
|
||
|
free(mm->setter_uid);
|
||
|
free(mm->setter_name);
|
||
|
free(mm->restored_from_uid);
|
||
|
free(mm->mark);
|
||
|
free(mm);
|
||
|
|
||
|
found = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (found) {
|
||
|
command_success_nodata(si, _("The mark has been deleted."));
|
||
|
logcommand(si, CMDLOG_ADMIN, "MARK:DEL: \2%s\2 \2%s\2", target, info);
|
||
|
} else {
|
||
|
command_fail(si, fault_nosuch_key, _("This mark does not exist"));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|