flags.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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. * flags.c -- handles:
  22. * all the flag matching/conversion functions in one neat package :)
  23. *
  24. */
  25. #include "common.h"
  26. #include "crypt.h"
  27. #include "src/mod/share.mod/share.h"
  28. #include "rfc1459.h"
  29. #include "userrec.h"
  30. #include "misc.h"
  31. #include "dccutil.h"
  32. #include "userent.h"
  33. #include "users.h"
  34. #include "chanprog.h"
  35. flag_t FLAG[128];
  36. struct rolecount role_counts[] = {
  37. {"voice", ROLE_VOICE, 1},
  38. {"flood", ROLE_FLOOD, 2},
  39. {"op", ROLE_OP, 1},
  40. {"deop", ROLE_DEOP, 1},
  41. {"kick", ROLE_KICK, 2},
  42. {"ban", ROLE_BAN, 2},
  43. {"topic", ROLE_TOPIC, 1},
  44. {"limit", ROLE_LIMIT, 1},
  45. {"resolv", ROLE_RESOLV, 2},
  46. {"revenge", ROLE_REVENGE, 3},
  47. {"chanmode", ROLE_CHANMODE, 1},
  48. {"protect", ROLE_PROTECT, 2},
  49. {NULL, 0, 0},
  50. };
  51. void
  52. init_flags()
  53. {
  54. unsigned char i;
  55. for (i = 0; i < 'A'; i++)
  56. FLAG[(int) i] = 0;
  57. for (; i <= 'Z'; i++)
  58. FLAG[(int) i] = (flag_t) 1 << (26 + (i - 'A'));
  59. for (; i < 'a'; i++)
  60. FLAG[(int) i] = 0;
  61. for (; i <= 'z'; i++)
  62. FLAG[(int) i] = (flag_t) 1 << (i - 'a');
  63. for (; i < 128; i++)
  64. FLAG[(int) i] = 0;
  65. }
  66. /* Some flags are mutually exclusive -- this roots them out
  67. */
  68. flag_t
  69. sanity_check(flag_t atr, int bot)
  70. {
  71. if (bot && (atr & (USER_PARTY | USER_MASTER | USER_OWNER | USER_ADMIN | USER_HUBA | USER_CHUBA)))
  72. atr &= ~(USER_PARTY | USER_MASTER | USER_OWNER | USER_ADMIN | USER_HUBA | USER_CHUBA);
  73. /* only bots should be there: */
  74. if (!bot && (atr & (BOT_DOLIMIT | BOT_DOVOICE | BOT_UPDATEHUB | BOT_CHANHUB | BOT_FLOODBOT )))
  75. atr &= ~(BOT_DOLIMIT | BOT_DOVOICE | BOT_UPDATEHUB | BOT_CHANHUB | BOT_FLOODBOT );
  76. if (atr & USER_AUTOOP)
  77. atr |= USER_OP;
  78. if ((atr & USER_OP) && (atr & USER_DEOP))
  79. atr &= ~(USER_OP | USER_DEOP);
  80. if ((atr & USER_AUTOOP) && (atr & USER_DEOP))
  81. atr &= ~(USER_AUTOOP | USER_DEOP);
  82. if ((atr & USER_VOICE) && (atr & USER_QUIET))
  83. atr &= ~(USER_VOICE | USER_QUIET);
  84. /* Can't be admin without also being owner and having hub access */
  85. if (atr & USER_ADMIN)
  86. atr |= USER_OWNER | USER_HUBA | USER_PARTY;
  87. /* Hub access gets chanhub access */
  88. if (atr & USER_HUBA)
  89. atr |= USER_CHUBA;
  90. if (atr & USER_OWNER) {
  91. atr |= USER_MASTER;
  92. }
  93. /* Master implies botmaster, op */
  94. if (atr & USER_MASTER)
  95. atr |= USER_OP;
  96. /* Can't be botnet master without party-line access */
  97. /* if (atr & USER_BOTMAST)
  98. atr |= USER_PARTY;
  99. */
  100. return atr;
  101. }
  102. /* Sanity check on channel attributes
  103. */
  104. flag_t
  105. chan_sanity_check(flag_t chatr, int bot)
  106. {
  107. /* these should only be global */
  108. if (chatr & (USER_PARTY | USER_ADMIN | USER_HUBA | USER_CHUBA | BOT_UPDATEHUB))
  109. chatr &= ~(USER_PARTY | USER_ADMIN | USER_HUBA | USER_CHUBA | BOT_UPDATEHUB);
  110. /* these should only be set on bots */
  111. if (!bot && (chatr & (BOT_DOLIMIT | BOT_DOVOICE | BOT_CHANHUB | BOT_FLOODBOT )))
  112. chatr &= ~(BOT_DOLIMIT | BOT_DOVOICE | BOT_CHANHUB | BOT_FLOODBOT );
  113. if ((chatr & USER_OP) && (chatr & USER_DEOP))
  114. chatr &= ~(USER_OP | USER_DEOP);
  115. if ((chatr & USER_AUTOOP) && (chatr & USER_DEOP))
  116. chatr &= ~(USER_AUTOOP | USER_DEOP);
  117. if ((chatr & USER_VOICE) && (chatr & USER_QUIET))
  118. chatr &= ~(USER_VOICE | USER_QUIET);
  119. /* Can't be channel owner without also being channel master */
  120. if (chatr & USER_OWNER)
  121. chatr |= USER_MASTER;
  122. /* Master implies op */
  123. if (chatr & USER_MASTER)
  124. chatr |= USER_OP;
  125. return chatr;
  126. }
  127. /* Get icon symbol for a user (depending on access level)
  128. *
  129. * (*) owner on any channel
  130. * (+) master on any channel
  131. * (%) botnet master
  132. * (@) op on any channel
  133. * (-) other
  134. */
  135. char
  136. geticon(int idx)
  137. {
  138. if (!dcc[idx].user)
  139. return '-';
  140. struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0 };
  141. get_user_flagrec(dcc[idx].user, &fr, NULL);
  142. if (glob_admin(fr))
  143. return '^';
  144. if (chan_owner(fr))
  145. return '*';
  146. if (chan_master(fr))
  147. return '+';
  148. if (chan_op(fr))
  149. return '@';
  150. return '-';
  151. }
  152. void
  153. break_down_flags(const char *string, struct flag_record *plus, struct flag_record *minus)
  154. {
  155. struct flag_record *which = plus;
  156. int chan = 0; /* 0 = glob, 1 = chan */
  157. int flags = plus->match;
  158. if (!(flags & FR_GLOBAL)) {
  159. if (flags & FR_CHAN)
  160. chan = 1;
  161. else
  162. return; /* We dont actually want any..huh? */
  163. }
  164. bzero(plus, sizeof(struct flag_record));
  165. if (minus)
  166. bzero(minus, sizeof(struct flag_record));
  167. plus->match = FR_OR; /* Default binding type OR */
  168. while (*string) {
  169. switch (*string) {
  170. case '+':
  171. which = plus;
  172. break;
  173. case '-':
  174. which = minus ? minus : plus;
  175. break;
  176. case '|':
  177. case '&':
  178. if (!chan) {
  179. if (*string == '|')
  180. plus->match = FR_OR;
  181. else
  182. plus->match = FR_AND;
  183. }
  184. which = plus;
  185. chan++;
  186. if (chan == 2)
  187. string = "";
  188. else if (chan == 3)
  189. chan = 1;
  190. break; /* switch() */
  191. default:
  192. {
  193. flag_t flagbit = FLAG[(int) *string];
  194. if (flagbit) {
  195. switch (chan) {
  196. case 0:
  197. /* which->global |= (flag_t) 1 << (*string - 'a'); */
  198. which->global |=flagbit;
  199. break;
  200. case 1:
  201. /* which->chan |= (flag_t) 1 << (*string - 'a'); */
  202. which->chan |= flagbit;
  203. break;
  204. }
  205. }
  206. }
  207. }
  208. string++;
  209. }
  210. for (which = plus; which; which = (which == plus ? minus : 0)) {
  211. if (flags & FR_BOT) {
  212. which->global &= BOT_VALID;
  213. which->chan &= BOT_CHAN_VALID;
  214. } else {
  215. which->global &= USER_VALID;
  216. which->chan &= USER_CHAN_VALID;
  217. }
  218. }
  219. plus->match |= flags;
  220. if (minus) {
  221. minus->match |= flags;
  222. if (!(plus->match & (FR_AND | FR_OR)))
  223. plus->match |= FR_OR;
  224. }
  225. }
  226. static int
  227. flag2str(char *string, flag_t flag)
  228. {
  229. unsigned char c;
  230. char *old = string;
  231. for (c = 0; c < 128; c++)
  232. if (flag & FLAG[(int) c])
  233. *string++ = c;
  234. if (string == old)
  235. *string++ = '-';
  236. return string - old;
  237. }
  238. int
  239. build_flags(char *string, struct flag_record *plus, struct flag_record *minus)
  240. {
  241. char *old = string;
  242. if (plus->match & FR_GLOBAL) {
  243. if (minus && plus->global)
  244. *string++ = '+';
  245. string += flag2str(string, plus->global);
  246. if (minus && minus->global) {
  247. *string++ = '-';
  248. string += flag2str(string, minus->global);
  249. }
  250. }
  251. if (plus->match & FR_CHAN) {
  252. if (plus->match & FR_GLOBAL)
  253. *string++ = (plus->match & FR_AND) ? '&' : '|';
  254. if (minus && plus->chan)
  255. *string++ = '+';
  256. string += flag2str(string, plus->chan);
  257. if (minus && minus->chan) {
  258. *string++ = '-';
  259. string += flag2str(string, minus->global);
  260. }
  261. }
  262. if (string == old) {
  263. *string++ = '-';
  264. *string = 0;
  265. return 0;
  266. }
  267. *string = 0;
  268. return string - old;
  269. }
  270. /* Returns 1 if flags match, 0 if they don't. */
  271. int
  272. flagrec_ok(struct flag_record *req, struct flag_record *have)
  273. {
  274. if (req->match & FR_AND) {
  275. return flagrec_eq(req, have);
  276. } else if (req->match & FR_OR) {
  277. int hav = have->global;
  278. /* no flags, is a match */
  279. if (!req->chan && !req->global)
  280. return 1;
  281. if (hav & req->global)
  282. return 1;
  283. if (have->chan & req->chan)
  284. return 1;
  285. return 0;
  286. }
  287. return 0;
  288. }
  289. /* Returns 1 if flags match, 0 if they don't. */
  290. int
  291. flagrec_eq(struct flag_record *req, struct flag_record *have)
  292. {
  293. if (req->match & FR_AND) {
  294. if (req->match & FR_GLOBAL) {
  295. if ((req->global &have->global) !=req->global)
  296. return 0;
  297. }
  298. if (req->match & FR_CHAN) {
  299. if ((req->chan & have->chan) != req->chan)
  300. return 0;
  301. }
  302. return 1;
  303. } else if (req->match & FR_OR) {
  304. if (!req->chan && !req->global)
  305. return 1;
  306. if (req->match & FR_GLOBAL) {
  307. if (have->global &req->global)
  308. return 1;
  309. }
  310. if (req->match & FR_CHAN) {
  311. if (have->chan & req->chan)
  312. return 1;
  313. }
  314. return 0;
  315. }
  316. return 0; /* fr0k3 binding, dont pass it */
  317. }
  318. void
  319. set_user_flagrec(struct userrec *u, struct flag_record *fr, const char *chname)
  320. {
  321. if (!u)
  322. return;
  323. struct chanuserrec *cr = NULL;
  324. flag_t oldflags = fr->match;
  325. char buffer[100] = "";
  326. struct chanset_t *ch;
  327. if (oldflags & FR_GLOBAL) {
  328. u->flags = fr->global;
  329. if (!noshare) {
  330. fr->match = FR_GLOBAL;
  331. build_flags(buffer, fr, NULL);
  332. shareout("a %s %s\n", u->handle, buffer);
  333. }
  334. }
  335. if ((oldflags & FR_CHAN) && chname) {
  336. for (cr = u->chanrec; cr; cr = cr->next)
  337. if (!rfc_casecmp(chname, cr->channel))
  338. break;
  339. ch = findchan_by_dname(chname);
  340. if (!cr && ch) {
  341. cr = (struct chanuserrec *) my_calloc(1, sizeof(struct chanuserrec));
  342. cr->next = u->chanrec;
  343. u->chanrec = cr;
  344. strlcpy(cr->channel, chname, sizeof cr->channel);
  345. }
  346. if (cr && ch) {
  347. cr->flags = fr->chan;
  348. if (!noshare) {
  349. fr->match = FR_CHAN;
  350. build_flags(buffer, fr, NULL);
  351. shareout("a %s %s %s\n", u->handle, buffer, chname);
  352. }
  353. }
  354. }
  355. fr->match = oldflags;
  356. }
  357. /* Always pass the dname (display name) to this function for chname <cybah>
  358. */
  359. void
  360. get_user_flagrec(const struct userrec *u, struct flag_record *fr, const char *chname, const struct chanset_t* chan)
  361. {
  362. fr->bot = 0;
  363. if (!u) {
  364. fr->global = fr->chan = 0;
  365. return;
  366. }
  367. if (u->bot)
  368. fr->bot = 1;
  369. fr->global = (fr->match & FR_GLOBAL) ? u->flags : 0;
  370. if (fr->match & FR_CHAN) {
  371. struct chanuserrec *cr = NULL;
  372. if ((fr->match & FR_ANYWH) || (fr->match & FR_ANYCH)) {
  373. if (fr->match & FR_ANYWH)
  374. fr->chan = u->flags;
  375. for (cr = u->chanrec; cr; cr = cr->next) {
  376. if (chan || findchan_by_dname(cr->channel)) {
  377. fr->chan |= cr->flags;
  378. }
  379. }
  380. } else {
  381. if (chname) {
  382. for (cr = u->chanrec; cr; cr = cr->next) {
  383. if (!rfc_casecmp(chname, cr->channel))
  384. break;
  385. }
  386. }
  387. if (cr) {
  388. fr->chan = cr->flags;
  389. } else {
  390. fr->chan = 0;
  391. }
  392. }
  393. }
  394. }
  395. /* private returns 0 if user has access, and 1 if they dont because of +private
  396. * This function does not check if the user has "op" access, it only checks if the user is
  397. * restricted by +private for the channel
  398. */
  399. int
  400. privchan(const struct flag_record fr, const struct chanset_t *chan, int type)
  401. {
  402. if (!chan || !channel_privchan(chan) || glob_bot(fr) || glob_owner(fr))
  403. return 0; /* user is implicitly not restricted by +private, they may however be lacking other flags */
  404. if (type == PRIV_OP) {
  405. /* |o implies all flags above. n| has access to all +private. Bots are exempt. */
  406. if (chan_op(fr))
  407. return 0;
  408. } else if (type == PRIV_VOICE) {
  409. if (chan_voice(fr) || chan_op(fr))
  410. return 0;
  411. }
  412. return 1; /* user is restricted by +private */
  413. }
  414. int
  415. real_chk_op(const struct flag_record fr, const struct chanset_t *chan, bool botbitch)
  416. {
  417. if (!chan && glob_op(fr))
  418. return 1;
  419. else if (!chan)
  420. return 0;
  421. if (!privchan(fr, chan, PRIV_OP) && !real_chk_deop(fr, chan, botbitch)) {
  422. if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr)))
  423. return 1;
  424. }
  425. return 0;
  426. }
  427. int
  428. chk_autoop(const struct flag_record fr, const struct chanset_t *chan)
  429. {
  430. if (glob_bot(fr))
  431. return 0;
  432. if (!chan || (!channel_take(chan) && !privchan(fr, chan, PRIV_OP) && chk_op(fr, chan) && !chk_deop(fr, chan))) {
  433. if (channel_autoop(chan) || chan_autoop(fr) || glob_autoop(fr))
  434. return 1;
  435. }
  436. return 0;
  437. }
  438. int
  439. real_chk_deop(const struct flag_record fr, const struct chanset_t *chan, bool botbitch)
  440. {
  441. if (chan && botbitch && channel_botbitch(chan) && !glob_bot(fr))
  442. return 1;
  443. if (chan_deop(fr) || (glob_deop(fr) && !chan_op(fr)))
  444. return 1;
  445. else
  446. return 0;
  447. }
  448. int
  449. doresolv(const struct chanset_t *chan)
  450. {
  451. if (!chan)
  452. return 0;
  453. if (chan->role & ROLE_RESOLV)
  454. return 1;
  455. struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_BOT, 0, 0, 0 };
  456. get_user_flagrec(conf.bot->u, &fr, chan->dname);
  457. if (glob_doresolv(fr) || chan_doresolv(fr))
  458. return 1;
  459. return 0;
  460. }
  461. int
  462. dovoice(const struct chanset_t *chan)
  463. {
  464. if (!chan)
  465. return 0;
  466. if (chan->role & ROLE_VOICE)
  467. return 1;
  468. struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_BOT, 0, 0, 0 };
  469. get_user_flagrec(conf.bot->u, &fr, chan->dname);
  470. if (glob_dovoice(fr) || chan_dovoice(fr))
  471. return 1;
  472. return 0;
  473. }
  474. int
  475. doflood(const struct chanset_t *chan)
  476. {
  477. if (!chan)
  478. return 0;
  479. if (chan->role & ROLE_FLOOD)
  480. return 1;
  481. struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_BOT, 0, 0, 0 };
  482. if (!chan)
  483. fr.match |= FR_ANYWH;
  484. get_user_flagrec(conf.bot->u, &fr, chan ? chan->dname : NULL);
  485. if (glob_doflood(fr) || chan_doflood(fr))
  486. return 1;
  487. return 0;
  488. }
  489. int
  490. dolimit(const struct chanset_t *chan)
  491. {
  492. if (!chan)
  493. return 0;
  494. if (chan->role & ROLE_LIMIT)
  495. return 1;
  496. struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_BOT, 0, 0, 0 };
  497. get_user_flagrec(conf.bot->u, &fr, chan->dname);
  498. if (glob_dolimit(fr) || chan_dolimit(fr))
  499. return 1;
  500. return 0;
  501. }
  502. int
  503. whois_access(struct userrec *user, struct userrec *whois_user)
  504. {
  505. if (user == whois_user)
  506. return 1;
  507. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0 }, whois = {
  508. FR_GLOBAL | FR_CHAN, 0, 0, 0};
  509. get_user_flagrec(user, &fr, NULL);
  510. get_user_flagrec(whois_user, &whois, NULL);
  511. /* Don't show hub bots from leaf bots. */
  512. if (!conf.bot->hub && whois_user->bot && bot_hublevel(whois_user) < 999)
  513. return 0;
  514. if (
  515. (isowner(whois_user->handle) && !isowner(user->handle)) ||
  516. (glob_admin(whois) && !glob_admin(fr)) ||
  517. (glob_owner(whois) && !glob_owner(fr)) ||
  518. (glob_master(whois) && !glob_master(fr)) ||
  519. (glob_bot(whois) && !glob_master(fr))
  520. )
  521. return 0;
  522. return 1;
  523. }
  524. deflag_t deflag_translate(const char *buf)
  525. {
  526. if (str_isdigit(buf))
  527. return (static_cast<deflag_t>(atoi(buf)));
  528. if (!strcasecmp(buf, "ignore"))
  529. return DEFLAG_IGNORE;
  530. else if (!strcasecmp(buf, "deop"))
  531. return DEFLAG_DEOP;
  532. else if (!strcasecmp(buf, "kick"))
  533. return DEFLAG_KICK;
  534. else if (!strcasecmp(buf, "delete") || !strcasecmp(buf, "remove"))
  535. return DEFLAG_DELETE;
  536. else if (!strcasecmp(buf, "react"))
  537. return DEFLAG_REACT;
  538. return DEFLAG_IGNORE;
  539. }
  540. void deflag_user(struct userrec *u, deflag_event_t why, const char *msg, const struct chanset_t *chan)
  541. {
  542. char tmp[50] = "", tmp2[1024] = "";
  543. struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  544. int which = 0;
  545. switch (why) {
  546. case DEFLAG_EVENT_BADCOOKIE:
  547. strlcpy(tmp, "Bad op cookie", sizeof(tmp));
  548. which = chan->bad_cookie;
  549. break;
  550. case DEFLAG_EVENT_MANUALOP:
  551. strlcpy(tmp, STR("Manual op in -manop channel"), sizeof(tmp));
  552. which = chan->manop;
  553. break;
  554. case DEFLAG_EVENT_REVENGE_DEOP:
  555. strlcpy(tmp, STR("Deopped bot in +revenge channel"), sizeof(tmp));
  556. which = chan->revenge;
  557. break;
  558. case DEFLAG_EVENT_REVENGE_KICK:
  559. strlcpy(tmp, STR("Kicked bot in +revenge channel"), sizeof(tmp));
  560. which = chan->revenge;
  561. break;
  562. case DEFLAG_EVENT_REVENGE_BAN:
  563. strlcpy(tmp, STR("Banned bot in +revenge channel"), sizeof(tmp));
  564. which = chan->revenge;
  565. break;
  566. case DEFLAG_EVENT_MDOP:
  567. strlcpy(tmp, "Mass deop", sizeof(tmp));
  568. which = chan->mdop;
  569. break;
  570. case DEFLAG_EVENT_MOP:
  571. strlcpy(tmp, "Mass op", sizeof(tmp));
  572. which = chan->mop;
  573. break;
  574. default:
  575. simple_snprintf(tmp, sizeof(tmp), "Reason #%i", why);
  576. }
  577. if (which == DEFLAG_DEOP) {
  578. putlog(LOG_WARN, "*", "Setting %s +d (%s): %s", u->handle, tmp, msg);
  579. simple_snprintf(tmp2, sizeof(tmp2), "+d: %s (%s)", tmp, msg);
  580. set_user(&USERENTRY_COMMENT, u, tmp2);
  581. get_user_flagrec(u, &fr, chan->dname);
  582. if (fr.global == USER_DEOP)
  583. fr.match &= ~FR_GLOBAL;
  584. else
  585. fr.global = USER_DEOP;
  586. if (fr.chan == USER_DEOP)
  587. fr.match &= ~FR_CHAN;
  588. else
  589. fr.chan = USER_DEOP;
  590. /* did anything change? */
  591. if (fr.match)
  592. set_user_flagrec(u, &fr, chan->dname);
  593. } else if (which == DEFLAG_KICK) {
  594. putlog(LOG_WARN, "*", "Setting %s +dk (%s): %s", u->handle, tmp, msg);
  595. simple_snprintf(tmp2, sizeof(tmp2), "+dk: %s (%s)", tmp, msg);
  596. set_user(&USERENTRY_COMMENT, u, tmp2);
  597. get_user_flagrec(u, &fr, chan->dname);
  598. if (fr.global == (USER_DEOP|USER_KICK))
  599. fr.match &= ~FR_GLOBAL;
  600. else
  601. fr.global = USER_DEOP | USER_KICK;
  602. if (fr.chan == (USER_DEOP|USER_KICK))
  603. fr.match &= ~FR_CHAN;
  604. else
  605. fr.chan = USER_DEOP | USER_KICK;
  606. /* did anything change */
  607. if (fr.match)
  608. set_user_flagrec(u, &fr, chan->dname);
  609. } else if (which == DEFLAG_DELETE) {
  610. putlog(LOG_WARN, "*", "Deleting %s (%s): %s", u->handle, tmp, msg);
  611. deluser(u->handle);
  612. } else {
  613. putlog(LOG_WARN, "*", "No user flag effects for %s (%s): %s", u->handle, tmp, msg);
  614. simple_snprintf(tmp2, sizeof(tmp2), "Warning: %s (%s)", tmp, msg);
  615. set_user(&USERENTRY_COMMENT, u, tmp2);
  616. }
  617. }
  618. /* vim: set sts=2 sw=2 ts=8 et: */