mode.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377
  1. #ifdef LEAF
  2. /*
  3. * mode.c -- part of irc.mod
  4. * queuing and flushing mode changes made by the bot
  5. * channel mode changes and the bot's reaction to them
  6. * setting and getting the current wanted channel modes
  7. *
  8. */
  9. /* Reversing this mode? */
  10. static int reversing = 0;
  11. #define PLUS BIT0
  12. #define MINUS BIT1
  13. #define CHOP BIT2
  14. #define BAN BIT3
  15. #define VOICE BIT4
  16. #define EXEMPT BIT5
  17. #define INVITE BIT6
  18. static struct flag_record user = {FR_GLOBAL | FR_CHAN, 0, 0};
  19. static struct flag_record victim = {FR_GLOBAL | FR_CHAN, 0, 0};
  20. static int do_op(char *nick, struct chanset_t *chan, int delay, int force)
  21. {
  22. memberlist *m = ismember(chan, nick);
  23. if (!me_op(chan) || !m || (m && !force && chan_hasop(m)))
  24. return 0;
  25. if (channel_fastop(chan) || channel_take(chan)) {
  26. add_mode(chan, '+', 'o', nick);
  27. } else {
  28. char *tmp = NULL;
  29. tmp = calloc(1, strlen(chan->name) + 200);
  30. makeopline(chan, nick, tmp);
  31. dprintf(DP_MODE, tmp);
  32. free(tmp);
  33. }
  34. return 1;
  35. }
  36. static void flush_mode(struct chanset_t *chan, int pri)
  37. {
  38. char *p = NULL, out[512] = "", post[512] = "";
  39. size_t postsize = sizeof(post);
  40. int plus = 2; /* 0 = '-', 1 = '+', 2 = none */
  41. unsigned int i = 0;
  42. /* dequeue_op_deop(chan); */
  43. p = out;
  44. post[0] = 0, postsize--;
  45. /* now does +o first.. */
  46. if (chan->mns[0]) {
  47. *p++ = '-', plus = 0;
  48. for (i = 0; i < strlen(chan->mns); i++)
  49. *p++ = chan->mns[i];
  50. chan->mns[0] = 0;
  51. }
  52. if (chan->pls[0]) {
  53. *p++ = '+', plus = 1;
  54. for (i = 0; i < strlen(chan->pls); i++)
  55. *p++ = chan->pls[i];
  56. chan->pls[0] = 0;
  57. }
  58. chan->bytes = 0;
  59. chan->compat = 0;
  60. /* +k or +l ? */
  61. if (chan->key && !chan->rmkey) {
  62. if (plus != 1) {
  63. *p++ = '+', plus = 1;
  64. }
  65. *p++ = 'k';
  66. postsize -= egg_strcatn(post, chan->key, sizeof(post));
  67. postsize -= egg_strcatn(post, " ", sizeof(post));
  68. free(chan->key), chan->key = NULL;
  69. }
  70. /* max +l is signed 2^32 on IRCnet at least... so makesure we've got at least
  71. * a 13 char buffer for '-2147483647 \0'. We'll be overwriting the existing
  72. * terminating null in 'post', so makesure postsize >= 12.
  73. */
  74. if (chan->limit != 0 && postsize >= 12) {
  75. if (plus != 1) {
  76. *p++ = '+', plus = 1;
  77. }
  78. *p++ = 'l';
  79. /* 'sizeof(post) - 1' is used because we want to overwrite the old null */
  80. postsize -= sprintf(&post[(sizeof(post) - 1) - postsize], "%d ", chan->limit);
  81. chan->limit = 0;
  82. }
  83. /* -k ? */
  84. if (chan->rmkey) {
  85. if (plus) {
  86. *p++ = '-', plus = 0;
  87. }
  88. *p++ = 'k';
  89. postsize -= egg_strcatn(post, chan->rmkey, sizeof(post));
  90. postsize -= egg_strcatn(post, " ", sizeof(post));
  91. free(chan->rmkey), chan->rmkey = NULL;
  92. }
  93. /* Do -{b,e,I} before +{b,e,I} to avoid the server ignoring overlaps */
  94. for (i = 0; i < modesperline; i++) {
  95. if ((chan->cmode[i].type & MINUS) &&
  96. postsize > strlen(chan->cmode[i].op)) {
  97. if (plus) {
  98. *p++ = '-', plus = 0;
  99. }
  100. *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
  101. ((chan->cmode[i].type & CHOP) ? 'o' :
  102. ((chan->cmode[i].type & EXEMPT) ? 'e' :
  103. ((chan->cmode[i].type & INVITE) ? 'I' : 'v'))));
  104. postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
  105. postsize -= egg_strcatn(post, " ", sizeof(post));
  106. free(chan->cmode[i].op), chan->cmode[i].op = NULL;
  107. chan->cmode[i].type = 0;
  108. }
  109. }
  110. /* now do all the + modes... */
  111. for (i = 0; i < modesperline; i++) {
  112. if ((chan->cmode[i].type & PLUS) &&
  113. postsize > strlen(chan->cmode[i].op)) {
  114. if (plus != 1) {
  115. *p++ = '+', plus = 1;
  116. }
  117. *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
  118. ((chan->cmode[i].type & CHOP) ? 'o' :
  119. ((chan->cmode[i].type & EXEMPT) ? 'e' :
  120. ((chan->cmode[i].type & INVITE) ? 'I' : 'v'))));
  121. postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
  122. postsize -= egg_strcatn(post, " ", sizeof(post));
  123. free(chan->cmode[i].op), chan->cmode[i].op = NULL;
  124. chan->cmode[i].type = 0;
  125. }
  126. }
  127. /* remember to terminate the buffer ('out')... */
  128. *p = 0;
  129. if (post[0]) {
  130. /* remove the trailing space... */
  131. size_t myindex = (sizeof(post) - 1) - postsize;
  132. if (myindex > 0 && post[myindex - 1] == ' ')
  133. post[myindex - 1] = 0;
  134. egg_strcatn(out, " ", sizeof(out));
  135. egg_strcatn(out, post, sizeof(out));
  136. }
  137. if (out[0]) {
  138. if (pri == QUICK) {
  139. char outbuf[201] = "";
  140. sprintf(outbuf, "MODE %s %s\n", chan->name, out);
  141. tputs(serv, outbuf, strlen(outbuf));
  142. /* dprintf(DP_MODE, "MODE %s %s\n", chan->name, out); */
  143. }
  144. else
  145. dprintf(DP_SERVER, "MODE %s %s\n", chan->name, out);
  146. }
  147. }
  148. /* Queue a channel mode change
  149. */
  150. void add_mode(struct chanset_t *chan, const unsigned char plus, const unsigned char mode, const char *op)
  151. {
  152. int type, modes, l;
  153. unsigned int i;
  154. masklist *m = NULL;
  155. memberlist *mx = NULL;
  156. char s[21] = "";
  157. if (!me_op(chan))
  158. return;
  159. if (mode == 'o' || mode == 'v') {
  160. mx = ismember(chan, op);
  161. if (!mx)
  162. return;
  163. if (plus == '-' && mode == 'o') {
  164. if (chan_sentdeop(mx) || !chan_hasop(mx))
  165. return;
  166. mx->flags |= SENTDEOP;
  167. }
  168. if (plus == '+' && mode == 'o') {
  169. if (chan_sentop(mx) || chan_hasop(mx))
  170. return;
  171. mx->flags |= SENTOP;
  172. }
  173. if (plus == '-' && mode == 'v') {
  174. if (chan_sentdevoice(mx) || !chan_hasvoice(mx))
  175. return;
  176. mx->flags |= SENTDEVOICE;
  177. }
  178. if (plus == '+' && mode == 'v') {
  179. if (chan_sentvoice(mx) || chan_hasvoice(mx))
  180. return;
  181. mx->flags |= SENTVOICE;
  182. }
  183. }
  184. if (chan->compat == 0) {
  185. if (mode == 'e' || mode == 'I')
  186. chan->compat = 2;
  187. else
  188. chan->compat = 1;
  189. } else if (mode == 'e' || mode == 'I') {
  190. if (prevent_mixing && chan->compat == 1)
  191. flush_mode(chan, NORMAL);
  192. } else if (prevent_mixing && chan->compat == 2)
  193. flush_mode(chan, NORMAL);
  194. if (mode == 'o' || mode == 'b' || mode == 'v' || mode == 'e' || mode == 'I') {
  195. type = (plus == '+' ? PLUS : MINUS) |
  196. (mode == 'o' ? CHOP :
  197. (mode == 'b' ? BAN :
  198. (mode == 'v' ? VOICE :
  199. (mode == 'e' ? EXEMPT : INVITE))));
  200. /*
  201. * FIXME: Some networks remove overlapped bans,
  202. * IRCnet does not (poptix/drummer)
  203. *
  204. * Note: On IRCnet ischanXXX() should be used, otherwise isXXXed().
  205. */
  206. if ((plus == '-' && ((mode == 'b' && !ischanban(chan, op)) ||
  207. (mode == 'e' && !ischanexempt(chan, op)) ||
  208. (mode == 'I' && !ischaninvite(chan, op)))) || (plus == '+' &&
  209. ((mode == 'b' && ischanban(chan, op)) ||
  210. (mode == 'e' && ischanexempt(chan, op)) ||
  211. (mode == 'I' && ischaninvite(chan, op)))))
  212. return;
  213. /* If there are already max_bans bans, max_exempts exemptions,
  214. * max_invites invitations or max_modes +b/+e/+I modes on the
  215. * channel, don't try to add one more.
  216. */
  217. if (plus == '+' && (mode == 'b' || mode == 'e' || mode == 'I')) {
  218. int bans = 0, exempts = 0, invites = 0;
  219. for (m = chan->channel.ban; m && m->mask[0]; m = m->next)
  220. bans++;
  221. if ((mode == 'b') && (bans >= max_bans))
  222. return;
  223. for (m = chan->channel.exempt; m && m->mask[0]; m = m->next)
  224. exempts++;
  225. if ((mode == 'e') && (exempts >= max_exempts))
  226. return;
  227. for (m = chan->channel.invite; m && m->mask[0]; m = m->next)
  228. invites++;
  229. if ((mode == 'I') && (invites >= max_invites))
  230. return;
  231. if (bans + exempts + invites >= max_modes)
  232. return;
  233. }
  234. /* op-type mode change */
  235. for (i = 0; i < modesperline; i++)
  236. if (chan->cmode[i].type == type && chan->cmode[i].op != NULL &&
  237. !rfc_casecmp(chan->cmode[i].op, op))
  238. return; /* Already in there :- duplicate */
  239. l = strlen(op) + 1;
  240. if (chan->bytes + l > mode_buf_len)
  241. flush_mode(chan, NORMAL);
  242. for (i = 0; i < modesperline; i++)
  243. if (chan->cmode[i].type == 0) {
  244. chan->cmode[i].type = type;
  245. chan->cmode[i].op = (char *) calloc(1, l);
  246. chan->bytes += l; /* Add 1 for safety */
  247. strcpy(chan->cmode[i].op, op);
  248. break;
  249. }
  250. }
  251. /* +k ? store key */
  252. else if (plus == '+' && mode == 'k') {
  253. if (chan->key)
  254. free(chan->key);
  255. chan->key = (char *) calloc(1, strlen(op) + 1);
  256. strcpy(chan->key, op);
  257. }
  258. /* -k ? store removed key */
  259. else if (plus == '-' && mode == 'k') {
  260. if (chan->rmkey)
  261. free(chan->rmkey);
  262. chan->rmkey = (char *) calloc(1, strlen(op) + 1);
  263. strcpy(chan->rmkey, op);
  264. }
  265. /* +l ? store limit */
  266. else if (plus == '+' && mode == 'l')
  267. chan->limit = atoi(op);
  268. else {
  269. /* Typical mode changes */
  270. if (plus == '+')
  271. strcpy(s, chan->pls);
  272. else
  273. strcpy(s, chan->mns);
  274. if (!strchr(s, mode)) {
  275. if (plus == '+') {
  276. chan->pls[strlen(chan->pls) + 1] = 0;
  277. chan->pls[strlen(chan->pls)] = mode;
  278. } else {
  279. chan->mns[strlen(chan->mns) + 1] = 0;
  280. chan->mns[strlen(chan->mns)] = mode;
  281. }
  282. }
  283. }
  284. modes = modesperline; /* Check for full buffer. */
  285. for (i = 0; i < modesperline; i++)
  286. if (chan->cmode[i].type)
  287. modes--;
  288. if (include_lk && chan->limit)
  289. modes--;
  290. if (include_lk && chan->rmkey)
  291. modes--;
  292. if (include_lk && chan->key)
  293. modes--;
  294. if (modes < 1)
  295. flush_mode(chan, NORMAL); /* Full buffer! Flush modes. */
  296. }
  297. /*
  298. * Mode parsing functions
  299. */
  300. static void got_key(struct chanset_t *chan, char *nick, char *from,
  301. char *key)
  302. {
  303. if ((!nick[0]) && (bounce_modes))
  304. reversing = 1;
  305. if (((reversing) && !(chan->key_prot[0])) ||
  306. ((chan->mode_mns_prot & CHANKEY) &&
  307. !(glob_master(user) || glob_bot(user) || chan_master(user)))) {
  308. if (strlen(key) != 0) {
  309. add_mode(chan, '-', 'k', key);
  310. } else {
  311. add_mode(chan, '-', 'k', "");
  312. }
  313. }
  314. }
  315. static void got_op(struct chanset_t *chan, char *nick, char *from,
  316. char *who, struct userrec *opu, struct flag_record *opper)
  317. {
  318. memberlist *m = NULL;
  319. char s[UHOSTLEN] = "";
  320. struct userrec *u;
  321. int check_chan = 0;
  322. int snm = chan->stopnethack_mode;
  323. m = ismember(chan, who);
  324. if (!m) {
  325. if (channel_pending(chan))
  326. return;
  327. putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
  328. dprintf(DP_MODE, "WHO %s\n", who);
  329. return;
  330. }
  331. /* Did *I* just get opped? */
  332. if (!me_op(chan) && match_my_nick(who)) {
  333. /* take asap. */
  334. if (channel_take(chan))
  335. do_take(chan);
  336. else
  337. check_chan = 1;
  338. }
  339. if (!m->user) {
  340. simple_sprintf(s, "%s!%s", m->nick, m->userhost);
  341. u = get_user_by_host(s);
  342. } else
  343. u = m->user;
  344. get_user_flagrec(u, &victim, chan->dname);
  345. /* Flags need to be set correctly right from the beginning now, so that
  346. * add_mode() doesn't get irritated.
  347. */
  348. m->flags |= CHANOP;
  349. /* Added new meaning of WASOP:
  350. * in mode binds it means: was he op before get (de)opped
  351. * (stupid IrcNet allows opped users to be opped again and
  352. * opless users to be deopped)
  353. * script now can use [wasop nick chan] proc to check
  354. * if user was op or wasnt (drummer)
  355. */
  356. m->flags &= ~SENTOP;
  357. if (channel_pending(chan))
  358. return;
  359. /* I'm opped, and the opper isn't me */
  360. if (me_op(chan) && !match_my_nick(who) &&
  361. /* and it isn't a server op */
  362. nick[0]) {
  363. /* Channis is +bitch, and the opper isn't a global master or a bot */
  364. /* deop if they are +d or it is +bitch */
  365. if ( chk_deop(victim, chan) ||
  366. (!loading && userlist && channel_bitch(chan) && !chk_op(victim, chan)) ) { /* chk_op covers +private */
  367. /* char outbuf[101] = ""; */
  368. /* if (target_priority(chan, m, 1)) */
  369. /* dprintf(DP_MODE, "MODE %s -o %s\n", chan->name, who); */
  370. add_mode(chan, '-', 'o', who);
  371. flush_mode(chan, QUICK);
  372. /* sprintf(outbuf, "MODE %s -o %s\n", chan->name, who);
  373. tputs(serv, outbuf, strlen(outbuf));
  374. */
  375. } else if (reversing) {
  376. add_mode(chan, '-', 'o', who);
  377. }
  378. } else if (reversing && !match_my_nick(who))
  379. add_mode(chan, '-', 'o', who);
  380. if (!nick[0] && me_op(chan) && !match_my_nick(who)) {
  381. if (chk_deop(victim, chan)) {
  382. m->flags |= FAKEOP;
  383. add_mode(chan, '-', 'o', who);
  384. } else if (snm > 0 && snm < 7 && !((0 || 0 ||
  385. 0) && (chan_op(victim) || (glob_op(victim) &&
  386. !chan_deop(victim)))) && !glob_exempt(victim) && !chan_exempt(victim)) {
  387. if (snm == 5) snm = channel_bitch(chan) ? 1 : 3;
  388. if (snm == 6) snm = channel_bitch(chan) ? 4 : 2;
  389. if (chan_wasoptest(victim) || glob_wasoptest(victim) ||
  390. snm == 2) {
  391. if (!chan_wasop(m)) {
  392. m->flags |= FAKEOP;
  393. add_mode(chan, '-', 'o', who);
  394. }
  395. } else if (!(chan_op(victim) ||
  396. (glob_op(victim) && !chan_deop(victim)))) {
  397. if (snm == 1 || snm == 4 || (snm == 3 && !chan_wasop(m))) {
  398. add_mode(chan, '-', 'o', who);
  399. m->flags |= FAKEOP;
  400. }
  401. } else if (snm == 4 && !chan_wasop(m)) {
  402. add_mode(chan, '-', 'o', who);
  403. m->flags |= FAKEOP;
  404. }
  405. }
  406. }
  407. m->flags |= WASOP;
  408. if (check_chan) {
  409. /* tell other bots to set jointime to 0 and join */
  410. char *buf = NULL;
  411. buf = calloc(1, strlen(chan->dname) + 3 + 1);
  412. sprintf(buf, "jn %s", chan->dname);
  413. putallbots(buf);
  414. free(buf);
  415. recheck_channel(chan, 1);
  416. }
  417. }
  418. static void got_deop(struct chanset_t *chan, char *nick, char *from,
  419. char *who, struct userrec *opu)
  420. {
  421. memberlist *m = NULL;
  422. char s[UHOSTLEN] = "", s1[UHOSTLEN] = "";
  423. struct userrec *u = NULL;
  424. m = ismember(chan, who);
  425. if (!m) {
  426. if (channel_pending(chan))
  427. return;
  428. putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who);
  429. dprintf(DP_MODE, "WHO %s\n", who);
  430. return;
  431. }
  432. simple_sprintf(s, "%s!%s", m->nick, m->userhost);
  433. simple_sprintf(s1, "%s!%s", nick, from);
  434. u = get_user_by_host(s);
  435. get_user_flagrec(u, &victim, chan->dname);
  436. /* Flags need to be set correctly right from the beginning now, so that
  437. * add_mode() doesn't get irritated.
  438. */
  439. m->flags &= ~(CHANOP | SENTDEOP | FAKEOP);
  440. /* Check comments in got_op() (drummer) */
  441. m->flags &= ~WASOP;
  442. if (channel_pending(chan))
  443. return;
  444. /* Deop'd someone on my oplist? */
  445. if (me_op(chan)) {
  446. int ok = 1;
  447. /* if they aren't d|d then check if they are something we should protect */
  448. if (!glob_deop(victim) && !chan_deop(victim)) {
  449. if (channel_protectops(chan) && (glob_master(victim) || chan_master(victim) ||
  450. glob_op(victim) || chan_op(victim)))
  451. ok = 0;
  452. }
  453. /* do we want to reop victim? */
  454. if ((reversing || !ok) && !match_my_nick(nick) &&
  455. rfc_casecmp(who, nick) && !match_my_nick(who) &&
  456. /* Is the deopper NOT a master or bot? */
  457. !glob_master(user) && !chan_master(user) && !glob_bot(user) &&
  458. ((chan_op(victim) || (glob_op(victim) && !chan_deop(victim))) ||
  459. !channel_bitch(chan)))
  460. /* Then we'll bless the victim */
  461. do_op(who, chan, 0, 0);
  462. }
  463. if (!nick[0])
  464. putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s",
  465. chan->dname, who, from);
  466. /* Check for mass deop */
  467. if (nick[0])
  468. detect_chan_flood(nick, from, s1, chan, FLOOD_DEOP, who);
  469. /* Having op hides your +v and +h status -- so now that someone's lost ops,
  470. * check to see if they have +v or +h
  471. */
  472. if (!channel_take(chan) && !channel_bitch(chan) && !(m->flags & (CHANVOICE | STOPWHO))) {
  473. dprintf(DP_HELP, "WHO %s\n", m->nick);
  474. m->flags |= STOPWHO;
  475. }
  476. /* Was the bot deopped? */
  477. if (match_my_nick(who)) {
  478. /* Cancel any pending kicks and modes */
  479. memberlist *m2;
  480. for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
  481. m2->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTVOICE | SENTDEVOICE);
  482. chan->channel.do_opreq=1;
  483. /* request_op(chan); */
  484. /* need: op */
  485. if (!nick[0])
  486. putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(",
  487. chan->dname);
  488. }
  489. if (nick[0])
  490. maybe_revenge(chan, s1, s, REVENGE_DEOP);
  491. }
  492. static void got_ban(struct chanset_t *chan, char *nick, char *from, char *who)
  493. {
  494. char me[UHOSTLEN] = "", s[UHOSTLEN] = "", s1[UHOSTLEN] = "";
  495. memberlist *m = NULL;
  496. struct userrec *u = NULL;
  497. egg_snprintf(me, sizeof me, "%s!%s", botname, botuserhost);
  498. egg_snprintf(s, sizeof s, "%s!%s", nick, from);
  499. newban(chan, who, s);
  500. if (channel_pending(chan) || !me_op(chan))
  501. return;
  502. if (wild_match(who, me) && !isexempted(chan, me)) {
  503. add_mode(chan, '-', 'b', who);
  504. reversing = 1;
  505. return;
  506. }
  507. if (!match_my_nick(nick)) {
  508. if (channel_nouserbans(chan) && nick[0] && !glob_bot(user) &&
  509. !glob_master(user) && !chan_master(user)) {
  510. add_mode(chan, '-', 'b', who);
  511. return;
  512. }
  513. /* remove bans on ops unless a master/bot set it */
  514. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  515. egg_snprintf(s1, sizeof s1, "%s!%s", m->nick, m->userhost);
  516. if (wild_match(who, s1)) {
  517. u = get_user_by_host(s1);
  518. if (u) {
  519. get_user_flagrec(u, &victim, chan->dname);
  520. if (chk_op(victim, chan) && !chan_master(user) && !glob_master(user) &&
  521. !glob_bot(user) && !isexempted(chan, s1)) {
  522. /* if (target_priority(chan, m, 0)) */
  523. add_mode(chan, '-', 'b', who);
  524. return;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. refresh_exempt(chan, who);
  531. /* This looks for bans added through bot and tacks on banned: if a description is found */
  532. if (nick[0] && channel_enforcebans(chan)) {
  533. register maskrec *b;
  534. int cycle;
  535. char resn[512]="";
  536. /* The point of this cycle crap is to first check chan->bans then global_bans */
  537. for (cycle = 0; cycle < 2; cycle++) {
  538. for (b = cycle ? chan->bans : global_bans; b; b = b->next) {
  539. if (wild_match(b->mask, who)) {
  540. if (b->desc && b->desc[0] != '@')
  541. egg_snprintf(resn, sizeof resn, "%s %s", IRC_PREBANNED, b->desc);
  542. else
  543. resn[0] = 0;
  544. }
  545. }
  546. }
  547. kick_all(chan, who, resn[0] ? resn : kickreason(KICK_BANNED), match_my_nick(nick) ? 0 : 1);
  548. }
  549. if (!nick[0] && (bounce_bans || bounce_modes) &&
  550. (!u_equals_mask(global_bans, who) || !u_equals_mask(chan->bans, who)))
  551. add_mode(chan, '-', 'b', who);
  552. }
  553. static void got_unban(struct chanset_t *chan, char *nick, char *from,
  554. char *who, struct userrec *u)
  555. {
  556. masklist *b = NULL, *old = NULL;
  557. for (b = chan->channel.ban; b->mask[0] && rfc_casecmp(b->mask, who);
  558. old = b, b = b->next)
  559. ;
  560. if (b->mask[0]) {
  561. if (old)
  562. old->next = b->next;
  563. else
  564. chan->channel.ban = b->next;
  565. free(b->mask);
  566. free(b->who);
  567. free(b);
  568. }
  569. if (channel_pending(chan))
  570. return;
  571. if (u_sticky_mask(chan->bans, who) || u_sticky_mask(global_bans, who)) {
  572. /* That's a sticky ban! No point in being
  573. * sticky unless we enforce it!!
  574. */
  575. add_mode(chan, '+', 'b', who);
  576. }
  577. if ((u_equals_mask(global_bans, who) || u_equals_mask(chan->bans, who)) &&
  578. me_op(chan) && !channel_dynamicbans(chan)) {
  579. /* That's a permban! */
  580. if (!glob_bot(user) && !chk_op(user, chan))
  581. add_mode(chan, '+', 'b', who);
  582. }
  583. }
  584. static void got_exempt(struct chanset_t *chan, char *nick, char *from,
  585. char *who)
  586. {
  587. char s[UHOSTLEN] = "";
  588. simple_sprintf(s, "%s!%s", nick, from);
  589. newexempt(chan, who, s);
  590. if (channel_pending(chan))
  591. return;
  592. if (!match_my_nick(nick)) { /* It's not my exemption */
  593. if (channel_nouserexempts(chan) && nick[0] && !glob_bot(user) &&
  594. !glob_master(user) && !chan_master(user)) {
  595. /* No exempts made by users */
  596. add_mode(chan, '-', 'e', who);
  597. return;
  598. }
  599. if (!nick[0] && bounce_modes)
  600. reversing = 1;
  601. }
  602. if (reversing || (bounce_exempts && !nick[0] &&
  603. (!u_equals_mask(global_exempts, who) ||
  604. !u_equals_mask(chan->exempts, who))))
  605. add_mode(chan, '-', 'e', who);
  606. }
  607. static void got_unexempt(struct chanset_t *chan, char *nick, char *from,
  608. char *who, struct userrec *u)
  609. {
  610. masklist *e = chan->channel.exempt, *old = NULL;
  611. masklist *b = NULL;
  612. int match = 0;
  613. while (e && e->mask[0] && rfc_casecmp(e->mask, who)) {
  614. old = e;
  615. e = e->next;
  616. }
  617. if (e && e->mask[0]) {
  618. if (old)
  619. old->next = e->next;
  620. else
  621. chan->channel.exempt = e->next;
  622. free(e->mask);
  623. free(e->who);
  624. free(e);
  625. }
  626. if (channel_pending(chan))
  627. return;
  628. if (u_sticky_mask(chan->exempts, who) || u_sticky_mask(global_exempts, who)) {
  629. /* That's a sticky exempt! No point in being sticky unless we enforce it!!
  630. */
  631. add_mode(chan, '+', 'e', who);
  632. }
  633. /* If exempt was removed by master then leave it else check for bans */
  634. if (!nick[0] && glob_bot(user) && !glob_master(user) && !chan_master(user)) {
  635. b = chan->channel.ban;
  636. while (b->mask[0] && !match) {
  637. if (wild_match(b->mask, who) ||
  638. wild_match(who, b->mask)) {
  639. add_mode(chan, '+', 'e', who);
  640. match = 1;
  641. } else
  642. b = b->next;
  643. }
  644. }
  645. if ((u_equals_mask(global_exempts, who) || u_equals_mask(chan->exempts, who)) &&
  646. me_op(chan) && !channel_dynamicexempts(chan) && !glob_bot(user))
  647. add_mode(chan, '+', 'e', who);
  648. }
  649. static void got_invite(struct chanset_t *chan, char *nick, char *from,
  650. char *who)
  651. {
  652. char s[UHOSTLEN] = "";
  653. simple_sprintf(s, "%s!%s", nick, from);
  654. newinvite(chan, who, s);
  655. if (channel_pending(chan))
  656. return;
  657. if (!match_my_nick(nick)) { /* It's not my invitation */
  658. if (channel_nouserinvites(chan) && nick[0] && !glob_bot(user) &&
  659. !glob_master(user) && !chan_master(user)) {
  660. /* No exempts made by users */
  661. add_mode(chan, '-', 'I', who);
  662. return;
  663. }
  664. if ((!nick[0]) && (bounce_modes))
  665. reversing = 1;
  666. }
  667. if (reversing || (bounce_invites && (!nick[0]) &&
  668. (!u_equals_mask(global_invites, who) ||
  669. !u_equals_mask(chan->invites, who))))
  670. add_mode(chan, '-', 'I', who);
  671. }
  672. static void got_uninvite(struct chanset_t *chan, char *nick, char *from,
  673. char *who, struct userrec *u)
  674. {
  675. masklist *inv = chan->channel.invite, *old = NULL;
  676. while (inv->mask[0] && rfc_casecmp(inv->mask, who)) {
  677. old = inv;
  678. inv = inv->next;
  679. }
  680. if (inv->mask[0]) {
  681. if (old)
  682. old->next = inv->next;
  683. else
  684. chan->channel.invite = inv->next;
  685. free(inv->mask);
  686. free(inv->who);
  687. free(inv);
  688. }
  689. if (channel_pending(chan))
  690. return;
  691. if (u_sticky_mask(chan->invites, who) || u_sticky_mask(global_invites, who)) {
  692. /* That's a sticky invite! No point in being sticky unless we enforce it!!
  693. */
  694. add_mode(chan, '+', 'I', who);
  695. }
  696. if (!nick[0] && glob_bot(user) && !glob_master(user) && !chan_master(user)
  697. && (chan->channel.mode & CHANINV))
  698. add_mode(chan, '+', 'I', who);
  699. if ((u_equals_mask(global_invites, who) ||
  700. u_equals_mask(chan->invites, who)) && me_op(chan) &&
  701. !channel_dynamicinvites(chan) && !glob_bot(user))
  702. add_mode(chan, '+', 'I', who);
  703. }
  704. static int gotmode(char *from, char *msg)
  705. {
  706. char *nick = NULL, *ch = NULL, *op = NULL, *chg = NULL, s[UHOSTLEN] = "", ms2[3] = "";
  707. int z;
  708. struct userrec *u = NULL;
  709. memberlist *m = NULL;
  710. struct chanset_t *chan = NULL;
  711. /* Usermode changes? */
  712. if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
  713. ch = newsplit(&msg);
  714. if (match_my_nick(ch))
  715. return 0;
  716. chan = findchan(ch);
  717. if (!chan) {
  718. putlog(LOG_MISC, "*", CHAN_FORCEJOIN, ch);
  719. dprintf(DP_SERVER, "PART %s\n", ch);
  720. return 0;
  721. }
  722. /* let's pre-emptively check for mass op/deop, manual ops and cookieops */
  723. if (strchr(from, '!')) {
  724. char *modes[5] = { NULL, NULL, NULL, NULL, NULL };
  725. char tmp[1024] = "", sign = '+', *nfrom = NULL, *hfrom = NULL, *wptr = NULL, *p = NULL, work[1024] = "";
  726. struct userrec *ufrom = NULL;
  727. int modecnt = 0, i = 0, n = 0, ops = 0, deops = 0, bans = 0, unbans = 0;
  728. /* Split up the mode: #chan modes param param param param */
  729. strncpyz(work, msg, sizeof(work));
  730. wptr = work;
  731. p = newsplit(&wptr);
  732. while (*p) {
  733. char *mp = NULL;
  734. if (*p == '+')
  735. sign = '+';
  736. else if (*p == '-')
  737. sign = '-';
  738. else if (strchr("oblkvIe", p[0])) {
  739. mp = newsplit(&wptr);
  740. if (strchr("ob", p[0])) {
  741. /* Just want o's and b's */
  742. modes[modecnt] = calloc(1, strlen(mp) + 4);
  743. sprintf(modes[modecnt], "%c%c %s", sign, p[0], mp);
  744. modecnt++;
  745. if (p[0] == 'o') {
  746. if (sign == '+')
  747. ops++;
  748. else
  749. deops++;
  750. }
  751. if (p[0] == 'b') {
  752. if (sign == '+')
  753. bans++;
  754. else
  755. unbans++;
  756. }
  757. }
  758. } else if (strchr("pstnmi", p[0])) {
  759. } else {
  760. /* hrmm... what modechar did i forget? */
  761. putlog(LOG_ERRORS, "*", "Forgotten modechar in irc:gotmode: %c", p[0]);
  762. }
  763. p++;
  764. }
  765. /* Split up from */
  766. ufrom = get_user_by_host(from);
  767. strncpyz(work, from, sizeof(work));
  768. p = strchr(work, '!');
  769. *p++ = 0;
  770. nfrom = work; /* nick */
  771. hfrom = p; /* host */
  772. /* Now we got modes[], chan, ufrom, nfrom, hfrom, and count of each relevant mode */
  773. /* check for mdop */
  774. if ((chan) && (deops >= 3) && me_op(chan)) {
  775. if ((!ufrom) || (!(ufrom->flags & USER_BOT))) {
  776. if (ROLE_KICK_MDOP) {
  777. m = ismember(chan, nfrom);
  778. if (m && !chan_sentkick(m)) {
  779. m->flags |= SENTKICK;
  780. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, nfrom, kickprefix, kickreason(KICK_MASSDEOP));
  781. tputs(serv, tmp, strlen(tmp));
  782. if (ufrom) {
  783. sprintf(tmp, "Mass deop on %s by %s", chan->dname, nfrom);
  784. deflag_user(ufrom, DEFLAG_MDOP, tmp, chan);
  785. }
  786. }
  787. }
  788. }
  789. }
  790. /* check for mop */
  791. if (chan && (ops >= 3) && me_op(chan)) {
  792. if (channel_nomop(chan)) {
  793. if ((!ufrom) || (!(ufrom->flags & USER_BOT))) {
  794. if (ROLE_KICK_MDOP) {
  795. m = ismember(chan, nfrom);
  796. if (m && !chan_sentkick(m)) {
  797. m->flags |= SENTKICK;
  798. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, nfrom, kickprefix, kickreason(KICK_MANUALOP));
  799. tputs(serv, tmp, strlen(tmp));
  800. if (ufrom) {
  801. sprintf(tmp, "Mass op on %s by %s", chan->dname, nfrom);
  802. deflag_user(ufrom, DEFLAG_MOP, tmp, chan);
  803. }
  804. }
  805. }
  806. }
  807. enforce_bitch(chan); /* deop quick! */
  808. }
  809. }
  810. if (chan && me_op(chan) && ops && (ufrom) && (ufrom->flags & USER_BOT) && !channel_fastop(chan) && !channel_take(chan)) {
  811. int isbadop = 0;
  812. if ((modecnt != 2) || (strncmp(modes[0], "+o", 2)) || (strncmp(modes[1], "-b", 2))) {
  813. isbadop = 1;
  814. } else {
  815. char enccookie[25] = "", plaincookie[25] = "", key[NICKLEN + 20] = "", goodcookie[25] = "";
  816. /* -b *!*@[...] */
  817. strncpyz(enccookie, (char *) &(modes[1][8]), sizeof(enccookie));
  818. p = enccookie + strlen(enccookie) - 1;
  819. strcpy(key, nfrom);
  820. strcat(key, SALT2);
  821. p = decrypt_string(key, enccookie);
  822. strncpyz(plaincookie, p, sizeof(plaincookie));
  823. free(p);
  824. /*
  825. * last 6 digits of time
  826. * last 5 chars of nick
  827. * last 5 regular chars of chan
  828. */
  829. makeplaincookie(chan->dname, (char *) (modes[0] + 3), goodcookie);
  830. if (strncmp((char *) &plaincookie[6], (char *) &goodcookie[6], 5))
  831. isbadop = 2;
  832. else if (strncmp((char *) &plaincookie[11], (char *) &goodcookie[11], 5))
  833. isbadop = 3;
  834. else {
  835. char ltmp[20] = "";
  836. time_t optime, off;
  837. /* this makes NO sense, optime should just be ltmp[4]-... but its not... ??? */
  838. sprintf(ltmp, "%010li", now + timesync);
  839. strncpyz((char *) &ltmp[4], plaincookie, 7);
  840. optime = atol(ltmp);
  841. off = (now + timesync - optime);
  842. if (abs(off) > OP_TIME_SLACK) {
  843. /* isbadop = 4; */
  844. putlog(LOG_DEBUG, "*", "%s opped with bad ts (not punishing.): %li was off by %li", nfrom, optime, off);
  845. }
  846. }
  847. }
  848. if (isbadop) {
  849. char trg[NICKLEN] = "";
  850. putlog(LOG_DEBUG, "*", "%s opped in %s with bad cookie(%d): %s", nfrom, chan->dname, isbadop, msg);
  851. n = i = 0;
  852. switch (role) {
  853. case 0:
  854. break;
  855. case 1:
  856. /* Kick opper */
  857. m = ismember(chan, nfrom);
  858. if (!m || !chan_sentkick(m)) {
  859. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, nfrom, kickprefix, kickreason(KICK_BADOP));
  860. tputs(serv, tmp, strlen(tmp));
  861. if (m)
  862. m->flags |= SENTKICK;
  863. }
  864. sprintf(tmp, "%s MODE %s", from, msg);
  865. deflag_user(ufrom, DEFLAG_BADCOOKIE, tmp, chan);
  866. break;
  867. default:
  868. n = role - 1;
  869. i = 0;
  870. while ((i < 5) && (n > 0)) {
  871. if (modes[i] && !strncmp(modes[i], "+o", 2))
  872. n--;
  873. if (n)
  874. i++;
  875. }
  876. if (!n) {
  877. strncpyz(trg, (char *) &modes[i][3], NICKLEN);
  878. m = ismember(chan, trg);
  879. if (m) {
  880. if (!(m->flags & CHANOP)) {
  881. if (!chan_sentkick(m)) {
  882. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, trg, kickprefix, kickreason(KICK_BADOPPED));
  883. tputs(serv, tmp, strlen(tmp));
  884. m->flags |= SENTKICK;
  885. }
  886. }
  887. }
  888. }
  889. }
  890. if (isbadop == 1)
  891. putlog(LOG_WARN, "*", "Missing cookie: %s MODE %s", from, msg);
  892. else if (isbadop == 2)
  893. putlog(LOG_WARN, "*", "Invalid cookie (bad nick): %s MODE %s", from, msg);
  894. else if (isbadop == 3)
  895. putlog(LOG_WARN, "*", "Invalid cookie (bad chan): %s MODE %s", from, msg);
  896. else if (isbadop == 4)
  897. putlog(LOG_WARN, "*", "Invalid cookie (bad time): %s MODE %s", from, msg);
  898. } else
  899. putlog(LOG_DEBUG, "@", "Good op: %s", msg);
  900. }
  901. if ((ops) && chan && me_op(chan) && !channel_manop(chan) && (ufrom) && !(ufrom->flags & USER_BOT)) {
  902. char trg[NICKLEN] = "";
  903. n = i = 0;
  904. switch (role) {
  905. case 0:
  906. break;
  907. case 1:
  908. /* Kick opper */
  909. m = ismember(chan, nfrom);
  910. if (!m || !chan_sentkick(m)) {
  911. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, nfrom, kickprefix, kickreason(KICK_MANUALOP));
  912. tputs(serv, tmp, strlen(tmp));
  913. if (m)
  914. m->flags |= SENTKICK;
  915. }
  916. sprintf(tmp, "%s MODE %s", from, msg);
  917. deflag_user(ufrom, DEFLAG_MANUALOP, tmp, chan);
  918. break;
  919. default:
  920. n = role - 1;
  921. i = 0;
  922. while ((i < 5) && (n > 0)) {
  923. if (modes[i] && !strncmp(modes[i], "+o", 2))
  924. n--;
  925. if (n)
  926. i++;
  927. }
  928. if (!n) {
  929. strncpyz(trg, (char *) &modes[i][3], NICKLEN);
  930. m = ismember(chan, trg);
  931. if (m) {
  932. if (!(m->flags & CHANOP) && (rfc_casecmp(botname, trg))) {
  933. if (!chan_sentkick(m)) {
  934. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, trg, kickprefix, kickreason(KICK_MANUALOPPED));
  935. tputs(serv, tmp, strlen(tmp));
  936. m->flags |= SENTKICK;
  937. }
  938. }
  939. } else {
  940. sprintf(tmp, "KICK %s %s :%s%s\n", chan->name, trg, kickprefix, kickreason(KICK_MANUALOPPED));
  941. tputs(serv, tmp, strlen(tmp));
  942. }
  943. }
  944. }
  945. }
  946. for (i = 0; i < 5; i++)
  947. if (modes[i])
  948. free(modes[i]);
  949. }
  950. /* Now do the modes again, this time throughly... */
  951. chg = newsplit(&msg);
  952. reversing = 0;
  953. if (channel_active(chan) || channel_pending(chan)) {
  954. z = strlen(msg);
  955. if (msg[--z] == ' ') /* I hate cosmetic bugs :P -poptix */
  956. msg[z] = 0;
  957. putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg, msg, from);
  958. u = get_user_by_host(from);
  959. get_user_flagrec(u, &user, ch);
  960. nick = splitnick(&from);
  961. m = ismember(chan, nick);
  962. if (m)
  963. m->last = now;
  964. if (channel_active(chan) && m && me_op(chan)) {
  965. if (chan_fakeop(m)) {
  966. putlog(LOG_MODES, ch, CHAN_FAKEMODE, ch);
  967. dprintf(DP_MODE, "KICK %s %s :%s%s\n", ch, nick, kickprefix,
  968. CHAN_FAKEMODE_KICK);
  969. m->flags |= SENTKICK;
  970. reversing = 1;
  971. } else if (m->nick && !strchr(m->nick, '.') && /* HOW ABOUT IF THEY ARENT A FUCKING SERVER? */
  972. !chan_hasop(m) &&
  973. !channel_nodesynch(chan)) {
  974. putlog(LOG_MODES, ch, CHAN_DESYNCMODE, ch);
  975. dprintf(DP_MODE, "KICK %s %s :%s%s\n", ch, nick, kickprefix,
  976. CHAN_DESYNCMODE_KICK);
  977. m->flags |= SENTKICK;
  978. reversing = 1;
  979. }
  980. }
  981. ms2[0] = '+';
  982. ms2[2] = 0;
  983. while ((ms2[1] = *chg)) {
  984. int todo = 0;
  985. switch (*chg) {
  986. case '+':
  987. ms2[0] = '+';
  988. break;
  989. case '-':
  990. ms2[0] = '-';
  991. break;
  992. case 'i':
  993. todo = CHANINV;
  994. if ((!nick[0]) && (bounce_modes))
  995. reversing = 1;
  996. break;
  997. case 'p':
  998. todo = CHANPRIV;
  999. if ((!nick[0]) && (bounce_modes))
  1000. reversing = 1;
  1001. break;
  1002. case 's':
  1003. todo = CHANSEC;
  1004. if ((!nick[0]) && (bounce_modes))
  1005. reversing = 1;
  1006. break;
  1007. case 'm':
  1008. todo = CHANMODER;
  1009. if ((!nick[0]) && (bounce_modes))
  1010. reversing = 1;
  1011. break;
  1012. case 'c':
  1013. todo = CHANNOCLR;
  1014. if ((!nick[0]) && (bounce_modes))
  1015. reversing = 1;
  1016. break;
  1017. case 'C':
  1018. todo = CHANNOCTCP;
  1019. if ((!nick[0]) && (bounce_modes))
  1020. reversing = 1;
  1021. break;
  1022. case 'R':
  1023. todo = CHANREGON;
  1024. if ((!nick[0]) && (bounce_modes))
  1025. reversing = 1;
  1026. break;
  1027. case 'M':
  1028. todo = CHANMODR;
  1029. if ((!nick[0]) && (bounce_modes))
  1030. reversing = 1;
  1031. break;
  1032. case 'r':
  1033. todo = CHANLONLY;
  1034. if ((!nick[0]) && (bounce_modes))
  1035. reversing = 1;
  1036. break;
  1037. case 't':
  1038. todo = CHANTOPIC;
  1039. if ((!nick[0]) && (bounce_modes))
  1040. reversing = 1;
  1041. break;
  1042. case 'n':
  1043. todo = CHANNOMSG;
  1044. if ((!nick[0]) && (bounce_modes))
  1045. reversing = 1;
  1046. break;
  1047. case 'a':
  1048. todo = CHANANON;
  1049. if ((!nick[0]) && (bounce_modes))
  1050. reversing = 1;
  1051. break;
  1052. case 'q':
  1053. todo = CHANQUIET;
  1054. if ((!nick[0]) && (bounce_modes))
  1055. reversing = 1;
  1056. break;
  1057. case 'l':
  1058. if ((!nick[0]) && (bounce_modes))
  1059. reversing = 1;
  1060. if (ms2[0] == '-') {
  1061. if (channel_active(chan)) {
  1062. if ((reversing) && (chan->channel.maxmembers != 0)) {
  1063. simple_sprintf(s, "%d", chan->channel.maxmembers);
  1064. add_mode(chan, '+', 'l', s);
  1065. } else if ((chan->limit_prot != 0) && !glob_master(user) && !chan_master(user)) {
  1066. simple_sprintf(s, "%d", chan->limit_prot);
  1067. add_mode(chan, '+', 'l', s);
  1068. } else {
  1069. if (dolimit(chan) &&
  1070. (!chan_master(user) && !glob_master(user) && !glob_bot(user))) {
  1071. if (chan->limitraise) {
  1072. chan->channel.maxmembers = 0; /* set this to 0 so a new limit is generated */
  1073. raise_limit(chan);
  1074. }
  1075. }
  1076. }
  1077. }
  1078. chan->channel.maxmembers = 0;
  1079. } else {
  1080. op = newsplit(&msg);
  1081. fixcolon(op);
  1082. if (op == '\0')
  1083. break;
  1084. chan->channel.maxmembers = atoi(op);
  1085. if (channel_pending(chan))
  1086. break;
  1087. if (((reversing) &&
  1088. !(chan->mode_pls_prot & CHANLIMIT)) ||
  1089. ((chan->mode_mns_prot & CHANLIMIT) &&
  1090. !glob_master(user) && !chan_master(user)))
  1091. add_mode(chan, '-', 'l', "");
  1092. if ((chan->limit_prot != chan->channel.maxmembers) &&
  1093. (chan->mode_pls_prot & CHANLIMIT) &&
  1094. (chan->limit_prot != 0) && /* arthur2 */
  1095. !glob_master(user) && !chan_master(user)) {
  1096. simple_sprintf(s, "%d", chan->limit_prot);
  1097. add_mode(chan, '+', 'l', s);
  1098. }
  1099. if (!glob_bot(user))
  1100. if (dolimit(chan) && (!chan_master(user) && !glob_master(user)))
  1101. if (chan->limitraise)
  1102. raise_limit(chan);
  1103. }
  1104. break;
  1105. case 'k':
  1106. if (ms2[0] == '+')
  1107. chan->channel.mode |= CHANKEY;
  1108. else
  1109. chan->channel.mode &= ~CHANKEY;
  1110. op = newsplit(&msg);
  1111. fixcolon(op);
  1112. if (op == '\0') {
  1113. break;
  1114. }
  1115. if (ms2[0] == '+') {
  1116. my_setkey(chan, op);
  1117. if (channel_active(chan))
  1118. got_key(chan, nick, from, op);
  1119. } else {
  1120. if (channel_active(chan)) {
  1121. if ((reversing) && (chan->channel.key[0]))
  1122. add_mode(chan, '+', 'k', chan->channel.key);
  1123. else if ((chan->key_prot[0]) && !glob_master(user)
  1124. && !chan_master(user))
  1125. add_mode(chan, '+', 'k', chan->key_prot);
  1126. }
  1127. my_setkey(chan, NULL);
  1128. }
  1129. break;
  1130. case 'o':
  1131. #ifdef S_AUTOLOCK
  1132. chan->channel.fighting++;
  1133. #endif /* S_AUTOLOCK */
  1134. op = newsplit(&msg);
  1135. fixcolon(op);
  1136. if (ms2[0] == '+')
  1137. got_op(chan, nick, from, op, u, &user);
  1138. else
  1139. got_deop(chan, nick, from, op, u);
  1140. break;
  1141. case 'v':
  1142. op = newsplit(&msg);
  1143. fixcolon(op);
  1144. m = ismember(chan, op);
  1145. if (!m) {
  1146. if (channel_pending(chan))
  1147. break;
  1148. putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, op);
  1149. dprintf(DP_MODE, "WHO %s\n", op);
  1150. } else {
  1151. int dv = 0;
  1152. simple_sprintf(s, "%s!%s", m->nick, m->userhost);
  1153. get_user_flagrec(m->user ? m->user : get_user_by_host(s),
  1154. &victim, chan->dname);
  1155. if (ms2[0] == '+') {
  1156. if (m->flags & EVOICE) {
  1157. if (!chan_master(user) && !glob_master(user)) {
  1158. dv++;
  1159. } else {
  1160. putlog(LOG_DEBUG, "@", "Stripping EVOICE flag from: %s (%s)", m->nick, chan->dname);
  1161. m->flags &= ~EVOICE;
  1162. }
  1163. }
  1164. m->flags &= ~SENTVOICE;
  1165. m->flags |= CHANVOICE;
  1166. if (channel_active(chan) && dovoice(chan)) {
  1167. if (dv || chk_devoice(victim, chan)) {
  1168. add_mode(chan, '-', 'v', op);
  1169. } else if (reversing) {
  1170. add_mode(chan, '-', 'v', op);
  1171. }
  1172. }
  1173. } else if (ms2[0] == '-') {
  1174. m->flags &= ~SENTDEVOICE;
  1175. m->flags &= ~CHANVOICE;
  1176. if (channel_active(chan) && dovoice(chan)) {
  1177. /* revoice +v users */
  1178. if (chk_voice(victim, chan)) {
  1179. add_mode(chan, '+', 'v', op);
  1180. } else if (reversing) {
  1181. add_mode(chan, '+', 'v', op);
  1182. /* if they arent +v|v and VOICER is m+ then EVOICE them */
  1183. } else {
  1184. if (!match_my_nick(nick) && channel_voice(chan) &&
  1185. (glob_master(user) || chan_master(user) || glob_bot(user))) {
  1186. /* if the user is not +q set them norEVOICE. */
  1187. if (!chan_quiet(victim) && !(m->flags & EVOICE)) {
  1188. putlog(LOG_DEBUG, "@", "Giving EVOICE flag to: %s (%s)", m->nick, chan->dname);
  1189. m->flags |= EVOICE;
  1190. }
  1191. }
  1192. }
  1193. }
  1194. }
  1195. }
  1196. break;
  1197. case 'b':
  1198. #ifdef S_AUTOLOCK
  1199. chan->channel.fighting++;
  1200. #endif /* S_AUTOLOCK */
  1201. op = newsplit(&msg);
  1202. fixcolon(op);
  1203. if (ms2[0] == '+')
  1204. got_ban(chan, nick, from, op);
  1205. else
  1206. got_unban(chan, nick, from, op, u);
  1207. break;
  1208. case 'e':
  1209. #ifdef S_AUTOLOCK
  1210. chan->channel.fighting++;
  1211. #endif /* S_AUTOLOCK */
  1212. op = newsplit(&msg);
  1213. fixcolon(op);
  1214. if (ms2[0] == '+')
  1215. got_exempt(chan, nick, from, op);
  1216. else
  1217. got_unexempt(chan, nick, from, op, u);
  1218. break;
  1219. case 'I':
  1220. #ifdef S_AUTOLOCK
  1221. chan->channel.fighting++;
  1222. #endif /* S_AUTOLOCK */
  1223. op = newsplit(&msg);
  1224. fixcolon(op);
  1225. if (ms2[0] == '+')
  1226. got_invite(chan, nick, from, op);
  1227. else
  1228. got_uninvite(chan, nick, from, op, u);
  1229. break;
  1230. }
  1231. if (todo) {
  1232. if (ms2[0] == '+')
  1233. chan->channel.mode |= todo;
  1234. else
  1235. chan->channel.mode &= ~todo;
  1236. if (channel_active(chan)) {
  1237. if ((((ms2[0] == '+') && (chan->mode_mns_prot & todo)) ||
  1238. ((ms2[0] == '-') && (chan->mode_pls_prot & todo))) &&
  1239. !glob_master(user) && !chan_master(user))
  1240. add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
  1241. else if (reversing &&
  1242. ((ms2[0] == '+') || (chan->mode_pls_prot & todo)) &&
  1243. ((ms2[0] == '-') || (chan->mode_mns_prot & todo)))
  1244. add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, "");
  1245. }
  1246. }
  1247. chg++;
  1248. }
  1249. if (chan->channel.do_opreq)
  1250. request_op(chan);
  1251. if (!me_op(chan) && !nick[0])
  1252. chan->status |= CHAN_ASKEDMODES;
  1253. }
  1254. }
  1255. return 0;
  1256. }
  1257. #endif /* LEAF */