cs_xop.c

Go to the documentation of this file.
00001 /* ChanServ core functions
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: cs_xop.c 1318 2007-12-15 15:50:16Z geniusdex $
00012  *
00013  */
00014 /*************************************************************************/
00015 
00016 #include "module.h"
00017 
00018 int do_xop(User * u, char *xname, int xlev, int *xmsgs);
00019 int do_aop(User * u);
00020 int do_hop(User * u);
00021 int do_sop(User * u);
00022 int do_vop(User * u);
00023 
00024 void myChanServHelp(User * u);
00025 
00026 int xop_msgs[4][14] = {
00027     {CHAN_AOP_SYNTAX,
00028      CHAN_AOP_DISABLED,
00029      CHAN_AOP_NICKS_ONLY,
00030      CHAN_AOP_ADDED,
00031      CHAN_AOP_MOVED,
00032      CHAN_AOP_NO_SUCH_ENTRY,
00033      CHAN_AOP_NOT_FOUND,
00034      CHAN_AOP_NO_MATCH,
00035      CHAN_AOP_DELETED,
00036      CHAN_AOP_DELETED_ONE,
00037      CHAN_AOP_DELETED_SEVERAL,
00038      CHAN_AOP_LIST_EMPTY,
00039      CHAN_AOP_LIST_HEADER,
00040      CHAN_AOP_CLEAR},
00041     {CHAN_SOP_SYNTAX,
00042      CHAN_SOP_DISABLED,
00043      CHAN_SOP_NICKS_ONLY,
00044      CHAN_SOP_ADDED,
00045      CHAN_SOP_MOVED,
00046      CHAN_SOP_NO_SUCH_ENTRY,
00047      CHAN_SOP_NOT_FOUND,
00048      CHAN_SOP_NO_MATCH,
00049      CHAN_SOP_DELETED,
00050      CHAN_SOP_DELETED_ONE,
00051      CHAN_SOP_DELETED_SEVERAL,
00052      CHAN_SOP_LIST_EMPTY,
00053      CHAN_SOP_LIST_HEADER,
00054      CHAN_SOP_CLEAR},
00055     {CHAN_VOP_SYNTAX,
00056      CHAN_VOP_DISABLED,
00057      CHAN_VOP_NICKS_ONLY,
00058      CHAN_VOP_ADDED,
00059      CHAN_VOP_MOVED,
00060      CHAN_VOP_NO_SUCH_ENTRY,
00061      CHAN_VOP_NOT_FOUND,
00062      CHAN_VOP_NO_MATCH,
00063      CHAN_VOP_DELETED,
00064      CHAN_VOP_DELETED_ONE,
00065      CHAN_VOP_DELETED_SEVERAL,
00066      CHAN_VOP_LIST_EMPTY,
00067      CHAN_VOP_LIST_HEADER,
00068      CHAN_VOP_CLEAR},
00069     {CHAN_HOP_SYNTAX,
00070      CHAN_HOP_DISABLED,
00071      CHAN_HOP_NICKS_ONLY,
00072      CHAN_HOP_ADDED,
00073      CHAN_HOP_MOVED,
00074      CHAN_HOP_NO_SUCH_ENTRY,
00075      CHAN_HOP_NOT_FOUND,
00076      CHAN_HOP_NO_MATCH,
00077      CHAN_HOP_DELETED,
00078      CHAN_HOP_DELETED_ONE,
00079      CHAN_HOP_DELETED_SEVERAL,
00080      CHAN_HOP_LIST_EMPTY,
00081      CHAN_HOP_LIST_HEADER,
00082      CHAN_HOP_CLEAR}
00083 };
00084 
00091 int AnopeInit(int argc, char **argv)
00092 {
00093     Command *c;
00094 
00095     moduleAddAuthor("Anope");
00096     moduleAddVersion("$Id: cs_xop.c 1318 2007-12-15 15:50:16Z geniusdex $");
00097     moduleSetType(CORE);
00098 
00099     c = createCommand("AOP", do_aop, NULL, CHAN_HELP_AOP, -1, -1, -1, -1);
00100     moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
00101     if (ircd->halfop) {
00102         c = createCommand("HOP", do_hop, NULL, CHAN_HELP_HOP, -1, -1, -1,
00103                           -1);
00104         moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
00105     }
00106     c = createCommand("SOP", do_sop, NULL, CHAN_HELP_SOP, -1, -1, -1, -1);
00107     moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
00108     c = createCommand("VOP", do_vop, NULL, CHAN_HELP_VOP, -1, -1, -1, -1);
00109     moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
00110 
00111     moduleSetChanHelp(myChanServHelp);
00112 
00113     return MOD_CONT;
00114 }
00115 
00119 void AnopeFini(void)
00120 {
00121 
00122 }
00123 
00124 
00125 
00130 void myChanServHelp(User * u)
00131 {
00132     notice_lang(s_ChanServ, u, CHAN_HELP_CMD_SOP);
00133     notice_lang(s_ChanServ, u, CHAN_HELP_CMD_AOP);
00134     if (ircd->halfop) {
00135         notice_lang(s_ChanServ, u, CHAN_HELP_CMD_HOP);
00136     }
00137     notice_lang(s_ChanServ, u, CHAN_HELP_CMD_VOP);
00138 }
00139 
00145 int do_aop(User * u)
00146 {
00147     return do_xop(u, "AOP", ACCESS_AOP, xop_msgs[0]);
00148 }
00149 
00150 /*************************************************************************/
00151 
00152 int do_hop(User * u)
00153 {
00154     return do_xop(u, "HOP", ACCESS_HOP, xop_msgs[3]);
00155 }
00156 
00157 /*************************************************************************/
00158 
00159 int do_sop(User * u)
00160 {
00161     return do_xop(u, "SOP", ACCESS_SOP, xop_msgs[1]);
00162 }
00163 
00164 /*************************************************************************/
00165 
00166 int do_vop(User * u)
00167 {
00168     return do_xop(u, "VOP", ACCESS_VOP, xop_msgs[2]);
00169 }
00170 
00171 /* `last' is set to the last index this routine was called with
00172  * `perm' is incremented whenever a permission-denied error occurs
00173  */
00174 
00175 int xop_del(User * u, ChannelInfo * ci, ChanAccess * access, int *perm, int uacc, int xlev)
00176 {
00177     if (!access->in_use || access->level != xlev)
00178         return 0;
00179     if (!is_services_admin(u) && uacc <= access->level) {
00180         (*perm)++;
00181         return 0;
00182     }
00183     access->nc = NULL;
00184     access->in_use = 0;
00185     send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick, access->nc->display);
00186     return 1;
00187 }
00188 
00189 int xop_del_callback(User * u, int num, va_list args)
00190 {
00191     ChannelInfo *ci = va_arg(args, ChannelInfo *);
00192     int *last = va_arg(args, int *);
00193     int *perm = va_arg(args, int *);
00194     int uacc = va_arg(args, int);
00195     int xlev = va_arg(args, int);
00196 
00197     if (num < 1 || num > ci->accesscount)
00198         return 0;
00199     *last = num;
00200 
00201     return xop_del(u, ci, &ci->access[num - 1], perm, uacc, xlev);
00202 }
00203 
00204 
00205 int xop_list(User * u, int index, ChannelInfo * ci,
00206              int *sent_header, int xlev, int xmsg)
00207 {
00208     ChanAccess *access = &ci->access[index];
00209 
00210     if (!access->in_use || access->level != xlev)
00211         return 0;
00212 
00213     if (!*sent_header) {
00214         notice_lang(s_ChanServ, u, xmsg, ci->name);
00215         *sent_header = 1;
00216     }
00217 
00218     notice_lang(s_ChanServ, u, CHAN_XOP_LIST_FORMAT, index + 1,
00219                 access->nc->display);
00220     return 1;
00221 }
00222 
00223 int xop_list_callback(User * u, int num, va_list args)
00224 {
00225     ChannelInfo *ci = va_arg(args, ChannelInfo *);
00226     int *sent_header = va_arg(args, int *);
00227     int xlev = va_arg(args, int);
00228     int xmsg = va_arg(args, int);
00229 
00230     if (num < 1 || num > ci->accesscount)
00231         return 0;
00232 
00233     return xop_list(u, num - 1, ci, sent_header, xlev, xmsg);
00234 }
00235 
00236 
00237 int do_xop(User * u, char *xname, int xlev, int *xmsgs)
00238 {
00239     char *chan = strtok(NULL, " ");
00240     char *cmd = strtok(NULL, " ");
00241     char *nick = strtok(NULL, " ");
00242     char event_access[BUFSIZE];
00243 
00244     ChannelInfo *ci;
00245     NickAlias *na;
00246     NickCore *nc;
00247 
00248     int i;
00249     int change = 0;
00250     short ulev;
00251     int is_list = (cmd && stricmp(cmd, "LIST") == 0);
00252     int is_servadmin = is_services_admin(u);
00253     ChanAccess *access;
00254 
00255     /* If CLEAR, we don't need any parameters.
00256      * If LIST, we don't *require* any parameters, but we can take any.
00257      * If DEL or ADD we require a nick. */
00258     if (!cmd || ((is_list || !stricmp(cmd, "CLEAR")) ? 0 : !nick)) {
00259         syntax_error(s_ChanServ, u, xname, xmsgs[0]);
00260     } else if (!(ci = cs_findchan(chan))) {
00261         notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
00262     } else if (ci->flags & CI_VERBOTEN) {
00263         notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
00264     } else if (!(ci->flags & CI_XOP)) {
00265         notice_lang(s_ChanServ, u, CHAN_XOP_ACCESS, s_ChanServ);
00266     } else if (stricmp(cmd, "ADD") == 0) {
00267         if (readonly) {
00268             notice_lang(s_ChanServ, u, xmsgs[1]);
00269             return MOD_CONT;
00270         }
00271 
00272         ulev = get_access(u, ci);
00273 
00274         if ((xlev >= ulev || ulev < ACCESS_AOP) && !is_servadmin) {
00275             notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00276             return MOD_CONT;
00277         }
00278 
00279         na = findnick(nick);
00280         if (!na) {
00281             notice_lang(s_ChanServ, u, xmsgs[2]);
00282             return MOD_CONT;
00283         } else if (na->status & NS_VERBOTEN) {
00284             notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, na->nick);
00285             return MOD_CONT;
00286         }
00287 
00288         nc = na->nc;
00289         for (access = ci->access, i = 0; i < ci->accesscount;
00290              access++, i++) {
00291             if (access->nc == nc) {
00295                 if ((access->level >= ulev) && (!is_servadmin)) {
00296                     notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00297                     return MOD_CONT;
00298                 }
00299                 change++;
00300                 break;
00301             }
00302         }
00303 
00304         if (!change) {
00305             /* All entries should be in use so we no longer need
00306              * to go over the entire list..
00307             for (i = 0; i < ci->accesscount; i++)
00308                 if (!ci->access[i].in_use)
00309                     break;
00310              */
00311 
00312             if (i < CSAccessMax) {
00313                 ci->accesscount++;
00314                 ci->access =
00315                     srealloc(ci->access,
00316                              sizeof(ChanAccess) * ci->accesscount);
00317             } else {
00318                 notice_lang(s_ChanServ, u, CHAN_XOP_REACHED_LIMIT,
00319                             CSAccessMax);
00320                 return MOD_CONT;
00321             }
00322 
00323             access = &ci->access[i];
00324             access->nc = nc;
00325         }
00326 
00327         access->in_use = 1;
00328         access->level = xlev;
00329         access->last_seen = 0;
00330 
00331         alog("%s: %s!%s@%s (level %d) %s access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->username, u->host, ulev, change ? "changed" : "set", access->level, na->nick, nc->display, ci->name);
00332 
00333         snprintf(event_access, BUFSIZE, "%d", access->level);
00334 
00335         if (!change) {
00336             send_event(EVENT_ACCESS_ADD, 4, ci->name, u->nick, na->nick,
00337                        event_access);
00338             notice_lang(s_ChanServ, u, xmsgs[3], access->nc->display,
00339                         ci->name);
00340         } else {
00341             send_event(EVENT_ACCESS_CHANGE, 4, ci->name, u->nick, na->nick,
00342                        event_access);
00343             notice_lang(s_ChanServ, u, xmsgs[4], access->nc->display,
00344                         ci->name);
00345         }
00346 
00347     } else if (stricmp(cmd, "DEL") == 0) {
00348         int deleted, a, b;
00349         if (readonly) {
00350             notice_lang(s_ChanServ, u, xmsgs[1]);
00351             return MOD_CONT;
00352         }
00353 
00354         if (ci->accesscount == 0) {
00355             notice_lang(s_ChanServ, u, xmsgs[11], chan);
00356             return MOD_CONT;
00357         }
00358 
00359         ulev = get_access(u, ci);
00360 
00361         if ((xlev >= ulev || ulev < ACCESS_AOP) && !is_servadmin) {
00362             notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00363             return MOD_CONT;
00364         }
00365 
00366         /* Special case: is it a number/list?  Only do search if it isn't. */
00367         if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) {
00368             int count, last = -1, perm = 0;
00369             deleted =
00370                 process_numlist(nick, &count, xop_del_callback, u, ci,
00371                                 &last, &perm, ulev, xlev);
00372             if (!deleted) {
00373                 if (perm) {
00374                     notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00375                 } else if (count == 1) {
00376                     notice_lang(s_ChanServ, u, xmsgs[5], last, ci->name);
00377                 } else {
00378                     notice_lang(s_ChanServ, u, xmsgs[7], ci->name);
00379                 }
00380             } else if (deleted == 1) {
00381                 notice_lang(s_ChanServ, u, xmsgs[9], ci->name);
00382             } else {
00383                 notice_lang(s_ChanServ, u, xmsgs[10], deleted, ci->name);
00384             }
00385         } else {
00386             na = findnick(nick);
00387             if (!na) {
00388                 notice_lang(s_ChanServ, u, NICK_X_NOT_REGISTERED, nick);
00389                 return MOD_CONT;
00390             }
00391             nc = na->nc;
00392 
00393             for (i = 0; i < ci->accesscount; i++)
00394                 if (ci->access[i].nc == nc && ci->access[i].level == xlev)
00395                     break;
00396 
00397             if (i == ci->accesscount) {
00398                 notice_lang(s_ChanServ, u, xmsgs[6], nick, chan);
00399                 return MOD_CONT;
00400             }
00401 
00402             access = &ci->access[i];
00403             if (!is_servadmin && ulev <= access->level) {
00404                 deleted = 0;
00405                 notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00406             } else {
00407                 notice_lang(s_ChanServ, u, xmsgs[8], access->nc->display,
00408                             ci->name);
00409                 access->nc = NULL;
00410                 access->in_use = 0;
00411                 send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick,
00412                            na->nick);
00413                 deleted = 1;
00414             }
00415         }
00416         if (deleted) {
00417             /* Reordering - DrStein */
00418             for (b = 0; b < ci->accesscount; b++) {
00419                 if (ci->access[b].in_use) {
00420                     for (a = 0; a < ci->accesscount; a++) {
00421                         if (a > b)
00422                             break;
00423                         if (!ci->access[a].in_use) {
00424                             ci->access[a].in_use = 1;
00425                             ci->access[a].level = ci->access[b].level;
00426                             ci->access[a].nc = ci->access[b].nc;
00427                             ci->access[a].last_seen =
00428                                 ci->access[b].last_seen;
00429                             ci->access[b].nc = NULL;
00430                             ci->access[b].in_use = 0;
00431                             break;
00432                         }
00433                     }
00434                 }
00435             }
00436 
00437             /* If the patch provided in bug #706 is applied, this should be placed
00438              * before sending the events! */
00439             /* After reordering only the entries at the end could still be empty.
00440              * We ll free the places no longer in use... */
00441             for (i = ci->accesscount - 1; i >= 0; i--) {
00442                 if (ci->access[i].in_use == 1)
00443                     break;
00444 
00445                 ci->accesscount--;
00446             }
00447             ci->access =
00448                 srealloc(ci->access,sizeof(ChanAccess) * ci->accesscount);
00449         }
00450     } else if (stricmp(cmd, "LIST") == 0) {
00451         int sent_header = 0;
00452 
00453         ulev = get_access(u, ci);
00454 
00455         if (!is_servadmin && ulev < ACCESS_AOP) {
00456             notice_lang(s_ChanServ, u, ACCESS_DENIED);
00457             return MOD_CONT;
00458         }
00459 
00460         if (ci->accesscount == 0) {
00461             notice_lang(s_ChanServ, u, xmsgs[11], ci->name);
00462             return MOD_CONT;
00463         }
00464 
00465         if (nick && strspn(nick, "1234567890,-") == strlen(nick)) {
00466             process_numlist(nick, NULL, xop_list_callback, u, ci,
00467                             &sent_header, xlev, xmsgs[12]);
00468         } else {
00469             for (i = 0; i < ci->accesscount; i++) {
00470                 if (nick && ci->access[i].nc
00471                     && !match_wild_nocase(nick, ci->access[i].nc->display))
00472                     continue;
00473                 xop_list(u, i, ci, &sent_header, xlev, xmsgs[12]);
00474             }
00475         }
00476         if (!sent_header)
00477             notice_lang(s_ChanServ, u, xmsgs[7], chan);
00478     } else if (stricmp(cmd, "CLEAR") == 0) {
00479         if (readonly) {
00480             notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
00481             return MOD_CONT;
00482         }
00483 
00484         if (ci->accesscount == 0) {
00485             notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
00486             return MOD_CONT;
00487         }
00488 
00489         if (!is_servadmin && !is_founder(u, ci)) {
00490             notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00491             return MOD_CONT;
00492         }
00493 
00494         for (i = 0; i < ci->accesscount; i++) {
00495             if (ci->access[i].in_use && ci->access[i].level == xlev) {
00496                 ci->access[i].nc = NULL;
00497                 ci->access[i].in_use = 0;
00498             }
00499         }
00500 
00501         send_event(EVENT_ACCESS_CLEAR, 2, ci->name, u->nick);
00502         
00503         notice_lang(s_ChanServ, u, xmsgs[13], ci->name);
00504     } else {
00505         syntax_error(s_ChanServ, u, xname, xmsgs[0]);
00506     }
00507     return MOD_CONT;
00508 }

Generated on Sun Dec 30 09:26:47 2007 for Anope by  doxygen 1.5.1-20070107