PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/src/userrec.c

https://github.com/eggheads/eggdrop-1.8
C | 927 lines | 749 code | 93 blank | 85 comment | 247 complexity | 644efcf74a53d20d057e1c85f25d47b4 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * userrec.c -- handles:
  3. * add_q() del_q() str2flags() flags2str() str2chflags() chflags2str()
  4. * a bunch of functions to find and change user records
  5. * change and check user (and channel-specific) flags
  6. *
  7. * $Id: userrec.c,v 1.2 2010/10/24 13:22:40 pseudo Exp $
  8. */
  9. /*
  10. * Copyright (C) 1997 Robey Pointer
  11. * Copyright (C) 1999 - 2010 Eggheads Development Team
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License
  15. * as published by the Free Software Foundation; either version 2
  16. * of the License, or (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  26. */
  27. #include <sys/stat.h>
  28. #include "main.h"
  29. #include "users.h"
  30. #include "chan.h"
  31. #include "modules.h"
  32. #include "tandem.h"
  33. extern struct dcc_t *dcc;
  34. extern struct chanset_t *chanset;
  35. extern int default_flags, default_uflags, quiet_save, dcc_total, share_greet;
  36. extern char userfile[], ver[], botnetnick[];
  37. extern time_t now;
  38. int noshare = 1; /* don't send out to sharebots */
  39. struct userrec *userlist = NULL; /* user records are stored here */
  40. struct userrec *lastuser = NULL; /* last accessed user record */
  41. maskrec *global_bans = NULL, *global_exempts = NULL, *global_invites = NULL;
  42. struct igrec *global_ign = NULL;
  43. int cache_hit = 0, cache_miss = 0; /* temporary cache accounting */
  44. int strict_host = 1;
  45. int userfile_perm = 0600; /* Userfile permissions
  46. * (default rw-------) */
  47. void *_user_malloc(int size, const char *file, int line)
  48. {
  49. #ifdef DEBUG_MEM
  50. char x[1024];
  51. const char *p;
  52. p = strrchr(file, '/');
  53. simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
  54. return n_malloc(size, x, line);
  55. #else
  56. return nmalloc(size);
  57. #endif
  58. }
  59. void *_user_realloc(void *ptr, int size, const char *file, int line)
  60. {
  61. #ifdef DEBUG_MEM
  62. char x[1024];
  63. const char *p;
  64. p = strrchr(file, '/');
  65. simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
  66. return n_realloc(ptr, size, x, line);
  67. #else
  68. return nrealloc(ptr, size);
  69. #endif
  70. }
  71. inline int expmem_mask(struct maskrec *m)
  72. {
  73. int result = 0;
  74. for (; m; m = m->next) {
  75. result += sizeof(struct maskrec);
  76. result += strlen(m->mask) + 1;
  77. if (m->user)
  78. result += strlen(m->user) + 1;
  79. if (m->desc)
  80. result += strlen(m->desc) + 1;
  81. }
  82. return result;
  83. }
  84. /* Memory we should be using
  85. */
  86. int expmem_users()
  87. {
  88. int tot;
  89. struct userrec *u;
  90. struct chanuserrec *ch;
  91. struct chanset_t *chan;
  92. struct user_entry *ue;
  93. struct igrec *i;
  94. tot = 0;
  95. for (u = userlist; u; u = u->next) {
  96. for (ch = u->chanrec; ch; ch = ch->next) {
  97. tot += sizeof(struct chanuserrec);
  98. if (ch->info != NULL)
  99. tot += strlen(ch->info) + 1;
  100. }
  101. tot += sizeof(struct userrec);
  102. for (ue = u->entries; ue; ue = ue->next) {
  103. tot += sizeof(struct user_entry);
  104. if (ue->name) {
  105. tot += strlen(ue->name) + 1;
  106. tot += list_type_expmem(ue->u.list);
  107. } else
  108. tot += ue->type->expmem(ue);
  109. }
  110. }
  111. /* Account for each channel's masks */
  112. for (chan = chanset; chan; chan = chan->next) {
  113. /* Account for each channel's ban-list user */
  114. tot += expmem_mask(chan->bans);
  115. /* Account for each channel's exempt-list user */
  116. tot += expmem_mask(chan->exempts);
  117. /* Account for each channel's invite-list user */
  118. tot += expmem_mask(chan->invites);
  119. }
  120. tot += expmem_mask(global_bans);
  121. tot += expmem_mask(global_exempts);
  122. tot += expmem_mask(global_invites);
  123. for (i = global_ign; i; i = i->next) {
  124. tot += sizeof(struct igrec);
  125. tot += strlen(i->igmask) + 1;
  126. if (i->user)
  127. tot += strlen(i->user) + 1;
  128. if (i->msg)
  129. tot += strlen(i->msg) + 1;
  130. }
  131. return tot;
  132. }
  133. int count_users(struct userrec *bu)
  134. {
  135. int tot = 0;
  136. struct userrec *u;
  137. for (u = bu; u; u = u->next)
  138. tot++;
  139. return tot;
  140. }
  141. /* Removes a username prefix (~+-^=) from a userhost.
  142. * e.g, "nick!~user@host" -> "nick!user@host"
  143. */
  144. char *fixfrom(char *s)
  145. {
  146. static char uhost[UHOSTLEN];
  147. char *p = uhost;
  148. if (!s || !*s || strict_host)
  149. return s;
  150. while (*s) {
  151. *p++ = *s;
  152. if (*s == '!' && strchr("~+-^=", s[1]) && s[2] != '@') {
  153. strcpy(p, s + 2);
  154. return uhost;
  155. }
  156. s++;
  157. }
  158. *p = 0;
  159. return uhost;
  160. }
  161. struct userrec *check_dcclist_hand(char *handle)
  162. {
  163. int i;
  164. for (i = 0; i < dcc_total; i++)
  165. if (!egg_strcasecmp(dcc[i].nick, handle))
  166. return dcc[i].user;
  167. return NULL;
  168. }
  169. struct userrec *get_user_by_handle(struct userrec *bu, char *handle)
  170. {
  171. struct userrec *u, *ret;
  172. if (!handle)
  173. return NULL;
  174. /* FIXME: This should be done outside of this function. */
  175. rmspace(handle);
  176. if (!handle[0] || (handle[0] == '*'))
  177. return NULL;
  178. if (bu == userlist) {
  179. if (lastuser && !egg_strcasecmp(lastuser->handle, handle)) {
  180. cache_hit++;
  181. return lastuser;
  182. }
  183. ret = check_dcclist_hand(handle);
  184. if (ret) {
  185. cache_hit++;
  186. return ret;
  187. }
  188. ret = check_chanlist_hand(handle);
  189. if (ret) {
  190. cache_hit++;
  191. return ret;
  192. }
  193. cache_miss++;
  194. }
  195. for (u = bu; u; u = u->next)
  196. if (!egg_strcasecmp(u->handle, handle)) {
  197. if (bu == userlist)
  198. lastuser = u;
  199. return u;
  200. }
  201. return NULL;
  202. }
  203. /* Fix capitalization, etc
  204. */
  205. void correct_handle(char *handle)
  206. {
  207. struct userrec *u;
  208. u = get_user_by_handle(userlist, handle);
  209. if (u == NULL || handle == u->handle)
  210. return;
  211. strcpy(handle, u->handle);
  212. }
  213. /* This will be usefull in a lot of places, much more code re-use so we
  214. * endup with a smaller executable bot. <cybah>
  215. */
  216. void clear_masks(maskrec *m)
  217. {
  218. maskrec *temp = NULL;
  219. for (; m; m = temp) {
  220. temp = m->next;
  221. if (m->mask)
  222. nfree(m->mask);
  223. if (m->user)
  224. nfree(m->user);
  225. if (m->desc)
  226. nfree(m->desc);
  227. nfree(m);
  228. }
  229. }
  230. void clear_userlist(struct userrec *bu)
  231. {
  232. struct userrec *u, *v;
  233. int i;
  234. for (u = bu; u; u = v) {
  235. v = u->next;
  236. freeuser(u);
  237. }
  238. if (userlist == bu) {
  239. struct chanset_t *cst;
  240. for (i = 0; i < dcc_total; i++)
  241. dcc[i].user = NULL;
  242. clear_chanlist();
  243. lastuser = NULL;
  244. while (global_ign)
  245. delignore(global_ign->igmask);
  246. clear_masks(global_bans);
  247. clear_masks(global_exempts);
  248. clear_masks(global_invites);
  249. global_exempts = global_invites = global_bans = NULL;
  250. for (cst = chanset; cst; cst = cst->next) {
  251. clear_masks(cst->bans);
  252. clear_masks(cst->exempts);
  253. clear_masks(cst->invites);
  254. cst->bans = cst->exempts = cst->invites = NULL;
  255. }
  256. }
  257. /* Remember to set your userlist to NULL after calling this */
  258. }
  259. /* Find CLOSEST host match
  260. * (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!)
  261. *
  262. * Checks the chanlist first, to possibly avoid needless search.
  263. */
  264. struct userrec *get_user_by_host(char *host)
  265. {
  266. struct userrec *u, *ret;
  267. struct list_type *q;
  268. int cnt, i;
  269. char host2[UHOSTLEN];
  270. if (host == NULL)
  271. return NULL;
  272. rmspace(host);
  273. if (!host[0])
  274. return NULL;
  275. ret = check_chanlist(host);
  276. cnt = 0;
  277. if (ret != NULL) {
  278. cache_hit++;
  279. return ret;
  280. }
  281. cache_miss++;
  282. strncpyz(host2, host, sizeof host2);
  283. host = fixfrom(host);
  284. for (u = userlist; u; u = u->next) {
  285. q = get_user(&USERENTRY_HOSTS, u);
  286. for (; q; q = q->next) {
  287. i = match_useraddr(q->extra, host);
  288. if (i > cnt) {
  289. ret = u;
  290. cnt = i;
  291. }
  292. }
  293. }
  294. if (ret != NULL) {
  295. lastuser = ret;
  296. set_chanlist(host2, ret);
  297. }
  298. return ret;
  299. }
  300. /* use fixfrom() or dont? (drummer)
  301. */
  302. struct userrec *get_user_by_equal_host(char *host)
  303. {
  304. struct userrec *u;
  305. struct list_type *q;
  306. for (u = userlist; u; u = u->next)
  307. for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next)
  308. if (!rfc_casecmp(q->extra, host))
  309. return u;
  310. return NULL;
  311. }
  312. /* Try: pass_match_by_host("-",host)
  313. * will return 1 if no password is set for that host
  314. */
  315. int u_pass_match(struct userrec *u, char *pass)
  316. {
  317. char *cmp, new[32];
  318. if (!u)
  319. return 0;
  320. cmp = get_user(&USERENTRY_PASS, u);
  321. if (!cmp && (!pass[0] || (pass[0] == '-')))
  322. return 1;
  323. if (!cmp || !pass || !pass[0] || (pass[0] == '-'))
  324. return 0;
  325. if (u->flags & USER_BOT) {
  326. if (!strcmp(cmp, pass))
  327. return 1;
  328. } else {
  329. if (strlen(pass) > 30)
  330. pass[30] = 0;
  331. encrypt_pass(pass, new);
  332. if (!strcmp(cmp, new))
  333. return 1;
  334. }
  335. return 0;
  336. }
  337. int write_user(struct userrec *u, FILE *f, int idx)
  338. {
  339. char s[181];
  340. long tv;
  341. struct chanuserrec *ch;
  342. struct chanset_t *cst;
  343. struct user_entry *ue;
  344. struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
  345. fr.global = u->flags;
  346. fr.udef_global = u->flags_udef;
  347. build_flags(s, &fr, NULL);
  348. if (fprintf(f, "%-10s - %-24s\n", u->handle, s) == EOF)
  349. return 0;
  350. for (ch = u->chanrec; ch; ch = ch->next) {
  351. cst = findchan_by_dname(ch->channel);
  352. if (cst && ((idx < 0) || channel_shared(cst))) {
  353. if (idx >= 0) {
  354. fr.match = (FR_CHAN | FR_BOT);
  355. get_user_flagrec(dcc[idx].user, &fr, ch->channel);
  356. } else
  357. fr.chan = BOT_SHARE;
  358. if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
  359. fr.match = FR_CHAN;
  360. fr.chan = ch->flags;
  361. fr.udef_chan = ch->flags_udef;
  362. build_flags(s, &fr, NULL);
  363. tv = ch->laston;
  364. if (fprintf(f, "! %-20s %lu %-10s %s\n", ch->channel, tv, s,
  365. (((idx < 0) || share_greet) && ch->info) ? ch->info : "") == EOF)
  366. return 0;
  367. }
  368. }
  369. }
  370. for (ue = u->entries; ue; ue = ue->next) {
  371. if (ue->name) {
  372. struct list_type *lt;
  373. for (lt = ue->u.list; lt; lt = lt->next)
  374. if (fprintf(f, "--%s %s\n", ue->name, lt->extra) == EOF)
  375. return 0;
  376. } else if (!ue->type->write_userfile(f, u, ue))
  377. return 0;
  378. }
  379. return 1;
  380. }
  381. int write_ignores(FILE *f, int idx)
  382. {
  383. struct igrec *i;
  384. char *mask;
  385. long expire, added;
  386. if (global_ign)
  387. if (fprintf(f, IGNORE_NAME " - -\n") == EOF) /* Daemus */
  388. return 0;
  389. for (i = global_ign; i; i = i->next) {
  390. mask = str_escape(i->igmask, ':', '\\');
  391. expire = i->expire;
  392. added = i->added;
  393. if (!mask ||
  394. fprintf(f, "- %s:%s%lu:%s:%lu:%s\n", mask,
  395. (i->flags & IGREC_PERM) ? "+" : "", expire,
  396. i->user ? i->user : botnetnick, added,
  397. i->msg ? i->msg : "") == EOF) {
  398. if (mask)
  399. nfree(mask);
  400. return 0;
  401. }
  402. nfree(mask);
  403. }
  404. return 1;
  405. }
  406. int sort_compare(struct userrec *a, struct userrec *b)
  407. {
  408. /* Order by flags, then alphabetically
  409. * first bots: +h / +a / +l / other bots
  410. * then users: +n / +m / +o / other users
  411. * return true if (a > b)
  412. */
  413. if (a->flags & b->flags & USER_BOT) {
  414. if (~bot_flags(a) & bot_flags(b) & BOT_HUB)
  415. return 1;
  416. if (bot_flags(a) & ~bot_flags(b) & BOT_HUB)
  417. return 0;
  418. if (~bot_flags(a) & bot_flags(b) & BOT_ALT)
  419. return 1;
  420. if (bot_flags(a) & ~bot_flags(b) & BOT_ALT)
  421. return 0;
  422. if (~bot_flags(a) & bot_flags(b) & BOT_LEAF)
  423. return 1;
  424. if (bot_flags(a) & ~bot_flags(b) & BOT_LEAF)
  425. return 0;
  426. } else {
  427. if (~a->flags & b->flags & USER_BOT)
  428. return 1;
  429. if (a->flags & ~b->flags & USER_BOT)
  430. return 0;
  431. if (~a->flags & b->flags & USER_OWNER)
  432. return 1;
  433. if (a->flags & ~b->flags & USER_OWNER)
  434. return 0;
  435. if (~a->flags & b->flags & USER_MASTER)
  436. return 1;
  437. if (a->flags & ~b->flags & USER_MASTER)
  438. return 0;
  439. if (~a->flags & b->flags & USER_OP)
  440. return 1;
  441. if (a->flags & ~b->flags & USER_OP)
  442. return 0;
  443. if (~a->flags & b->flags & USER_HALFOP)
  444. return 1;
  445. if (a->flags & ~b->flags & USER_HALFOP)
  446. return 0;
  447. }
  448. return (egg_strcasecmp(a->handle, b->handle) > 0);
  449. }
  450. void sort_userlist()
  451. {
  452. int again;
  453. struct userrec *last, *p, *c, *n;
  454. again = 1;
  455. last = NULL;
  456. while ((userlist != last) && (again)) {
  457. p = NULL;
  458. c = userlist;
  459. n = c->next;
  460. again = 0;
  461. while (n != last) {
  462. if (sort_compare(c, n)) {
  463. again = 1;
  464. c->next = n->next;
  465. n->next = c;
  466. if (p == NULL)
  467. userlist = n;
  468. else
  469. p->next = n;
  470. }
  471. p = c;
  472. c = n;
  473. n = n->next;
  474. }
  475. last = c;
  476. }
  477. }
  478. /* Rewrite the entire user file. Call USERFILE hook as well, probably
  479. * causing the channel file to be rewritten as well.
  480. */
  481. void write_userfile(int idx)
  482. {
  483. FILE *f;
  484. char *new_userfile;
  485. char s1[81];
  486. time_t tt;
  487. struct userrec *u;
  488. int ok;
  489. if (userlist == NULL)
  490. return; /* No point in saving userfile */
  491. new_userfile = nmalloc(strlen(userfile) + 5);
  492. sprintf(new_userfile, "%s~new", userfile);
  493. f = fopen(new_userfile, "w");
  494. chmod(new_userfile, userfile_perm);
  495. if (f == NULL) {
  496. putlog(LOG_MISC, "*", USERF_ERRWRITE);
  497. nfree(new_userfile);
  498. return;
  499. }
  500. if (!quiet_save)
  501. putlog(LOG_MISC, "*", USERF_WRITING);
  502. sort_userlist();
  503. tt = now;
  504. strcpy(s1, ctime(&tt));
  505. fprintf(f, "#4v: %s -- %s -- written %s", ver, botnetnick, s1);
  506. ok = 1;
  507. for (u = userlist; u && ok; u = u->next)
  508. if (!write_user(u, f, idx))
  509. ok = 0;
  510. if (!ok || !write_ignores(f, -1) || fflush(f)) {
  511. putlog(LOG_MISC, "*", "%s (%s)", USERF_ERRWRITE, strerror(ferror(f)));
  512. fclose(f);
  513. nfree(new_userfile);
  514. return;
  515. }
  516. fclose(f);
  517. call_hook(HOOK_USERFILE);
  518. movefile(new_userfile, userfile);
  519. nfree(new_userfile);
  520. }
  521. int change_handle(struct userrec *u, char *newh)
  522. {
  523. int i;
  524. char s[HANDLEN + 1];
  525. if (!u)
  526. return 0;
  527. /* Nothing that will confuse the userfile */
  528. if (!newh[1] && strchr(BADHANDCHARS, newh[0]))
  529. return 0;
  530. check_tcl_nkch(u->handle, newh);
  531. /* Yes, even send bot nick changes now: */
  532. if (!noshare && !(u->flags & USER_UNSHARED))
  533. shareout(NULL, "h %s %s\n", u->handle, newh);
  534. strncpyz(s, u->handle, sizeof s);
  535. strncpyz(u->handle, newh, sizeof u->handle);
  536. for (i = 0; i < dcc_total; i++)
  537. if ((dcc[i].type == &DCC_CHAT || dcc[i].type == &DCC_CHAT_PASS) &&
  538. !egg_strcasecmp(dcc[i].nick, s)) {
  539. strncpyz(dcc[i].nick, newh, sizeof dcc[i].nick);
  540. if (dcc[i].type == &DCC_CHAT && dcc[i].u.chat->channel >= 0) {
  541. chanout_but(-1, dcc[i].u.chat->channel,
  542. "*** Handle change: %s -> %s\n", s, newh);
  543. if (dcc[i].u.chat->channel < GLOBAL_CHANS)
  544. botnet_send_nkch(i, s);
  545. }
  546. }
  547. return 1;
  548. }
  549. extern int noxtra;
  550. struct userrec *adduser(struct userrec *bu, char *handle, char *host,
  551. char *pass, int flags)
  552. {
  553. struct userrec *u, *x;
  554. struct xtra_key *xk;
  555. int oldshare = noshare;
  556. long tv;
  557. noshare = 1;
  558. u = nmalloc(sizeof *u);
  559. /* u->next=bu; bu=u; */
  560. strncpyz(u->handle, handle, sizeof u->handle);
  561. u->next = NULL;
  562. u->chanrec = NULL;
  563. u->entries = NULL;
  564. if (flags != USER_DEFAULT) { /* drummer */
  565. u->flags = flags;
  566. u->flags_udef = 0;
  567. } else {
  568. u->flags = default_flags;
  569. u->flags_udef = default_uflags;
  570. }
  571. set_user(&USERENTRY_PASS, u, pass);
  572. if (!noxtra) {
  573. char *now2;
  574. xk = nmalloc(sizeof *xk);
  575. xk->key = nmalloc(8);
  576. strcpy(xk->key, "created");
  577. now2 = nmalloc(15);
  578. tv = now;
  579. sprintf(now2, "%li", tv);
  580. xk->data = nmalloc(strlen(now2) + 1);
  581. sprintf(xk->data, "%li", tv);
  582. set_user(&USERENTRY_XTRA, u, xk);
  583. nfree(now2);
  584. }
  585. /* Strip out commas -- they're illegal */
  586. if (host && host[0]) {
  587. char *p;
  588. /* About this fixfrom():
  589. * We should use this fixfrom before every call of adduser()
  590. * but its much easier to use here... (drummer)
  591. * Only use it if we have a host :) (dw)
  592. */
  593. host = fixfrom(host);
  594. p = strchr(host, ',');
  595. while (p != NULL) {
  596. *p = '?';
  597. p = strchr(host, ',');
  598. }
  599. set_user(&USERENTRY_HOSTS, u, host);
  600. } else
  601. set_user(&USERENTRY_HOSTS, u, "none");
  602. if (bu == userlist)
  603. clear_chanlist();
  604. noshare = oldshare;
  605. if ((!noshare) && (handle[0] != '*') && (!(flags & USER_UNSHARED)) &&
  606. (bu == userlist)) {
  607. struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
  608. char x[100];
  609. fr.global = u->flags;
  610. fr.udef_global = u->flags_udef;
  611. build_flags(x, &fr, 0);
  612. shareout(NULL, "n %s %s %s %s\n", handle, host && host[0] ? host : "none",
  613. pass, x);
  614. }
  615. if (bu == NULL)
  616. bu = u;
  617. else {
  618. if ((bu == userlist) && (lastuser != NULL))
  619. x = lastuser;
  620. else
  621. x = bu;
  622. while (x->next != NULL)
  623. x = x->next;
  624. x->next = u;
  625. if (bu == userlist)
  626. lastuser = u;
  627. }
  628. return bu;
  629. }
  630. void freeuser(struct userrec *u)
  631. {
  632. struct user_entry *ue, *ut;
  633. struct chanuserrec *ch, *z;
  634. if (u == NULL)
  635. return;
  636. ch = u->chanrec;
  637. while (ch) {
  638. z = ch;
  639. ch = ch->next;
  640. if (z->info != NULL)
  641. nfree(z->info);
  642. nfree(z);
  643. }
  644. u->chanrec = NULL;
  645. for (ue = u->entries; ue; ue = ut) {
  646. ut = ue->next;
  647. if (ue->name) {
  648. struct list_type *lt, *ltt;
  649. for (lt = ue->u.list; lt; lt = ltt) {
  650. ltt = lt->next;
  651. nfree(lt->extra);
  652. nfree(lt);
  653. }
  654. nfree(ue->name);
  655. nfree(ue);
  656. } else
  657. ue->type->kill(ue);
  658. }
  659. nfree(u);
  660. }
  661. int deluser(char *handle)
  662. {
  663. struct userrec *u = userlist, *prev = NULL;
  664. int fnd = 0;
  665. while ((u != NULL) && (!fnd)) {
  666. if (!egg_strcasecmp(u->handle, handle))
  667. fnd = 1;
  668. else {
  669. prev = u;
  670. u = u->next;
  671. }
  672. }
  673. if (!fnd)
  674. return 0;
  675. if (prev == NULL)
  676. userlist = u->next;
  677. else
  678. prev->next = u->next;
  679. if (!noshare && (handle[0] != '*') && !(u->flags & USER_UNSHARED))
  680. shareout(NULL, "k %s\n", handle);
  681. for (fnd = 0; fnd < dcc_total; fnd++)
  682. if (dcc[fnd].user == u)
  683. dcc[fnd].user = 0; /* Clear any dcc users for this entry,
  684. * null is safe-ish */
  685. clear_chanlist();
  686. freeuser(u);
  687. lastuser = NULL;
  688. return 1;
  689. }
  690. int delhost_by_handle(char *handle, char *host)
  691. {
  692. struct userrec *u;
  693. struct list_type *q, *qnext, *qprev;
  694. struct user_entry *e = NULL;
  695. int i = 0;
  696. u = get_user_by_handle(userlist, handle);
  697. if (!u)
  698. return 0;
  699. q = get_user(&USERENTRY_HOSTS, u);
  700. qprev = q;
  701. if (q) {
  702. if (!rfc_casecmp(q->extra, host)) {
  703. e = find_user_entry(&USERENTRY_HOSTS, u);
  704. e->u.extra = q->next;
  705. nfree(q->extra);
  706. nfree(q);
  707. i++;
  708. qprev = NULL;
  709. q = e->u.extra;
  710. } else
  711. q = q->next;
  712. while (q) {
  713. qnext = q->next;
  714. if (!rfc_casecmp(q->extra, host)) {
  715. if (qprev)
  716. qprev->next = q->next;
  717. else if (e) {
  718. e->u.extra = q->next;
  719. qprev = NULL;
  720. }
  721. nfree(q->extra);
  722. nfree(q);
  723. i++;
  724. } else
  725. qprev = q;
  726. q = qnext;
  727. }
  728. }
  729. if (!qprev)
  730. set_user(&USERENTRY_HOSTS, u, "none");
  731. if (!noshare && i && !(u->flags & USER_UNSHARED))
  732. shareout(NULL, "-h %s %s\n", handle, host);
  733. clear_chanlist();
  734. return i;
  735. }
  736. void addhost_by_handle(char *handle, char *host)
  737. {
  738. struct userrec *u = get_user_by_handle(userlist, handle);
  739. set_user(&USERENTRY_HOSTS, u, host);
  740. /* u will be cached, so really no overhead, even tho this looks dumb: */
  741. if ((!noshare) && !(u->flags & USER_UNSHARED)) {
  742. if (u->flags & USER_BOT)
  743. shareout(NULL, "+bh %s %s\n", handle, host);
  744. else
  745. shareout(NULL, "+h %s %s\n", handle, host);
  746. }
  747. clear_chanlist();
  748. }
  749. void touch_laston(struct userrec *u, char *where, time_t timeval)
  750. {
  751. if (!u)
  752. return;
  753. if (timeval > 1) {
  754. struct laston_info *li = get_user(&USERENTRY_LASTON, u);
  755. if (!li)
  756. li = nmalloc(sizeof *li);
  757. else if (li->lastonplace)
  758. nfree(li->lastonplace);
  759. li->laston = timeval;
  760. if (where) {
  761. li->lastonplace = nmalloc(strlen(where) + 1);
  762. strcpy(li->lastonplace, where);
  763. } else
  764. li->lastonplace = NULL;
  765. set_user(&USERENTRY_LASTON, u, li);
  766. } else if (timeval == 1)
  767. set_user(&USERENTRY_LASTON, u, 0);
  768. }
  769. /* Go through all channel records and try to find a matching
  770. * nick. Will return the user's user record if that is known
  771. * to the bot. (Fabian)
  772. *
  773. * Warning: This is unreliable by concept!
  774. */
  775. struct userrec *get_user_by_nick(char *nick)
  776. {
  777. struct chanset_t *chan;
  778. memberlist *m;
  779. for (chan = chanset; chan; chan = chan->next) {
  780. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  781. if (!rfc_casecmp(nick, m->nick)) {
  782. char word[512];
  783. egg_snprintf(word, sizeof word, "%s!%s", m->nick, m->userhost);
  784. /* No need to check the return value ourself */
  785. return get_user_by_host(word);;
  786. }
  787. }
  788. }
  789. /* Sorry, no matches */
  790. return NULL;
  791. }
  792. void user_del_chan(char *dname)
  793. {
  794. struct chanuserrec *ch, *och;
  795. struct userrec *u;
  796. for (u = userlist; u; u = u->next) {
  797. ch = u->chanrec;
  798. och = NULL;
  799. while (ch) {
  800. if (!rfc_casecmp(dname, ch->channel)) {
  801. if (och)
  802. och->next = ch->next;
  803. else
  804. u->chanrec = ch->next;
  805. if (ch->info)
  806. nfree(ch->info);
  807. nfree(ch);
  808. break;
  809. }
  810. och = ch;
  811. ch = ch->next;
  812. }
  813. }
  814. }
  815. /* Check if the console flags specified in md are permissible according
  816. * to the given flagrec. If the FR_CHAN flag is not set in fr->match,
  817. * only global user flags will be considered.
  818. * Returns: md with all unallowed flags masked out.
  819. */
  820. int check_conflags(struct flag_record *fr, int md)
  821. {
  822. if (!glob_owner(*fr))
  823. md &= ~(LOG_RAW | LOG_SRVOUT | LOG_BOTNET | LOG_BOTSHARE);
  824. if (!glob_master(*fr)) {
  825. md &= ~(LOG_FILES | LOG_LEV1 | LOG_LEV2 | LOG_LEV3 | LOG_LEV4 |
  826. LOG_LEV5 | LOG_LEV6 | LOG_LEV7 | LOG_LEV8 | LOG_DEBUG |
  827. LOG_WALL);
  828. if ((fr->match & FR_CHAN) && !chan_master(*fr))
  829. md &= ~(LOG_MISC | LOG_CMDS);
  830. }
  831. if (!glob_botmast(*fr))
  832. md &= ~LOG_BOTS;
  833. return md;
  834. }