mode.cc 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2014 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /*
  21. * mode.c -- part of irc.mod
  22. * queuing and flushing mode changes made by the bot
  23. * channel mode changes and the bot's reaction to them
  24. * setting and getting the current wanted channel modes
  25. *
  26. */
  27. #include "src/shell.h"
  28. /* Reversing this mode? */
  29. static bool reversing = 0;
  30. static bool massop = 0;
  31. static bool mdop_reversing = 1;
  32. # define PLUS BIT0
  33. # define MINUS BIT1
  34. # define CHOP BIT2
  35. # define BAN BIT3
  36. # define VOICE BIT4
  37. # define EXEMPT BIT5
  38. # define INVITE BIT6
  39. static struct flag_record user = { FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  40. static struct flag_record victim = { FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  41. /* This implementation wont overrun dst - 'max' is the max bytes that dst
  42. * can be, including the null terminator. So if 'dst' is a 128 byte buffer,
  43. * pass 128 as 'max'. The function will _always_ null-terminate 'dst'.
  44. *
  45. * Returns: The number of characters appended to 'dst'.
  46. *
  47. * Usage eg.
  48. *
  49. * char buf[128];
  50. * size_t bufsize = sizeof(buf);
  51. *
  52. * buf[0] = 0, bufsize--;
  53. *
  54. * while (blah && bufsize) {
  55. * bufsize -= egg_strcatn(buf, <some-long-string>, sizeof(buf));
  56. * }
  57. *
  58. * <Cybah>
  59. */
  60. static size_t egg_strcatn(char *dst, const char *src, size_t max)
  61. {
  62. size_t tmpmax = 0;
  63. /* find end of 'dst' */
  64. while (*dst && max > 0) {
  65. dst++;
  66. max--;
  67. }
  68. /* Store 'max', so we can use it to workout how many characters were
  69. * written later on.
  70. */
  71. tmpmax = max;
  72. /* copy upto, but not including the null terminator */
  73. while (*src && max > 1) {
  74. *dst++ = *src++;
  75. max--;
  76. }
  77. /* null-terminate the buffer */
  78. /* Don't include the terminating null in our count, as it will cumulate
  79. * in loops - causing a headache for the caller.
  80. */
  81. return tmpmax - max;
  82. }
  83. static bool
  84. do_op(memberlist *m, struct chanset_t *chan, bool delay, bool force)
  85. {
  86. if (!me_op(chan) || !m || (!force && (chan_hasop(m) || chan_sentop(m))))
  87. return 0;
  88. if (delay) {
  89. m->delay = now + chan->auto_delay;
  90. m->flags |= SENTOP;
  91. return 1;
  92. }
  93. if (channel_fastop(chan) || channel_take(chan) || cookies_disabled) {
  94. add_mode(chan, '+', 'o', m);
  95. } else if (!connect_bursting) {
  96. add_cookie(chan, m);
  97. } else {
  98. /* Failed to give the mode, so requeue it. */
  99. do_op(m, chan, 1, 0);
  100. }
  101. return 1;
  102. }
  103. static void
  104. flush_cookies(struct chanset_t *chan, int pri)
  105. {
  106. if (connect_bursting) // Make sure not in burst mode
  107. return;
  108. char out[512] = "", *p = out, post[512] = "";
  109. size_t postsize = sizeof(post) - 1;
  110. memberlist *nicks[3] = { NULL, NULL, NULL };
  111. chan->cbytes = 0;
  112. int nick_i = 0;
  113. for (unsigned int i = 0; i < (modesperline - 1); i++) {
  114. if (chan->ccmode[i].op && postsize > strlen(chan->ccmode[i].op)) {
  115. memberlist* mx = ismember(chan, chan->ccmode[i].op);
  116. /* We queued them, but they might not be in the channel any more! */
  117. if (mx) {
  118. /* Build modes .. */
  119. *p++ = '+';
  120. *p++ = 'o';
  121. /* .. and params */
  122. postsize -= egg_strcatn(post, chan->ccmode[i].op, sizeof(post));
  123. postsize -= egg_strcatn(post, " ", sizeof(post));
  124. nicks[nick_i++] = mx;
  125. }
  126. free(chan->ccmode[i].op);
  127. chan->ccmode[i].op = NULL;
  128. }
  129. }
  130. /* remember to terminate the buffer ('out')... */
  131. if (out[0]) {
  132. *p++ = '-';
  133. *p++ = 'b';
  134. }
  135. *p = 0;
  136. if (post[0]) {
  137. memberlist* me = ismember(chan, botname);
  138. if (me)
  139. member_getuser(me);
  140. /* Am I even on the channel? */
  141. if (!me || !me->user)
  142. return;
  143. /* remove the trailing space... */
  144. size_t myindex = (sizeof(post) - 1) - postsize;
  145. if (myindex > 0 && post[--myindex] == ' ')
  146. post[myindex] = 0;
  147. //myindex is how long post is
  148. egg_strcatn(&out[0], " ", sizeof(out));
  149. egg_strcatn(&out[1], post, sizeof(out));
  150. egg_strcatn(&out[myindex + 1], " ", sizeof(out));
  151. myindex += (p - out) + 2; //(p-out)=outlen + 2 spaces
  152. makecookie(&out[myindex], sizeof(out) - myindex, chan->dname, me, nicks[0], nicks[1], nicks[2]);
  153. }
  154. if (out[0]) {
  155. // Enabling this creates a queued cookie and a dumped cookie, resulting in out-of-order counters.
  156. if (pri == QUICK && 0) {
  157. char outbuf[201] = "";
  158. const size_t len = simple_snprintf(outbuf, sizeof(outbuf), "MODE %s %s\r\n", chan->name, out);
  159. dprintf_real(DP_MODE, outbuf, len, sizeof(outbuf));
  160. /* dprintf(DP_MODE, "MODE %s %s\n", chan->name, out); */
  161. } else
  162. dprintf(DP_MODE, "MODE %s %s\n", chan->name, out);
  163. }
  164. }
  165. static void
  166. flush_mode(struct chanset_t *chan, int pri)
  167. {
  168. if (!modesperline) /* Haven't received 005 yet :) */
  169. return;
  170. char out[512] = "", *p = out, post[512] = "";
  171. size_t postsize = sizeof(post) - 1;
  172. int plus = 2; /* 0 = '-', 1 = '+', 2 = none */
  173. unsigned int i = 0;
  174. flush_cookies(chan, pri);
  175. /* dequeue_op_deop(chan); */
  176. /* now does +o first.. */
  177. if (chan->mns[0]) {
  178. *p++ = '-', plus = 0;
  179. for (i = 0; i < strlen(chan->mns); i++)
  180. *p++ = chan->mns[i];
  181. chan->mns[0] = 0;
  182. }
  183. if (chan->pls[0]) {
  184. *p++ = '+', plus = 1;
  185. for (i = 0; i < strlen(chan->pls); i++)
  186. *p++ = chan->pls[i];
  187. chan->pls[0] = 0;
  188. }
  189. chan->bytes = 0;
  190. chan->compat = 0;
  191. /* +k or +l ? */
  192. if (chan->key && !chan->rmkey) {
  193. if (plus != 1) {
  194. *p++ = '+', plus = 1;
  195. }
  196. *p++ = 'k';
  197. postsize -= egg_strcatn(post, chan->key, sizeof(post));
  198. postsize -= egg_strcatn(post, " ", sizeof(post));
  199. free(chan->key), chan->key = NULL;
  200. }
  201. /* max +l is signed 2^32 on IRCnet at least... so makesure we've got at least
  202. * a 13 char buffer for '-2147483647 \0'. We'll be overwriting the existing
  203. * terminating null in 'post', so makesure postsize >= 12.
  204. */
  205. if (chan->limit != 0 && postsize >= 12) {
  206. if (plus != 1) {
  207. *p++ = '+', plus = 1;
  208. }
  209. *p++ = 'l';
  210. /* 'sizeof(post) - 1' is used because we want to overwrite the old null */
  211. postsize -= simple_sprintf(&post[(sizeof(post) - 1) - postsize], "%d ", chan->limit);
  212. chan->limit = 0;
  213. }
  214. /* -k ? */
  215. if (chan->rmkey) {
  216. if (plus) {
  217. *p++ = '-', plus = 0;
  218. }
  219. *p++ = 'k';
  220. postsize -= egg_strcatn(post, chan->rmkey, sizeof(post));
  221. postsize -= egg_strcatn(post, " ", sizeof(post));
  222. free(chan->rmkey), chan->rmkey = NULL;
  223. }
  224. /* Do -{b,e,I} before +{b,e,I} to avoid the server ignoring overlaps */
  225. for (i = 0; i < modesperline; i++) {
  226. if (chan->cmode[i].op && (chan->cmode[i].type & MINUS) && postsize > strlen(chan->cmode[i].op)) {
  227. if (plus) {
  228. *p++ = '-', plus = 0;
  229. }
  230. *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
  231. ((chan->cmode[i].type & CHOP) ? 'o' :
  232. ((chan->cmode[i].type & EXEMPT) ? 'e' : ((chan->cmode[i].type & INVITE) ? 'I' : 'v'))));
  233. postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
  234. postsize -= egg_strcatn(post, " ", sizeof(post));
  235. free(chan->cmode[i].op), chan->cmode[i].op = NULL;
  236. chan->cmode[i].type = 0;
  237. }
  238. }
  239. /* now do all the + modes... */
  240. for (i = 0; i < modesperline; i++) {
  241. if (chan->cmode[i].op && (chan->cmode[i].type & PLUS) && postsize > strlen(chan->cmode[i].op)) {
  242. if (plus != 1) {
  243. *p++ = '+', plus = 1;
  244. }
  245. *p++ = ((chan->cmode[i].type & BAN) ? 'b' :
  246. ((chan->cmode[i].type & CHOP) ? 'o' :
  247. ((chan->cmode[i].type & EXEMPT) ? 'e' : ((chan->cmode[i].type & INVITE) ? 'I' : 'v'))));
  248. postsize -= egg_strcatn(post, chan->cmode[i].op, sizeof(post));
  249. postsize -= egg_strcatn(post, " ", sizeof(post));
  250. free(chan->cmode[i].op), chan->cmode[i].op = NULL;
  251. chan->cmode[i].type = 0;
  252. }
  253. }
  254. /* remember to terminate the buffer ('out')... */
  255. *p = 0;
  256. if (post[0]) {
  257. /* remove the trailing space... */
  258. size_t myindex = (sizeof(post) - 1) - postsize;
  259. if (myindex > 0 && post[myindex - 1] == ' ')
  260. post[myindex - 1] = 0;
  261. egg_strcatn(out, " ", sizeof(out));
  262. egg_strcatn(out, post, sizeof(out));
  263. }
  264. if (out[0]) {
  265. if (pri == QUICK) {
  266. /* floods too much
  267. char outbuf[201] = "";
  268. const size_t len = simple_snprintf(outbuf, sizeof(outbuf), "MODE %s %s\r\n", chan->name, out);
  269. tputs(serv, outbuf, len);
  270. */
  271. dprintf(DP_MODE, "MODE %s %s\n", chan->name, out);
  272. } else
  273. dprintf(DP_SERVER, "MODE %s %s\n", chan->name, out);
  274. }
  275. }
  276. /* Queue a channel mode change
  277. */
  278. void
  279. real_add_mode(struct chanset_t *chan, const char plus, const char mode, const char *op, bool cookie, memberlist *mx)
  280. {
  281. if (!me_op(chan))
  282. return;
  283. if (mode == 'o' || mode == 'v') {
  284. if (!mx)
  285. mx = ismember(chan, op);
  286. if (!mx)
  287. return;
  288. if (plus == '-' && mode == 'o') {
  289. if (chan_sentdeop(mx) || !chan_hasop(mx))
  290. return;
  291. mx->flags |= SENTDEOP;
  292. }
  293. if (plus == '+' && mode == 'o') {
  294. if (chan_sentop(mx) || chan_hasop(mx))
  295. return;
  296. mx->flags |= SENTOP;
  297. }
  298. if (plus == '-' && mode == 'v') {
  299. if (chan_sentdevoice(mx) || !chan_hasvoice(mx))
  300. return;
  301. mx->flags |= SENTDEVOICE;
  302. }
  303. if (plus == '+' && mode == 'v') {
  304. if (chan_sentvoice(mx) || chan_hasvoice(mx))
  305. return;
  306. mx->flags |= SENTVOICE;
  307. }
  308. }
  309. int type, modes;
  310. size_t len = 0;
  311. unsigned int i;
  312. masklist *m = NULL;
  313. char s[21] = "";
  314. if (chan->compat == 0) {
  315. if (mode == 'e' || mode == 'I')
  316. chan->compat = 2;
  317. else
  318. chan->compat = 1;
  319. } else if (mode == 'e' || mode == 'I') {
  320. if (prevent_mixing && chan->compat == 1)
  321. flush_mode(chan, NORMAL);
  322. } else if (prevent_mixing && chan->compat == 2)
  323. flush_mode(chan, NORMAL);
  324. if (mode == 'o' || mode == 'b' || mode == 'v' || mode == 'e' || mode == 'I') {
  325. type = (plus == '+' ? PLUS : MINUS) |
  326. (mode == 'o' ? CHOP : (mode == 'b' ? BAN : (mode == 'v' ? VOICE : (mode == 'e' ? EXEMPT : INVITE))));
  327. /*
  328. * FIXME: Some networks remove overlapped bans,
  329. * IRCnet does not (poptix/drummer)
  330. *
  331. * Note: On IRCnet ischanXXX() should be used, otherwise isXXXed().
  332. */
  333. if ((plus == '-' && ((mode == 'b' && !ischanban(chan, op)) ||
  334. (mode == 'e' && !ischanexempt(chan, op)) ||
  335. (mode == 'I' && !ischaninvite(chan, op)))) || (plus == '+' &&
  336. ((mode == 'b' && ischanban(chan, op))
  337. || (mode == 'e' &&
  338. ischanexempt(chan, op)) ||
  339. (mode == 'I' &&
  340. ischaninvite(chan, op)))))
  341. return;
  342. /* If there are already max_bans bans, max_exempts exemptions,
  343. * max_invites invitations or max_modes +b/+e/+I modes on the
  344. * channel, don't try to add one more.
  345. */
  346. if (plus == '+' && (mode == 'b' || mode == 'e' || mode == 'I')) {
  347. int bans = 0, exempts = 0, invites = 0;
  348. for (m = chan->channel.ban; m && m->mask[0]; m = m->next)
  349. bans++;
  350. if ((mode == 'b') && (bans >= max_bans))
  351. return;
  352. for (m = chan->channel.exempt; m && m->mask[0]; m = m->next)
  353. exempts++;
  354. if ((mode == 'e') && (exempts >= max_exempts))
  355. return;
  356. for (m = chan->channel.invite; m && m->mask[0]; m = m->next)
  357. invites++;
  358. if ((mode == 'I') && (invites >= max_invites))
  359. return;
  360. if (bans + exempts + invites >= max_modes)
  361. return;
  362. }
  363. /* op-type mode change */
  364. /* for cookie ops, use ccmode instead of cmode */
  365. if (cookie) {
  366. for (i = 0; i < (modesperline - 1); i++)
  367. if (chan->ccmode[i].op != NULL && !rfc_casecmp(chan->ccmode[i].op, op))
  368. return; /* Already in there :- duplicate */
  369. len = strlen(op) + 1;
  370. if (chan->cbytes + len > mode_buf_len)
  371. flush_mode(chan, NORMAL);
  372. for (i = 0; i < (modesperline - 1); i++)
  373. if (!chan->ccmode[i].op) {
  374. chan->ccmode[i].op = (char *) calloc(1, len);
  375. chan->cbytes += len; /* Add 1 for safety */
  376. strlcpy(chan->ccmode[i].op, op, len);
  377. break;
  378. }
  379. } else {
  380. for (i = 0; i < modesperline; i++)
  381. if (chan->cmode[i].type == type && chan->cmode[i].op != NULL && !rfc_casecmp(chan->cmode[i].op, op))
  382. return; /* Already in there :- duplicate */
  383. len = strlen(op) + 1;
  384. if (chan->bytes + len > mode_buf_len)
  385. flush_mode(chan, NORMAL);
  386. for (i = 0; i < modesperline; i++)
  387. if (chan->cmode[i].type == 0) {
  388. chan->cmode[i].type = type;
  389. chan->cmode[i].op = (char *) calloc(1, len);
  390. chan->bytes += len; /* Add 1 for safety */
  391. strlcpy(chan->cmode[i].op, op, len);
  392. break;
  393. }
  394. }
  395. }
  396. /* +k ? store key */
  397. else if (plus == '+' && mode == 'k') {
  398. if (chan->key)
  399. free(chan->key);
  400. len = strlen(op) + 1;
  401. chan->key = (char *) calloc(1, len);
  402. strlcpy(chan->key, op, len);
  403. }
  404. /* -k ? store removed key */
  405. else if (plus == '-' && mode == 'k') {
  406. if (chan->rmkey)
  407. free(chan->rmkey);
  408. len = strlen(op) + 1;
  409. chan->rmkey = (char *) calloc(1, len);
  410. strlcpy(chan->rmkey, op, len);
  411. }
  412. /* +l ? store limit */
  413. else if (plus == '+' && mode == 'l')
  414. chan->limit = atoi(op);
  415. else {
  416. /* Typical mode changes */
  417. if (plus == '+')
  418. strlcpy(s, chan->pls, sizeof(s));
  419. else
  420. strlcpy(s, chan->mns, sizeof(s));
  421. if (!strchr(s, mode)) {
  422. if (plus == '+') {
  423. chan->pls[strlen(chan->pls) + 1] = 0;
  424. chan->pls[strlen(chan->pls)] = mode;
  425. } else {
  426. chan->mns[strlen(chan->mns) + 1] = 0;
  427. chan->mns[strlen(chan->mns)] = mode;
  428. }
  429. }
  430. }
  431. modes = modesperline; /* Check for full buffer. */
  432. for (i = 0; i < modesperline; i++)
  433. if (chan->cmode[i].type)
  434. modes--;
  435. if (include_lk && chan->limit)
  436. modes--;
  437. if (include_lk && chan->rmkey)
  438. modes--;
  439. if (include_lk && chan->key)
  440. modes--;
  441. if (modes < 1)
  442. flush_mode(chan, NORMAL); /* Full buffer! Flush modes. */
  443. /* flush full cookie queue */
  444. modes = modesperline - 1;
  445. for (i = 0; i < (modesperline - 1); i++)
  446. if (chan->ccmode[i].op)
  447. modes--;
  448. if (modes < 1)
  449. flush_cookies(chan, NORMAL);
  450. }
  451. /*
  452. * Mode parsing functions
  453. */
  454. static void
  455. got_key(struct chanset_t *chan, char *key)
  456. {
  457. if (((reversing) && !(chan->key_prot[0])) ||
  458. ((chan->mode_mns_prot & CHANKEY) && !(glob_master(user) || glob_bot(user) || chan_master(user)))) {
  459. if (key && key[0]) {
  460. add_mode(chan, '-', 'k', key);
  461. } else {
  462. add_mode(chan, '-', 'k', "");
  463. }
  464. }
  465. }
  466. /* m may not exist */
  467. static void
  468. got_op(struct chanset_t *chan, memberlist *m, memberlist *mv)
  469. {
  470. bool check_chan = 0;
  471. const bool me_opped = mv->is_me;
  472. bool meop = me_op(chan);
  473. const bool was_op = chan_hasop(mv);
  474. // No need to punish someone who was already opped.
  475. if (massop && was_op)
  476. return;
  477. /* Did *I* just get opped? */
  478. if (!meop && me_opped) {
  479. check_chan = 1;
  480. meop = 1;
  481. }
  482. get_user_flagrec(mv->user, &victim, chan->dname, chan);
  483. // Did some other bot just get opped, and I'm not opped yet?
  484. if (mv->user && mv->user->bot && !me_opped && !meop) {
  485. chan->channel.do_opreq = 1;
  486. }
  487. /* Flags need to be set correctly right from the beginning now, so that
  488. * add_mode() doesn't get irritated.
  489. */
  490. mv->flags |= CHANOP;
  491. /* Added new meaning of WASOP:
  492. * in mode binds it means: was he op before get (de)opped
  493. * (stupid IrcNet allows opped users to be opped again and
  494. * opless users to be deopped)
  495. * script now can use [wasop nick chan] proc to check
  496. * if user was op or wasnt (drummer)
  497. */
  498. mv->flags &= ~SENTOP;
  499. /* This skips the recheck_channel until we get the end of the WHO list */
  500. if (channel_pending(chan))
  501. return;
  502. /* I'm opped, and the opper isn't me, and it isn't a server op */
  503. if (m && meop && !me_opped) {
  504. /* deop if they are +d or it is +bitch */
  505. int bitch = chan_bitch(chan);
  506. if (reversing || chk_deop(victim, chan) || (!loading && userlist && bitch && !chk_op(victim, chan))) { /* chk_op covers +private */
  507. int num = randint(10);
  508. char outbuf[101] = "";
  509. size_t len = 0;
  510. /* should kick the oppee first, then deal with the opper */
  511. #ifdef old
  512. if (num == 4) {
  513. len = simple_snprintf(outbuf, sizeof(outbuf), "MODE %s -o %s\r\n", chan->name, mv->nick);
  514. mv->flags |= SENTDEOP;
  515. } else if (num == 5) {
  516. len = simple_snprintf(outbuf, sizeof(outbuf), "MODE %s -o %s\r\n", chan->name, m->nick);
  517. m->flags |= SENTDEOP;
  518. #endif
  519. if (num == 5) {
  520. add_mode(chan, '-', 'o', m);
  521. } else if (bitch && num == 6) {
  522. len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, mv->nick, response(RES_BITCHOPPED));
  523. mv->flags |= SENTKICK;
  524. } else if (bitch && num == 7) {
  525. len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, m->nick, response(RES_BITCHOP));
  526. m->flags |= SENTKICK;
  527. } else
  528. add_mode(chan, '-', 'o', mv);
  529. if (len)
  530. dprintf_real(DP_MODE_NEXT, outbuf, len, sizeof(outbuf));
  531. }
  532. } else if (reversing && !me_opped)
  533. add_mode(chan, '-', 'o', mv);
  534. /* server op */
  535. if (!m && meop && !me_opped) {
  536. if (chk_deop(victim, chan) || (chan_bitch(chan) && !chk_op(victim, chan))) {
  537. mv->flags |= FAKEOP;
  538. add_mode(chan, '-', 'o', mv);
  539. }
  540. }
  541. mv->flags |= WASOP;
  542. if (check_chan) {
  543. #ifdef no
  544. /* tell other bots to set jointime to 0 and join */
  545. char *buf = NULL;
  546. size_t siz = strlen(chan->dname) + 3 + 1;
  547. buf = calloc(1, siz);
  548. simple_snprintf(buf, siz, "jn %s", chan->dname);
  549. putallbots(buf);
  550. free(buf);
  551. #endif
  552. /* check exempts/invites and shit */
  553. recheck_channel(chan, 2);
  554. }
  555. }
  556. static void
  557. got_deop(struct chanset_t *chan, memberlist *m, memberlist *mv, char *isserver)
  558. {
  559. const bool was_op = chan_hasop(mv);
  560. if (mdop_reversing && !was_op)
  561. return;
  562. /* m is NULL if a server made the change */
  563. get_user_flagrec(mv->user, &victim, chan->dname, chan);
  564. /* Flags need to be set correctly right from the beginning now, so that
  565. * add_mode() doesn't get irritated.
  566. */
  567. mv->flags &= ~(CHANOP | SENTDEOP | FAKEOP);
  568. /* Check comments in got_op() (drummer) */
  569. mv->flags &= ~WASOP;
  570. if (channel_pending(chan))
  571. return;
  572. /* Deop'd someone on my oplist? */
  573. if (me_op(chan)) {
  574. /* do we want to reop victim? */
  575. if (
  576. /* I didn't deop them, another bot didn't deop them and they didn't deop themselves. */
  577. (was_op && ((m && !m->is_me && mv != m && !(m->user && m->user->bot)) || (!m))) && (
  578. /*
  579. * reversing
  580. * They are either an op or this chan is -bitch
  581. */
  582. (reversing && (!chan_bitch(chan) || chk_op(victim, chan))) ||
  583. /* Reop bots to avoid them needing to ask */
  584. (role == 3 && mv->user && mv->user->bot && chk_op(victim, chan))
  585. )
  586. ) {
  587. /* Then we'll bless the victim */
  588. do_op(mv, chan, 0, 0);
  589. }
  590. }
  591. if (isserver[0]) /* !m */
  592. putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s", chan->dname, mv->nick, isserver);
  593. /* Check for mass deop */
  594. else if (m) {
  595. detect_chan_flood(m, m->from, chan, FLOOD_DEOP, mv->nick);
  596. }
  597. /* Having op hides your +v and +h status -- so now that someone's lost ops,
  598. * check to see if they have +v or +h
  599. */
  600. // WHO CARES
  601. // if (!channel_take(chan) && !chan_bitch(chan) && !(mv->flags & (CHANVOICE | STOPWHO))) {
  602. // send_chan_who(DP_HELP, chan);
  603. // mv->flags |= STOPWHO;
  604. // }
  605. /* Was the bot deopped? */
  606. if (mv->is_me) {
  607. /* Cancel any pending kicks and modes */
  608. memberlist *m2 = NULL;
  609. for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
  610. m2->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTVOICE | SENTDEVOICE);
  611. chan->channel.do_opreq = 1;
  612. /* request_op(chan); */
  613. /* need: op */
  614. if (!m)
  615. putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(", chan->dname);
  616. } else {
  617. // Revenge kick clients that deop our bots
  618. if (chan->revenge && m && m != mv && mv->user && mv->user->bot && !(m->user && m->user->bot)) {
  619. if (role < 5 && !chan_sentkick(m) && me_op(chan)) {
  620. m->flags |= SENTKICK;
  621. dprintf(DP_MODE_NEXT, "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_REVENGE));
  622. } else {
  623. if (m->user) {
  624. char tmp[128] = "";
  625. simple_snprintf(tmp, sizeof(tmp), "Deopped bot %s on %s", mv->nick, chan->dname);
  626. deflag_user(m->user, DEFLAG_EVENT_REVENGE_DEOP, tmp, chan);
  627. }
  628. }
  629. }
  630. }
  631. }
  632. static void
  633. got_ban(struct chanset_t *chan, memberlist *m, char *mask, char *isserver)
  634. {
  635. const memberlist *me = ismember(chan, botname);
  636. char s[UHOSTLEN] = "";
  637. simple_snprintf(s, sizeof s, "%s!%s", m ? m->nick : "", m ? m->userhost : isserver);
  638. if (m && newban(chan, mask, m->from))
  639. return; /* The ban was already set, don't bother with it */
  640. if (channel_pending(chan) || !me_op(chan))
  641. return;
  642. // Make an array of all matching users
  643. bd::Array<memberlist*> matchedUserMembers;
  644. memberlist *matched_bot = NULL;
  645. for (memberlist *mv = chan->channel.member; mv && mv->nick[0]; mv = mv->next) {
  646. member_getuser(mv);
  647. if (mv->user) {
  648. if ((wild_match(mask, mv->from) || match_cidr(mask, mv->from))) {
  649. if (!matched_bot && mv != m && mv->user->bot) {
  650. matched_bot = mv;
  651. }
  652. if (mv->user && !isexempted(chan, mv->from)) {
  653. matchedUserMembers << mv;
  654. }
  655. }
  656. }
  657. }
  658. // Revenge kick clients that ban our bots
  659. if (chan->revenge && m && matched_bot && !(m->user && m->user->bot)) {
  660. if (role < 5 && !chan_sentkick(m)) {
  661. m->flags |= SENTKICK;
  662. dprintf(DP_MODE_NEXT, "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_REVENGE));
  663. } else {
  664. if (m->user) {
  665. char tmp[128] = "";
  666. simple_snprintf(tmp, sizeof(tmp), "Banned bot %s (%s) on %s", matched_bot->nick, mask, chan->dname);
  667. deflag_user(m->user, DEFLAG_EVENT_REVENGE_BAN, tmp, chan);
  668. }
  669. }
  670. }
  671. if ((wild_match(mask, me->from) || match_cidr(mask, me->fromip)) && !isexempted(chan, me->from)) {
  672. add_mode(chan, '-', 'b', mask);
  673. reversing = 1;
  674. return;
  675. }
  676. if (m && !m->is_me) {
  677. if (channel_nouserbans(chan) && !glob_bot(user)) {
  678. add_mode(chan, '-', 'b', mask);
  679. return;
  680. }
  681. /* remove bans on ops unless a master/bot set it */
  682. for (size_t n = 0; n < matchedUserMembers.size(); ++n) {
  683. const memberlist *mv = matchedUserMembers[n];
  684. get_user_flagrec(mv->user, &victim, chan->dname, chan);
  685. if (!(glob_kick(victim) || chan_kick(victim)) &&
  686. (((chk_op(victim, chan) && !chan_master(user) && !glob_master(user) && !glob_bot(user)) ||
  687. (mv->user->bot && findbot(mv->user->handle))))) {
  688. /* if (target_priority(chan, m, 0)) */
  689. add_mode(chan, '-', 'b', mask);
  690. return;
  691. }
  692. }
  693. }
  694. refresh_exempt(chan, mask);
  695. /* This looks for bans added through bot and tacks on banned: if a description is found */
  696. if (m && channel_enforcebans(chan)) {
  697. maskrec *b = NULL;
  698. char resn[512] = "";
  699. /* The point of this cycle crap is to first check chan->bans then global_bans for a reason */
  700. for (int cycle = 0; cycle < 2; cycle++) {
  701. for (b = cycle ? chan->bans : global_bans; b; b = b->next) {
  702. if (wild_match(b->mask, mask) || match_cidr(b->mask, mask)) {
  703. if (b->desc && b->desc[0] != '@')
  704. simple_snprintf(resn, sizeof resn, "banned: %s", b->desc);
  705. else
  706. resn[0] = 0;
  707. }
  708. }
  709. }
  710. kick_all(chan, mask, resn[0] ? (const char *) resn : r_banned(chan), m->is_me ? 0 : 1);
  711. }
  712. if (!m && (bounce_bans || bounce_modes) &&
  713. (!u_equals_mask(global_bans, mask) || !u_equals_mask(chan->bans, mask)))
  714. add_mode(chan, '-', 'b', mask);
  715. }
  716. static void
  717. got_unban(struct chanset_t *chan, memberlist *m, char *mask)
  718. {
  719. masklist *b = NULL, *old = NULL;
  720. for (b = chan->channel.ban; b->mask[0] && rfc_casecmp(b->mask, mask); old = b, b = b->next) ;
  721. if (b->mask[0]) {
  722. if (old)
  723. old->next = b->next;
  724. else
  725. chan->channel.ban = b->next;
  726. free(b->mask);
  727. free(b->who);
  728. free(b);
  729. } else {
  730. /* The ban was not even set, why continue? */
  731. return;
  732. }
  733. if (channel_pending(chan))
  734. return;
  735. if (u_sticky_mask(chan->bans, mask) || u_sticky_mask(global_bans, mask)) {
  736. /* That's a sticky ban! No point in being
  737. * sticky unless we enforce it!!
  738. */
  739. add_mode(chan, '+', 'b', mask);
  740. }
  741. if ((u_equals_mask(global_bans, mask) || u_equals_mask(chan->bans, mask)) &&
  742. me_op(chan) && !channel_dynamicbans(chan)) {
  743. /* That's a permban! */
  744. if (!glob_bot(user) && !chk_op(user, chan))
  745. add_mode(chan, '+', 'b', mask);
  746. }
  747. }
  748. static void
  749. got_exempt(struct chanset_t *chan, memberlist *m, char *mask, char *isserver)
  750. {
  751. char s[UHOSTLEN] = "";
  752. simple_snprintf(s, sizeof(s), "%s!%s", m ? m->nick : "", m ? m->userhost : isserver);
  753. if (newexempt(chan, mask, s))
  754. return; /* The exempt was already set, don't bother with it */
  755. if (channel_pending(chan))
  756. return;
  757. if (m && !m->is_me) { /* It's not my exemption */
  758. if (channel_nouserexempts(chan) && !glob_bot(user) && !glob_master(user) && !chan_master(user)) {
  759. /* No exempts made by users */
  760. add_mode(chan, '-', 'e', mask);
  761. return;
  762. }
  763. }
  764. if (reversing || (!m && bounce_exempts &&
  765. (!u_equals_mask(global_exempts, mask) || !u_equals_mask(chan->exempts, mask))))
  766. add_mode(chan, '-', 'e', mask);
  767. }
  768. static void
  769. got_unexempt(struct chanset_t *chan, memberlist *m, char *mask)
  770. {
  771. masklist *e = chan->channel.exempt, *old = NULL;
  772. masklist *b = NULL;
  773. int match = 0;
  774. while (e && e->mask[0] && rfc_casecmp(e->mask, mask)) {
  775. old = e;
  776. e = e->next;
  777. }
  778. if (e && e->mask[0]) {
  779. if (old)
  780. old->next = e->next;
  781. else
  782. chan->channel.exempt = e->next;
  783. free(e->mask);
  784. free(e->who);
  785. free(e);
  786. } else {
  787. /* The exempt was not even set, why continue? */
  788. return;
  789. }
  790. if (channel_pending(chan))
  791. return;
  792. if (u_sticky_mask(chan->exempts, mask) || u_sticky_mask(global_exempts, mask)) {
  793. /* That's a sticky exempt! No point in being sticky unless we enforce it!!
  794. */
  795. add_mode(chan, '+', 'e', mask);
  796. }
  797. /* If exempt was removed by master then leave it else check for bans */
  798. /* FIXME: this is impossible, if server !isbot ? */
  799. if (!m && glob_bot(user) && !glob_master(user) && !chan_master(user)) {
  800. b = chan->channel.ban;
  801. while (b->mask[0] && !match) {
  802. if (wild_match(b->mask, mask) || wild_match(mask, b->mask)) {
  803. add_mode(chan, '+', 'e', mask);
  804. match = 1;
  805. } else
  806. b = b->next;
  807. }
  808. }
  809. if ((u_equals_mask(global_exempts, mask) || u_equals_mask(chan->exempts, mask)) &&
  810. me_op(chan) && !channel_dynamicexempts(chan) && !glob_bot(user))
  811. add_mode(chan, '+', 'e', mask);
  812. if (channel_enforcebans(chan))
  813. enforce_bans(chan);
  814. }
  815. static void
  816. got_invite(struct chanset_t *chan, memberlist *m, char *mask, char *isserver)
  817. {
  818. char s[UHOSTLEN] = "";
  819. simple_snprintf(s, sizeof(s), "%s!%s", m ? m->nick : "", m ? m->userhost : isserver);
  820. if (newinvite(chan, mask, s))
  821. return; /* The Invite was already set, don't bother with it */
  822. if (channel_pending(chan))
  823. return;
  824. if (m && !m->is_me) { /* It's not my invitation */
  825. if (channel_nouserinvites(chan) && !glob_bot(user) && !glob_master(user) && !chan_master(user)) {
  826. /* No exempts made by users */
  827. add_mode(chan, '-', 'I', mask);
  828. return;
  829. }
  830. }
  831. if (reversing || (bounce_invites && !m &&
  832. (!u_equals_mask(global_invites, mask) || !u_equals_mask(chan->invites, mask))))
  833. add_mode(chan, '-', 'I', mask);
  834. }
  835. static void
  836. got_uninvite(struct chanset_t *chan, memberlist *m, char *mask)
  837. {
  838. masklist *inv = chan->channel.invite, *old = NULL;
  839. while (inv->mask[0] && rfc_casecmp(inv->mask, mask)) {
  840. old = inv;
  841. inv = inv->next;
  842. }
  843. if (inv->mask[0]) {
  844. if (old)
  845. old->next = inv->next;
  846. else
  847. chan->channel.invite = inv->next;
  848. free(inv->mask);
  849. free(inv->who);
  850. free(inv);
  851. } else {
  852. /* The Invite was not even set, why continue? */
  853. return;
  854. }
  855. if (channel_pending(chan))
  856. return;
  857. if (u_sticky_mask(chan->invites, mask) || u_sticky_mask(global_invites, mask)) {
  858. /* That's a sticky invite! No point in being sticky unless we enforce it!!
  859. */
  860. add_mode(chan, '+', 'I', mask);
  861. }
  862. if (!m && glob_bot(user) && !glob_master(user) && !chan_master(user) && (chan->channel.mode & CHANINV))
  863. add_mode(chan, '+', 'I', mask);
  864. if ((u_equals_mask(global_invites, mask) ||
  865. u_equals_mask(chan->invites, mask)) && me_op(chan) && !channel_dynamicinvites(chan) && !glob_bot(user))
  866. add_mode(chan, '+', 'I', mask);
  867. }
  868. static memberlist *assert_ismember(struct chanset_t *chan, const char *nick)
  869. {
  870. memberlist *m = ismember(chan, nick);
  871. if (m) {
  872. member_getuser(m);
  873. } else {
  874. if (channel_pending(chan))
  875. return NULL;
  876. putlog(LOG_MISC, chan->dname, "* Mode change on %s for nonexistant %s!", chan->dname, nick);
  877. send_chan_who(DP_MODE, chan);
  878. }
  879. return m;
  880. }
  881. static int
  882. gotmode(char *from, char *msg)
  883. {
  884. #define msign modes[i][0]
  885. #define mmode modes[i][1]
  886. /* 2 = space */
  887. #define mparam &modes[i][3]
  888. /* Usermode changes? */
  889. if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
  890. char *ch = newsplit(&msg);
  891. struct chanset_t *chan = findchan(ch);
  892. if (unlikely(!chan)) {
  893. if (unlikely(match_my_nick(ch)))
  894. return 0;
  895. putlog(LOG_MISC, "*", "Oops. Someone made me join %s... leaving...", ch);
  896. dprintf(DP_SERVER, "PART %s\n", ch);
  897. return 0;
  898. }
  899. /* let's pre-emptively check for mass op/deop, manual ops and cookieops */
  900. if ((channel_active(chan) || channel_pending(chan))) {
  901. char isserver[100] = "";
  902. size_t z = strlen(msg);
  903. struct userrec *u = NULL;
  904. memberlist *m = NULL;
  905. const char *nick = NULL;
  906. if (!strchr(from, '!'))
  907. strlcpy(isserver, from, sizeof(isserver));
  908. if (msg[--z] == ' ') /* I hate cosmetic bugs :P -poptix */
  909. msg[z] = 0;
  910. /* Split up from */
  911. if (!isserver[0]) {
  912. nick = splitnick(&from);
  913. if ((m = ismember(chan, nick))) {
  914. m->last = now;
  915. member_getuser(m);
  916. u = m->user;
  917. } else {
  918. if (channel_pending(chan))
  919. return 0;
  920. dprintf(DP_MODE, "KICK %s %s :Desync\n", chan->name[0] ? chan->name : chan->dname, nick);
  921. putlog(LOG_MISC, chan->dname, "* Mode change on %s from nonexistant %s!", chan->dname, nick);
  922. send_chan_who(DP_MODE, chan);
  923. return 0;
  924. }
  925. } else
  926. nick = splitnick(&from);
  927. int i = 0, modecnt = 0, ops = 0, deops = 0, /*bans = 0,*/ unbans = 0;
  928. bool me_opped = 0;
  929. char **modes = (char **) calloc(1, sizeof(char *));
  930. char s[UHOSTLEN] = "";
  931. memberlist *mv = NULL;
  932. massop = reversing = 0;
  933. irc_log(chan, "%s!%s sets mode: %s", nick, from, msg);
  934. get_user_flagrec(u, &user, ch);
  935. if (1) { // Place in block to hint chg/sign to be destroyed when done
  936. /* Split up the mode: #chan modes param param param param */
  937. char *chg = newsplit(&msg);
  938. char sign = 0;
  939. while (*chg) { /* +MODES PARAM PARAM PARAM ... */
  940. if (strchr("+-", *chg))
  941. sign = *chg;
  942. else {
  943. char* mp = NULL;
  944. if (strchr("beIlkov", chg[0])) {
  945. mp = newsplit(&msg); /* PARAM as noted above */
  946. fixcolon(mp);
  947. }
  948. /* Just want o's and b's */
  949. modes = (char **) realloc(modes, (modecnt * sizeof(char *)) + sizeof(char *));
  950. // char **modes = (char **) calloc(modesperline + 1, sizeof(char *));
  951. size_t siz = (mp ? strlen(mp) : 0) + 3 + 1;
  952. modes[modecnt] = (char *) calloc(1, siz);
  953. simple_snprintf(modes[modecnt], siz, "%c%c %s", sign, chg[0], mp ? mp : "");
  954. ++modecnt;
  955. if (chg[0] == 'o') {
  956. if (sign == '+') {
  957. ++ops;
  958. if (match_my_nick(mp))
  959. me_opped = 1;
  960. } else {
  961. deops++;
  962. if (match_my_nick(mp))
  963. me_opped = 0;
  964. }
  965. } else if (chg[0] == 'b') {
  966. if (sign == '-')
  967. ++unbans;
  968. #if 0
  969. else
  970. ++bans;
  971. #endif
  972. }
  973. }
  974. ++chg;
  975. }
  976. }
  977. /* take ASAP */
  978. if (me_opped && !me_op(chan) && channel_take(chan))
  979. do_take(chan);
  980. /* Now we got modes[], chan, u, nick, and count of each relevant mode */
  981. /* check for mdop */
  982. if (me_op(chan)) {
  983. char tmp[1024] = "";
  984. if (!isserver[0] && role && (!u || (u && !u->bot))) {
  985. if (m && deops >= 3) {
  986. if (chan->mdop) {
  987. if (role < 5 && !chan_sentkick(m)) {
  988. m->flags |= SENTKICK;
  989. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_MASSDEOP));
  990. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  991. } else {
  992. if (u) {
  993. simple_snprintf(tmp, sizeof(tmp), "Mass deop on %s by %s", chan->dname, m->nick);
  994. deflag_user(u, DEFLAG_EVENT_MDOP, tmp, chan);
  995. }
  996. }
  997. reversing = mdop_reversing = 1;
  998. }
  999. if (channel_protect(chan))
  1000. do_protect(chan, "Mass Deop");
  1001. }
  1002. /* check for mop */
  1003. if (ops >= 3) {
  1004. if (chan->mop) {
  1005. if (m && !chan_sentkick(m)) {
  1006. if (role < 5) {
  1007. m->flags |= SENTKICK;
  1008. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_MANUALOP));
  1009. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  1010. } else {
  1011. if (u) {
  1012. simple_snprintf(tmp, sizeof(tmp), "Mass op on %s by %s", chan->dname, m->nick);
  1013. deflag_user(u, DEFLAG_EVENT_MOP, tmp, chan);
  1014. }
  1015. }
  1016. }
  1017. // Don't mass deop if protect is set, it'll happen anyway below
  1018. if (channel_bitch(chan) && !channel_protect(chan))
  1019. enforce_bitch(chan); /* deop quick! */
  1020. else
  1021. reversing = massop = 1; // Reverse via got_op
  1022. }
  1023. if (channel_protect(chan))
  1024. do_protect(chan, "Mass OP");
  1025. }
  1026. }
  1027. if (ops) {
  1028. int n = 0;
  1029. /* Check cookies */
  1030. if (u && m && u->bot && !channel_fastop(chan) && !channel_take(chan) && !cookies_disabled) {
  1031. int isbadop = 0;
  1032. bool failure = 0;
  1033. /* If no unbans or the -b is not the LAST mode, it's bad. */
  1034. if (unbans != 1 || (strncmp(modes[modecnt - 1], "-b", 2))) {
  1035. isbadop = BC_NOCOOKIE;
  1036. failure = 1;
  1037. } else {
  1038. /* Check the hash for each opped nick and punish the opped client if it fails
  1039. * Punish the opper lastly (and once)
  1040. */
  1041. for (i = 0; i < (modecnt - 1); i++) { /* Don't need to hit the -b */
  1042. if (msign == '+' && mmode == 'o') {
  1043. mv = assert_ismember(chan, mparam);
  1044. // Unknown client - I am desycned, don't punish or it may lead to fight
  1045. if (!mv) continue;
  1046. const char *cookie = &(modes[modecnt - 1][3]);
  1047. if ((isbadop = checkcookie(chan->dname, m, mv, cookie, i))) {
  1048. //if (!failure) { /* First failure */
  1049. failure = 1;
  1050. //}
  1051. /* Kick the opped client */
  1052. if (randint(7) == (unsigned int) i) {
  1053. if (!mv || !chan_sentkick(mv)) {
  1054. if (mv)
  1055. mv->flags |= SENTKICK;
  1056. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, mparam, kickprefix, response(RES_BADOPPED));
  1057. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  1058. }
  1059. }
  1060. }
  1061. }
  1062. }
  1063. }
  1064. if (unlikely(failure)) { /* One of the hashes failed! */
  1065. /* Did *I* do this heinous act? */
  1066. if (m->is_me) {
  1067. detected(DETECT_HIJACK, "Possible Hijack: bad cookie");
  1068. }
  1069. if (randint(7) == 0) {
  1070. /* Kick opper */
  1071. if (!chan_sentkick(m)) {
  1072. m->flags |= SENTKICK;
  1073. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_BADOP));
  1074. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  1075. }
  1076. simple_snprintf(tmp, sizeof(tmp), "%s MODE %s %s", m->from, chan->dname, modes[modecnt - 1]);
  1077. deflag_user(u, DEFLAG_EVENT_BADCOOKIE, tmp, chan);
  1078. }
  1079. /* Do the logging last as it can slow down the KICK pushing */
  1080. putlog(LOG_WARNING, "*", "%s opped in %s with bad cookie(%d): %s", m->nick, chan->dname, isbadop, msg);
  1081. if (isbadop == BC_NOCOOKIE)
  1082. putlog(LOG_WARN, "*", "Missing cookie: %s!%s MODE %s %s",
  1083. m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
  1084. else if (isbadop == BC_HASH)
  1085. putlog(LOG_WARN, "*", "Invalid cookie (bad hash): %s!%s MODE %s %s",
  1086. m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
  1087. else if (isbadop == BC_SLACK)
  1088. putlog(LOG_WARN, "*", "Invalid cookie (bad time): %s!%s MODE %s %s",
  1089. m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
  1090. else if (isbadop == BC_COUNTER)
  1091. putlog(LOG_WARN, "*", "Invalid cookie (bad count): %s!%s MODE %s %s",
  1092. m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
  1093. }
  1094. #ifdef DEBUG
  1095. else
  1096. putlog(LOG_DEBUG, "@", "Good op: %s", modes[modecnt - 1]);
  1097. #endif
  1098. }
  1099. /* manop */
  1100. if (chan->manop && u && !u->bot) {
  1101. i = 0;
  1102. switch (role) {
  1103. case 0:
  1104. break;
  1105. case 1:
  1106. if (m) {
  1107. /* Kick opper */
  1108. if (!chan_sentkick(m)) {
  1109. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_MANUALOP));
  1110. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  1111. m->flags |= SENTKICK;
  1112. }
  1113. simple_snprintf(tmp, sizeof(tmp), "%s MODE %s %s", m->from, chan->dname, modes[modecnt - 1]);
  1114. deflag_user(u, DEFLAG_EVENT_MANUALOP, tmp, chan);
  1115. }
  1116. break;
  1117. default:
  1118. /* KICK the opped */
  1119. n = role - 1;
  1120. i = 0;
  1121. while ((i < modecnt) && (n > 0)) {
  1122. if (modes[i] && !strncmp(modes[i], "+o", 2))
  1123. n--;
  1124. if (n)
  1125. i++;
  1126. }
  1127. if (!n) {
  1128. for (i = 0; i < modecnt; i++) {
  1129. if (msign == '+' && mmode == 'o' && !match_my_nick(mparam)) {
  1130. mv = ismember(chan, mparam);
  1131. if (!mv || !chan_sentkick(mv)) {
  1132. if (mv)
  1133. mv->flags |= SENTKICK;
  1134. const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, mparam, kickprefix, response(RES_MANUALOPPED));
  1135. dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
  1136. }
  1137. }
  1138. }
  1139. }
  1140. }
  1141. }
  1142. }
  1143. }
  1144. /* Now do the modes again, this time thoroughly... */
  1145. if (m && channel_active(chan) && me_op(chan)) {
  1146. if (chan_fakeop(m)) {
  1147. putlog(LOG_MODES, ch, "Mode change by fake op on %s! Reversing...", ch);
  1148. dprintf(DP_MODE, "KICK %s %s :%sAbusing ill-gained server ops\n", ch, m->nick, kickprefix);
  1149. m->flags |= SENTKICK;
  1150. reversing = 1;
  1151. } else if (!chan_hasop(m) && !channel_nodesynch(chan)) {
  1152. if (u && u->bot && chk_op(user, chan)) {
  1153. putlog(LOG_MODES, ch, "Mode change by friendly non-chanop on %s! Opping...", ch);
  1154. do_op(m, chan, 0, 0);
  1155. } else {
  1156. putlog(LOG_MODES, ch, "Mode change by non-chanop on %s! Reversing...", ch);
  1157. dprintf(DP_MODE, "KICK %s %s :%sAbusing desync\n", ch, m->nick, kickprefix);
  1158. m->flags |= SENTKICK;
  1159. reversing = 1;
  1160. }
  1161. }
  1162. }
  1163. for (i = 0; i < modecnt; i++) {
  1164. int todo = 0;
  1165. if (isserver[0] && bounce_modes)
  1166. reversing = 1;
  1167. switch (mmode) { /* parse mode */
  1168. case 'i':
  1169. todo = CHANINV;
  1170. if (isserver[0] && (bounce_modes))
  1171. reversing = 1;
  1172. break;
  1173. case 'p':
  1174. todo = CHANPRIV;
  1175. if (isserver[0] && (bounce_modes))
  1176. reversing = 1;
  1177. break;
  1178. case 's':
  1179. todo = CHANSEC;
  1180. if (isserver[0] && (bounce_modes))
  1181. reversing = 1;
  1182. break;
  1183. case 'm':
  1184. todo = CHANMODER;
  1185. if (isserver[0] && (bounce_modes))
  1186. reversing = 1;
  1187. break;
  1188. case 'c':
  1189. todo = CHANNOCLR;
  1190. if (isserver[0] && (bounce_modes))
  1191. reversing = 1;
  1192. break;
  1193. case 'C':
  1194. todo = CHANNOCTCP;
  1195. if (isserver[0] && (bounce_modes))
  1196. reversing = 1;
  1197. break;
  1198. case 'R':
  1199. todo = CHANREGON;
  1200. if (isserver[0] && (bounce_modes))
  1201. reversing = 1;
  1202. break;
  1203. case 'M':
  1204. todo = CHANMODR;
  1205. if (isserver[0] && (bounce_modes))
  1206. reversing = 1;
  1207. break;
  1208. case 'r':
  1209. todo = CHANLONLY;
  1210. if (isserver[0] && (bounce_modes))
  1211. reversing = 1;
  1212. break;
  1213. case 't':
  1214. todo = CHANTOPIC;
  1215. if (isserver[0] && (bounce_modes))
  1216. reversing = 1;
  1217. break;
  1218. case 'n':
  1219. todo = CHANNOMSG;
  1220. if (isserver[0] && (bounce_modes))
  1221. reversing = 1;
  1222. break;
  1223. case 'a':
  1224. todo = CHANANON;
  1225. if (isserver[0] && (bounce_modes))
  1226. reversing = 1;
  1227. break;
  1228. case 'q':
  1229. todo = CHANQUIET;
  1230. if (isserver[0] && (bounce_modes))
  1231. reversing = 1;
  1232. break;
  1233. case 'l':
  1234. if (isserver[0] && (bounce_modes))
  1235. reversing = 1;
  1236. if (msign == '-') {
  1237. if (channel_active(chan)) {
  1238. if ((reversing) && (chan->channel.maxmembers != 0)) {
  1239. simple_snprintf(s, sizeof(s), "%d", chan->channel.maxmembers);
  1240. add_mode(chan, '+', 'l', s);
  1241. } else if ((chan->limit_prot != 0) && !glob_master(user) && !chan_master(user)) {
  1242. simple_snprintf(s, sizeof(s), "%d", chan->limit_prot);
  1243. add_mode(chan, '+', 'l', s);
  1244. } else {
  1245. if (chan->limitraise && dolimit(chan) && (!chan_master(user) && !glob_master(user) && !glob_bot(user))) {
  1246. chan->channel.maxmembers = 0; /* set this to 0 so a new limit is generated */
  1247. raise_limit(chan);
  1248. }
  1249. }
  1250. }
  1251. chan->channel.maxmembers = 0;
  1252. } else { /* + */
  1253. if (*mparam == '\0')
  1254. break;
  1255. chan->channel.maxmembers = atoi(mparam);
  1256. if (channel_pending(chan))
  1257. break;
  1258. if (((reversing) &&
  1259. !(chan->mode_pls_prot & CHANLIMIT)) ||
  1260. ((chan->mode_mns_prot & CHANLIMIT) &&
  1261. !glob_bot(user) && !glob_master(user) && !chan_master(user)))
  1262. add_mode(chan, '-', 'l', "");
  1263. if ((chan->limit_prot != chan->channel.maxmembers) && (chan->mode_pls_prot & CHANLIMIT) && (chan->limit_prot != 0) &&
  1264. !glob_bot(user) && !glob_master(user) && !chan_master(user)) {
  1265. simple_snprintf(s, sizeof(s), "%d", chan->limit_prot);
  1266. add_mode(chan, '+', 'l', s);
  1267. }
  1268. if (chan->limitraise && dolimit(chan) && !glob_bot(user) && (!chan_master(user) && !glob_master(user)))
  1269. raise_limit(chan);
  1270. }
  1271. break;
  1272. case 'k':
  1273. if (msign == '+')
  1274. chan->channel.mode |= CHANKEY;
  1275. else
  1276. chan->channel.mode &= ~CHANKEY;
  1277. if (*mparam == '\0')
  1278. break;
  1279. if (msign == '+') {
  1280. my_setkey(chan, mparam);
  1281. if (channel_active(chan))
  1282. got_key(chan, mparam);
  1283. } else {
  1284. if (channel_active(chan)) {
  1285. if ((reversing) && (chan->channel.key[0]))
  1286. add_mode(chan, '+', 'k', chan->channel.key);
  1287. else if ((chan->key_prot[0]) && !glob_master(user) && !chan_master(user))
  1288. add_mode(chan, '+', 'k', chan->key_prot);
  1289. }
  1290. my_setkey(chan, NULL);
  1291. }
  1292. break;
  1293. case 'o':
  1294. if (!u || (u && !u->bot))
  1295. chan->channel.fighting++;
  1296. mv = assert_ismember(chan, mparam);
  1297. if (mv) {
  1298. if (msign == '+')
  1299. got_op(chan, m, mv);
  1300. else
  1301. got_deop(chan, m, mv, isserver);
  1302. }
  1303. break;
  1304. case 'v':
  1305. mv = assert_ismember(chan, mparam);
  1306. if (mv) {
  1307. bool dv = 0;
  1308. get_user_flagrec(mv->user, &victim, chan->dname, chan);
  1309. if (msign == '+') {
  1310. if (mv->flags & EVOICE) {
  1311. if (!chk_op(user, chan) && !chk_voice(victim, chan)) {
  1312. dv = 1;
  1313. } else {
  1314. mv->flags &= ~EVOICE;
  1315. }
  1316. }
  1317. mv->flags &= ~SENTVOICE;
  1318. mv->flags |= CHANVOICE;
  1319. if (channel_active(chan) && dovoice(chan)) {
  1320. if (dv || chk_devoice(victim) || (channel_voicebitch(chan) && !chk_voice(victim, chan))) {
  1321. add_mode(chan, '-', 'v', mv);
  1322. } else if (reversing) {
  1323. add_mode(chan, '-', 'v', mv);
  1324. }
  1325. }
  1326. } else if (msign == '-') {
  1327. mv->flags &= ~SENTDEVOICE;
  1328. mv->flags &= ~CHANVOICE;
  1329. if (channel_active(chan) && dovoice(chan) && !chan_hasop(mv)) {
  1330. /* revoice +v users */
  1331. if (chk_voice(victim, chan)) {
  1332. add_mode(chan, '+', 'v', mv);
  1333. } else if (reversing) {
  1334. add_mode(chan, '+', 'v', mv);
  1335. /* if they arent +v|v and VOICER is m+ then EVOICE them */
  1336. } else {
  1337. if (!match_my_nick(nick) && channel_voice(chan) &&
  1338. (chk_op(user, chan) || glob_bot(user)) &&
  1339. rfc_casecmp(nick, mparam)) {
  1340. /* if the user is not +q set them norEVOICE. */
  1341. if (!chan_quiet(victim)) {
  1342. set_devoice(chan, mv);
  1343. }
  1344. }
  1345. }
  1346. }
  1347. }
  1348. }
  1349. break;
  1350. case 'b':
  1351. if (!u || (u && !u->bot))
  1352. chan->channel.fighting++;
  1353. if (msign == '+')
  1354. got_ban(chan, m, mparam, isserver);
  1355. else
  1356. got_unban(chan, m, mparam);
  1357. break;
  1358. case 'e':
  1359. if (!u || (u && !u->bot))
  1360. chan->channel.fighting++;
  1361. if (msign == '+')
  1362. got_exempt(chan, m, mparam, isserver);
  1363. else
  1364. got_unexempt(chan, m, mparam);
  1365. break;
  1366. case 'I':
  1367. if (!u || (u && !u->bot))
  1368. chan->channel.fighting++;
  1369. if (msign == '+')
  1370. got_invite(chan, m, mparam, isserver);
  1371. else
  1372. got_uninvite(chan, m, mparam);
  1373. break;
  1374. }
  1375. if (todo) {
  1376. if (msign == '+')
  1377. chan->channel.mode |= todo;
  1378. else
  1379. chan->channel.mode &= ~todo;
  1380. if (channel_active(chan)) {
  1381. if ((((msign == '+') && (chan->mode_mns_prot & todo)) ||
  1382. ((msign == '-') && (chan->mode_pls_prot & todo))) &&
  1383. !glob_master(user) && !chan_master(user))
  1384. add_mode(chan, msign == '+' ? '-' : '+', mmode, "");
  1385. else if (reversing &&
  1386. ((msign == '+') || (chan->mode_pls_prot & todo)) &&
  1387. ((msign == '-') || (chan->mode_mns_prot & todo)))
  1388. add_mode(chan, msign == '+' ? '-' : '+', mmode, "");
  1389. }
  1390. }
  1391. }
  1392. // If reversing, dump the modes out
  1393. if (reversing)
  1394. flush_mode(chan, QUICK);
  1395. for (i = 0; i < modecnt; i++)
  1396. if (modes[i])
  1397. free(modes[i]);
  1398. free(modes);
  1399. if (chan->channel.do_opreq)
  1400. request_op(chan);
  1401. if (!me_op(chan) && isserver[0]) /* FIXME, WTF IS THIS? */
  1402. chan->ircnet_status |= CHAN_ASKEDMODES;
  1403. }
  1404. }
  1405. return 0;
  1406. }
  1407. /* vim: set sts=2 sw=2 ts=8 et: */