00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 static int reversing = 0;
00030
00031 #define PLUS 0x01
00032 #define MINUS 0x02
00033 #define CHOP 0x04
00034 #define BAN 0x08
00035 #define VOICE 0x10
00036 #define EXEMPT 0x20
00037 #define INVITE 0x40
00038 #define CHHOP 0x80
00039
00040 static struct flag_record user = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00041 static struct flag_record victim = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00042
00043
00044
00045
00046
00047 struct chanset_t *modebind_refresh(char *chname,
00048 char *usrhost, struct flag_record *usr,
00049 char *vcrhost, struct flag_record *vcr)
00050 {
00051 struct userrec *u;
00052 struct chanset_t *chan;
00053
00054 if (!chname || !(chan = findchan(chname)))
00055 return NULL;
00056 if (usrhost) {
00057 u = get_user_by_host(usrhost);
00058 get_user_flagrec(u, usr, chan->dname);
00059 }
00060 if (vcrhost) {
00061 u = get_user_by_host(vcrhost);
00062 get_user_flagrec(u, vcr, chan->dname);
00063 }
00064 return chan;
00065 }
00066
00067 static void flush_mode(struct chanset_t *chan, int pri)
00068 {
00069 char *p, out[512], post[512];
00070 size_t postsize = sizeof(post);
00071 int i, plus = 2;
00072
00073 p = out;
00074 post[0] = 0, postsize--;
00075
00076 if (chan->mns[0]) {
00077 *p++ = '-', plus = 0;
00078 for (i = 0; i < strlen(chan->mns); i++)
00079 *p++ = chan->mns[i];
00080 chan->mns[0] = 0;
00081 }
00082
00083 if (chan->pls[0]) {
00084 *p++ = '+', plus = 1;
00085 for (i = 0; i < strlen(chan->pls); i++)
00086 *p++ = chan->pls[i];
00087 chan->pls[0] = 0;
00088 }
00089
00090 chan->bytes = 0;
00091 chan->compat = 0;
00092
00093
00094 if (chan->key && !chan->rmkey) {
00095 if (plus != 1) {
00096 *p++ = '+', plus = 1;
00097 }
00098 *p++ = 'k';
00099
00100 postsize -= egg_strcatn(post, chan->key, sizeof(post));
00101 postsize -= egg_strcatn(post, " ", sizeof(post));
00102
00103 nfree(chan->key), chan->key = NULL;
00104 }
00105
00106
00107
00108
00109
00110 if (chan->limit != 0 && postsize >= 12) {
00111 if (plus != 1) {
00112 *p++ = '+', plus = 1;
00113 }
00114 *p++ = 'l';
00115
00116
00117 postsize -=
00118 sprintf(&post[(sizeof(post) - 1) - postsize], "%d ", chan->limit);
00119
00120 chan->limit = 0;
00121 }
00122
00123
00124 if (chan->rmkey) {
00125 if (plus) {
00126 *p++ = '-', plus = 0;
00127 }
00128 *p++ = 'k';
00129
00130 postsize -= egg_strcatn(post, chan->rmkey, sizeof(post));
00131 postsize -= egg_strcatn(post, " ", sizeof(post));
00132
00133 nfree(chan->rmkey), chan->rmkey = NULL;
00134 }
00135
00136
00137 for (i = 0; i < modesperline; i++) {
00138 if ((chan->cmode[i].type & MINUS) && postsize > strlen(chan->cmode[i].op)) {
00139 if (plus) {
00140 *p++ = '-', plus = 0;
00141 }
00142
00143 *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
00144 ((chan->cmode[i].type & CHOP) ? 'o' :
00145 ((chan->cmode[i].type & CHHOP) ? 'h' :
00146 ((chan->cmode[i].type & EXEMPT) ? 'e' :
00147 ((chan->cmode[i].type & INVITE) ? 'I' : 'v')))));
00148
00149 postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
00150 postsize -= egg_strcatn(post, " ", sizeof(post));
00151
00152 nfree(chan->cmode[i].op), chan->cmode[i].op = NULL;
00153 chan->cmode[i].type = 0;
00154 }
00155 }
00156
00157
00158 for (i = 0; i < modesperline; i++) {
00159 if ((chan->cmode[i].type & PLUS) && postsize > strlen(chan->cmode[i].op)) {
00160 if (plus != 1) {
00161 *p++ = '+', plus = 1;
00162 }
00163
00164 *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
00165 ((chan->cmode[i].type & CHOP) ? 'o' :
00166 ((chan->cmode[i].type & CHHOP) ? 'h' :
00167 ((chan->cmode[i].type & EXEMPT) ? 'e' :
00168 ((chan->cmode[i].type & INVITE) ? 'I' : 'v')))));
00169
00170 postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
00171 postsize -= egg_strcatn(post, " ", sizeof(post));
00172
00173 nfree(chan->cmode[i].op), chan->cmode[i].op = NULL;
00174 chan->cmode[i].type = 0;
00175 }
00176 }
00177
00178
00179 *p = 0;
00180
00181 if (post[0]) {
00182
00183 size_t index = (sizeof(post) - 1) - postsize;
00184
00185 if (index > 0 && post[index - 1] == ' ')
00186 post[index - 1] = 0;
00187
00188 egg_strcatn(out, " ", sizeof(out));
00189 egg_strcatn(out, post, sizeof(out));
00190 }
00191 if (out[0]) {
00192 if (pri == QUICK)
00193 dprintf(DP_MODE, "MODE %s %s\n", chan->name, out);
00194 else
00195 dprintf(DP_SERVER, "MODE %s %s\n", chan->name, out);
00196 }
00197 }
00198
00199
00200
00201 static void real_add_mode(struct chanset_t *chan,
00202 char plus, char mode, char *op)
00203 {
00204 int i, type, modes, l;
00205 masklist *m;
00206 memberlist *mx;
00207 char s[21];
00208
00209
00210
00211 #ifdef NO_HALFOP_CHANMODES
00212 if (!me_op(chan))
00213 #else
00214 if (HALFOP_CANTDOMODE(mode))
00215 #endif
00216 return;
00217
00218 if (mode == 'o' || mode == 'h' || mode == 'v') {
00219 mx = ismember(chan, op);
00220 if (!mx)
00221 return;
00222 if (plus == '-' && mode == 'o') {
00223 if (chan_sentdeop(mx) || !chan_hasop(mx))
00224 return;
00225 mx->flags |= SENTDEOP;
00226 }
00227 if (plus == '+' && mode == 'o') {
00228 if (chan_sentop(mx) || chan_hasop(mx))
00229 return;
00230 mx->flags |= SENTOP;
00231 }
00232 if (plus == '-' && mode == 'h') {
00233 if (chan_sentdehalfop(mx) || !chan_hashalfop(mx))
00234 return;
00235 mx->flags |= SENTDEHALFOP;
00236 }
00237 if (plus == '+' && mode == 'h') {
00238 if (chan_senthalfop(mx) || chan_hashalfop(mx))
00239 return;
00240 mx->flags |= SENTHALFOP;
00241 }
00242 if (plus == '-' && mode == 'v') {
00243 if (chan_sentdevoice(mx) || !chan_hasvoice(mx))
00244 return;
00245 mx->flags |= SENTDEVOICE;
00246 }
00247 if (plus == '+' && mode == 'v') {
00248 if (chan_sentvoice(mx) || chan_hasvoice(mx))
00249 return;
00250 mx->flags |= SENTVOICE;
00251 }
00252 }
00253
00254 if (chan->compat == 0) {
00255 if (mode == 'e' || mode == 'I')
00256 chan->compat = 2;
00257 else
00258 chan->compat = 1;
00259 } else if (mode == 'e' || mode == 'I') {
00260 if (prevent_mixing && chan->compat == 1)
00261 flush_mode(chan, NORMAL);
00262 } else if (prevent_mixing && chan->compat == 2)
00263 flush_mode(chan, NORMAL);
00264
00265 if (mode == 'o' || mode == 'h' || mode == 'b' || mode == 'v' || mode == 'e' ||
00266 mode == 'I') {
00267 type = (plus == '+' ? PLUS : MINUS) | (mode == 'o' ? CHOP : (mode == 'h' ?
00268 CHHOP : (mode == 'b' ? BAN : (mode == 'v' ? VOICE : (mode == 'e' ?
00269 EXEMPT : INVITE)))));
00270
00271
00272
00273
00274
00275
00276 if ((plus == '-' && ((mode == 'b' && !ischanban(chan, op)) ||
00277 (mode == 'e' && !ischanexempt(chan, op)) ||
00278 (mode == 'I' && !ischaninvite(chan, op)))) || (plus == '+' &&
00279 ((mode == 'b' && ischanban(chan, op)) ||
00280 (mode == 'e' && ischanexempt(chan, op)) ||
00281 (mode == 'I' && ischaninvite(chan, op)))))
00282 return;
00283
00284
00285
00286
00287
00288 if (plus == '+' && (mode == 'b' || mode == 'e' || mode == 'I')) {
00289 int bans = 0, exempts = 0, invites = 0;
00290
00291 for (m = chan->channel.ban; m && m->mask[0]; m = m->next)
00292 bans++;
00293 if ((mode == 'b') && (bans >= max_bans))
00294 return;
00295
00296 for (m = chan->channel.exempt; m && m->mask[0]; m = m->next)
00297 exempts++;
00298 if ((mode == 'e') && (exempts >= max_exempts))
00299 return;
00300
00301 for (m = chan->channel.invite; m && m->mask[0]; m = m->next)
00302 invites++;
00303 if ((mode == 'I') && (invites >= max_invites))
00304 return;
00305
00306 if (bans + exempts + invites >= max_modes)
00307 return;
00308 }
00309
00310
00311 for (i = 0; i < modesperline; i++)
00312 if (chan->cmode[i].type == type && chan->cmode[i].op != NULL &&
00313 !rfc_casecmp(chan->cmode[i].op, op))
00314 return;
00315 l = strlen(op) + 1;
00316 if (chan->bytes + l > mode_buf_len)
00317 flush_mode(chan, NORMAL);
00318 for (i = 0; i < modesperline; i++)
00319 if (chan->cmode[i].type == 0) {
00320 chan->cmode[i].type = type;
00321 chan->cmode[i].op = (char *) channel_malloc(l);
00322 chan->bytes += l;
00323 strcpy(chan->cmode[i].op, op);
00324 break;
00325 }
00326 }
00327
00328
00329 else if (plus == '+' && mode == 'k') {
00330 if (chan->key)
00331 nfree(chan->key);
00332 chan->key = (char *) channel_malloc(strlen(op) + 1);
00333 if (chan->key)
00334 strcpy(chan->key, op);
00335 }
00336
00337 else if (plus == '-' && mode == 'k') {
00338 if (chan->rmkey)
00339 nfree(chan->rmkey);
00340 chan->rmkey = (char *) channel_malloc(strlen(op) + 1);
00341 if (chan->rmkey)
00342 strcpy(chan->rmkey, op);
00343 }
00344
00345 else if (plus == '+' && mode == 'l')
00346 chan->limit = atoi(op);
00347 else {
00348
00349 if (plus == '+')
00350 strcpy(s, chan->pls);
00351 else
00352 strcpy(s, chan->mns);
00353 if (!strchr(s, mode)) {
00354 if (plus == '+') {
00355 chan->pls[strlen(chan->pls) + 1] = 0;
00356 chan->pls[strlen(chan->pls)] = mode;
00357 } else {
00358 chan->mns[strlen(chan->mns) + 1] = 0;
00359 chan->mns[strlen(chan->mns)] = mode;
00360 }
00361 }
00362 }
00363 modes = modesperline;
00364 for (i = 0; i < modesperline; i++)
00365 if (chan->cmode[i].type)
00366 modes--;
00367 if (include_lk && chan->limit)
00368 modes--;
00369 if (include_lk && chan->rmkey)
00370 modes--;
00371 if (include_lk && chan->key)
00372 modes--;
00373 if (modes < 1)
00374 flush_mode(chan, NORMAL);
00375 }
00376
00377
00378
00379
00380
00381
00382 static void got_key(struct chanset_t *chan, char *nick, char *from, char *key)
00383 {
00384 if (!nick[0] && bounce_modes)
00385 reversing = 1;
00386
00387 if (!(glob_master(user) || glob_bot(user) || chan_master(user)) &&
00388 !match_my_nick(nick)) {
00389 if ((reversing && !chan->key_prot[0]) || (chan->mode_mns_prot & CHANKEY)) {
00390 if (strlen(key) != 0)
00391 add_mode(chan, '-', 'k', key);
00392 else
00393 add_mode(chan, '-', 'k', "");
00394 }
00395 if ((chan->mode_pls_prot & CHANKEY) && (chan->key_prot[0] != 0) &&
00396 strcmp(key, chan->key_prot)) {
00397 add_mode(chan, '+', 'k', chan->key_prot);
00398 }
00399 }
00400 }
00401
00402 static void got_op(struct chanset_t *chan, char *nick, char *from,
00403 char *who, struct userrec *opu, struct flag_record *opper)
00404 {
00405 memberlist *m;
00406 char ch[sizeof chan->name];
00407 char s[UHOSTLEN];
00408 struct userrec *u;
00409 int check_chan = 0, snm = chan->stopnethack_mode;
00410
00411 m = ismember(chan, who);
00412 if (!m) {
00413 if (channel_pending(chan))
00414 return;
00415 putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
00416 chan->status |= CHAN_PEND;
00417 refresh_who_chan(chan->name);
00418 return;
00419 }
00420
00421
00422 if (!me_op(chan) && match_my_nick(who))
00423 check_chan = 1;
00424
00425 strcpy(ch, chan->name);
00426 simple_sprintf(s, "%s!%s", m->nick, m->userhost);
00427 if (!m->user)
00428 u = get_user_by_host(s);
00429 else
00430 u = m->user;
00431
00432 get_user_flagrec(u, &victim, chan->dname);
00433
00434
00435
00436 m->flags |= CHANOP;
00437 check_tcl_mode(nick, from, opu, chan->dname, "+o", who);
00438 if (!(chan = modebind_refresh(ch, from, opper, s, &victim)) ||
00439 !(m = ismember(chan, who)))
00440 return;
00441
00442
00443
00444
00445
00446 m->flags &= ~SENTOP;
00447
00448 if (channel_pending(chan))
00449 return;
00450
00451 if (nick[0] && HALFOP_CANDOMODE('o') && !match_my_nick(who) &&
00452 !match_my_nick(nick)) {
00453 if (channel_bitch(chan) && !(glob_master(*opper) || glob_bot(*opper)) &&
00454 !chan_master(*opper) && !(glob_op(victim) || glob_bot(victim)) &&
00455 !chan_op(victim))
00456 add_mode(chan, '-', 'o', who);
00457 else if ((chan_deop(victim) || (glob_deop(victim) && !chan_op(victim))) &&
00458 !glob_master(*opper) && !chan_master(*opper))
00459 add_mode(chan, '-', 'o', who);
00460 else if (reversing)
00461 add_mode(chan, '-', 'o', who);
00462 } else if (reversing && HALFOP_CANDOMODE('o') && !match_my_nick(who) &&
00463 !match_my_nick(nick))
00464 add_mode(chan, '-', 'o', who);
00465 if (!nick[0] && HALFOP_CANDOMODE('o') && !match_my_nick(who)) {
00466 if (chan_deop(victim) || (glob_deop(victim) && !chan_op(victim))) {
00467 m->flags |= FAKEOP;
00468 add_mode(chan, '-', 'o', who);
00469 } else if (snm > 0 && snm < 7 && !((channel_autoop(chan) ||
00470 glob_autoop(victim) || chan_autoop(victim)) && (chan_op(victim) ||
00471 (glob_op(victim) && !chan_deop(victim)))) &&
00472 !glob_exempt(victim) && !chan_exempt(victim)) {
00473 if (snm == 5)
00474 snm = channel_bitch(chan) ? 1 : 3;
00475 if (snm == 6)
00476 snm = channel_bitch(chan) ? 4 : 2;
00477 if (chan_wasoptest(victim) || glob_wasoptest(victim) || snm == 2) {
00478 if (!chan_wasop(m)) {
00479 m->flags |= FAKEOP;
00480 add_mode(chan, '-', 'o', who);
00481 }
00482 } else if (!(chan_op(victim) || (glob_op(victim) && !chan_deop(victim)))) {
00483 if (snm == 1 || snm == 4 || (snm == 3 && !chan_wasop(m))) {
00484 add_mode(chan, '-', 'o', who);
00485 m->flags |= FAKEOP;
00486 }
00487 } else if (snm == 4 && !chan_wasop(m)) {
00488 add_mode(chan, '-', 'o', who);
00489 m->flags |= FAKEOP;
00490 }
00491 }
00492 }
00493 m->flags |= WASOP;
00494 if (check_chan)
00495 recheck_channel(chan, 1);
00496 }
00497
00498 static void got_halfop(struct chanset_t *chan, char *nick, char *from,
00499 char *who, struct userrec *opu,
00500 struct flag_record *opper)
00501 {
00502 memberlist *m;
00503 char s[UHOSTLEN];
00504 char ch[sizeof chan->name];
00505 struct userrec *u;
00506 int check_chan = 0;
00507 int snm = chan->stopnethack_mode;
00508
00509 m = ismember(chan, who);
00510 if (!m) {
00511 if (channel_pending(chan))
00512 return;
00513 putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
00514 chan->status |= CHAN_PEND;
00515 refresh_who_chan(chan->name);
00516 return;
00517 }
00518
00519
00520 if (!me_op(chan) && !me_halfop(chan) && match_my_nick(who))
00521 check_chan = 1;
00522
00523 strcpy(ch, chan->name);
00524 simple_sprintf(s, "%s!%s", m->nick, m->userhost);
00525 if (!m->user)
00526 u = get_user_by_host(s);
00527 else
00528 u = m->user;
00529
00530 get_user_flagrec(u, &victim, chan->dname);
00531
00532
00533
00534 m->flags |= CHANHALFOP;
00535 check_tcl_mode(nick, from, opu, chan->dname, "+h", who);
00536 if (!(chan = modebind_refresh(ch, from, opper, s, &victim)) ||
00537 !(m = ismember(chan, who)))
00538 return;
00539 m->flags &= ~SENTHALFOP;
00540
00541 if (channel_pending(chan))
00542 return;
00543
00544 if (nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who) &&
00545 !match_my_nick(nick)) {
00546 if (channel_bitch(chan) && !(glob_master(*opper) || glob_bot(*opper)) &&
00547 !chan_master(*opper) && !(glob_halfop(victim) || glob_op(victim) ||
00548 glob_bot(victim)) && !chan_op(victim) && !chan_halfop(victim))
00549 add_mode(chan, '-', 'h', who);
00550 else if ((chan_dehalfop(victim) || (glob_dehalfop(victim) &&
00551 !chan_halfop(victim))) && !glob_master(*opper) &&
00552 !chan_master(*opper))
00553 add_mode(chan, '-', 'h', who);
00554 else if (reversing)
00555 add_mode(chan, '-', 'h', who);
00556 } else if (reversing && HALFOP_CANDOMODE('h') && !match_my_nick(who) &&
00557 !match_my_nick(nick))
00558 add_mode(chan, '-', 'h', who);
00559 if (!nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who)) {
00560 if (chan_dehalfop(victim) || (glob_dehalfop(victim) &&
00561 !chan_halfop(victim))) {
00562 m->flags |= FAKEHALFOP;
00563 add_mode(chan, '-', 'h', who);
00564 } else if (snm > 0 && snm < 7 && !((channel_autohalfop(chan) ||
00565 glob_autohalfop(victim) || chan_autohalfop(victim)) &&
00566 (chan_halfop(victim) || (glob_halfop(victim) &&
00567 !chan_dehalfop(victim)))) && !glob_exempt(victim) &&
00568 !chan_exempt(victim)) {
00569 if (snm == 5)
00570 snm = channel_bitch(chan) ? 1 : 3;
00571 if (snm == 6)
00572 snm = channel_bitch(chan) ? 4 : 2;
00573 if (chan_washalfoptest(victim) || glob_washalfoptest(victim) || snm == 2) {
00574 if (!chan_washalfop(m)) {
00575 m->flags |= FAKEHALFOP;
00576 add_mode(chan, '-', 'h', who);
00577 }
00578 } else if (!(chan_halfop(victim) || (glob_halfop(victim) &&
00579 !chan_dehalfop(victim)))) {
00580 if (snm == 1 || snm == 4 || (snm == 3 && !chan_washalfop(m))) {
00581 add_mode(chan, '-', 'h', who);
00582 m->flags |= FAKEHALFOP;
00583 }
00584 } else if (snm == 4 && !chan_washalfop(m)) {
00585 add_mode(chan, '-', 'h', who);
00586 m->flags |= FAKEHALFOP;
00587 }
00588 }
00589 }
00590 m->flags |= WASHALFOP;
00591 if (check_chan)
00592 recheck_channel(chan, 1);
00593 }
00594
00595 static void got_deop(struct chanset_t *chan, char *nick, char *from,
00596 char *who, struct userrec *opu)
00597 {
00598 memberlist *m;
00599 char ch[sizeof chan->name];
00600 char s[UHOSTLEN], s1[UHOSTLEN];
00601 struct userrec *u;
00602 int had_halfop;
00603
00604 m = ismember(chan, who);
00605 if (!m) {
00606 if (channel_pending(chan))
00607 return;
00608 putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
00609 chan->status |= CHAN_PEND;
00610 refresh_who_chan(chan->name);
00611 return;
00612 }
00613
00614 strcpy(ch, chan->name);
00615 simple_sprintf(s, "%s!%s", m->nick, m->userhost);
00616 simple_sprintf(s1, "%s!%s", nick, from);
00617 u = get_user_by_host(s);
00618 get_user_flagrec(u, &victim, chan->dname);
00619
00620 had_halfop = chan_hasop(m);
00621
00622
00623
00624 m->flags &= ~(CHANOP | SENTDEOP | FAKEOP);
00625 check_tcl_mode(nick, from, opu, chan->dname, "-o", who);
00626 if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) ||
00627 !(m = ismember(chan, who)))
00628 return;
00629 m->flags &= ~WASOP;
00630
00631 if (channel_pending(chan))
00632 return;
00633
00634 if (HALFOP_CANDOMODE('o')) {
00635 int ok = 1;
00636
00637 if (!glob_deop(victim) && !chan_deop(victim)) {
00638 if (channel_protectops(chan) && (glob_master(victim) ||
00639 chan_master(victim) || glob_op(victim) || chan_op(victim)))
00640 ok = 0;
00641 else if (channel_protectfriends(chan) && (glob_friend(victim) ||
00642 chan_friend(victim)))
00643 ok = 0;
00644 }
00645 if ((reversing || !ok) && had_halfop && !match_my_nick(nick) &&
00646 rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) &&
00647 !chan_master(user) && !glob_bot(user) && ((chan_op(victim) ||
00648 (glob_op(victim) && !chan_deop(victim))) || !channel_bitch(chan)))
00649 add_mode(chan, '+', 'o', who);
00650 }
00651
00652 if (!nick[0])
00653 putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s",
00654 chan->dname, who, from);
00655
00656
00657 if (nick[0])
00658 detect_chan_flood(nick, from, s1, chan, FLOOD_DEOP, who);
00659
00660
00661
00662
00663 if (!(m->flags & (CHANVOICE | CHANHALFOP | STOPWHO))) {
00664 chan->status |= CHAN_PEND;
00665 refresh_who_chan(chan->name);
00666 m->flags |= STOPWHO;
00667 }
00668
00669
00670 if (match_my_nick(who)) {
00671
00672 memberlist *m2;
00673
00674 for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
00675 m2->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTVOICE | SENTDEVOICE);
00676
00677 check_tcl_need(chan->dname, "op");
00678 if (chan->need_op[0])
00679 do_tcl("need-op", chan->need_op);
00680 if (!nick[0])
00681 putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(",
00682 chan->dname);
00683 }
00684 if (nick[0])
00685 maybe_revenge(chan, s1, s, REVENGE_DEOP);
00686 }
00687
00688 static void got_dehalfop(struct chanset_t *chan, char *nick, char *from,
00689 char *who, struct userrec *opu)
00690 {
00691 memberlist *m;
00692 char ch[sizeof chan->name];
00693 char s[UHOSTLEN], s1[UHOSTLEN];
00694 struct userrec *u;
00695 int had_halfop;
00696
00697 m = ismember(chan, who);
00698 if (!m) {
00699 if (channel_pending(chan))
00700 return;
00701 putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
00702 chan->status |= CHAN_PEND;
00703 refresh_who_chan(chan->name);
00704 return;
00705 }
00706
00707 strcpy(ch, chan->name);
00708 simple_sprintf(s, "%s!%s", m->nick, m->userhost);
00709 simple_sprintf(s1, "%s!%s", nick, from);
00710 u = get_user_by_host(s);
00711 get_user_flagrec(u, &victim, chan->dname);
00712
00713 had_halfop = chan_hasop(m);
00714
00715
00716
00717 m->flags &= ~(CHANHALFOP | SENTDEHALFOP | FAKEHALFOP);
00718 check_tcl_mode(nick, from, opu, chan->dname, "-h", who);
00719 if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) ||
00720 !(m = ismember(chan, who)))
00721 return;
00722
00723 m->flags &= ~WASHALFOP;
00724
00725 if (channel_pending(chan))
00726 return;
00727
00728
00729 if (HALFOP_CANDOMODE('h')) {
00730 int ok = 1;
00731
00732 if (!glob_dehalfop(victim) && !chan_dehalfop(victim)) {
00733 if (channel_protecthalfops(chan) && (glob_master(victim) ||
00734 chan_master(victim) || glob_halfop(victim) || chan_halfop(victim)))
00735 ok = 0;
00736 else if (channel_protectfriends(chan) && (glob_friend(victim) ||
00737 chan_friend(victim)))
00738 ok = 0;
00739 }
00740 if ((reversing || !ok) && had_halfop && !match_my_nick(nick) &&
00741 rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) &&
00742 !chan_master(user) && !glob_bot(user) && ((chan_halfop(victim) ||
00743 (glob_halfop(victim) && !chan_dehalfop(victim))) ||
00744 !channel_bitch(chan)))
00745 add_mode(chan, '+', 'h', who);
00746 }
00747
00748 if (!nick[0])
00749 putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s",
00750 chan->dname, who, from);
00751 if (!(m->flags & (CHANVOICE | STOPWHO))) {
00752 chan->status |= CHAN_PEND;
00753 refresh_who_chan(chan->name);
00754 m->flags |= STOPWHO;
00755 }
00756 }
00757
00758 static void got_ban(struct chanset_t *chan, char *nick, char *from, char *who,
00759 char *ch, struct userrec *u)
00760 {
00761 char me[UHOSTLEN], s[UHOSTLEN], s1[UHOSTLEN];
00762 memberlist *m;
00763 struct userrec *targ;
00764
00765 egg_snprintf(me, sizeof me, "%s!%s", botname, botuserhost);
00766 egg_snprintf(s, sizeof s, "%s!%s", nick, from);
00767 newban(chan, who, s);
00768 check_tcl_mode(nick, from, u, chan->dname, "+b", who);
00769 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00770 return;
00771
00772 if (channel_pending(chan) || HALFOP_CANTDOMODE('b'))
00773 return;
00774
00775 if (match_addr(who, me) && !isexempted(chan, me)) {
00776 add_mode(chan, '-', 'b', who);
00777 reversing = 1;
00778 return;
00779 }
00780 if (!match_my_nick(nick)) {
00781 if (nick[0] && channel_nouserbans(chan) && !glob_bot(user) &&
00782 !glob_master(user) && !chan_master(user)) {
00783 add_mode(chan, '-', 'b', who);
00784 return;
00785 }
00786 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00787 egg_snprintf(s1, sizeof s1, "%s!%s", m->nick, m->userhost);
00788 if (match_addr(who, s1)) {
00789 targ = get_user_by_host(s1);
00790 if (targ) {
00791 get_user_flagrec(targ, &victim, chan->dname);
00792 if ((glob_friend(victim) || (glob_op(victim) && !chan_deop(victim)) ||
00793 chan_friend(victim) || chan_op(victim)) && !glob_master(user) &&
00794 !glob_bot(user) && !chan_master(user) && !isexempted(chan, s1)) {
00795 add_mode(chan, '-', 'b', who);
00796 return;
00797 }
00798 }
00799 }
00800 }
00801 }
00802 refresh_exempt(chan, who);
00803 if (nick[0] && channel_enforcebans(chan)) {
00804 register maskrec *b;
00805 int cycle;
00806 char resn[512] = "";
00807
00808 for (cycle = 0; cycle < 2; cycle++) {
00809 for (b = cycle ? chan->bans : global_bans; b; b = b->next) {
00810 if (match_addr(b->mask, who)) {
00811 if (b->desc && b->desc[0] != '@')
00812 egg_snprintf(resn, sizeof resn, "%s %s", IRC_PREBANNED, b->desc);
00813 else
00814 resn[0] = 0;
00815 }
00816 }
00817 }
00818 kick_all(chan, who, resn[0] ? resn : IRC_BANNED,
00819 match_my_nick(nick) ? 0 : 1);
00820 }
00821 if (!nick[0] && (bounce_bans || bounce_modes) &&
00822 (!u_equals_mask(global_bans, who) || !u_equals_mask(chan->bans, who)))
00823 add_mode(chan, '-', 'b', who);
00824 }
00825
00826 static void got_unban(struct chanset_t *chan, char *nick, char *from,
00827 char *who, char *ch, struct userrec *u)
00828 {
00829 masklist *b, *old;
00830
00831 old = NULL;
00832 for (b = chan->channel.ban; b->mask[0] && rfc_casecmp(b->mask, who);
00833 old = b, b = b->next);
00834 if (b->mask[0]) {
00835 if (old)
00836 old->next = b->next;
00837 else
00838 chan->channel.ban = b->next;
00839 nfree(b->mask);
00840 nfree(b->who);
00841 nfree(b);
00842 }
00843 check_tcl_mode(nick, from, u, chan->dname, "-b", who);
00844 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00845 return;
00846
00847 if (channel_pending(chan))
00848 return;
00849
00850 if ((u_sticky_mask(chan->bans, who) || u_sticky_mask(global_bans, who)) ||
00851 ((u_equals_mask(global_bans, who) || u_equals_mask(chan->bans, who)) &&
00852 !channel_dynamicbans(chan) && ((!glob_bot(user) ||
00853 !(bot_flags(u) & BOT_SHARE)) && ((!glob_op(user) || chan_deop(user)) &&
00854 !chan_op(user)) && ((!glob_halfop(user) || chan_dehalfop(user)) &&
00855 !chan_halfop(user)))))
00856 add_mode(chan, '+', 'b', who);
00857 }
00858
00859 static void got_exempt(struct chanset_t *chan, char *nick, char *from,
00860 char *who, char *ch, struct userrec *u)
00861 {
00862 char s[UHOSTLEN];
00863
00864 simple_sprintf(s, "%s!%s", nick, from);
00865 newexempt(chan, who, s);
00866 check_tcl_mode(nick, from, u, chan->dname, "+e", who);
00867 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00868 return;
00869
00870 if (channel_pending(chan) || HALFOP_CANTDOMODE('e'))
00871 return;
00872
00873 if (!match_my_nick(nick)) {
00874 if (nick[0] && channel_nouserexempts(chan) && !glob_bot(user) &&
00875 !glob_master(user) && !chan_master(user)) {
00876 add_mode(chan, '-', 'e', who);
00877 return;
00878 }
00879 if (!nick[0] && bounce_modes)
00880 reversing = 1;
00881 }
00882 if (reversing || (bounce_exempts && !nick[0] &&
00883 (!u_equals_mask(global_exempts, who) ||
00884 !u_equals_mask(chan->exempts, who))))
00885 add_mode(chan, '-', 'e', who);
00886 }
00887
00888 static void got_unexempt(struct chanset_t *chan, char *nick, char *from,
00889 char *who, char *ch, struct userrec *u)
00890 {
00891 masklist *e = chan->channel.exempt, *old = NULL;
00892 masklist *b;
00893 int match = 0;
00894
00895 while (e && e->mask[0] && rfc_casecmp(e->mask, who)) {
00896 old = e;
00897 e = e->next;
00898 }
00899 if (e && e->mask[0]) {
00900 if (old)
00901 old->next = e->next;
00902 else
00903 chan->channel.exempt = e->next;
00904 nfree(e->mask);
00905 nfree(e->who);
00906 nfree(e);
00907 }
00908 check_tcl_mode(nick, from, u, chan->dname, "-e", who);
00909 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00910 return;
00911
00912 if (channel_pending(chan))
00913 return;
00914
00915 if (u_sticky_mask(chan->exempts, who) || u_sticky_mask(global_exempts, who))
00916 add_mode(chan, '+', 'e', who);
00917
00918
00919 if (!nick[0] && glob_bot(user) && !glob_master(user) && !chan_master(user)) {
00920 b = chan->channel.ban;
00921 while (b->mask[0] && !match) {
00922 if (mask_match(b->mask, who)) {
00923 add_mode(chan, '+', 'e', who);
00924 match = 1;
00925 } else
00926 b = b->next;
00927 }
00928 }
00929 if ((u_equals_mask(global_exempts, who) ||
00930 u_equals_mask(chan->exempts, who)) && me_op(chan) &&
00931 !channel_dynamicexempts(chan) && (!glob_bot(user) ||
00932 !(bot_flags(u) & BOT_SHARE)))
00933 add_mode(chan, '+', 'e', who);
00934 }
00935
00936 static void got_invite(struct chanset_t *chan, char *nick, char *from,
00937 char *who, char *ch, struct userrec *u)
00938 {
00939 char s[UHOSTLEN];
00940
00941 simple_sprintf(s, "%s!%s", nick, from);
00942 newinvite(chan, who, s);
00943 check_tcl_mode(nick, from, u, chan->dname, "+I", who);
00944 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00945 return;
00946
00947 if (channel_pending(chan) || HALFOP_CANTDOMODE('I'))
00948 return;
00949
00950 if (!match_my_nick(nick)) {
00951 if (nick[0] && channel_nouserinvites(chan) && !glob_bot(user) &&
00952 !glob_master(user) && !chan_master(user)) {
00953 add_mode(chan, '-', 'I', who);
00954 return;
00955 }
00956 if ((!nick[0]) && (bounce_modes))
00957 reversing = 1;
00958 }
00959 if (reversing || (bounce_invites && (!nick[0]) &&
00960 (!u_equals_mask(global_invites, who) ||
00961 !u_equals_mask(chan->invites, who))))
00962 add_mode(chan, '-', 'I', who);
00963 }
00964
00965 static void got_uninvite(struct chanset_t *chan, char *nick, char *from,
00966 char *who, char *ch, struct userrec *u)
00967 {
00968 masklist *inv = chan->channel.invite, *old = NULL;
00969
00970 while (inv->mask[0] && rfc_casecmp(inv->mask, who)) {
00971 old = inv;
00972 inv = inv->next;
00973 }
00974 if (inv->mask[0]) {
00975 if (old)
00976 old->next = inv->next;
00977 else
00978 chan->channel.invite = inv->next;
00979 nfree(inv->mask);
00980 nfree(inv->who);
00981 nfree(inv);
00982 }
00983 check_tcl_mode(nick, from, u, chan->dname, "-I", who);
00984 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
00985 return;
00986
00987 if (channel_pending(chan))
00988 return;
00989
00990 if (u_sticky_mask(chan->invites, who) || u_sticky_mask(global_invites, who))
00991 add_mode(chan, '+', 'I', who);
00992 if (!nick[0] && glob_bot(user) && !glob_master(user) && !chan_master(user) &&
00993 (chan->channel.mode & CHANINV))
00994 add_mode(chan, '+', 'I', who);
00995 if ((u_equals_mask(global_invites, who) ||
00996 u_equals_mask(chan->invites, who)) && me_op(chan) &&
00997 !channel_dynamicinvites(chan) && (!glob_bot(user) ||
00998 !(bot_flags(u) & BOT_SHARE)))
00999 add_mode(chan, '+', 'I', who);
01000 }
01001
01002 static int gotmode(char *from, char *origmsg)
01003 {
01004 char *nick, *ch, *op, *chg, *msg;
01005 char s[UHOSTLEN], buf[511];
01006 char ms2[3];
01007 int z;
01008 struct userrec *u;
01009 memberlist *m;
01010 struct chanset_t *chan;
01011
01012 strncpy(buf, origmsg, 510);
01013 buf[510] = 0;
01014 msg = buf;
01015
01016 if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
01017 ch = newsplit(&msg);
01018 chg = newsplit(&msg);
01019 reversing = 0;
01020 chan = findchan(ch);
01021 if (!chan) {
01022 putlog(LOG_MISC, "*", CHAN_FORCEJOIN, ch);
01023 dprintf(DP_SERVER, "PART %s\n", ch);
01024 } else if (channel_active(chan) || channel_pending(chan)) {
01025 z = strlen(msg);
01026 if (msg[--z] == ' ')
01027 msg[z] = 0;
01028 putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg,
01029 msg, from);
01030 u = get_user_by_host(from);
01031 get_user_flagrec(u, &user, ch);
01032 nick = splitnick(&from);
01033 m = ismember(chan, nick);
01034 if (m)
01035 m->last = now;
01036 if (m && channel_active(chan) && (me_op(chan) || (me_halfop(chan) &&
01037 !chan_hasop(m))) && !(glob_friend(user) || chan_friend(user) ||
01038 (channel_dontkickops(chan) && (chan_op(user) || (glob_op(user) &&
01039 !chan_deop(user))))) && !match_my_nick(nick)) {
01040 if (chan_fakeop(m) || chan_fakehalfop(m)) {
01041 putlog(LOG_MODES, ch, CHAN_FAKEMODE, ch);
01042 dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_FAKEMODE_KICK);
01043 m->flags |= SENTKICK;
01044 reversing = 1;
01045 } else if (!chan_hasop(m) && !chan_hashalfop(m) &&
01046 !channel_nodesynch(chan)) {
01047 putlog(LOG_MODES, ch, CHAN_DESYNCMODE, ch);
01048 dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_DESYNCMODE_KICK);
01049 m->flags |= SENTKICK;
01050 reversing = 1;
01051 }
01052 }
01053 ms2[0] = '+';
01054 ms2[2] = 0;
01055 while ((ms2[1] = *chg)) {
01056 int todo = 0;
01057
01058 switch (*chg) {
01059 case '+':
01060 ms2[0] = '+';
01061 break;
01062 case '-':
01063 ms2[0] = '-';
01064 break;
01065 case 'i':
01066 todo = CHANINV;
01067 if (!nick[0] && bounce_modes)
01068 reversing = 1;
01069 break;
01070 case 'p':
01071 todo = CHANPRIV;
01072 if (!nick[0] && bounce_modes)
01073 reversing = 1;
01074 break;
01075 case 's':
01076 todo = CHANSEC;
01077 if (!nick[0] && bounce_modes)
01078 reversing = 1;
01079 break;
01080 case 'm':
01081 todo = CHANMODER;
01082 if (!nick[0] && bounce_modes)
01083 reversing = 1;
01084 break;
01085 case 'c':
01086 todo = CHANNOCLR;
01087 if (!nick[0] && bounce_modes)
01088 reversing = 1;
01089 break;
01090 case 'C':
01091 todo = CHANNOCTCP;
01092 if (!nick[0] && bounce_modes)
01093 reversing = 1;
01094 break;
01095 case 'R':
01096 todo = CHANREGON;
01097 if (!nick[0] && bounce_modes)
01098 reversing = 1;
01099 break;
01100 case 'M':
01101 todo = CHANMODREG;
01102 if (!nick[0] && bounce_modes)
01103 reversing = 1;
01104 break;
01105 case 'r':
01106 todo = CHANLONLY;
01107 if (!nick[0] && bounce_modes)
01108 reversing = 1;
01109 break;
01110 case 'D':
01111 todo = CHANDELJN;
01112 if (!nick[0] && bounce_modes)
01113 reversing = 1;
01114 break;
01115 case 'u':
01116 todo = CHANSTRIP;
01117 if (!nick[0] && bounce_modes)
01118 reversing = 1;
01119 break;
01120 case 'N':
01121 todo = CHANNONOTC;
01122 if (!nick[0] && bounce_modes)
01123 reversing = 1;
01124 break;
01125 case 'T':
01126 todo = CHANNOAMSG;
01127 if (!nick[0] && bounce_modes)
01128 reversing = 1;
01129 break;
01130 case 'd':
01131 todo = CHANINVIS;
01132 break;
01133 case 't':
01134 todo = CHANTOPIC;
01135 if (!nick[0] && bounce_modes)
01136 reversing = 1;
01137 break;
01138 case 'n':
01139 todo = CHANNOMSG;
01140 if (!nick[0] && bounce_modes)
01141 reversing = 1;
01142 break;
01143 case 'a':
01144 todo = CHANANON;
01145 if (!nick[0] && bounce_modes)
01146 reversing = 1;
01147 break;
01148 case 'q':
01149 todo = CHANQUIET;
01150 if (!nick[0] && bounce_modes)
01151 reversing = 1;
01152 break;
01153 case 'l':
01154 if (!nick[0] && bounce_modes)
01155 reversing = 1;
01156 if (ms2[0] == '-') {
01157 check_tcl_mode(nick, from, u, chan->dname, ms2, "");
01158
01159 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
01160 return 0;
01161 if (channel_active(chan)) {
01162 if (reversing && (chan->channel.maxmembers != 0)) {
01163 simple_sprintf(s, "%d", chan->channel.maxmembers);
01164 add_mode(chan, '+', 'l', s);
01165 } else if ((chan->limit_prot != 0) && !glob_master(user) &&
01166 !chan_master(user) && !match_my_nick(nick)) {
01167 simple_sprintf(s, "%d", chan->limit_prot);
01168 add_mode(chan, '+', 'l', s);
01169 }
01170 }
01171 chan->channel.maxmembers = 0;
01172 } else {
01173 op = newsplit(&msg);
01174 fixcolon(op);
01175 if (op == '\0')
01176 break;
01177 chan->channel.maxmembers = atoi(op);
01178 check_tcl_mode(nick, from, u, chan->dname, ms2,
01179 int_to_base10(chan->channel.maxmembers));
01180
01181 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
01182 return 0;
01183 if (channel_pending(chan))
01184 break;
01185 if ((reversing && !(chan->mode_pls_prot & CHANLIMIT)) ||
01186 ((chan->mode_mns_prot & CHANLIMIT) && !glob_master(user) &&
01187 !chan_master(user)))
01188 add_mode(chan, '-', 'l', "");
01189 if ((chan->limit_prot != chan->channel.maxmembers) &&
01190 (chan->mode_pls_prot & CHANLIMIT) && (chan->limit_prot != 0) &&
01191 !glob_master(user) && !chan_master(user)) {
01192 simple_sprintf(s, "%d", chan->limit_prot);
01193 add_mode(chan, '+', 'l', s);
01194 }
01195 }
01196 break;
01197 case 'k':
01198 if (ms2[0] == '+')
01199 chan->channel.mode |= CHANKEY;
01200 else
01201 chan->channel.mode &= ~CHANKEY;
01202 op = newsplit(&msg);
01203 fixcolon(op);
01204 if (op == '\0') {
01205 break;
01206 }
01207 check_tcl_mode(nick, from, u, chan->dname, ms2, op);
01208
01209 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
01210 return 0;
01211 if (ms2[0] == '+') {
01212 set_key(chan, op);
01213 if (channel_active(chan))
01214 got_key(chan, nick, from, op);
01215 } else {
01216 if (channel_active(chan)) {
01217 if (reversing && chan->channel.key[0])
01218 add_mode(chan, '+', 'k', chan->channel.key);
01219 else if (chan->key_prot[0] && !glob_master(user) &&
01220 !chan_master(user) && !match_my_nick(nick))
01221 add_mode(chan, '+', 'k', chan->key_prot);
01222 }
01223 set_key(chan, NULL);
01224 }
01225 break;
01226 case 'o':
01227 op = newsplit(&msg);
01228 fixcolon(op);
01229 if (ms2[0] == '+')
01230 got_op(chan, nick, from, op, u, &user);
01231 else
01232 got_deop(chan, nick, from, op, u);
01233 break;
01234 case 'h':
01235 op = newsplit(&msg);
01236 fixcolon(op);
01237 if (ms2[0] == '+')
01238 got_halfop(chan, nick, from, op, u, &user);
01239 else
01240 got_dehalfop(chan, nick, from, op, u);
01241 break;
01242 case 'v':
01243 op = newsplit(&msg);
01244 fixcolon(op);
01245 m = ismember(chan, op);
01246 if (!m) {
01247 if (channel_pending(chan))
01248 break;
01249 putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, op);
01250 chan->status |= CHAN_PEND;
01251 refresh_who_chan(chan->name);
01252 } else {
01253 simple_sprintf(s, "%s!%s", m->nick, m->userhost);
01254 get_user_flagrec(m->user ? m->user : get_user_by_host(s),
01255 &victim, chan->dname);
01256 if (ms2[0] == '+') {
01257 m->flags &= ~SENTVOICE;
01258 m->flags |= CHANVOICE;
01259 check_tcl_mode(nick, from, u, chan->dname, ms2, op);
01260 if (!(chan = modebind_refresh(ch, from, &user, s, &victim)))
01261 return 0;
01262 if (channel_active(chan) && !glob_master(user) &&
01263 !chan_master(user) && !match_my_nick(nick)) {
01264 if (chan_quiet(victim) ||
01265 (glob_quiet(victim) && !chan_voice(victim)))
01266 add_mode(chan, '-', 'v', op);
01267 else if (reversing)
01268 add_mode(chan, '-', 'v', op);
01269 }
01270 } else {
01271 m->flags &= ~SENTDEVOICE;
01272 m->flags &= ~CHANVOICE;
01273 check_tcl_mode(nick, from, u, chan->dname, ms2, op);
01274 if (!(chan = modebind_refresh(ch, from, &user, s, &victim)))
01275 return 0;
01276 if (channel_active(chan) && !glob_master(user) &&
01277 !chan_master(user) && !match_my_nick(nick)) {
01278 if ((channel_autovoice(chan) && !chan_quiet(victim) &&
01279 (chan_voice(victim) || glob_voice(victim))) ||
01280 (!chan_quiet(victim) && (glob_gvoice(victim) ||
01281 chan_gvoice(victim))))
01282 add_mode(chan, '+', 'v', op);
01283 else if (reversing)
01284 add_mode(chan, '+', 'v', op);
01285 }
01286 }
01287 }
01288 break;
01289 case 'b':
01290 op = newsplit(&msg);
01291 fixcolon(op);
01292 if (ms2[0] == '+')
01293 got_ban(chan, nick, from, op, ch, u);
01294 else
01295 got_unban(chan, nick, from, op, ch, u);
01296 break;
01297 case 'e':
01298 op = newsplit(&msg);
01299 fixcolon(op);
01300 if (ms2[0] == '+')
01301 got_exempt(chan, nick, from, op, ch, u);
01302 else
01303 got_unexempt(chan, nick, from, op, ch, u);
01304 break;
01305 case 'I':
01306 op = newsplit(&msg);
01307 fixcolon(op);
01308 if (ms2[0] == '+')
01309 got_invite(chan, nick, from, op, ch, u);
01310 else
01311 got_uninvite(chan, nick, from, op, ch, u);
01312 break;
01313 }
01314 if (todo) {
01315 check_tcl_mode(nick, from, u, chan->dname, ms2, "");
01316 if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL)))
01317 return 0;
01318 if (ms2[0] == '+')
01319 chan->channel.mode |= todo;
01320 else
01321 chan->channel.mode &= ~todo;
01322 if (channel_active(chan)) {
01323 if ((((ms2[0] == '+') && (chan->mode_mns_prot & todo)) ||
01324 ((ms2[0] == '-') && (chan->mode_pls_prot & todo))) &&
01325 !glob_master(user) && !chan_master(user) &&
01326 !match_my_nick(nick))
01327 add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
01328 else if (reversing && ((ms2[0] == '+') ||
01329 (chan->mode_pls_prot & todo)) && ((ms2[0] == '-') ||
01330 (chan->mode_mns_prot & todo)))
01331 add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
01332 }
01333 }
01334 chg++;
01335 }
01336 if (!me_op(chan) && !nick[0])
01337 chan->status |= CHAN_ASKEDMODES;
01338 }
01339 }
01340 return 0;
01341 }