diff --git a/modules/m_grant.c b/modules/m_grant.c index bbad72c9..30684a32 100644 --- a/modules/m_grant.c +++ b/modules/m_grant.c @@ -30,16 +30,131 @@ static struct flag_list flaglist[] = { {NULL, 0}, }; +static int m_grant(struct Client *, struct Client *, int, const char **); static int me_grant(struct Client *, struct Client *, int, const char **); struct Message grant_msgtab = { "GRANT", 0, 0, 0, MFLG_SLOW, - {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_grant, 4}, mg_ignore} + {mg_unreg, {m_grant, 4}, mg_ignore, mg_ignore, {me_grant, 4}, mg_ignore} }; mapi_clist_av1 grant_clist[] = { &grant_msgtab, NULL }; DECLARE_MODULE_AV1(grant, NULL, NULL, grant_clist, NULL, NULL, "Charybdis development team"); +static void +apply_flags(struct membership *msptr, const char *flagspec, unsigned int flagmask) +{ + char *s, *t, *p; + + /* unset all chanroles as we're setting new ones */ + msptr->roles = 0; + + t = LOCAL_COPY(flagspec); + for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p)) + { + const char *priv = s + 1; /* The actual priv */ + struct flag_list *fl; + unsigned int flag = 0; + + /* Go through the flags list... */ + for(fl = flaglist; fl->name != NULL; fl++) + { + if (strcasecmp(fl->name, priv) == 0) + { + /* flagmask exists to ensure users can't give privileges they + * don't possess themselves */ + if (!flagmask || (flagmask & fl->flag)) + flag = fl->flag; + break; + } + } + + /* Ack no flag! */ + if (!flag) + continue; + + if (s[0] == '-') + RemoveChanRole(msptr, flag); + else if (s[0] == '+') + SetChanRole(msptr, flag); + } +} + +/* + * m_grant + * + * parv[1] = channel + * parv[2] = target nickname + * parv[3] = flag spec + */ +static int +m_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +{ + struct Channel *chptr; + struct Client *target_p; + struct membership *cmsptr, *tmsptr; + char flagspec[BUFSIZE]; + const char *flagptr; + + if(parc > 4) + { + int i; + char *buf = flagspec; + + flagptr = flagspec; + + for (i = 3; i < parc; i++) + /* Rest assured it can't overflow, parv contents will always be < BUFSIZE + * --Elizabeth */ + buf += rb_sprintf(buf, "%s ", parv[i]); + + *buf = '\0'; + } + else + flagptr = parv[3]; + + if (!(chptr = find_channel(parv[1]))) + { + sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); + return 0; + } + + if(!(cmsptr = find_channel_membership(chptr, client_p))) + /* Can't happen */ + return 0; + + /* Check for grant privilege */ + if(get_channel_access(source_p, cmsptr, CHANROLE_GRANT) < CHFL_CHANOP) + { + sendto_one_numeric(source_p, ERR_CHANOPRIVSNEEDED, form_str(ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, parv[2]); + return 0; + } + + if (!(target_p = find_named_person(parv[2]))) + { + sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[2]); + return 0; + } + + /* Send it to the server the user is on if not local */ + if(!MyClient(target_p)) + { + struct Client *cptr = target_p->servptr; + sendto_one(cptr, ":%s ENCAP %s GRANT %s %s :%s", + get_id(source_p, cptr), cptr->name, chptr->chname, + get_id(target_p, cptr), flagptr); + return 0; + } + + if (!(tmsptr = find_channel_membership(chptr, target_p))) + return 0; + + apply_flags(tmsptr, flagptr, cmsptr->roles); + + return 0; +} + /* * me_grant * @@ -53,7 +168,6 @@ me_grant(struct Client *client_p, struct Client *source_p, int parc, const char struct Channel *chptr; struct Client *target_p; struct membership *msptr; - char *s, *t, *p; if (!(chptr = find_channel(parv[1]))) return 0; @@ -68,35 +182,7 @@ me_grant(struct Client *client_p, struct Client *source_p, int parc, const char if (!(msptr = find_channel_membership(chptr, target_p))) return 0; - /* unset all chanroles as we're setting new ones */ - msptr->roles = 0; - - t = LOCAL_COPY(parv[3]); - for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p)) - { - const char *priv = s + 1; /* The actual priv */ - struct flag_list *fl; - int flag = 0; - - /* Go through the flags list... */ - for(fl = flaglist; fl->name != NULL; fl++) - { - if (strcasecmp(fl->name, priv) == 0) - { - flag = fl->flag; - break; - } - } - - /* Ack no flag! */ - if (!flag) - continue; - - if (s[0] == '-') - RemoveChanRole(msptr, flag); - else if (s[0] == '+') - SetChanRole(msptr, flag); - } + apply_flags(msptr, parv[3], 0); return 0; } diff --git a/src/chmode.c b/src/chmode.c index f6354389..aae52b88 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -903,7 +903,7 @@ chm_op(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count++].client = targ_p; mstptr->flags |= CHFL_CHANOP; - if (msptr->roles & CHANROLE_UNSET) + if (mstptr->roles & CHANROLE_UNSET) { mstptr->roles &= ~CHANROLE_UNSET; mstptr->roles = CHANROLE_INITIAL | CHANROLE_INHERIT;