diff --git a/include/config.h b/include/config.h index fc182edd4..86525ebbf 100644 --- a/include/config.h +++ b/include/config.h @@ -317,6 +317,8 @@ #define MODDATA_MAX_CHANNEL 8 #define MODDATA_MAX_MEMBER 4 #define MODDATA_MAX_MEMBERSHIP 4 +#define MODDATA_MAX_LOCALVAR 500 +#define MODDATA_MAX_GLOBALVAR 500 /* If EXPERIMENTAL is #define'd then all users will receive a notice about * this when they connect, along with a pointer to bugs.unrealircd.org where diff --git a/include/h.h b/include/h.h index 3ec4a48e2..c6d19999e 100644 --- a/include/h.h +++ b/include/h.h @@ -39,6 +39,8 @@ extern MODVAR Membership *freemembership; extern MODVAR MembershipL *freemembershipL; extern MODVAR aClient me; extern MODVAR aChannel *channel; +extern MODVAR ModData localvar_moddata[MODDATA_MAX_LOCALVAR]; +extern MODVAR ModData globalvar_moddata[MODDATA_MAX_GLOBALVAR]; extern MODVAR struct stats *ircstp; extern MODVAR int bootopt; extern MODVAR time_t timeofday; @@ -692,6 +694,8 @@ extern MODVAR void (*broadcast_sinfo)(aClient *acptr, aClient *to, aClient *exce extern MODVAR void (*parse_message_tags)(aClient *cptr, char **str, MessageTag **mtag_list); extern MODVAR char *(*mtags_to_string)(MessageTag *m, aClient *acptr); extern MODVAR int (*can_send)(aClient *cptr, aChannel *chptr, char **msgtext, char **errmsg, int notice); +extern MODVAR void (*broadcast_md_globalvar)(ModDataInfo *mdi, ModData *md); +extern MODVAR void (*broadcast_md_globalvar_cmd)(aClient *except, aClient *sender, char *varname, char *value); /* /Efuncs */ extern MODVAR aMotdFile opermotd, svsmotd, motd, botmotd, smotd, rules; diff --git a/include/modules.h b/include/modules.h index c96a4ae7f..736902bf0 100644 --- a/include/modules.h +++ b/include/modules.h @@ -134,7 +134,7 @@ typedef struct { Module *owner; /**< Module that owns this snomask */ } Snomask; -typedef enum ModDataType { MODDATATYPE_CLIENT=1, MODDATATYPE_CHANNEL=2, MODDATATYPE_MEMBER=3, MODDATATYPE_MEMBERSHIP=4 } ModDataType; +typedef enum ModDataType { MODDATATYPE_LOCALVAR=1, MODDATATYPE_GLOBALVAR=2, MODDATATYPE_CLIENT=3, MODDATATYPE_CHANNEL=4, MODDATATYPE_MEMBER=5, MODDATATYPE_MEMBERSHIP=6 } ModDataType; typedef struct _moddatainfo ModDataInfo; @@ -155,6 +155,8 @@ struct _moddatainfo { #define moddata_channel(chptr, md) chptr->moddata[md->slot] #define moddata_member(m, md) m->moddata[md->slot] #define moddata_membership(m, md) m->moddata[md->slot] +#define moddata_localvar(md) localvar_moddata[md->slot] +#define moddata_globalvar(md) globalvar_moddata[md->slot] #define EXCHK_ACCESS 0 /* Check access */ #define EXCHK_ACCESS_ERR 1 /* Check access and send error if needed */ @@ -1209,6 +1211,8 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum #define EFUNC_TKL_CHARTOTYPE 63 #define EFUNC_TKL_TYPE_STRING 64 #define EFUNC_CAN_SEND 65 +#define EFUNC_BROADCAST_MD_GLOBALVAR 66 +#define EFUNC_BROADCAST_MD_GLOBALVAR_CMD 67 /* Module flags */ #define MODFLAG_NONE 0x0000 diff --git a/src/moddata.c b/src/moddata.c index 15c20e01d..c0a196436 100644 --- a/src/moddata.c +++ b/src/moddata.c @@ -24,6 +24,9 @@ MODVAR ModDataInfo *MDInfo = NULL; +MODVAR ModData localvar_moddata[MODDATA_MAX_LOCALVAR]; +MODVAR ModData globalvar_moddata[MODDATA_MAX_GLOBALVAR]; + ModDataInfo *ModDataAdd(Module *module, ModDataInfo req) { short i = 0, j = 0; @@ -57,7 +60,9 @@ ModDataInfo *ModDataAdd(Module *module, ModDataInfo req) } /* Now check if we are within bounds (if we really have a free slot available) */ - if (((req.type == MODDATATYPE_CLIENT) && (slotav >= MODDATA_MAX_CLIENT)) || + if (((req.type == MODDATATYPE_LOCALVAR) && (slotav >= MODDATA_MAX_LOCALVAR)) || + ((req.type == MODDATATYPE_GLOBALVAR) && (slotav >= MODDATA_MAX_GLOBALVAR)) || + ((req.type == MODDATATYPE_CLIENT) && (slotav >= MODDATA_MAX_CLIENT)) || ((req.type == MODDATATYPE_CHANNEL) && (slotav >= MODDATA_MAX_CHANNEL)) || ((req.type == MODDATATYPE_MEMBER) && (slotav >= MODDATA_MAX_MEMBER)) || ((req.type == MODDATATYPE_MEMBERSHIP) && (slotav >= MODDATA_MAX_MEMBERSHIP))) @@ -156,6 +161,16 @@ void unload_moddata_commit(ModDataInfo *md) { switch(md->type) { + case MODDATATYPE_LOCALVAR: + if (md->free && moddata_localvar(md).ptr) + md->free(&moddata_localvar(md)); + memset(&moddata_localvar(md), 0, sizeof(ModData)); + break; + case MODDATATYPE_GLOBALVAR: + if (md->free && moddata_globalvar(md).ptr) + md->free(&moddata_globalvar(md)); + memset(&moddata_globalvar(md), 0, sizeof(ModData)); + break; case MODDATATYPE_CLIENT: { aClient *acptr; @@ -321,6 +336,59 @@ char *moddata_client_get(aClient *acptr, char *varname) return md->serialize(&moddata_client(acptr, md)); /* can be NULL */ } +/** Set localvar or globalvar moddata (via variable name, string value) */ +int moddata_localvar_set(char *varname, char *value) +{ + ModDataInfo *md; + + md = findmoddata_byname(varname, MODDATATYPE_CLIENT); + + if (!md) + return 0; + + if (value) + { + /* SET */ + md->unserialize(value, &moddata_localvar(md)); + } + else + { + /* UNSET */ + md->free(&moddata_localvar(md)); + memset(&moddata_localvar(md), 0, sizeof(ModData)); + } + + return 1; +} + +/** Set globalvar or globalvar moddata (via variable name, string value) */ +int moddata_globalvar_set(char *varname, char *value) +{ + ModDataInfo *md; + + md = findmoddata_byname(varname, MODDATATYPE_CLIENT); + + if (!md) + return 0; + + if (value) + { + /* SET */ + md->unserialize(value, &moddata_globalvar(md)); + } + else + { + /* UNSET */ + md->free(&moddata_globalvar(md)); + memset(&moddata_globalvar(md), 0, sizeof(ModData)); + } + + if (md->sync) + broadcast_md_globalvar_cmd(NULL, &me, md->name, value); + + return 1; +} + /* The rest of the MD related functions, the send/receive functions, * are in src/modules/m_md.c */ diff --git a/src/modules.c b/src/modules.c index be014e3fd..372a558d7 100644 --- a/src/modules.c +++ b/src/modules.c @@ -124,6 +124,8 @@ extern void parse_message_tags_default_handler(aClient *cptr, char **str, Messag char *(*mtags_to_string)(MessageTag *m, aClient *acptr); extern char *mtags_to_string_default_handler(MessageTag *m, aClient *acptr); int (*can_send)(aClient *cptr, aChannel *chptr, char **msgtext, char **errmsg, int notice); +void (*broadcast_md_globalvar)(ModDataInfo *mdi, ModData *md); +void (*broadcast_md_globalvar_cmd)(aClient *except, aClient *sender, char *varname, char *value); static const EfunctionsList efunction_table[MAXEFUNCTIONS] = { /* 00 */ {NULL, NULL, NULL}, @@ -192,7 +194,9 @@ static const EfunctionsList efunction_table[MAXEFUNCTIONS] = { /* 63 */ {"tkl_chartotype", (void *)&tkl_chartotype, NULL}, /* 64 */ {"tkl_type_string", (void *)&tkl_type_string, NULL}, /* 65 */ {"can_send", (void *)&can_send, NULL}, -/* 66 */ {NULL, NULL, NULL}, +/* 66 */ {"broadcast_md_globalvar", (void *)&broadcast_md_globalvar, NULL}, +/* 67 */ {"broadcast_md_globalvar_cmd", (void *)&broadcast_md_globalvar_cmd, NULL}, +/* 68 */ {NULL, NULL, NULL}, }; #ifdef UNDERSCORE diff --git a/src/modules/m_md.c b/src/modules/m_md.c index 77487a9cc..b8a69776d 100644 --- a/src/modules/m_md.c +++ b/src/modules/m_md.c @@ -22,10 +22,12 @@ void _broadcast_md_client(ModDataInfo *mdi, aClient *acptr, ModData *md); void _broadcast_md_channel(ModDataInfo *mdi, aChannel *chptr, ModData *md); void _broadcast_md_member(ModDataInfo *mdi, aChannel *chptr, Member *m, ModData *md); void _broadcast_md_membership(ModDataInfo *mdi, aClient *acptr, Membership *m, ModData *md); +void _broadcast_md_globalvar(ModDataInfo *mdi, ModData *md); void _broadcast_md_client_cmd(aClient *except, aClient *sender, aClient *acptr, char *varname, char *value); void _broadcast_md_channel_cmd(aClient *except, aClient *sender, aChannel *chptr, char *varname, char *value); void _broadcast_md_member_cmd(aClient *except, aClient *sender, aChannel *chptr, aClient *acptr, char *varname, char *value); void _broadcast_md_membership_cmd(aClient *except, aClient *sender, aClient *acptr, aChannel *chptr, char *varname, char *value); +void _broadcast_md_globalvar_cmd(aClient *except, aClient *sender, char *varname, char *value); void _send_moddata_client(aClient *srv, aClient *acptr); void _send_moddata_channel(aClient *srv, aChannel *chptr); void _send_moddata_members(aClient *srv); @@ -40,10 +42,12 @@ MOD_TEST(m_md) EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CHANNEL, _broadcast_md_channel); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBER, _broadcast_md_member); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBERSHIP, _broadcast_md_membership); + EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_GLOBALVAR, _broadcast_md_globalvar); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CLIENT_CMD, _broadcast_md_client_cmd); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CHANNEL_CMD, _broadcast_md_channel_cmd); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBER_CMD, _broadcast_md_member_cmd); EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBERSHIP_CMD, _broadcast_md_membership_cmd); + EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_GLOBALVAR_CMD, _broadcast_md_globalvar_cmd); EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_CLIENT, _send_moddata_client); EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_CHANNEL, _send_moddata_channel); EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_MEMBERS, _send_moddata_members); @@ -89,12 +93,12 @@ CMD_FUNC(m_md) if (!IsServer(sptr) || (parc < 4) || BadPtr(parv[3])) return 0; - + type = parv[1]; objname = parv[2]; varname = parv[3]; value = parv[4]; /* may be NULL */ - + if (!strcmp(type, "client")) { aClient *acptr = find_client(objname, NULL); @@ -135,7 +139,7 @@ CMD_FUNC(m_md) aChannel *chptr; Member *m; char *p; - + /* for member the object name is like '#channel/Syzop' */ p = strchr(objname, ':'); if (!p) @@ -145,7 +149,7 @@ CMD_FUNC(m_md) chptr = find_channel(objname, NULL); if (!chptr) return 0; - + acptr = find_person(p, NULL); if (!acptr) return 0; @@ -153,7 +157,7 @@ CMD_FUNC(m_md) m = find_member_link(chptr->members, acptr); if (!m) return 0; - + md = findmoddata_byname(varname, MODDATATYPE_MEMBER); if (!md || !md->unserialize) return 0; @@ -175,7 +179,7 @@ CMD_FUNC(m_md) aChannel *chptr; Membership *m; char *p; - + /* for membership the object name is like 'Syzop/#channel' */ p = strchr(objname, ':'); if (!p) @@ -185,7 +189,7 @@ CMD_FUNC(m_md) acptr = find_person(objname, NULL); if (!acptr) return 0; - + chptr = find_channel(p, NULL); if (!chptr) return 0; @@ -193,7 +197,7 @@ CMD_FUNC(m_md) m = find_membership_link(acptr->user->channel, chptr); if (!m) return 0; - + md = findmoddata_byname(varname, MODDATATYPE_MEMBERSHIP); if (!md || !md->unserialize) return 0; @@ -208,6 +212,23 @@ CMD_FUNC(m_md) } /* Pass on to other servers */ broadcast_md_membership_cmd(cptr, sptr, acptr, chptr, varname, value); + } else + if (!strcmp(type, "globalvar")) + { + /* objname is ignored */ + md = findmoddata_byname(varname, MODDATATYPE_GLOBALVAR); + if (!md || !md->unserialize) + return 0; + if (value) + md->unserialize(value, &moddata_globalvar(md)); + else + { + if (md->free) + md->free(&moddata_globalvar(md)); + memset(&moddata_globalvar(md), 0, sizeof(ModData)); + } + /* Pass on to other servers */ + broadcast_md_globalvar_cmd(cptr, sptr, varname, value); } return 0; } @@ -276,6 +297,24 @@ void _broadcast_md_membership_cmd(aClient *except, aClient *sender, aClient *acp } } +void _broadcast_md_globalvar_cmd(aClient *except, aClient *sender, char *varname, char *value) +{ + if (value) + { + sendto_server(except, PROTO_SID, 0, NULL, ":%s MD %s %s :%s", + sender->name, "globalvar", varname, value); + sendto_server(except, 0, PROTO_SID, NULL, ":%s MD %s %s :%s", + sender->name, "globalvar", varname, value); + } + else + { + sendto_server(except, PROTO_SID, 0, NULL, ":%s MD %s %s", + sender->name, "globalvar", varname); + sendto_server(except, 0, PROTO_SID, NULL, ":%s MD %s %s", + sender->name, "globalvar", varname); + } +} + /** Send module data update to all servers. * @param mdi Module Data Info structure (which you received from ModDataAdd) * @param acptr The affected client @@ -285,31 +324,38 @@ void _broadcast_md_membership_cmd(aClient *except, aClient *sender, aClient *acp void _broadcast_md_client(ModDataInfo *mdi, aClient *acptr, ModData *md) { char *value = md ? mdi->serialize(md) : NULL; - + broadcast_md_client_cmd(NULL, &me, acptr, mdi->name, value); } void _broadcast_md_channel(ModDataInfo *mdi, aChannel *chptr, ModData *md) { char *value = md ? mdi->serialize(md) : NULL; - + broadcast_md_channel_cmd(NULL, &me, chptr, mdi->name, value); } void _broadcast_md_member(ModDataInfo *mdi, aChannel *chptr, Member *m, ModData *md) { char *value = md ? mdi->serialize(md) : NULL; - + broadcast_md_member_cmd(NULL, &me, chptr, m->cptr, mdi->name, value); } void _broadcast_md_membership(ModDataInfo *mdi, aClient *acptr, Membership *m, ModData *md) { char *value = md ? mdi->serialize(md) : NULL; - + broadcast_md_membership_cmd(NULL, &me, acptr, m->chptr, mdi->name, value); } +void _broadcast_md_globalvar(ModDataInfo *mdi, ModData *md) +{ + char *value = md ? mdi->serialize(md) : NULL; + + broadcast_md_globalvar_cmd(NULL, &me, mdi->name, value); +} + /** Send all moddata attached to client 'acptr' to remote server 'srv' (if the module wants this), called by .. */ void _send_moddata_client(aClient *srv, aClient *acptr) { @@ -358,7 +404,7 @@ void _send_moddata_members(aClient *srv) for (m = chptr->members; m; m = m->next) { char *user = CHECKPROTO(srv, PROTO_SID) ? ID(m->cptr) : m->cptr->name; - + if (m->cptr->from == srv) continue; /* from srv's direction */ for (mdi = MDInfo; mdi; mdi = mdi->next) @@ -373,7 +419,7 @@ void _send_moddata_members(aClient *srv) } } } - + list_for_each_entry(acptr, &client_list, client_node) { Membership *m;