users.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320
  1. /*
  2. * users.c -- handles:
  3. * testing and enforcing ignores
  4. * adding and removing ignores
  5. * listing ignores
  6. * auto-linking bots
  7. * sending and receiving a userfile from a bot
  8. * listing users ('.whois' and '.match')
  9. * reading the user file
  10. *
  11. * dprintf'ized, 9nov1995
  12. *
  13. */
  14. #include "eggmain.h"
  15. #include "users.h"
  16. #include "rfc1459.h"
  17. #include "salt.h"
  18. #include "userrec.h"
  19. #include "misc.h"
  20. #include "cfg.h"
  21. #include "match.h"
  22. #include "main.h"
  23. #include "chanprog.h"
  24. #include "dccutil.h"
  25. #include "crypt.h"
  26. #include "botnet.h"
  27. #include "chan.h"
  28. #include "modules.h"
  29. #include "tandem.h"
  30. #include <netinet/in.h>
  31. #include <arpa/inet.h>
  32. #ifdef HUB
  33. #include "misc_file.h"
  34. #endif /* HUB */
  35. extern struct dcc_t *dcc;
  36. extern struct userrec *userlist, *lastuser;
  37. extern struct chanset_t *chanset;
  38. extern int dcc_total, noshare, egg_numver;
  39. extern char botnetnick[], tempdir[];
  40. extern time_t now;
  41. char natip[121] = "";
  42. char userfile[121] = ""; /* where the user records are stored */
  43. int ignore_time = 10; /* how many minutes will ignores last? */
  44. /* is this nick!user@host being ignored? */
  45. int match_ignore(char *uhost)
  46. {
  47. struct igrec *ir;
  48. for (ir = global_ign; ir; ir = ir->next)
  49. if (wild_match(ir->igmask, uhost))
  50. return 1;
  51. return 0;
  52. }
  53. int equals_ignore(char *uhost)
  54. {
  55. struct igrec *u = global_ign;
  56. for (; u; u = u->next)
  57. if (!rfc_casecmp(u->igmask, uhost)) {
  58. if (u->flags & IGREC_PERM)
  59. return 2;
  60. else
  61. return 1;
  62. }
  63. return 0;
  64. }
  65. int delignore(char *ign)
  66. {
  67. int i, j;
  68. struct igrec **u;
  69. struct igrec *t;
  70. char temp[256];
  71. i = 0;
  72. if (!strchr(ign, '!') && (j = atoi(ign))) {
  73. for (u = &global_ign, j--; *u && j; u = &((*u)->next), j--);
  74. if (*u) {
  75. strncpyz(temp, (*u)->igmask, sizeof temp);
  76. i = 1;
  77. }
  78. } else {
  79. /* find the matching host, if there is one */
  80. for (u = &global_ign; *u && !i; u = &((*u)->next))
  81. if (!rfc_casecmp(ign, (*u)->igmask)) {
  82. strncpyz(temp, ign, sizeof temp);
  83. i = 1;
  84. break;
  85. }
  86. }
  87. if (i) {
  88. if (!noshare) {
  89. char *mask = str_escape(temp, ':', '\\');
  90. if (mask) {
  91. shareout(NULL, STR("-i %s\n"), mask);
  92. free(mask);
  93. }
  94. }
  95. free((*u)->igmask);
  96. if ((*u)->msg)
  97. free((*u)->msg);
  98. if ((*u)->user)
  99. free((*u)->user);
  100. t = *u;
  101. *u = (*u)->next;
  102. free(t);
  103. }
  104. return i;
  105. }
  106. void addignore(char *ign, char *from, char *mnote, time_t expire_time)
  107. {
  108. struct igrec *p = NULL, *l;
  109. for (l = global_ign; l; l = l->next)
  110. if (!rfc_casecmp(l->igmask, ign)) {
  111. p = l;
  112. break;
  113. }
  114. if (p == NULL) {
  115. p = malloc(sizeof(struct igrec));
  116. p->next = global_ign;
  117. global_ign = p;
  118. } else {
  119. free(p->igmask);
  120. free(p->user);
  121. free(p->msg);
  122. }
  123. p->expire = expire_time;
  124. p->added = now;
  125. p->flags = expire_time ? 0 : IGREC_PERM;
  126. p->igmask = strdup(ign);
  127. p->user = strdup(from);
  128. p->msg = strdup(mnote);
  129. if (!noshare) {
  130. char *mask = str_escape(ign, ':', '\\');
  131. if (mask) {
  132. shareout(NULL, STR("+i %s %lu %c %s %s\n"), mask, expire_time - now,
  133. (p->flags & IGREC_PERM) ? 'p' : '-', from, mnote);
  134. free(mask);
  135. }
  136. }
  137. }
  138. /* take host entry from ignore list and display it ignore-style */
  139. void display_ignore(int idx, int number, struct igrec *ignore)
  140. {
  141. char dates[81], s[41];
  142. if (ignore->added) {
  143. daysago(now, ignore->added, s);
  144. sprintf(dates, STR("Started %s"), s);
  145. } else
  146. dates[0] = 0;
  147. if (ignore->flags & IGREC_PERM)
  148. strcpy(s, STR("(perm)"));
  149. else {
  150. char s1[41];
  151. days(ignore->expire, now, s1);
  152. sprintf(s, STR("(expires %s)"), s1);
  153. }
  154. if (number >= 0)
  155. dprintf(idx, STR(" [%3d] %s %s\n"), number, ignore->igmask, s);
  156. else
  157. dprintf(idx, STR("IGNORE: %s %s\n"), ignore->igmask, s);
  158. if (ignore->msg && ignore->msg[0])
  159. dprintf(idx, STR(" %s: %s\n"), ignore->user, ignore->msg);
  160. else
  161. dprintf(idx, STR(" %s %s\n"), MODES_PLACEDBY, ignore->user);
  162. if (dates[0])
  163. dprintf(idx, STR(" %s\n"), dates);
  164. }
  165. /* list the ignores and how long they've been active */
  166. void tell_ignores(int idx, char *match)
  167. {
  168. struct igrec *u = global_ign;
  169. int k = 1;
  170. if (u == NULL) {
  171. dprintf(idx, STR("No ignores.\n"));
  172. return;
  173. }
  174. dprintf(idx, STR("%s:\n"), IGN_CURRENT);
  175. for (; u; u = u->next) {
  176. if (match[0]) {
  177. if (wild_match(match, u->igmask) ||
  178. wild_match(match, u->msg) ||
  179. wild_match(match, u->user))
  180. display_ignore(idx, k, u);
  181. k++;
  182. } else
  183. display_ignore(idx, k++, u);
  184. }
  185. }
  186. /* check for expired timed-ignores */
  187. void check_expired_ignores()
  188. {
  189. struct igrec **u = &global_ign;
  190. if (!*u)
  191. return;
  192. while (*u) {
  193. if (!((*u)->flags & IGREC_PERM) && (now >= (*u)->expire)) {
  194. putlog(LOG_MISC, "*", STR("%s %s (%s)"), IGN_NOLONGER, (*u)->igmask,
  195. MISC_EXPIRED);
  196. delignore((*u)->igmask);
  197. } else {
  198. u = &((*u)->next);
  199. }
  200. }
  201. }
  202. /* Channel mask loaded from user file. This function is
  203. * add(ban|invite|exempt)_fully merged into one. <cybah>
  204. */
  205. static void addmask_fully(struct chanset_t *chan, maskrec **m, maskrec **global,
  206. char *mask, char *from,
  207. char *note, time_t expire_time, int flags,
  208. time_t added, time_t last)
  209. {
  210. maskrec *p = malloc(sizeof(maskrec));
  211. maskrec **u = (chan) ? m : global;
  212. p->next = *u;
  213. *u = p;
  214. p->expire = expire_time;
  215. p->added = added;
  216. p->lastactive = last;
  217. p->flags = flags;
  218. p->mask = strdup(mask);
  219. p->user = strdup(from);
  220. p->desc = strdup(note);
  221. }
  222. static void restore_chanban(struct chanset_t *chan, char *host)
  223. {
  224. char *expi, *add, *last, *user, *desc;
  225. int flags = 0;
  226. expi = strchr_unescape(host, ':', '\\');
  227. if (expi) {
  228. if (*expi == '+') {
  229. flags |= MASKREC_PERM;
  230. expi++;
  231. }
  232. add = strchr(expi, ':');
  233. if (add) {
  234. if (add[-1] == '*') {
  235. flags |= MASKREC_STICKY;
  236. add[-1] = 0;
  237. } else
  238. *add = 0;
  239. add++;
  240. if (*add == '+') {
  241. last = strchr(add, ':');
  242. if (last) {
  243. *last = 0;
  244. last++;
  245. user = strchr(last, ':');
  246. if (user) {
  247. *user = 0;
  248. user++;
  249. desc = strchr(user, ':');
  250. if (desc) {
  251. *desc = 0;
  252. desc++;
  253. addmask_fully(chan, &chan->bans, &global_bans, host, user,
  254. desc, atoi(expi), flags, atoi(add), atoi(last));
  255. return;
  256. }
  257. }
  258. }
  259. } else {
  260. desc = strchr(add, ':');
  261. if (desc) {
  262. *desc = 0;
  263. desc++;
  264. addmask_fully(chan, &chan->bans, &global_bans, host, add, desc,
  265. atoi(expi), flags, now, 0);
  266. return;
  267. }
  268. }
  269. }
  270. }
  271. putlog(LOG_MISC, "*", STR("*** Malformed banline for %s."),
  272. chan ? chan->dname : STR("global_bans"));
  273. }
  274. static void restore_chanexempt(struct chanset_t *chan, char *host)
  275. {
  276. char *expi, *add, *last, *user, *desc;
  277. int flags = 0;
  278. expi = strchr_unescape(host, ':', '\\');
  279. if (expi) {
  280. if (*expi == '+') {
  281. flags |= MASKREC_PERM;
  282. expi++;
  283. }
  284. add = strchr(expi, ':');
  285. if (add) {
  286. if (add[-1] == '*') {
  287. flags |= MASKREC_STICKY;
  288. add[-1] = 0;
  289. } else
  290. *add = 0;
  291. add++;
  292. if (*add == '+') {
  293. last = strchr(add, ':');
  294. if (last) {
  295. *last = 0;
  296. last++;
  297. user = strchr(last, ':');
  298. if (user) {
  299. *user = 0;
  300. user++;
  301. desc = strchr(user, ':');
  302. if (desc) {
  303. *desc = 0;
  304. desc++;
  305. addmask_fully(chan, &chan->exempts, &global_exempts, host, user,
  306. desc, atoi(expi), flags, atoi(add), atoi(last));
  307. return;
  308. }
  309. }
  310. }
  311. } else {
  312. desc = strchr(add, ':');
  313. if (desc) {
  314. *desc = 0;
  315. desc++;
  316. addmask_fully(chan, &chan->exempts, &global_exempts, host, add,
  317. desc, atoi(expi), flags, now, 0);
  318. return;
  319. }
  320. }
  321. }
  322. }
  323. putlog(LOG_MISC, "*", STR("*** Malformed exemptline for %s."),
  324. chan ? chan->dname : STR("global_exempts"));
  325. }
  326. static void restore_chaninvite(struct chanset_t *chan, char *host)
  327. {
  328. char *expi, *add, *last, *user, *desc;
  329. int flags = 0;
  330. expi = strchr_unescape(host, ':', '\\');
  331. if (expi) {
  332. if (*expi == '+') {
  333. flags |= MASKREC_PERM;
  334. expi++;
  335. }
  336. add = strchr(expi, ':');
  337. if (add) {
  338. if (add[-1] == '*') {
  339. flags |= MASKREC_STICKY;
  340. add[-1] = 0;
  341. } else
  342. *add = 0;
  343. add++;
  344. if (*add == '+') {
  345. last = strchr(add, ':');
  346. if (last) {
  347. *last = 0;
  348. last++;
  349. user = strchr(last, ':');
  350. if (user) {
  351. *user = 0;
  352. user++;
  353. desc = strchr(user, ':');
  354. if (desc) {
  355. *desc = 0;
  356. desc++;
  357. addmask_fully(chan, &chan->invites, &global_invites, host, user,
  358. desc, atoi(expi), flags, atoi(add), atoi(last));
  359. return;
  360. }
  361. }
  362. }
  363. } else {
  364. desc = strchr(add, ':');
  365. if (desc) {
  366. *desc = 0;
  367. desc++;
  368. addmask_fully(chan, &chan->invites, &global_invites, host, add,
  369. desc, atoi(expi), flags, now, 0);
  370. return;
  371. }
  372. }
  373. }
  374. }
  375. putlog(LOG_MISC, "*", STR("*** Malformed inviteline for %s."),
  376. chan ? chan->dname : STR("global_invites"));
  377. }
  378. static void restore_ignore(char *host)
  379. {
  380. char *expi, *user, *added, *desc;
  381. int flags = 0;
  382. struct igrec *p;
  383. expi = strchr_unescape(host, ':', '\\');
  384. if (expi) {
  385. if (*expi == '+') {
  386. flags |= IGREC_PERM;
  387. expi++;
  388. }
  389. user = strchr(expi, ':');
  390. if (user) {
  391. *user = 0;
  392. user++;
  393. added = strchr(user, ':');
  394. if (added) {
  395. *added = 0;
  396. added++;
  397. desc = strchr(added, ':');
  398. if (desc) {
  399. *desc = 0;
  400. desc++;
  401. } else
  402. desc = NULL;
  403. } else {
  404. added = "0";
  405. desc = NULL;
  406. }
  407. p = malloc(sizeof(struct igrec));
  408. p->next = global_ign;
  409. global_ign = p;
  410. p->expire = atoi(expi);
  411. p->added = atoi(added);
  412. p->flags = flags;
  413. p->igmask = strdup(host);
  414. p->user = strdup(user);
  415. if (desc) {
  416. p->msg = strdup(desc);
  417. } else
  418. p->msg = NULL;
  419. return;
  420. }
  421. }
  422. putlog(LOG_MISC, "*", STR("*** Malformed ignore line."));
  423. }
  424. void tell_user(int idx, struct userrec *u, int master)
  425. {
  426. char s[81], s1[81];
  427. char format[81];
  428. int n = 0;
  429. time_t now2;
  430. struct chanuserrec *ch;
  431. struct chanset_t *chan;
  432. struct user_entry *ue;
  433. struct laston_info *li;
  434. struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
  435. module_entry *me = module_find("notes", 0, 0);
  436. if (me) {
  437. Function *func = me->funcs;
  438. n = (func[5]) (u->handle);
  439. }
  440. fr.global = u->flags;
  441. fr.udef_global = u->flags_udef;
  442. build_flags(s, &fr, NULL);
  443. li = get_user(&USERENTRY_LASTON, u);
  444. if (!li || !li->laston)
  445. strcpy(s1, "never");
  446. else {
  447. now2 = now - li->laston;
  448. if (now2 > 86400)
  449. #ifdef S_UTCTIME
  450. egg_strftime(s1, 7, "%d %b", gmtime(&li->laston));
  451. #else /* !S_UTCTIME */
  452. egg_strftime(s1, 7, "%d %b", localtime(&li->laston));
  453. #endif /* S_UTCTIME */
  454. else
  455. #ifdef S_UTCTIME
  456. egg_strftime(s1, 6, "%H:%M", gmtime(&li->laston));
  457. #else /* !S_UTCTIME */
  458. egg_strftime(s1, 6, "%H:%M", localtime(&li->laston));
  459. #endif /* S_UTCTIME */
  460. }
  461. egg_snprintf(format, sizeof format, "%%-%us %%-5s%%5d %%-15s %%s (%%-10.10s)",
  462. HANDLEN);
  463. dprintf(idx, format, u->handle,
  464. get_user(&USERENTRY_PASS, u) ? "yes" : "no", n, s, s1,
  465. (li && li->lastonplace) ? li->lastonplace : "nowhere");
  466. dprintf(idx, "\n");
  467. /* channel flags? */
  468. for (ch = u->chanrec; ch; ch = ch->next) {
  469. fr.match = FR_CHAN | FR_GLOBAL;
  470. chan = findchan_by_dname(ch->channel);
  471. get_user_flagrec(dcc[idx].user, &fr, ch->channel);
  472. if (!channel_private(chan) || (channel_private(chan) && (chan_op(fr) || glob_owner(fr)))) {
  473. if (glob_op(fr) || chan_op(fr)) {
  474. if (ch->laston == 0L)
  475. strcpy(s1, "never");
  476. else {
  477. now2 = now - (ch->laston);
  478. if (now2 > 86400)
  479. #ifdef S_UTCTIME
  480. egg_strftime(s1, 7, "%d %b", gmtime(&ch->laston));
  481. #else /* !S_UTCTIME */
  482. egg_strftime(s1, 7, "%d %b", localtime(&ch->laston));
  483. #endif /* S_UTCTIME */
  484. else
  485. #ifdef S_UTCTIME
  486. egg_strftime(s1, 6, "%H:%M", gmtime(&ch->laston));
  487. #else /* !S_UTCTIME */
  488. egg_strftime(s1, 6, "%H:%M", localtime(&ch->laston));
  489. #endif /* S_UTCTIME */
  490. }
  491. fr.match = FR_CHAN;
  492. fr.chan = ch->flags;
  493. fr.udef_chan = ch->flags_udef;
  494. build_flags(s, &fr, NULL);
  495. egg_snprintf(format, sizeof format, "%%%us %%-18s %%-15s %%s\n", HANDLEN-9);
  496. dprintf(idx, format, " ", ch->channel, s, s1);
  497. if (ch->info != NULL)
  498. dprintf(idx, " INFO: %s\n", ch->info);
  499. }
  500. }
  501. }
  502. /* user-defined extra fields */
  503. for (ue = u->entries; ue; ue = ue->next)
  504. if (!ue->name && ue->type->display)
  505. ue->type->display(idx, ue, u);
  506. }
  507. /* show user by ident */
  508. void tell_user_ident(int idx, char *id, int master)
  509. {
  510. char format[81];
  511. struct userrec *u;
  512. struct flag_record user = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
  513. get_user_flagrec(dcc[idx].user, &user, NULL);
  514. u = get_user_by_handle(userlist, id);
  515. if (u == NULL)
  516. u = get_user_by_host(id);
  517. if (u == NULL || (u && !whois_access(dcc[idx].user, u))) {
  518. dprintf(idx, "%s.\n", USERF_NOMATCH);
  519. return;
  520. }
  521. egg_snprintf(format, sizeof format, STR("%%-%us PASS NOTES FLAGS LAST\n"),
  522. HANDLEN);
  523. dprintf(idx, format, STR("HANDLE"));
  524. tell_user(idx, u, master);
  525. }
  526. /* match string:
  527. * wildcard to match nickname or hostmasks
  528. * +attr to find all with attr */
  529. void tell_users_match(int idx, char *mtch, int start, int limit,
  530. int master, char *chname)
  531. {
  532. char format[81];
  533. struct userrec *u;
  534. int fnd = 0, cnt, nomns = 0, flags = 0;
  535. struct list_type *q;
  536. struct flag_record user, pls, mns;
  537. dprintf(idx, STR("*** %s '%s':\n"), MISC_MATCHING, mtch);
  538. cnt = 0;
  539. egg_snprintf(format, sizeof format, STR("%%-%us PASS NOTES FLAGS LAST\n"),
  540. HANDLEN);
  541. dprintf(idx, format, STR("HANDLE"));
  542. if (start > 1)
  543. dprintf(idx, STR("(%s %d)\n"), MISC_SKIPPING, start - 1);
  544. if (strchr("+-&|", *mtch)) {
  545. user.match = pls.match = FR_GLOBAL | FR_BOT | FR_CHAN;
  546. break_down_flags(mtch, &pls, &mns);
  547. mns.match = pls.match ^ (FR_AND | FR_OR);
  548. if (!mns.global && !mns.udef_global && !mns.chan && !mns.udef_chan &&
  549. !mns.bot) {
  550. nomns = 1;
  551. if (!pls.global && !pls.udef_global && !pls.chan && !pls.udef_chan &&
  552. !pls.bot) {
  553. /* happy now BB you weenie :P */
  554. dprintf(idx, STR("Unknown flag specified for matching!!\n"));
  555. return;
  556. }
  557. }
  558. if (!chname || !chname[0])
  559. chname = dcc[idx].u.chat->con_chan;
  560. flags = 1;
  561. }
  562. for (u = userlist; u; u = u->next) {
  563. if (!whois_access(dcc[idx].user, u)) {
  564. continue;
  565. } else if (flags) {
  566. get_user_flagrec(u, &user, chname);
  567. if (flagrec_eq(&pls, &user)) {
  568. if (nomns || !flagrec_eq(&mns, &user)) {
  569. cnt++;
  570. if ((cnt <= limit) && (cnt >= start))
  571. tell_user(idx, u, master);
  572. if (cnt == limit + 1)
  573. dprintf(idx, MISC_TRUNCATED, limit);
  574. }
  575. }
  576. } else if (wild_match(mtch, u->handle)) {
  577. cnt++;
  578. if ((cnt <= limit) && (cnt >= start))
  579. tell_user(idx, u, master);
  580. if (cnt == limit + 1)
  581. dprintf(idx, MISC_TRUNCATED, limit);
  582. } else {
  583. fnd = 0;
  584. for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next) {
  585. if ((wild_match(mtch, q->extra)) && (!fnd)) {
  586. cnt++;
  587. fnd = 1;
  588. if ((cnt <= limit) && (cnt >= start)) {
  589. tell_user(idx, u, master);
  590. }
  591. if (cnt == limit + 1)
  592. dprintf(idx, MISC_TRUNCATED, limit);
  593. }
  594. }
  595. }
  596. }
  597. dprintf(idx, MISC_FOUNDMATCH, cnt, cnt == 1 ? "" : MISC_MATCH_PLURAL);
  598. }
  599. #ifdef HUB
  600. void backup_userfile()
  601. {
  602. char s[DIRMAX], s2[DIRMAX];
  603. putlog(LOG_MISC, "*", USERF_BACKUP);
  604. egg_snprintf(s, sizeof s, "%s.u.0", tempdir);
  605. egg_snprintf(s2, sizeof s2, "%s.u.1", tempdir);
  606. movefile(s, s2);
  607. copyfile(userfile, s);
  608. }
  609. #endif /* HUB */
  610. /*
  611. * tagged lines in the user file:
  612. * * OLD:
  613. * # (comment)
  614. * ; (comment)
  615. * - hostmask(s)
  616. * + email
  617. * * dcc directory
  618. * = comment
  619. * : info line
  620. * . xtra (Tcl)
  621. * ! channel-specific
  622. * !! global laston
  623. * :: channel-specific bans
  624. * NEW:
  625. * *ban global bans
  626. * *ignore global ignores
  627. * ::#chan channel bans
  628. * - entries in each
  629. * + denotes tcl command
  630. * <handle> begin user entry
  631. * --KEY INFO - info on each
  632. * NEWER:
  633. * % exemptmask(s)
  634. * @ Invitemask(s)
  635. * *exempt global exempts
  636. * *Invite global Invites
  637. * && channel-specific exempts
  638. * &&#chan channel exempts
  639. * $$ channel-specific Invites
  640. * $$#chan channel Invites
  641. */
  642. int readuserfile(char *file, struct userrec **ret)
  643. {
  644. char *p, buf[1024], lasthand[512], *attr, *pass, *code, s1[1024], *s, cbuf[1024], *temps;
  645. FILE *f;
  646. struct userrec *bu, *u = NULL;
  647. struct chanset_t *cst = NULL;
  648. int i, line = 0;
  649. char ignored[512];
  650. struct flag_record fr;
  651. struct chanuserrec *cr;
  652. bu = (*ret);
  653. ignored[0] = 0;
  654. if (bu == userlist) {
  655. clear_chanlist();
  656. lastuser = NULL;
  657. global_bans = NULL;
  658. global_ign = NULL;
  659. global_exempts = NULL;
  660. global_invites = NULL;
  661. }
  662. lasthand[0] = 0;
  663. f = fopen(file, "r");
  664. if (f == NULL)
  665. return 0;
  666. noshare = 1;
  667. /* read opening comment */
  668. s = buf;
  669. fgets(cbuf, 180, f);
  670. temps = (char *) decrypt_string(SALT1, cbuf);
  671. egg_snprintf(s, 180, temps);
  672. free(temps);
  673. if (s[1] < '4') {
  674. fatal(USERF_OLDFMT, 0);
  675. }
  676. if (s[1] > '4')
  677. fatal(USERF_INVALID, 0);
  678. while (!feof(f)) {
  679. s = buf;
  680. fgets(cbuf, 1024, f);
  681. temps = (char *) decrypt_string(SALT1, cbuf);
  682. egg_snprintf(s, 1024, temps);
  683. free(temps);
  684. if (!feof(f)) {
  685. line++;
  686. if (s[0] != '#' && s[0] != ';' && s[0]) {
  687. code = newsplit(&s);
  688. rmspace(s);
  689. if (!strcmp(code, "-")) {
  690. if (!lasthand[0])
  691. continue; /* Skip this entry. */
  692. if (u) { /* only break it down if there a real users */
  693. p = strchr(s, ',');
  694. while (p != NULL) {
  695. splitc(s1, s, ',');
  696. rmspace(s1);
  697. if (s1[0])
  698. set_user(&USERENTRY_HOSTS, u, s1);
  699. p = strchr(s, ',');
  700. }
  701. }
  702. /* channel bans are never stacked with , */
  703. if (s[0]) {
  704. if (lasthand[0] && strchr(CHANMETA, lasthand[0]) != NULL)
  705. restore_chanban(cst, s);
  706. else if (lasthand[0] == '*') {
  707. if (lasthand[1] == IGNORE_NAME[1])
  708. restore_ignore(s);
  709. #ifdef S_DCCPASS
  710. else if (lasthand[1] == CONFIG_NAME[1]) {
  711. set_cmd_pass(s, 1);
  712. }
  713. #endif /* S_DCCPASS */
  714. else
  715. restore_chanban(NULL, s);
  716. } else if (lasthand[0])
  717. set_user(&USERENTRY_HOSTS, u, s);
  718. }
  719. } else if (!strcmp(code, "%")) { /* exemptmasks */
  720. if (!lasthand[0])
  721. continue; /* Skip this entry. */
  722. if (s[0]) {
  723. if (lasthand[0] == '#' || lasthand[0] == '+')
  724. restore_chanexempt(cst,s);
  725. else if (lasthand[0] == '*')
  726. if (lasthand[1] == EXEMPT_NAME[1])
  727. restore_chanexempt(NULL, s);
  728. }
  729. } else if (!strcmp(code, "@")) { /* Invitemasks */
  730. if (!lasthand[0])
  731. continue; /* Skip this entry. */
  732. if (s[0]) {
  733. if (lasthand[0] == '#' || lasthand[0] == '+') {
  734. restore_chaninvite(cst,s);
  735. } else if (lasthand[0] == '*') {
  736. if (lasthand[1] == INVITE_NAME[1]) {
  737. restore_chaninvite(NULL, s);
  738. } else if (lasthand[1] == CONFIG_NAME[1]) {
  739. userfile_cfg_line(s);
  740. }
  741. }
  742. }
  743. } else if (!strcmp(code, "!")) {
  744. /* ! #chan laston flags [info] */
  745. char *chname, *st, *fl;
  746. if (u) {
  747. chname = newsplit(&s);
  748. st = newsplit(&s);
  749. fl = newsplit(&s);
  750. rmspace(s);
  751. fr.match = FR_CHAN;
  752. break_down_flags(fl, &fr, 0);
  753. if (findchan_by_dname(chname)) {
  754. for (cr = u->chanrec; cr; cr = cr->next)
  755. if (!rfc_casecmp(cr->channel, chname))
  756. break;
  757. if (!cr) {
  758. cr = (struct chanuserrec *)
  759. malloc(sizeof(struct chanuserrec));
  760. cr->next = u->chanrec;
  761. u->chanrec = cr;
  762. strncpyz(cr->channel, chname, 80);
  763. cr->laston = atoi(st);
  764. cr->flags = fr.chan;
  765. cr->flags_udef = fr.udef_chan;
  766. if (s[0]) {
  767. cr->info = strdup(s);
  768. } else
  769. cr->info = NULL;
  770. }
  771. }
  772. }
  773. } else if (!strcmp(code, "+")) {
  774. if (s[0] && lasthand[0] == '*' && lasthand[1] == CHANS_NAME[1]) {
  775. module_entry *me = module_find("channels", 0, 0);
  776. if (me) {
  777. Function *func = me->funcs;
  778. char *options = strdup(s), *chan = NULL, *my_ptr = NULL;
  779. my_ptr = options;
  780. newsplit(&options);
  781. newsplit(&options);
  782. chan = newsplit(&options);
  783. /* FIXME: THIS HACK FOR { } REMOVAL SHOULD JUST NOT WRITE THEM? */
  784. newsplit(&options);
  785. options[strlen(options) - 1] = 0;
  786. /* Above is a hack to remove { } */
  787. // putlog(LOG_MISC, "*", "TCL_CHANNEL_ADD: (%s) %s", chan, options);
  788. if ((func[37]) (0, chan, options) != TCL_OK) { /* tcl_channel_add() */
  789. putlog(LOG_MISC, "*", "Tcl error in userfile on line %d", line);
  790. free(my_ptr);
  791. return 0;
  792. }
  793. free(my_ptr);
  794. }
  795. }
  796. } else if (!strncmp(code, "::", 2)) {
  797. /* channel-specific bans */
  798. strcpy(lasthand, &code[2]);
  799. u = NULL;
  800. if (!findchan_by_dname(lasthand)) {
  801. strcpy(s1, lasthand);
  802. strcat(s1, " ");
  803. if (strstr(ignored, s1) == NULL) {
  804. strcat(ignored, lasthand);
  805. strcat(ignored, " ");
  806. }
  807. lasthand[0] = 0;
  808. } else {
  809. /* Remove all bans for this channel to avoid dupes */
  810. /* NOTE only remove bans for when getting a userfile
  811. * from another bot & that channel is shared */
  812. cst = findchan_by_dname(lasthand);
  813. if ((*ret == userlist) || channel_shared(cst)) {
  814. clear_masks(cst->bans);
  815. cst->bans = NULL;
  816. } else {
  817. /* otherwise ignore any bans for this channel */
  818. cst = NULL;
  819. lasthand[0] = 0;
  820. }
  821. }
  822. } else if (!strncmp(code, "&&", 2)) {
  823. /* channel-specific exempts */
  824. strcpy(lasthand, &code[2]);
  825. u = NULL;
  826. if (!findchan_by_dname(lasthand)) {
  827. strcpy(s1, lasthand);
  828. strcat(s1, " ");
  829. if (strstr(ignored, s1) == NULL) {
  830. strcat(ignored, lasthand);
  831. strcat(ignored, " ");
  832. }
  833. lasthand[0] = 0;
  834. } else {
  835. /* Remove all exempts for this channel to avoid dupes */
  836. /* NOTE only remove exempts for when getting a userfile
  837. * from another bot & that channel is shared */
  838. cst = findchan_by_dname(lasthand);
  839. if ((*ret == userlist) || channel_shared(cst)) {
  840. clear_masks(cst->exempts);
  841. cst->exempts = NULL;
  842. } else {
  843. /* otherwise ignore any exempts for this channel */
  844. cst = NULL;
  845. lasthand[0] = 0;
  846. }
  847. }
  848. } else if (!strncmp(code, "$$", 2)) {
  849. /* channel-specific invites */
  850. strcpy(lasthand, &code[2]);
  851. u = NULL;
  852. if (!findchan_by_dname(lasthand)) {
  853. strcpy(s1, lasthand);
  854. strcat(s1, " ");
  855. if (strstr(ignored, s1) == NULL) {
  856. strcat(ignored, lasthand);
  857. strcat(ignored, " ");
  858. }
  859. lasthand[0] = 0;
  860. } else {
  861. /* Remove all invites for this channel to avoid dupes */
  862. /* NOTE only remove invites for when getting a userfile
  863. * from another bot & that channel is shared */
  864. cst = findchan_by_dname(lasthand);
  865. if ((*ret == userlist) || channel_shared(cst)) {
  866. clear_masks(cst->invites);
  867. cst->invites = NULL;
  868. } else {
  869. /* otherwise ignore any invites for this channel */
  870. cst = NULL;
  871. lasthand[0] = 0;
  872. }
  873. }
  874. } else if (!strncmp(code, "--", 2)) {
  875. if (u) {
  876. /* new format storage */
  877. struct user_entry *ue;
  878. int ok = 0;
  879. for (ue = u->entries; ue && !ok; ue = ue->next)
  880. if (ue->name && !egg_strcasecmp(code + 2, ue->name)) {
  881. struct list_type *list;
  882. list = malloc(sizeof(struct list_type));
  883. list->next = NULL;
  884. list->extra = strdup(s);
  885. list_append((&ue->u.list), list);
  886. ok = 1;
  887. }
  888. if (!ok) {
  889. ue = malloc(sizeof(struct user_entry));
  890. ue->name = malloc(strlen(code + 1));
  891. ue->type = NULL;
  892. strcpy(ue->name, code + 2);
  893. ue->u.list = malloc(sizeof(struct list_type));
  894. ue->u.list->next = NULL;
  895. ue->u.list->extra = strdup(s);
  896. list_insert((&u->entries), ue);
  897. }
  898. }
  899. } else if (!rfc_casecmp(code, BAN_NAME)) {
  900. strcpy(lasthand, code);
  901. u = NULL;
  902. } else if (!rfc_casecmp(code, IGNORE_NAME)) {
  903. strcpy(lasthand, code);
  904. u = NULL;
  905. } else if (!rfc_casecmp(code, EXEMPT_NAME)) {
  906. strcpy(lasthand, code);
  907. u = NULL;
  908. } else if (!rfc_casecmp(code, INVITE_NAME)) {
  909. strcpy(lasthand, code);
  910. u = NULL;
  911. } else if (!rfc_casecmp(code, CHANS_NAME)) {
  912. strcpy(lasthand, code);
  913. u = NULL;
  914. } else if (!rfc_casecmp(code, CONFIG_NAME)) {
  915. strcpy(lasthand, code);
  916. u = NULL;
  917. } else if (code[0] == '*') {
  918. lasthand[0] = 0;
  919. u = NULL;
  920. } else {
  921. pass = newsplit(&s);
  922. attr = newsplit(&s);
  923. rmspace(s);
  924. if (!attr[0] || !pass[0]) {
  925. putlog(LOG_MISC, "*", "* %s line: %d!", USERF_CORRUPT, line);
  926. lasthand[0] = 0;
  927. return 0;
  928. } else {
  929. u = get_user_by_handle(bu, code);
  930. if (u && !(u->flags & USER_UNSHARED)) {
  931. putlog(LOG_ERROR, "@", "* %s '%s'!", USERF_DUPE, code);
  932. lasthand[0] = 0;
  933. u = NULL;
  934. } else if (u) {
  935. lasthand[0] = 0;
  936. u = NULL;
  937. } else {
  938. fr.match = FR_GLOBAL;
  939. break_down_flags(attr, &fr, 0);
  940. strcpy(lasthand, code);
  941. cst = NULL;
  942. if (strlen(code) > HANDLEN)
  943. code[HANDLEN] = 0;
  944. if (strlen(pass) > 20) {
  945. putlog(LOG_MISC, "*", "* %s '%s'", USERF_BROKEPASS, code);
  946. strcpy(pass, "-");
  947. }
  948. bu = adduser(bu, code, 0, pass,
  949. sanity_check(fr.global &USER_VALID));
  950. u = get_user_by_handle(bu, code);
  951. for (i = 0; i < dcc_total; i++)
  952. if (!egg_strcasecmp(code, dcc[i].nick))
  953. dcc[i].user = u;
  954. u->flags_udef = fr.udef_global;
  955. /* if s starts with '/' it's got file info */
  956. }
  957. }
  958. }
  959. }
  960. }
  961. }
  962. fclose(f);
  963. (*ret) = bu;
  964. if (ignored[0]) {
  965. putlog(LOG_MISC, "*", "%s %s", USERF_IGNBANS, ignored);
  966. }
  967. putlog(LOG_MISC, "*", "Userfile loaded, unpacking...");
  968. for (u = bu; u; u = u->next) {
  969. struct user_entry *e;
  970. if (!(u->flags & USER_BOT) && !egg_strcasecmp (u->handle, botnetnick)) {
  971. putlog(LOG_MISC, "*", "(!) I have a user record, but without +b");
  972. /* u->flags |= USER_BOT; */
  973. }
  974. for (e = u->entries; e; e = e->next)
  975. if (e->name) {
  976. struct user_entry_type *uet = find_entry_type(e->name);
  977. if (uet) {
  978. e->type = uet;
  979. uet->unpack(u, e);
  980. free(e->name);
  981. e->name = NULL;
  982. }
  983. }
  984. }
  985. /* process the user data *now* */
  986. #ifdef LEAF
  987. unlink(userfile);
  988. #endif /* LEAF */
  989. noshare = 0;
  990. return 1;
  991. }
  992. /* New methodology - cycle through list 3 times
  993. * 1st time scan for +sh bots and link if none connected
  994. * 2nd time scan for +h bots
  995. * 3rd time scan for +a/+h bots */
  996. void link_pref_val(struct userrec *u, char *val)
  997. {
  998. /* val must be HANDLEN + 4 chars minimum */
  999. struct bot_addr *ba;
  1000. val[0] = 'Z';
  1001. val[1] = 0;
  1002. if (!u)
  1003. return;
  1004. if (!(u->flags & USER_BOT))
  1005. return;
  1006. ba = get_user(&USERENTRY_BOTADDR, u);
  1007. if (!ba)
  1008. return;
  1009. if (!ba->hublevel)
  1010. return;
  1011. sprintf(val, STR("%02d%s"), ba->hublevel, u->handle);
  1012. }
  1013. struct userrec *next_hub(struct userrec *current, char *lowval, char *highval)
  1014. {
  1015. /*
  1016. starting at "current" or "userlist" if NULL, find next bot with a
  1017. link_pref_val higher than "lowval" and lower than "highval"
  1018. If none found return bot with best overall link_pref_val
  1019. If still not found return NULL
  1020. */
  1021. char thisval[NICKLEN + 4],
  1022. bestmatchval[NICKLEN + 4] = "z",
  1023. bestallval[NICKLEN + 4] = "z";
  1024. struct userrec *cur = NULL,
  1025. *bestmatch = NULL,
  1026. *bestall = NULL;
  1027. if (current)
  1028. cur = current->next;
  1029. else
  1030. cur = userlist;
  1031. while (cur != current) {
  1032. if (!cur)
  1033. cur = userlist;
  1034. if (cur == current)
  1035. break;
  1036. if ((cur->flags & USER_BOT) && (strcmp(cur->handle, botnetnick))) {
  1037. link_pref_val(cur, thisval);
  1038. if ((strcmp(thisval, lowval) < 0) && (strcmp(thisval, highval) > 0) &&(strcmp(thisval, bestmatchval) < 0)) {
  1039. strcpy(bestmatchval, thisval);
  1040. bestmatch = cur;
  1041. }
  1042. if ((strcmp(thisval, lowval) < 0)
  1043. && (strcmp(thisval, bestallval) < 0)) {
  1044. strcpy(bestallval, thisval);
  1045. bestall = cur;
  1046. }
  1047. }
  1048. cur = cur->next;
  1049. }
  1050. if (bestmatch)
  1051. return bestmatch;
  1052. if (bestall)
  1053. return bestall;
  1054. return NULL;
  1055. }
  1056. #ifdef HUB
  1057. void autolink_cycle(char *start)
  1058. {
  1059. struct userrec *u = NULL;
  1060. int i;
  1061. char bestval[HANDLEN + 4],
  1062. curval[HANDLEN + 4],
  1063. myval[HANDLEN + 4];
  1064. u = get_user_by_handle(userlist, botnetnick);
  1065. link_pref_val(u, myval);
  1066. strcpy(bestval, myval);
  1067. for (i = 0; i < dcc_total; i++) {
  1068. if (dcc[i].type == &DCC_BOT_NEW)
  1069. return;
  1070. if (dcc[i].type == &DCC_FORK_BOT)
  1071. return;
  1072. if (dcc[i].type == &DCC_BOT) {
  1073. if (dcc[i].status & (STAT_OFFEREDU | STAT_GETTINGU | STAT_SENDINGU))
  1074. continue; //lets let the binary have it's peace.
  1075. if (dcc[i].u.bot->numver != egg_numver)
  1076. continue; //same thing.
  1077. if (dcc[i].status & (STAT_SHARE | STAT_OFFERED | STAT_SENDING | STAT_GETTING)) {
  1078. link_pref_val(dcc[i].user, curval);
  1079. if (strcmp(myval, curval) < 0) {
  1080. /* I should be aggressive to this one */
  1081. if (dcc[i].status & STAT_AGGRESSIVE) {
  1082. putlog(LOG_MISC, "*", STR("Passively sharing with %s but should be aggressive"), dcc[i].user->handle);
  1083. putlog(LOG_DEBUG, "*", STR("My linkval: %s - %s linkval: %s"), myval, dcc[i].nick, curval);
  1084. botunlink(-2, dcc[i].nick, STR("Marked passive, should be aggressive"));
  1085. return;
  1086. }
  1087. } else {
  1088. /* I should be passive to this one */
  1089. if (!(dcc[i].status & STAT_AGGRESSIVE)) {
  1090. putlog(LOG_MISC, "*", STR("Aggressively sharing with %s but should be passive"), dcc[i].user->handle);
  1091. putlog(LOG_DEBUG, "*", STR("My linkval: %s - %s linkval: %s"), myval, dcc[i].nick, curval);
  1092. botunlink(-2, dcc[i].nick, STR("Marked aggressive, should be passive"));
  1093. return;
  1094. }
  1095. if (strcmp(curval, bestval) < 0)
  1096. strcpy(bestval, curval);
  1097. }
  1098. } else {
  1099. botunlink(-2, dcc[i].nick, STR("Linked but not sharing?"));
  1100. }
  1101. }
  1102. }
  1103. if (start)
  1104. u = get_user_by_handle(userlist, start);
  1105. else
  1106. u = NULL;
  1107. if (u) {
  1108. link_pref_val(u, curval);
  1109. if (strcmp(bestval, curval) < 0) {
  1110. /* This shouldn't happen. Getting a failed link attempt (start!=NULL)
  1111. while a dcc scan indicates we *are* connected to a better bot than
  1112. the one we failed a link to.
  1113. */
  1114. putlog(LOG_BOTS, "*", STR("Failed link attempt to %s but connected to %s already???"), u->handle, (char *) &bestval[3]);
  1115. return;
  1116. }
  1117. } else
  1118. strcpy(curval, "0");
  1119. u = next_hub(u, bestval, curval);
  1120. if ((u) && (!in_chain(u->handle)))
  1121. botlink("", -3, u->handle);
  1122. }
  1123. #endif /* HUB */
  1124. #ifdef LEAF
  1125. typedef struct hublist_entry {
  1126. struct hublist_entry *next;
  1127. struct userrec *u;
  1128. } tag_hublist_entry;
  1129. int botlinkcount = 0;
  1130. void autolink_cycle(char *start)
  1131. {
  1132. struct userrec *my_u = NULL, *u = NULL;
  1133. struct hublist_entry *hl = NULL, *hl2 = NULL;
  1134. struct bot_addr *my_ba;
  1135. char uplink[HANDLEN + 1], avoidbot[HANDLEN + 1], curhub[HANDLEN + 1];
  1136. int i, hlc;
  1137. struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
  1138. /* Reset connection attempts if we ain't called due to a failed link */
  1139. if (!start)
  1140. botlinkcount = 0;
  1141. my_u = get_user_by_handle(userlist, botnetnick);
  1142. my_ba = get_user(&USERENTRY_BOTADDR, my_u);
  1143. if (my_ba && (my_ba->uplink[0])) {
  1144. strncpyz(uplink, my_ba->uplink, sizeof(uplink));
  1145. } else {
  1146. uplink[0] = 0;
  1147. }
  1148. curhub[0] = 0;
  1149. for (i = 0; i < dcc_total; i++) {
  1150. if ((dcc[i].type == &DCC_BOT_NEW) || (dcc[i].type == &DCC_FORK_BOT))
  1151. return;
  1152. if (dcc[i].type == &DCC_BOT) {
  1153. strcpy(curhub, dcc[i].nick);
  1154. break;
  1155. }
  1156. }
  1157. if (curhub[0]) {
  1158. /* we are linked to a bot (hub) */
  1159. if (uplink[0] && !strcmp(curhub, uplink))
  1160. /* Connected to uplink, nothing more to do */
  1161. return;
  1162. if (start)
  1163. /* Failed a link... let's just wait for next regular call */
  1164. return;
  1165. if (uplink[0]) {
  1166. /* Trying the uplink */
  1167. botlink("", -3, uplink);
  1168. return;
  1169. }
  1170. /* we got a hub currently, and no set uplink. Stay here */
  1171. return;
  1172. } else {
  1173. /* no hubs connected... pick one */
  1174. if (!start) {
  1175. /* Regular interval call, no previous failed link */
  1176. if (uplink[0]) {
  1177. /* We have a set uplink, try it */
  1178. botlink("", -3, uplink);
  1179. return;
  1180. }
  1181. /* No preferred uplink, we need a random bot */
  1182. avoidbot[0] = 0;
  1183. } else {
  1184. /* We got a failed link... */
  1185. botlinkcount++;
  1186. if (botlinkcount >= 3)
  1187. /* tried 3+ random hubs without success, wait for next regular interval call */
  1188. return;
  1189. /* We need a random bot but *not* the last we tried */
  1190. strcpy(avoidbot, start);
  1191. }
  1192. }
  1193. /* Pick a random hub, but avoid 'avoidbot' */
  1194. hlc = 0;
  1195. for (u = userlist; u; u = u->next) {
  1196. get_user_flagrec(u, &fr, NULL);
  1197. if (glob_bot(fr) && strcmp(u->handle, botnetnick) && strcmp(u->handle, avoidbot) && (bot_hublevel(u) < 999)) {
  1198. putlog(LOG_DEBUG, "@", STR("Adding %s to hublist"), u->handle);
  1199. hl2 = hl;
  1200. hl = malloc(sizeof(struct hublist_entry));
  1201. egg_bzero(hl, sizeof(struct hublist_entry));
  1202. hl->next = hl2;
  1203. hlc++;
  1204. hl->u = u;
  1205. }
  1206. }
  1207. putlog(LOG_DEBUG, "@", STR("Picking random hub from %d hubs"), hlc);
  1208. hlc = random() % hlc;
  1209. putlog(LOG_DEBUG, "@", STR("Picked #%d for hub"), hlc);
  1210. while (hl) {
  1211. if (!hlc) {
  1212. putlog(LOG_DEBUG, "@", STR("Which is bot: %s"), hl->u->handle);
  1213. botlink("", -3, hl->u->handle);
  1214. }
  1215. hlc--;
  1216. hl2 = hl->next;
  1217. free(hl);
  1218. hl = hl2;
  1219. }
  1220. }
  1221. #endif /* LEAF */
  1222. int whois_access(struct userrec *user, struct userrec *whois_user)
  1223. {
  1224. struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
  1225. struct flag_record whois = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
  1226. get_user_flagrec(user, &fr, NULL);
  1227. get_user_flagrec(whois_user, &whois, NULL);
  1228. if ((glob_master(whois) && !glob_master(fr)) ||
  1229. (glob_owner(whois) && !glob_owner(fr)) ||
  1230. (glob_admin(whois) && !glob_admin(fr)) ||
  1231. (glob_bot(whois) && !glob_master(fr)))
  1232. return 0;
  1233. return 1;
  1234. }