flags.c 17 KB

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