diff --git a/include/client.h b/include/client.h index 38a0ca9..07cf716 100644 --- a/include/client.h +++ b/include/client.h @@ -84,6 +84,8 @@ struct User char *away; /* pointer to away message */ int refcnt; /* Number of times this block is referenced */ + struct Dictionary *metadata; + char suser[NICKLEN+1]; }; @@ -311,6 +313,12 @@ struct ListClient */ }; +struct Metadata +{ + const char *name; + const char *value; +}; + /* * status macros. */ @@ -613,4 +621,8 @@ extern char *generate_uid(void); void allocate_away(struct Client *); void free_away(struct Client *); +extern struct Metadata *user_metadata_add(struct Client *target, const char *name, const char *value, int propegate); +extern void user_metadata_delete(struct Client *target, const char *name, int propegate); +extern struct Metadata *user_metadata_find(struct Client *target, const char *name); + #endif /* INCLUDED_client_h */ diff --git a/modules/Makefile.in b/modules/Makefile.in index dd96664..6c80e21 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -42,6 +42,7 @@ CORE_SRCS = \ core/m_kick.c \ core/m_kill.c \ core/m_message.c \ + core/m_metadata.c \ core/m_mode.c \ core/m_nick.c \ core/m_part.c \ diff --git a/src/client.c b/src/client.c index cad1b7f..d22c7ef 100644 --- a/src/client.c +++ b/src/client.c @@ -1659,6 +1659,7 @@ struct User * make_user(struct Client *client_p) { struct User *user; + struct Dictionary *metadata; user = client_p->user; if(!user) @@ -1666,6 +1667,9 @@ make_user(struct Client *client_p) user = (struct User *) rb_bh_alloc(user_heap); user->refcnt = 1; client_p->user = user; + + metadata = irc_dictionary_create(irccmp); + client_p->user->metadata = metadata; } return user; } @@ -1705,10 +1709,19 @@ free_user(struct User *user, struct Client *client_p) { free_away(client_p); + /* get rid of any metadata the user may have */ + if(IsOper(client_p)) + { + user_metadata_delete(client_p, "swhois", 0); + user_metadata_delete(client_p, "operstring", 0); + } + user_metadata_delete(client_p, "OACCEPT", 0); + if(--user->refcnt <= 0) { if(user->away) rb_free((char *) user->away); + /* * sanity check */ @@ -1924,3 +1937,81 @@ error_exit_client(struct Client *client_p, int error) exit_client(client_p, client_p, &me, errmsg); } + +/* + * user_metadata_add + * + * inputs - pointer to client struct + * - name of metadata item you wish to add + * - value of metadata item + * - 1 if metadata should be propegated, 0 if not + * output - none + * side effects - metadata is added to the user in question + * - metadata is propegated if propegate is set. + */ +struct Metadata * +user_metadata_add(struct Client *target, const char *name, const char *value, int propegate) +{ + struct Metadata *md; + + if(irc_dictionary_find(target->user->metadata, name) != NULL) + return NULL; + + md = rb_malloc(sizeof(struct Metadata)); + md->name = rb_strdup(name); + md->value = rb_strdup(value); + + irc_dictionary_add(target->user->metadata, md->name, md); + + if(propegate) + sendto_match_servs(&me, "*", CAP_ENCAP, NOCAPS, "ENCAP * METADATA ADD %s %s :%s", + target->name, name, value); + + return md; +} + +/* + * user_metadata_delete + * + * inputs - pointer to client struct + * - name of metadata item you wish to delete + * output - none + * side effects - metadata is deleted from the user in question + * - deletion is propegated if propegate is set + */ +void +user_metadata_delete(struct Client *target, const char *name, int propegate) +{ + struct Metadata *md = user_metadata_find(target, name); + + if(!md) + return; + + irc_dictionary_delete(target->user->metadata, md->name); + + rb_free(md); + + if(propegate) + sendto_match_servs(&me, "*", CAP_ENCAP, NOCAPS, "ENCAP * METADATA DELETE %s %s", + target->name, name); +} + +/* + * user_metadata_find + * + * inputs - pointer to client struct + * - name of metadata item you wish to read + * output - the requested metadata, if it exists, elsewise null. + * side effects - + */ +struct Metadata * +user_metadata_find(struct Client *target, const char *name) +{ + if(!target->user) + return NULL; + + if(!target->user->metadata) + return NULL; + + return irc_dictionary_retrieve(target->user->metadata, name); +} diff --git a/src/modules.c b/src/modules.c index ba56c96..4547e42 100644 --- a/src/modules.c +++ b/src/modules.c @@ -63,6 +63,7 @@ static const char *core_module_table[] = { "m_kick", "m_kill", "m_message", + "m_metadata", "m_mode", "m_nick", "m_part", diff --git a/src/s_serv.c b/src/s_serv.c index 0cd1369..e66c021 100644 --- a/src/s_serv.c +++ b/src/s_serv.c @@ -54,6 +54,7 @@ #include "msg.h" #include "reject.h" #include "sslproc.h" +#include "irc_dictionary.h" #ifndef INADDR_NONE #define INADDR_NONE ((unsigned int) 0xffffffff) @@ -469,6 +470,8 @@ burst_TS6(struct Client *client_p) char *t; int tlen, mlen; int cur_len = 0; + struct Metadata *md; + struct DictionaryIter iter; hclientinfo.client = hchaninfo.client = client_p; @@ -520,6 +523,12 @@ burst_TS6(struct Client *client_p) use_id(target_p), target_p->user->suser); } + DICTIONARY_FOREACH(md, &iter, target_p->user->metadata) + { + sendto_one(client_p, ":%s ENCAP * METADATA %s %s :%s", + use_id(target_p), use_id(target_p), md->name, md->value); + } + if(ConfigFileEntry.burst_away && !EmptyString(target_p->user->away)) sendto_one(client_p, ":%s AWAY :%s", use_id(target_p), diff --git a/src/s_user.c b/src/s_user.c index d5f163d..04b1838 100644 --- a/src/s_user.c +++ b/src/s_user.c @@ -1031,6 +1031,11 @@ user_mode(struct Client *client_p, struct Client *source_p, int parc, const char Count.oper--; + /* Do we need to propegate these? I'm not 100% sure + * so we should test it when we have a testnet */ + user_metadata_delete(source_p, "OPERSTRING", 1); + user_metadata_delete(source_p, "SWHOIS", 1); + if(MyConnect(source_p)) { source_p->umodes &= ~ConfigFileEntry.oper_only_umodes;