botnet.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795
  1. /*
  2. * botnet.c -- handles:
  3. * keeping track of which bot's connected where in the chain
  4. * dumping a list of bots or a bot tree to a user
  5. * channel name associations on the party line
  6. * rejecting a bot
  7. * linking, unlinking, and relaying to another bot
  8. * pinging the bots periodically and checking leaf status
  9. *
  10. */
  11. #include "main.h"
  12. #include "tandem.h"
  13. extern int dcc_total, backgrd, connect_timeout, max_dcc,
  14. egg_numver, cfg_count;
  15. extern struct userrec *userlist;
  16. extern struct dcc_t *dcc;
  17. extern time_t now;
  18. extern Tcl_Interp *interp;
  19. extern struct cfg_entry **cfg;
  20. tand_t *tandbot; /* Keep track of tandem bots on the
  21. botnet */
  22. party_t *party; /* Keep track of people on the botnet */
  23. static int maxparty = 200; /* Maximum space for party line members
  24. currently */
  25. int tands = 0; /* Number of bots on the botnet */
  26. int parties = 0; /* Number of people on the botnet */
  27. char botnetnick[HANDLEN + 1] = ""; /* Botnet nickname */
  28. int share_unlinks = 1; /* Allow remote unlinks of my
  29. sharebots? */
  30. int expmem_botnet()
  31. {
  32. int size = 0, i;
  33. tand_t *bot;
  34. for (bot = tandbot; bot; bot = bot->next)
  35. size += sizeof(tand_t);
  36. size += (maxparty * sizeof(party_t));
  37. for (i = 0; i < parties; i++) {
  38. if (party[i].away)
  39. size += strlen(party[i].away) + 1;
  40. if (party[i].from)
  41. size += strlen(party[i].from) + 1;
  42. }
  43. return size;
  44. }
  45. void init_bots()
  46. {
  47. tandbot = NULL;
  48. /* Grab space for 50 bots for now -- expand later as needed */
  49. maxparty = 50;
  50. party = (party_t *) nmalloc(maxparty * sizeof(party_t));
  51. }
  52. tand_t *findbot(char *who)
  53. {
  54. tand_t *ptr;
  55. for (ptr = tandbot; ptr; ptr = ptr->next)
  56. if (!egg_strcasecmp(ptr->bot, who))
  57. return ptr;
  58. return NULL;
  59. }
  60. /* Add a tandem bot to our chain list
  61. */
  62. void addbot(char *who, char *from, char *next, char flag, int vernum)
  63. {
  64. tand_t **ptr = &tandbot, *ptr2;
  65. while (*ptr) {
  66. if (!egg_strcasecmp((*ptr)->bot, who))
  67. putlog(LOG_BOTS, "*", "!!! Duplicate botnet bot entry!!");
  68. ptr = &((*ptr)->next);
  69. }
  70. ptr2 = nmalloc(sizeof(tand_t));
  71. strncpy(ptr2->bot, who, HANDLEN);
  72. ptr2->bot[HANDLEN] = 0;
  73. ptr2->share = flag;
  74. ptr2->ver = vernum;
  75. ptr2->next = *ptr;
  76. *ptr = ptr2;
  77. /* May be via itself */
  78. ptr2->via = findbot(from);
  79. if (!egg_strcasecmp(next, botnetnick))
  80. ptr2->uplink = (tand_t *) 1;
  81. else
  82. ptr2->uplink = findbot(next);
  83. tands++;
  84. }
  85. #ifdef HUB
  86. #ifdef G_BACKUP
  87. void check_should_backup()
  88. {
  89. struct chanset_t *chan;
  90. for (chan = chanset; chan; chan = chan->next) {
  91. if (chan->channel.backup_time && (chan->channel.backup_time < now) && !channel_backup(chan)) {
  92. do_chanset(chan, STR("+backup"), 1);
  93. chan->channel.backup_time = 0;
  94. }
  95. }
  96. }
  97. #endif /* G_BACKUP */
  98. #endif /* HUB */
  99. void updatebot(int idx, char *who, char share, int vernum)
  100. {
  101. tand_t *ptr = findbot(who);
  102. if (ptr) {
  103. if (share)
  104. ptr->share = share;
  105. if (vernum)
  106. ptr->ver = vernum;
  107. botnet_send_update(idx, ptr);
  108. }
  109. }
  110. /* For backward 1.0 compatibility:
  111. * grab the (first) sock# for a user on another bot
  112. */
  113. int partysock(char *bot, char *nick)
  114. {
  115. int i;
  116. for (i = 0; i < parties; i++) {
  117. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  118. (!egg_strcasecmp(party[i].nick, nick)))
  119. return party[i].sock;
  120. }
  121. return 0;
  122. }
  123. /* New botnet member
  124. */
  125. int addparty(char *bot, char *nick, int chan, char flag, int sock,
  126. char *from, int *idx)
  127. {
  128. int i;
  129. for (i = 0; i < parties; i++) {
  130. /* Just changing the channel of someone already on? */
  131. if (!egg_strcasecmp(party[i].bot, bot) &&
  132. (party[i].sock == sock)) {
  133. int oldchan = party[i].chan;
  134. party[i].chan = chan;
  135. party[i].timer = now;
  136. if (from[0]) {
  137. if (flag == ' ')
  138. flag = '-';
  139. party[i].flag = flag;
  140. if (party[i].from)
  141. nfree(party[i].from);
  142. party[i].from = nmalloc(strlen(from) + 1);
  143. strcpy(party[i].from, from);
  144. }
  145. *idx = i;
  146. return oldchan;
  147. }
  148. }
  149. /* New member */
  150. if (parties == maxparty) {
  151. maxparty += 50;
  152. party = (party_t *) nrealloc((void *) party, maxparty * sizeof(party_t));
  153. }
  154. strncpy(party[parties].nick, nick, HANDLEN);
  155. party[parties].nick[HANDLEN] = 0;
  156. strncpy(party[parties].bot, bot, HANDLEN);
  157. party[parties].bot[HANDLEN] = 0;
  158. party[parties].chan = chan;
  159. party[parties].sock = sock;
  160. party[parties].status = 0;
  161. party[parties].away = 0;
  162. party[parties].timer = now; /* cope. */
  163. if (from[0]) {
  164. if (flag == ' ')
  165. flag = '-';
  166. party[parties].flag = flag;
  167. party[parties].from = nmalloc(strlen(from) + 1);
  168. strcpy(party[parties].from, from);
  169. } else {
  170. party[parties].flag = ' ';
  171. party[parties].from = nmalloc(10);
  172. strcpy(party[parties].from, "(unknown)");
  173. }
  174. *idx = parties;
  175. parties++;
  176. return -1;
  177. }
  178. /* Alter status flags for remote party-line user.
  179. */
  180. void partystat(char *bot, int sock, int add, int rem)
  181. {
  182. int i;
  183. for (i = 0; i < parties; i++) {
  184. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  185. (party[i].sock == sock)) {
  186. party[i].status |= add;
  187. party[i].status &= ~rem;
  188. }
  189. }
  190. }
  191. /* Other bot is sharing idle info.
  192. */
  193. void partysetidle(char *bot, int sock, int secs)
  194. {
  195. int i;
  196. for (i = 0; i < parties; i++) {
  197. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  198. (party[i].sock == sock)) {
  199. party[i].timer = (now - (time_t) secs);
  200. }
  201. }
  202. }
  203. /* Return someone's chat channel.
  204. */
  205. int getparty(char *bot, int sock)
  206. {
  207. int i;
  208. for (i = 0; i < parties; i++) {
  209. if (!egg_strcasecmp(party[i].bot, bot) &&
  210. (party[i].sock == sock)) {
  211. return i;
  212. }
  213. }
  214. return -1;
  215. }
  216. /* Un-idle someone
  217. */
  218. int partyidle(char *bot, char *nick)
  219. {
  220. int i, ok = 0;
  221. for (i = 0; i < parties; i++) {
  222. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  223. (!egg_strcasecmp(party[i].nick, nick))) {
  224. party[i].timer = now;
  225. ok = 1;
  226. }
  227. }
  228. return ok;
  229. }
  230. /* Change someone's nick
  231. */
  232. int partynick(char *bot, int sock, char *nick)
  233. {
  234. char work[HANDLEN + 1];
  235. int i;
  236. for (i = 0; i < parties; i++) {
  237. if (!egg_strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
  238. strcpy(work, party[i].nick);
  239. strncpy(party[i].nick, nick, HANDLEN);
  240. party[i].nick[HANDLEN] = 0;
  241. strcpy(nick, work);
  242. return i;
  243. }
  244. }
  245. return -1;
  246. }
  247. /* Set away message
  248. */
  249. void partyaway(char *bot, int sock, char *msg)
  250. {
  251. int i;
  252. for (i = 0; i < parties; i++) {
  253. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  254. (party[i].sock == sock)) {
  255. if (party[i].away)
  256. nfree(party[i].away);
  257. if (msg[0]) {
  258. party[i].away = nmalloc(strlen(msg) + 1);
  259. strcpy(party[i].away, msg);
  260. } else
  261. party[i].away = 0;
  262. }
  263. }
  264. }
  265. /* Remove a tandem bot from the chain list
  266. */
  267. void rembot(char *who)
  268. {
  269. tand_t **ptr = &tandbot, *ptr2;
  270. struct userrec *u;
  271. while (*ptr) {
  272. if (!egg_strcasecmp((*ptr)->bot, who))
  273. break;
  274. ptr = &((*ptr)->next);
  275. }
  276. if (!*ptr)
  277. /* May have just .unlink *'d */
  278. return;
  279. check_tcl_disc(who);
  280. u = get_user_by_handle(userlist, who);
  281. if (u != NULL)
  282. touch_laston(u, "unlinked", now);
  283. ptr2 = *ptr;
  284. *ptr = ptr2->next;
  285. nfree(ptr2);
  286. tands--;
  287. dupwait_notify(who);
  288. }
  289. void remparty(char *bot, int sock)
  290. {
  291. int i;
  292. for (i = 0; i < parties; i++)
  293. if ((!egg_strcasecmp(party[i].bot, bot)) &&
  294. (party[i].sock == sock)) {
  295. parties--;
  296. if (party[i].from)
  297. nfree(party[i].from);
  298. if (party[i].away)
  299. nfree(party[i].away);
  300. if (i < parties) {
  301. strcpy(party[i].bot, party[parties].bot);
  302. strcpy(party[i].nick, party[parties].nick);
  303. party[i].chan = party[parties].chan;
  304. party[i].sock = party[parties].sock;
  305. party[i].flag = party[parties].flag;
  306. party[i].status = party[parties].status;
  307. party[i].timer = party[parties].timer;
  308. party[i].from = party[parties].from;
  309. party[i].away = party[parties].away;
  310. }
  311. }
  312. }
  313. /* Cancel every user that was on a certain bot
  314. */
  315. void rempartybot(char *bot)
  316. {
  317. int i;
  318. for (i = 0; i < parties; i++)
  319. if (!egg_strcasecmp(party[i].bot, bot)) {
  320. if (party[i].chan >= 0)
  321. check_tcl_chpt(bot, party[i].nick, party[i].sock, party[i].chan);
  322. remparty(bot, party[i].sock);
  323. i--;
  324. }
  325. }
  326. /* Remove every bot linked 'via' bot <x>
  327. */
  328. void unvia(int idx, tand_t * who)
  329. {
  330. tand_t *bot, *bot2;
  331. if (!who)
  332. return; /* Safety */
  333. rempartybot(who->bot);
  334. bot = tandbot;
  335. while (bot) {
  336. if (bot->uplink == who) {
  337. unvia(idx, bot);
  338. bot2 = bot->next;
  339. rembot(bot->bot);
  340. bot = bot2;
  341. } else
  342. bot = bot->next;
  343. }
  344. }
  345. void besthub(char *hub)
  346. {
  347. tand_t *ptr = tandbot;
  348. struct userrec *u, *besthub = NULL;
  349. char bestlval[20], lval[20];
  350. hub[0] = 0;
  351. strcpy(bestlval, "z");
  352. while (ptr) {
  353. u = get_user_by_handle(userlist, ptr->bot);
  354. if (u) {
  355. link_pref_val(u, lval);
  356. if (strcmp(lval, bestlval) < 0) {
  357. strcpy(bestlval, lval);
  358. besthub = u;
  359. }
  360. }
  361. ptr = ptr->next;
  362. }
  363. if (besthub)
  364. strcpy(hub, besthub->handle);
  365. return;
  366. }
  367. /* Return index into dcc list of the bot that connects us to bot <x>
  368. */
  369. int nextbot(char *who)
  370. {
  371. int j;
  372. tand_t *bot = findbot(who);
  373. if (!bot)
  374. return -1;
  375. for (j = 0; j < dcc_total; j++)
  376. if (bot->via && !egg_strcasecmp(bot->via->bot, dcc[j].nick) &&
  377. (dcc[j].type == &DCC_BOT))
  378. return j;
  379. return -1; /* We're not connected to 'via' */
  380. }
  381. /* Return name of the bot that is directly connected to bot X
  382. */
  383. char *lastbot(char *who)
  384. {
  385. tand_t *bot = findbot(who);
  386. if (!bot)
  387. return "*";
  388. else if (bot->uplink == (tand_t *) 1)
  389. return botnetnick;
  390. else
  391. return bot->uplink->bot;
  392. }
  393. /* Modern version of 'whom' (use local data)
  394. */
  395. void answer_local_whom(int idx, int chan)
  396. {
  397. char format[81];
  398. char c, idle[40];
  399. int i, t, nicklen, botnicklen, total=0;
  400. if (chan == (-1))
  401. dprintf(idx, "%s (+: %s, *: %s)\n", BOT_BOTNETUSERS, BOT_PARTYLINE,
  402. BOT_LOCALCHAN);
  403. else if (chan > 0) {
  404. simple_sprintf(idle, "assoc %d", chan);
  405. if ((Tcl_Eval(interp, idle) != TCL_OK) || !interp->result[0])
  406. dprintf(idx, "%s %s%d:\n", BOT_USERSONCHAN,
  407. (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
  408. else
  409. dprintf(idx, "%s '%s%s' (%s%d):\n", BOT_USERSONCHAN,
  410. (chan < GLOBAL_CHANS) ? "" : "*", interp->result,
  411. (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
  412. }
  413. /* Find longest nick and botnick */
  414. nicklen = botnicklen = 0;
  415. for (i = 0; i < dcc_total; i++)
  416. if (dcc[i].type == &DCC_CHAT) {
  417. if ((chan == (-1)) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
  418. t = strlen(dcc[i].nick); if(t > nicklen) nicklen = t;
  419. t = strlen(botnetnick); if(t > botnicklen) botnicklen = t;
  420. }
  421. }
  422. for (i = 0; i < parties; i++) {
  423. if ((chan == (-1)) || ((chan >= 0) && (party[i].chan == chan))) {
  424. t = strlen(party[i].nick); if(t > nicklen) nicklen = t;
  425. t = strlen(party[i].bot); if(t > botnicklen) botnicklen = t;
  426. }
  427. }
  428. if(nicklen < 9) nicklen = 9;
  429. if(botnicklen < 9) botnicklen = 9;
  430. #ifdef HUB
  431. egg_snprintf(format, sizeof format, "%%-%us %%-%us %%s\n",
  432. nicklen, botnicklen);
  433. dprintf(idx, format, " Nick", " Bot", " Host");
  434. dprintf(idx, format, "----------", "---------", "--------------------");
  435. egg_snprintf(format, sizeof format, "%%c%%-%us %%c %%-%us %%s%%s\n",
  436. nicklen, botnicklen);
  437. #else /* !HUB */
  438. egg_snprintf(format, sizeof format, "%%-%us\n", nicklen);
  439. dprintf(idx, format, " Nick");
  440. dprintf(idx, format, "----------");
  441. egg_snprintf(format, sizeof format, "%%c%%-%us %%c %%s\n", nicklen);
  442. #endif /* HUB */
  443. for (i = 0; i < dcc_total; i++)
  444. if (dcc[i].type == &DCC_CHAT) {
  445. if ((chan == (-1)) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
  446. c = geticon(i);
  447. if (c == '-')
  448. c = ' ';
  449. if (now - dcc[i].timeval > 300) {
  450. unsigned long days, hrs, mins;
  451. days = (now - dcc[i].timeval) / 86400;
  452. hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
  453. mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
  454. if (days > 0)
  455. sprintf(idle, " [idle %lud%luh]", days, hrs);
  456. else if (hrs > 0)
  457. sprintf(idle, " [idle %luh%lum]", hrs, mins);
  458. else
  459. sprintf(idle, " [idle %lum]", mins);
  460. } else
  461. idle[0] = 0;
  462. total++;
  463. dprintf(idx, format, c, dcc[i].nick,
  464. (dcc[i].u.chat->channel == 0) && (chan == (-1)) ? '+' :
  465. (dcc[i].u.chat->channel > GLOBAL_CHANS) &&
  466. #ifdef HUB
  467. (chan == (-1)) ? '*' : ' ', botnetnick, dcc[i].host, idle);
  468. #else /* !HUB */
  469. (chan == (-1)) ? '*' : ' ', idle);
  470. #endif /* HUB */
  471. if (dcc[i].u.chat->away != NULL)
  472. dprintf(idx, " AWAY: %s\n", dcc[i].u.chat->away);
  473. }
  474. }
  475. for (i = 0; i < parties; i++) {
  476. if ((chan == (-1)) || ((chan >= 0) && (party[i].chan == chan))) {
  477. c = party[i].flag;
  478. if (c == '-')
  479. c = ' ';
  480. if (party[i].timer == 0L)
  481. strcpy(idle, " [idle?]");
  482. else if (now - party[i].timer > 300) {
  483. unsigned long days, hrs, mins;
  484. days = (now - party[i].timer) / 86400;
  485. hrs = ((now - party[i].timer) - (days * 86400)) / 3600;
  486. mins = ((now - party[i].timer) - (hrs * 3600)) / 60;
  487. if (days > 0)
  488. sprintf(idle, " [idle %lud%luh]", days, hrs);
  489. else if (hrs > 0)
  490. sprintf(idle, " [idle %luh%lum]", hrs, mins);
  491. else
  492. sprintf(idle, " [idle %lum]", mins);
  493. } else
  494. idle[0] = 0;
  495. total++;
  496. dprintf(idx, format, c, party[i].nick,
  497. (party[i].chan == 0) && (chan == (-1)) ? '+' : ' ',
  498. #ifdef HUB
  499. party[i].bot, party[i].from, idle);
  500. #else /* !HUB */
  501. idle);
  502. #endif /* HUB */
  503. if (party[i].status & PLSTAT_AWAY)
  504. dprintf(idx, " %s: %s\n", MISC_AWAY,
  505. party[i].away ? party[i].away : "");
  506. }
  507. }
  508. dprintf(idx, "Total users: %d\n", total);
  509. }
  510. /* Show z a list of all bots connected
  511. */
  512. void tell_bots(int idx)
  513. {
  514. char s[512];
  515. int i;
  516. tand_t *bot;
  517. if (!tands) {
  518. dprintf(idx, STR("No bots linked\n"));
  519. return;
  520. }
  521. strcpy(s, botnetnick);
  522. i = strlen(botnetnick);
  523. for (bot = tandbot; bot; bot = bot->next) {
  524. if (i > (500 - HANDLEN)) {
  525. dprintf(idx, STR("Bots: %s\n"), s);
  526. s[0] = 0;
  527. i = 0;
  528. }
  529. if (i) {
  530. s[i++] = ',';
  531. s[i++] = ' ';
  532. }
  533. strcpy(s + i, bot->bot);
  534. i += strlen(bot->bot);
  535. }
  536. if (s[0])
  537. dprintf(idx, STR("Bots: %s\n"), s);
  538. dprintf(idx, STR("(Total up: %d)\n"), tands + 1);
  539. }
  540. /* Show a simpleton bot tree
  541. */
  542. void tell_bottree(int idx, int showver)
  543. {
  544. char s[161];
  545. tand_t *last[20], *this, *bot, *bot2 = NULL;
  546. int lev = 0, more = 1, mark[20], ok, cnt, i, imark;
  547. char work[1024];
  548. int tothops = 0;
  549. if (tands == 0) {
  550. dprintf(idx, "%s\n", BOT_NOBOTSLINKED);
  551. return;
  552. }
  553. s[0] = 0;
  554. i = 0;
  555. for (bot = tandbot; bot; bot = bot->next)
  556. if (!bot->uplink) {
  557. if (i) {
  558. s[i++] = ',';
  559. s[i++] = ' ';
  560. }
  561. strcpy(s + i, bot->bot);
  562. i += strlen(bot->bot);
  563. }
  564. if (s[0])
  565. dprintf(idx, "(%s %s)\n", BOT_NOTRACEINFO, s);
  566. if (showver)
  567. dprintf(idx, "%s (%d.%d.%d.%d)\n", botnetnick,
  568. egg_numver / 1000000,
  569. egg_numver % 1000000 / 10000,
  570. egg_numver % 10000 / 100,
  571. egg_numver % 100);
  572. else
  573. dprintf(idx, "%s\n", botnetnick);
  574. this = (tand_t *) 1;
  575. work[0] = 0;
  576. while (more) {
  577. if (lev == 20) {
  578. dprintf(idx, "\n%s\n", BOT_COMPLEXTREE);
  579. return;
  580. }
  581. cnt = 0;
  582. tothops += lev;
  583. for (bot = tandbot; bot; bot = bot->next)
  584. if (bot->uplink == this)
  585. cnt++;
  586. if (cnt) {
  587. imark = 0;
  588. for (i = 0; i < lev; i++) {
  589. if (mark[i])
  590. strcpy(work + imark, " | ");
  591. else
  592. strcpy(work + imark, " ");
  593. imark += 5;
  594. }
  595. if (cnt > 1)
  596. strcpy(work + imark, " |-");
  597. else
  598. strcpy(work + imark, " `-");
  599. s[0] = 0;
  600. bot = tandbot;
  601. while (!s[0]) {
  602. if (bot->uplink == this) {
  603. if (bot->ver) {
  604. i = sprintf(s, "%c%s", bot->share, bot->bot);
  605. if (showver)
  606. sprintf(s + i, " (%d.%d.%d.%d)",
  607. bot->ver / 1000000,
  608. bot->ver % 1000000 / 10000,
  609. bot->ver % 10000 / 100,
  610. bot->ver % 100);
  611. } else {
  612. sprintf(s, "-%s", bot->bot);
  613. }
  614. } else
  615. bot = bot->next;
  616. }
  617. dprintf(idx, "%s%s\n", work, s);
  618. if (cnt > 1)
  619. mark[lev] = 1;
  620. else
  621. mark[lev] = 0;
  622. work[0] = 0;
  623. last[lev] = this;
  624. this = bot;
  625. lev++;
  626. more = 1;
  627. } else {
  628. while (cnt == 0) {
  629. /* No subtrees from here */
  630. if (lev == 0) {
  631. dprintf(idx, "(( tree error ))\n");
  632. return;
  633. }
  634. ok = 0;
  635. for (bot = tandbot; bot; bot = bot->next) {
  636. if (bot->uplink == last[lev - 1]) {
  637. if (this == bot)
  638. ok = 1;
  639. else if (ok) {
  640. cnt++;
  641. if (cnt == 1) {
  642. bot2 = bot;
  643. if (bot->ver) {
  644. i = sprintf(s, "%c%s", bot->share, bot->bot);
  645. if (showver)
  646. sprintf(s + i, " (%d.%d.%d.%d)",
  647. bot->ver / 1000000,
  648. bot->ver % 1000000 / 10000,
  649. bot->ver % 10000 / 100,
  650. bot->ver % 100);
  651. } else {
  652. sprintf(s, "-%s", bot->bot);
  653. }
  654. }
  655. }
  656. }
  657. }
  658. if (cnt) {
  659. imark = 0;
  660. for (i = 1; i < lev; i++) {
  661. if (mark[i - 1])
  662. strcpy(work + imark, " | ");
  663. else
  664. strcpy(work + imark, " ");
  665. imark += 5;
  666. }
  667. more = 1;
  668. if (cnt > 1)
  669. dprintf(idx, "%s |-%s\n", work, s);
  670. else
  671. dprintf(idx, "%s `-%s\n", work, s);
  672. this = bot2;
  673. work[0] = 0;
  674. if (cnt > 1)
  675. mark[lev - 1] = 1;
  676. else
  677. mark[lev - 1] = 0;
  678. } else {
  679. /* This was the last child */
  680. lev--;
  681. if (lev == 0) {
  682. more = 0;
  683. cnt = 999;
  684. } else {
  685. more = 1;
  686. this = last[lev];
  687. }
  688. }
  689. }
  690. }
  691. }
  692. /* Hop information: (9d) */
  693. dprintf(idx, "Average hops: %3.1f, total bots: %d\n",
  694. ((float) tothops) / ((float) tands), tands + 1);
  695. }
  696. /* Dump list of links to a new bot
  697. */
  698. void dump_links(int z)
  699. {
  700. register int i, l;
  701. char x[1024];
  702. tand_t *bot;
  703. for (bot = tandbot; bot; bot = bot->next) {
  704. char *p;
  705. if (bot->uplink == (tand_t *) 1)
  706. p = botnetnick;
  707. else
  708. p = bot->uplink->bot;
  709. l = simple_sprintf(x, "n %s %s %c%D\n", bot->bot, p,
  710. bot->share, bot->ver);
  711. tputs(dcc[z].sock, x, l);
  712. }
  713. if (!(bot_flags(dcc[z].user) & BOT_ISOLATE)) {
  714. /* Dump party line members */
  715. for (i = 0; i < dcc_total; i++) {
  716. if (dcc[i].type == &DCC_CHAT) {
  717. if ((dcc[i].u.chat->channel >= 0) &&
  718. (dcc[i].u.chat->channel < GLOBAL_CHANS)) {
  719. l = simple_sprintf(x, "j !%s %s %D %c%D %s\n",
  720. botnetnick, dcc[i].nick,
  721. dcc[i].u.chat->channel, geticon(i),
  722. dcc[i].sock, dcc[i].host);
  723. tputs(dcc[z].sock, x, l);
  724. l = simple_sprintf(x, "i %s %D %D %s\n", botnetnick,
  725. dcc[i].sock, now - dcc[i].timeval,
  726. dcc[i].u.chat->away ? dcc[i].u.chat->away : "");
  727. tputs(dcc[z].sock, x, l);
  728. }
  729. }
  730. }
  731. for (i = 0; i < parties; i++) {
  732. l = simple_sprintf(x, "j %s %s %D %c%D %s\n",
  733. party[i].bot, party[i].nick,
  734. party[i].chan, party[i].flag,
  735. party[i].sock, party[i].from);
  736. tputs(dcc[z].sock, x, l);
  737. if ((party[i].status & PLSTAT_AWAY) || (party[i].timer != 0)) {
  738. l = simple_sprintf(x, "i %s %D %D %s\n", party[i].bot,
  739. party[i].sock, now - party[i].timer,
  740. party[i].away ? party[i].away : "");
  741. tputs(dcc[z].sock, x, l);
  742. }
  743. }
  744. }
  745. }
  746. int in_chain(char *who)
  747. {
  748. if (findbot(who))
  749. return 1;
  750. if (!egg_strcasecmp(who, botnetnick))
  751. return 1;
  752. return 0;
  753. }
  754. int bots_in_subtree(tand_t *bot)
  755. {
  756. int nr = 1;
  757. tand_t *b;
  758. if (!bot)
  759. return 0;
  760. for (b = tandbot; b; b = b->next) {
  761. if (b->bot && (b->uplink == bot)) {
  762. nr += bots_in_subtree(b);
  763. }
  764. }
  765. return nr;
  766. }
  767. int users_in_subtree(tand_t *bot)
  768. {
  769. int i, nr;
  770. tand_t *b;
  771. nr = 0;
  772. if (!bot)
  773. return 0;
  774. for (i = 0; i < parties; i++)
  775. if (!egg_strcasecmp(party[i].bot, bot->bot))
  776. nr++;
  777. for (b = tandbot; b; b = b->next)
  778. if (b->bot && (b->uplink == bot))
  779. nr += users_in_subtree(b);
  780. return nr;
  781. }
  782. /* Break link with a tandembot
  783. */
  784. int botunlink(int idx, char *nick, char *reason)
  785. {
  786. char s[20];
  787. register int i;
  788. int bots, users;
  789. tand_t *bot;
  790. if (nick[0] == '*')
  791. dprintf(idx, "%s\n", BOT_UNLINKALL);
  792. for (i = 0; i < dcc_total; i++) {
  793. if ((nick[0] == '*') || !egg_strcasecmp(dcc[i].nick, nick)) {
  794. if (dcc[i].type == &DCC_FORK_BOT) {
  795. if (idx >= 0)
  796. dprintf(idx, "%s: %s -> %s.\n", BOT_KILLLINKATTEMPT,
  797. dcc[i].nick, dcc[i].host);
  798. putlog(LOG_BOTS, "*", "%s: %s -> %s:%d",
  799. BOT_KILLLINKATTEMPT, dcc[i].nick,
  800. dcc[i].host, dcc[i].port);
  801. killsock(dcc[i].sock);
  802. lostdcc(i);
  803. if (nick[0] != '*')
  804. return 1;
  805. } else if (dcc[i].type == &DCC_BOT_NEW) {
  806. if (idx >= 0)
  807. dprintf(idx, "%s %s.\n", BOT_ENDLINKATTEMPT,
  808. dcc[i].nick);
  809. putlog(LOG_BOTS, "*", "%s %s @ %s:%d",
  810. "Stopped trying to link", dcc[i].nick,
  811. dcc[i].host, dcc[i].port);
  812. killsock(dcc[i].sock);
  813. lostdcc(i);
  814. if (nick[0] != '*')
  815. return 1;
  816. } else if (dcc[i].type == &DCC_BOT) {
  817. char s[1024];
  818. if (idx >= 0)
  819. dprintf(idx, "%s %s.\n", BOT_BREAKLINK, dcc[i].nick);
  820. else if ((idx == -3) && (b_status(i) & STAT_SHARE) && !share_unlinks)
  821. return -1;
  822. bot = findbot(dcc[i].nick);
  823. bots = bots_in_subtree(bot);
  824. users = users_in_subtree(bot);
  825. if (reason && reason[0]) {
  826. simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
  827. BOT_UNLINKEDFROM, dcc[i].nick, reason, bots,
  828. (bots != 1) ? "s" : "", users, (users != 1) ?
  829. "s" : "");
  830. dprintf(i, "bye %s\n", reason);
  831. } else {
  832. simple_sprintf(s, "%s %s (lost %d bot%s and %d user%s)",
  833. BOT_UNLINKEDFROM, dcc[i].nick, bots, (bots != 1) ?
  834. "s" : "", users, (users != 1) ? "s" : "");
  835. dprintf(i, "bye No reason\n");
  836. }
  837. chatout("*** %s\n", s);
  838. botnet_send_unlinked(i, dcc[i].nick, s);
  839. killsock(dcc[i].sock);
  840. lostdcc(i);
  841. if (nick[0] != '*')
  842. return 1;
  843. }
  844. }
  845. }
  846. if (idx >= 0 && nick[0] != '*')
  847. dprintf(idx, "%s\n", BOT_NOTCONNECTED);
  848. if (nick[0] != '*') {
  849. bot = findbot(nick);
  850. if (bot) {
  851. /* The internal bot list is desynched from the dcc list
  852. sometimes. While we still search for the bug, provide
  853. an easy way to clear out those `ghost'-bots.
  854. Fabian (2000-08-02) */
  855. char *ghost = "BUG!!: Found bot `%s' in internal bot list, but it\n"
  856. " shouldn't have been there! Removing.\n"
  857. " This is a known bug we haven't fixed yet. If this\n"
  858. " bot is the newest eggdrop version available and you\n"
  859. " know a *reliable* way to reproduce the bug, please\n"
  860. " contact us - we need your help!\n";
  861. if (idx >= 0)
  862. dprintf(idx, ghost, nick);
  863. else
  864. putlog(LOG_MISC, "*", ghost, nick);
  865. rembot(bot->bot);
  866. return 1;
  867. }
  868. }
  869. if (nick[0] == '*') {
  870. dprintf(idx, "%s\n", BOT_WIPEBOTTABLE);
  871. while (tandbot)
  872. rembot(tandbot->bot);
  873. while (parties) {
  874. parties--;
  875. /* Assert? */
  876. if (party[i].chan >= 0)
  877. check_tcl_chpt(party[i].bot, party[i].nick, party[i].sock,
  878. party[i].chan);
  879. }
  880. strcpy(s, "killassoc &");
  881. Tcl_Eval(interp, s);
  882. }
  883. return 0;
  884. }
  885. static void botlink_resolve_success(int);
  886. static void botlink_resolve_failure(int);
  887. /* Link to another bot
  888. */
  889. int botlink(char *linker, int idx, char *nick)
  890. {
  891. struct bot_addr *bi;
  892. struct userrec *u;
  893. register int i;
  894. u = get_user_by_handle(userlist, nick);
  895. if (!u || !(u->flags & USER_BOT)) {
  896. if (idx >= 0)
  897. dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
  898. } else if (!egg_strcasecmp(nick, botnetnick)) {
  899. if (idx >= 0)
  900. dprintf(idx, "%s\n", BOT_CANTLINKMYSELF);
  901. } else if (in_chain(nick) && (idx != -3)) {
  902. if (idx >= 0)
  903. dprintf(idx, "%s\n", BOT_ALREADYLINKED);
  904. } else {
  905. for (i = 0; i < dcc_total; i++)
  906. if ((dcc[i].user == u) &&
  907. ((dcc[i].type == &DCC_FORK_BOT) ||
  908. (dcc[i].type == &DCC_BOT_NEW))) {
  909. if (idx >= 0)
  910. dprintf(idx, "%s\n", BOT_ALREADYLINKING);
  911. return 0;
  912. }
  913. /* Address to connect to is in 'info' */
  914. bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
  915. if (!bi || !strlen(bi->address) || !bi->telnet_port || (bi->telnet_port <= 0)) {
  916. if (idx >= 0) {
  917. dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
  918. dprintf(idx, "%s .chaddr %s %s\n",
  919. MISC_USEFORMAT, nick, MISC_CHADDRFORMAT);
  920. }
  921. } else if (dcc_total == max_dcc) {
  922. if (idx >= 0)
  923. dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
  924. } else {
  925. correct_handle(nick);
  926. if (idx > -2)
  927. putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
  928. bi->address, bi->telnet_port);
  929. i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
  930. dcc[i].timeval = now;
  931. dcc[i].port = bi->telnet_port;
  932. dcc[i].user = u;
  933. strcpy(dcc[i].nick, nick);
  934. strcpy(dcc[i].host, bi->address);
  935. dcc[i].u.dns->ibuf = idx;
  936. dcc[i].u.dns->cptr = get_data_ptr(strlen(linker) + 1);
  937. strcpy(dcc[i].u.dns->cptr, linker);
  938. dcc[i].u.dns->host = get_data_ptr(strlen(dcc[i].host) + 1);
  939. strcpy(dcc[i].u.dns->host, dcc[i].host);
  940. dcc[i].u.dns->dns_success = botlink_resolve_success;
  941. dcc[i].u.dns->dns_failure = botlink_resolve_failure;
  942. dcc[i].u.dns->dns_type = RES_IPBYHOST;
  943. dcc[i].u.dns->type = &DCC_FORK_BOT;
  944. #ifdef USE_IPV6
  945. botlink_resolve_success(i);
  946. #else
  947. dcc_dnsipbyhost(bi->address);
  948. #endif /* USE_IPV6 */
  949. return 1;
  950. }
  951. }
  952. return 0;
  953. }
  954. static void botlink_resolve_failure(int i)
  955. {
  956. nfree(dcc[i].u.dns->cptr);
  957. lostdcc(i);
  958. }
  959. static void botlink_resolve_success(int i)
  960. {
  961. int idx = dcc[i].u.dns->ibuf;
  962. char *linker = dcc[i].u.dns->cptr;
  963. dcc[i].addr = dcc[i].u.dns->ip;
  964. changeover_dcc(i, &DCC_FORK_BOT, sizeof(struct bot_info));
  965. dcc[i].timeval = now;
  966. strcpy(dcc[i].u.bot->linker, linker);
  967. strcpy(dcc[i].u.bot->version, "(primitive bot)");
  968. strcpy(dcc[i].u.bot->sysname, "*");
  969. dcc[i].u.bot->numver = idx;
  970. dcc[i].u.bot->port = dcc[i].port; /* Remember where i started */
  971. #ifdef USE_IPV6
  972. dcc[i].sock = getsock(SOCK_STRONGCONN, hostprotocol(dcc[i].host));
  973. #else
  974. dcc[i].sock = getsock(SOCK_STRONGCONN);
  975. #endif /* USE_IPV6 */
  976. nfree(linker);
  977. if (dcc[i].sock < 0 ||
  978. #ifdef USE_IPV6
  979. open_telnet_raw(dcc[i].sock, dcc[i].host,
  980. #else
  981. open_telnet_raw(dcc[i].sock, iptostr(htonl(dcc[i].addr)),
  982. #endif /* USE_IPV6 */
  983. dcc[i].port) < 0)
  984. failed_link(i);
  985. else { /* let's attempt to initiate SSL before ANYTHING else... */
  986. #ifdef HAVE_SSL
  987. /* if (!ssl_link(dcc[i].sock, CONNECT_SSL)) {
  988. debug2("back from ssl_link(%d, %d) for botlink (failed)", dcc[i].sock, CONNECT_SSL);
  989. dcc[i].ssl = 0;
  990. putlog(LOG_BOTS, "*", "SSL link for '%s' failed", dcc[i].nick);
  991. } else */
  992. dcc[i].ssl = 1;
  993. #else
  994. dcc[i].ssl = 0;
  995. #endif /* HAVE_SSL */
  996. }
  997. }
  998. static void failed_tandem_relay(int idx)
  999. {
  1000. int uidx = (-1), i;
  1001. for (i = 0; i < dcc_total; i++)
  1002. if ((dcc[i].type == &DCC_PRE_RELAY) &&
  1003. (dcc[i].u.relay->sock == dcc[idx].sock))
  1004. uidx = i;
  1005. if (uidx < 0) {
  1006. putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
  1007. dcc[idx].sock, dcc[idx].u.relay->sock);
  1008. killsock(dcc[idx].sock);
  1009. lostdcc(idx);
  1010. return;
  1011. }
  1012. if (dcc[idx].port >= dcc[idx].u.relay->port + 3) {
  1013. struct chat_info *ci = dcc[uidx].u.relay->chat;
  1014. dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
  1015. dcc[uidx].status = dcc[uidx].u.relay->old_status;
  1016. nfree(dcc[uidx].u.relay);
  1017. dcc[uidx].u.chat = ci;
  1018. dcc[uidx].type = &DCC_CHAT;
  1019. killsock(dcc[idx].sock);
  1020. lostdcc(idx);
  1021. return;
  1022. }
  1023. killsock(dcc[idx].sock);
  1024. #ifdef USE_IPV6
  1025. dcc[idx].sock = getsock(SOCK_STRONGCONN, hostprotocol(dcc[idx].host));
  1026. #else
  1027. dcc[idx].sock = getsock(SOCK_STRONGCONN);
  1028. #endif /* USE_IPV6 */
  1029. dcc[uidx].u.relay->sock = dcc[idx].sock;
  1030. dcc[idx].port++;
  1031. dcc[idx].timeval = now;
  1032. if (dcc[idx].sock < 0 ||
  1033. #ifdef USE_IPV6
  1034. open_telnet_raw(dcc[idx].sock, dcc[idx].host,
  1035. #else
  1036. if (dcc[idx].sock < 0 ||
  1037. open_telnet_raw(dcc[idx].sock, dcc[idx].addr ?
  1038. iptostr(htonl(dcc[idx].addr)) :
  1039. dcc[idx].host,
  1040. #endif /* USE_IPV6 */
  1041. dcc[idx].port) < 0)
  1042. failed_tandem_relay(idx);
  1043. }
  1044. static void tandem_relay_resolve_failure(int);
  1045. static void tandem_relay_resolve_success(int);
  1046. /* Relay to another tandembot
  1047. */
  1048. void tandem_relay(int idx, char *nick, register int i)
  1049. {
  1050. struct userrec *u;
  1051. struct bot_addr *bi;
  1052. struct chat_info *ci;
  1053. u = get_user_by_handle(userlist, nick);
  1054. if (!u || !(u->flags & USER_BOT)) {
  1055. dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
  1056. return;
  1057. }
  1058. if (!egg_strcasecmp(nick, botnetnick)) {
  1059. dprintf(idx, "%s\n", BOT_CANTRELAYMYSELF);
  1060. return;
  1061. }
  1062. /* Address to connect to is in 'info' */
  1063. bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
  1064. if (!bi || !strlen(bi->address) || !bi->relay_port || (bi->relay_port <= 0)) {
  1065. dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
  1066. dprintf(idx, "%s .chaddr %s %s\n",
  1067. MISC_USEFORMAT, nick, MISC_CHADDRFORMAT);
  1068. return;
  1069. }
  1070. i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
  1071. if (i < 0) {
  1072. dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
  1073. return;
  1074. }
  1075. #ifdef USE_IPV6
  1076. dcc[i].sock = getsock(SOCK_STRONGCONN | SOCK_VIRTUAL, hostprotocol(bi->address));
  1077. #else
  1078. dcc[i].sock = getsock(SOCK_STRONGCONN | SOCK_VIRTUAL);
  1079. #endif /* USE_IPV6 */
  1080. if (dcc[i].sock < 0) {
  1081. lostdcc(i);
  1082. dprintf(idx, "%s\n", MISC_NOFREESOCK);
  1083. return;
  1084. }
  1085. dcc[i].port = bi->relay_port;
  1086. dcc[i].addr = 0L;
  1087. strcpy(dcc[i].nick, nick);
  1088. dcc[i].user = u;
  1089. strcpy(dcc[i].host, bi->address);
  1090. #ifdef HUB
  1091. dprintf(idx, "%s %s @ %s:%d ...\n", BOT_CONNECTINGTO, nick, bi->address, bi->relay_port);
  1092. #endif /* HUB */
  1093. dprintf(idx, "%s\n", BOT_BYEINFO1);
  1094. dcc[idx].type = &DCC_PRE_RELAY;
  1095. ci = dcc[idx].u.chat;
  1096. dcc[idx].u.relay = get_data_ptr(sizeof(struct relay_info));
  1097. dcc[idx].u.relay->chat = ci;
  1098. dcc[idx].u.relay->old_status = dcc[idx].status;
  1099. dcc[idx].u.relay->sock = dcc[i].sock;
  1100. dcc[i].timeval = now;
  1101. dcc[i].u.dns->ibuf = dcc[idx].sock;
  1102. dcc[i].u.dns->host = get_data_ptr(strlen(bi->address) + 1);
  1103. strcpy(dcc[i].u.dns->host, bi->address);
  1104. dcc[i].u.dns->dns_success = tandem_relay_resolve_success;
  1105. dcc[i].u.dns->dns_failure = tandem_relay_resolve_failure;
  1106. dcc[i].u.dns->dns_type = RES_IPBYHOST;
  1107. dcc[i].u.dns->type = &DCC_FORK_RELAY;
  1108. #ifdef USE_IPV6
  1109. tandem_relay_resolve_success(i);
  1110. #else
  1111. dcc_dnsipbyhost(bi->address);
  1112. #endif /* USE_IPV6 */
  1113. }
  1114. static void tandem_relay_resolve_failure(int idx)
  1115. {
  1116. struct chat_info *ci;
  1117. register int uidx = (-1), i;
  1118. for (i = 0; i < dcc_total; i++)
  1119. if ((dcc[i].type == &DCC_PRE_RELAY) &&
  1120. (dcc[i].u.relay->sock == dcc[idx].sock)) {
  1121. uidx = i;
  1122. break;
  1123. }
  1124. if (uidx < 0) {
  1125. putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
  1126. dcc[idx].sock, dcc[idx].u.relay->sock);
  1127. killsock(dcc[idx].sock);
  1128. lostdcc(idx);
  1129. return;
  1130. }
  1131. ci = dcc[uidx].u.relay->chat;
  1132. dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
  1133. dcc[uidx].status = dcc[uidx].u.relay->old_status;
  1134. nfree(dcc[uidx].u.relay);
  1135. dcc[uidx].u.chat = ci;
  1136. dcc[uidx].type = &DCC_CHAT;
  1137. killsock(dcc[idx].sock);
  1138. lostdcc(idx);
  1139. }
  1140. static void tandem_relay_resolve_success(int i)
  1141. {
  1142. int sock = dcc[i].u.dns->ibuf;
  1143. dcc[i].addr = dcc[i].u.dns->ip;
  1144. changeover_dcc(i, &DCC_FORK_RELAY, sizeof(struct relay_info));
  1145. dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info));
  1146. dcc[i].u.relay->sock = sock;
  1147. dcc[i].u.relay->port = dcc[i].port;
  1148. dcc[i].u.relay->chat->away = NULL;
  1149. dcc[i].u.relay->chat->msgs_per_sec = 0;
  1150. dcc[i].u.relay->chat->con_flags = 0;
  1151. dcc[i].u.relay->chat->buffer = NULL;
  1152. dcc[i].u.relay->chat->max_line = 0;
  1153. dcc[i].u.relay->chat->line_count = 0;
  1154. dcc[i].u.relay->chat->current_lines = 0;
  1155. dcc[i].timeval = now;
  1156. #ifdef USE_IPV6
  1157. if (open_telnet_raw(dcc[i].sock, dcc[i].host,
  1158. #else
  1159. if (open_telnet_raw(dcc[i].sock, iptostr(htonl(dcc[i].addr)),
  1160. #endif /* USE_IPV6 */
  1161. dcc[i].port) < 0)
  1162. failed_tandem_relay(i);
  1163. }
  1164. /* Input from user before connect is ready
  1165. */
  1166. static void pre_relay(int idx, char *buf, register int i)
  1167. {
  1168. register int tidx = (-1);
  1169. for (i = 0; i < dcc_total; i++)
  1170. if ((dcc[i].type == &DCC_FORK_RELAY) &&
  1171. (dcc[i].u.relay->sock == dcc[idx].sock)) {
  1172. tidx = i;
  1173. break;
  1174. }
  1175. if (tidx < 0) {
  1176. /* Now try to find it among the DNSWAIT sockets instead. */
  1177. for (i = 0; i < dcc_total; i++)
  1178. if ((dcc[i].type == &DCC_DNSWAIT) &&
  1179. (dcc[i].sock == dcc[idx].u.relay->sock)) {
  1180. tidx = i;
  1181. break;
  1182. }
  1183. }
  1184. if (tidx < 0) {
  1185. putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
  1186. dcc[idx].sock, dcc[idx].u.relay->sock);
  1187. killsock(dcc[idx].sock);
  1188. lostdcc(idx);
  1189. return;
  1190. }
  1191. if (!egg_strcasecmp(buf, "*bye*")) {
  1192. /* Disconnect */
  1193. struct chat_info *ci = dcc[idx].u.relay->chat;
  1194. dprintf(idx, "%s %s.\n", BOT_ABORTRELAY1, dcc[tidx].nick);
  1195. dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
  1196. putlog(LOG_MISC, "*", "%s %s -> %s", BOT_ABORTRELAY3, dcc[idx].nick,
  1197. dcc[tidx].nick);
  1198. dcc[idx].status = dcc[idx].u.relay->old_status;
  1199. nfree(dcc[idx].u.relay);
  1200. dcc[idx].u.chat = ci;
  1201. dcc[idx].type = &DCC_CHAT;
  1202. killsock(dcc[tidx].sock);
  1203. lostdcc(tidx);
  1204. return;
  1205. }
  1206. }
  1207. /* User disconnected before her relay had finished connecting
  1208. */
  1209. static void failed_pre_relay(int idx)
  1210. {
  1211. register int tidx = (-1), i;
  1212. for (i = 0; i < dcc_total; i++)
  1213. if ((dcc[i].type == &DCC_FORK_RELAY) &&
  1214. (dcc[i].u.relay->sock == dcc[idx].sock)) {
  1215. tidx = i;
  1216. break;
  1217. }
  1218. if (tidx < 0) {
  1219. /* Now try to find it among the DNSWAIT sockets instead. */
  1220. for (i = 0; i < dcc_total; i++)
  1221. if ((dcc[i].type == &DCC_DNSWAIT) &&
  1222. (dcc[i].sock == dcc[idx].u.relay->sock)) {
  1223. tidx = i;
  1224. break;
  1225. }
  1226. }
  1227. if (tidx < 0) {
  1228. putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
  1229. dcc[idx].sock, dcc[idx].u.relay->sock);
  1230. killsock(dcc[idx].sock);
  1231. lostdcc(idx);
  1232. return;
  1233. }
  1234. putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
  1235. dcc[idx].host, dcc[idx].port);
  1236. putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPINGRELAY, dcc[tidx].nick);
  1237. if ((dcc[tidx].sock != STDOUT) || backgrd) {
  1238. if (idx > tidx) {
  1239. int t = tidx;
  1240. tidx = idx;
  1241. idx = t;
  1242. }
  1243. killsock(dcc[tidx].sock);
  1244. lostdcc(tidx);
  1245. } else {
  1246. fatal("Lost my terminal?!", 0);
  1247. }
  1248. killsock(dcc[idx].sock);
  1249. lostdcc(idx);
  1250. }
  1251. static void cont_tandem_relay(int idx, char *buf, register int i)
  1252. {
  1253. register int uidx = (-1);
  1254. struct relay_info *ri;
  1255. for (i = 0; i < dcc_total; i++)
  1256. if ((dcc[i].type == &DCC_PRE_RELAY) &&
  1257. (dcc[i].u.relay->sock == dcc[idx].sock))
  1258. uidx = i;
  1259. if (uidx < 0) {
  1260. putlog(LOG_MISC, "*", "%s %d -> %d", BOT_CANTFINDRELAYUSER,
  1261. dcc[i].sock, dcc[i].u.relay->sock);
  1262. killsock(dcc[i].sock);
  1263. lostdcc(i);
  1264. return;
  1265. }
  1266. dcc[idx].type = &DCC_RELAY;
  1267. dcc[idx].u.relay->sock = dcc[uidx].sock;
  1268. dcc[uidx].u.relay->sock = dcc[idx].sock;
  1269. dprintf(uidx, "%s %s ...\n", BOT_RELAYSUCCESS, dcc[idx].nick);
  1270. dprintf(uidx, "%s\n\n", BOT_BYEINFO2);
  1271. putlog(LOG_MISC, "*", "%s %s -> %s", BOT_RELAYLINK,
  1272. dcc[uidx].nick, dcc[idx].nick);
  1273. ri = dcc[uidx].u.relay; /* YEAH */
  1274. dcc[uidx].type = &DCC_CHAT;
  1275. dcc[uidx].u.chat = ri->chat;
  1276. if (dcc[uidx].u.chat->channel >= 0) {
  1277. chanout_but(-1, dcc[uidx].u.chat->channel, "*** %s %s\n",
  1278. dcc[uidx].nick, BOT_PARTYLEFT);
  1279. if (dcc[uidx].u.chat->channel < GLOBAL_CHANS)
  1280. botnet_send_part_idx(uidx, NULL);
  1281. check_tcl_chpt(botnetnick, dcc[uidx].nick, dcc[uidx].sock,
  1282. dcc[uidx].u.chat->channel);
  1283. }
  1284. check_tcl_chof(dcc[uidx].nick, dcc[uidx].sock);
  1285. dcc[uidx].type = &DCC_RELAYING;
  1286. dcc[uidx].u.relay = ri;
  1287. }
  1288. static void eof_dcc_relay(int idx)
  1289. {
  1290. register int j;
  1291. struct chat_info *ci;
  1292. for (j = 0; j < dcc_total; j++)
  1293. if (dcc[j].sock == dcc[idx].u.relay->sock)
  1294. break;
  1295. if (j == dcc_total) {
  1296. killsock(dcc[idx].sock);
  1297. lostdcc(idx);
  1298. return;
  1299. }
  1300. dcc[j].status = dcc[j].u.relay->old_status;
  1301. /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
  1302. if (dcc[j].status & STAT_TELNET)
  1303. dprintf(j, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
  1304. putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_ENDRELAY1, dcc[j].nick,
  1305. dcc[idx].nick);
  1306. dprintf(j, "\n\n*** %s %s\n", BOT_ENDRELAY2, botnetnick);
  1307. ci = dcc[j].u.relay->chat;
  1308. nfree(dcc[j].u.relay);
  1309. dcc[j].u.chat = ci;
  1310. dcc[j].type = &DCC_CHAT;
  1311. if (dcc[j].u.chat->channel >= 0) {
  1312. chanout_but(-1, dcc[j].u.chat->channel, "*** %s %s.\n",
  1313. dcc[j].nick, BOT_PARTYREJOINED);
  1314. if (dcc[j].u.chat->channel < GLOBAL_CHANS)
  1315. botnet_send_join_idx(j, -1);
  1316. }
  1317. check_tcl_chon(dcc[j].nick, dcc[j].sock);
  1318. check_tcl_chjn(botnetnick, dcc[j].nick, dcc[j].u.chat->channel,
  1319. geticon(j), dcc[j].sock, dcc[j].host);
  1320. killsock(dcc[idx].sock);
  1321. lostdcc(idx);
  1322. }
  1323. static void eof_dcc_relaying(int idx)
  1324. {
  1325. register int j, x = dcc[idx].u.relay->sock;
  1326. putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
  1327. dcc[idx].host, dcc[idx].port);
  1328. killsock(dcc[idx].sock);
  1329. lostdcc(idx);
  1330. for (j = 0; (dcc[j].sock != x) || (dcc[j].type == &DCC_FORK_RELAY); j++);
  1331. putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPEDRELAY, dcc[j].nick);
  1332. killsock(dcc[j].sock);
  1333. lostdcc(j); /* Drop connection to the bot */
  1334. }
  1335. static void dcc_relay(int idx, char *buf, int j)
  1336. {
  1337. unsigned char *p = (unsigned char *) buf;
  1338. int mark;
  1339. for (j = 0; dcc[j].sock != dcc[idx].u.relay->sock ||
  1340. dcc[j].type != &DCC_RELAYING; j++);
  1341. /* If redirecting to a non-telnet user, swallow telnet codes and
  1342. escape sequences. */
  1343. if (!(dcc[j].status & STAT_TELNET)) {
  1344. while (*p != 0) {
  1345. while (*p != 255 && (*p != '\033' || *(p + 1) != '[') && *p != '\r' && *p)
  1346. p++; /* Search for IAC, escape sequences and CR. */
  1347. if (*p == 255) {
  1348. mark = 2;
  1349. if (!*(p + 1))
  1350. mark = 1; /* Bogus */
  1351. if ((*(p + 1) >= 251) || (*(p + 1) <= 254)) {
  1352. mark = 3;
  1353. if (!*(p + 2))
  1354. mark = 2; /* Bogus */
  1355. }
  1356. strcpy((char *) p, (char *) (p + mark));
  1357. } else if (*p == '\033') {
  1358. unsigned char *e;
  1359. // Search for the end of the escape sequence.
  1360. for (e = p + 2; *e != 'm' && *e; e++)
  1361. ;
  1362. strcpy((char *) p, (char *) (e + 1));
  1363. } else if (*p == '\r')
  1364. strcpy((char *) p, (char *) (p + 1));
  1365. }
  1366. if (!buf[0])
  1367. dprintf(-dcc[idx].u.relay->sock, " \n");
  1368. else
  1369. dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
  1370. return;
  1371. }
  1372. /* Telnet user */
  1373. if (!buf[0])
  1374. dprintf(-dcc[idx].u.relay->sock, " \r\n");
  1375. else
  1376. dprintf(-dcc[idx].u.relay->sock, "%s\r\n", buf);
  1377. }
  1378. static void dcc_relaying(int idx, char *buf, int j)
  1379. {
  1380. struct chat_info *ci;
  1381. if (egg_strcasecmp(buf, "*bye*")) {
  1382. dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
  1383. return;
  1384. }
  1385. for (j = 0; (dcc[j].sock != dcc[idx].u.relay->sock) ||
  1386. (dcc[j].type != &DCC_RELAY); j++);
  1387. dcc[idx].status = dcc[idx].u.relay->old_status;
  1388. /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
  1389. if (dcc[idx].status & STAT_TELNET)
  1390. dprintf(idx, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
  1391. dprintf(idx, "\n(%s %s.)\n", BOT_BREAKRELAY, dcc[j].nick);
  1392. dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
  1393. putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_RELAYBROKEN,
  1394. dcc[idx].nick, dcc[j].nick);
  1395. if (dcc[idx].u.relay->chat->channel >= 0) {
  1396. chanout_but(-1, dcc[idx].u.relay->chat->channel,
  1397. "*** %s joined the party line.\n", dcc[idx].nick);
  1398. if (dcc[idx].u.relay->chat->channel < GLOBAL_CHANS)
  1399. botnet_send_join_idx(idx, -1);
  1400. }
  1401. ci = dcc[idx].u.relay->chat;
  1402. nfree(dcc[idx].u.relay);
  1403. dcc[idx].u.chat = ci;
  1404. dcc[idx].type = &DCC_CHAT;
  1405. check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
  1406. if (dcc[idx].u.chat->channel >= 0)
  1407. check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
  1408. geticon(idx), dcc[idx].sock, dcc[idx].host);
  1409. killsock(dcc[j].sock);
  1410. lostdcc(j);
  1411. }
  1412. static void display_relay(int i, char *other)
  1413. {
  1414. sprintf(other, "rela -> sock %d", dcc[i].u.relay->sock);
  1415. }
  1416. static void display_relaying(int i, char *other)
  1417. {
  1418. sprintf(other, ">rly -> sock %d", dcc[i].u.relay->sock);
  1419. }
  1420. static void display_tandem_relay(int i, char *other)
  1421. {
  1422. strcpy(other, "other rela");
  1423. }
  1424. static void display_pre_relay(int i, char *other)
  1425. {
  1426. strcpy(other, "other >rly");
  1427. }
  1428. static int expmem_relay(void *x)
  1429. {
  1430. register struct relay_info *p = (struct relay_info *) x;
  1431. int tot = sizeof(struct relay_info);
  1432. if (p->chat)
  1433. tot += DCC_CHAT.expmem(p->chat);
  1434. return tot;
  1435. }
  1436. static void kill_relay(int idx, void *x)
  1437. {
  1438. register struct relay_info *p = (struct relay_info *) x;
  1439. if (p->chat)
  1440. DCC_CHAT.kill(idx, p->chat);
  1441. nfree(p);
  1442. }
  1443. struct dcc_table DCC_RELAY =
  1444. {
  1445. "RELAY",
  1446. 0, /* Flags */
  1447. eof_dcc_relay,
  1448. dcc_relay,
  1449. NULL,
  1450. NULL,
  1451. display_relay,
  1452. expmem_relay,
  1453. kill_relay,
  1454. NULL
  1455. };
  1456. static void out_relay(int idx, char *buf, void *x)
  1457. {
  1458. register struct relay_info *p = (struct relay_info *) x;
  1459. if (p && p->chat)
  1460. DCC_CHAT.output(idx, buf, p->chat);
  1461. else
  1462. tputs(dcc[idx].sock, buf, strlen(buf));
  1463. }
  1464. struct dcc_table DCC_RELAYING =
  1465. {
  1466. "RELAYING",
  1467. 0, /* Flags */
  1468. eof_dcc_relaying,
  1469. dcc_relaying,
  1470. NULL,
  1471. NULL,
  1472. display_relaying,
  1473. expmem_relay,
  1474. kill_relay,
  1475. out_relay
  1476. };
  1477. struct dcc_table DCC_FORK_RELAY =
  1478. {
  1479. "FORK_RELAY",
  1480. 0, /* Flags */
  1481. failed_tandem_relay,
  1482. cont_tandem_relay,
  1483. &connect_timeout,
  1484. failed_tandem_relay,
  1485. display_tandem_relay,
  1486. expmem_relay,
  1487. kill_relay,
  1488. NULL
  1489. };
  1490. struct dcc_table DCC_PRE_RELAY =
  1491. {
  1492. "PRE_RELAY",
  1493. 0, /* Flags */
  1494. failed_pre_relay,
  1495. pre_relay,
  1496. NULL,
  1497. NULL,
  1498. display_pre_relay,
  1499. expmem_relay,
  1500. kill_relay,
  1501. NULL
  1502. };
  1503. /* Once a minute, send 'ping' to each bot -- no exceptions
  1504. */
  1505. void check_botnet_pings()
  1506. {
  1507. int i;
  1508. int bots, users;
  1509. tand_t *bot;
  1510. for (i = 0; i < dcc_total; i++) {
  1511. if (dcc[i].type == &DCC_BOT)
  1512. if (dcc[i].status & STAT_PINGED) {
  1513. char s[1024];
  1514. putlog(LOG_BOTS, "*", "%s: %s", BOT_PINGTIMEOUT, dcc[i].nick);
  1515. bot = findbot(dcc[i].nick);
  1516. bots = bots_in_subtree(bot);
  1517. users = users_in_subtree(bot);
  1518. simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", BOT_PINGTIMEOUT,
  1519. dcc[i].nick, bots, (bots != 1) ? "s" : "",
  1520. users, (users != 1) ? "s" : "");
  1521. chatout("*** %s\n", s);
  1522. botnet_send_unlinked(i, dcc[i].nick, s);
  1523. killsock(dcc[i].sock);
  1524. lostdcc(i);
  1525. }
  1526. }
  1527. for (i = 0; i < dcc_total; i++) {
  1528. if (dcc[i].type == &DCC_BOT) {
  1529. botnet_send_ping(i);
  1530. dcc[i].status |= STAT_PINGED;
  1531. }
  1532. }
  1533. for (i = 0; i < dcc_total; i++) {
  1534. if ((dcc[i].type == &DCC_BOT) && (dcc[i].status & STAT_LEAF)) {
  1535. tand_t *bot, *via = findbot(dcc[i].nick);
  1536. for (bot = tandbot; bot; bot = bot->next) {
  1537. if ((via == bot->via) && (bot != via)) {
  1538. /* Not leaflike behavior */
  1539. if (dcc[i].status & STAT_WARNED) {
  1540. char s[1024];
  1541. putlog(LOG_BOTS, "*", "%s %s (%s).", BOT_DISCONNECTED,
  1542. dcc[i].nick, BOT_BOTNOTLEAFLIKE);
  1543. dprintf(i, "bye %s\n", BOT_BOTNOTLEAFLIKE);
  1544. bot = findbot(dcc[i].nick);
  1545. bots = bots_in_subtree(bot);
  1546. users = users_in_subtree(bot);
  1547. simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
  1548. BOT_DISCONNECTED, dcc[i].nick, BOT_BOTNOTLEAFLIKE,
  1549. bots, (bots != 1) ? "s" : "", users, (users != 1) ?
  1550. "s" : "");
  1551. chatout("*** %s\n", s);
  1552. botnet_send_unlinked(i, dcc[i].nick, s);
  1553. killsock(dcc[i].sock);
  1554. lostdcc(i);
  1555. } else {
  1556. putlog(LOG_MISC, "*", "I am lame, and am now rejecting %s", bot->bot);
  1557. botnet_send_reject(i, botnetnick, NULL, bot->bot,
  1558. NULL, NULL);
  1559. dcc[i].status |= STAT_WARNED;
  1560. }
  1561. } else
  1562. dcc[i].status &= ~STAT_WARNED;
  1563. }
  1564. }
  1565. }
  1566. #ifdef HUB
  1567. #ifdef S_AUTOLOCK
  1568. local_check_should_lock();
  1569. #endif /* S_AUTOLOCK */
  1570. #ifdef G_BACKUP
  1571. check_should_backup();
  1572. #endif /* G_BACKUP */
  1573. #endif /* HUB */
  1574. }
  1575. void zapfbot(int idx)
  1576. {
  1577. char s[1024];
  1578. int bots, users;
  1579. tand_t *bot;
  1580. bot = findbot(dcc[idx].nick);
  1581. bots = bots_in_subtree(bot);
  1582. users = users_in_subtree(bot);
  1583. simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", BOT_BOTDROPPED,
  1584. dcc[idx].nick, bots, (bots != 1) ? "s" : "", users,
  1585. (users != 1) ? "s" : "");
  1586. chatout("*** %s\n", s);
  1587. botnet_send_unlinked(idx, dcc[idx].nick, s);
  1588. killsock(dcc[idx].sock);
  1589. lostdcc(idx);
  1590. }
  1591. void restart_chons()
  1592. {
  1593. int i;
  1594. /* Dump party line members */
  1595. for (i = 0; i < dcc_total; i++) {
  1596. if (dcc[i].type == &DCC_CHAT) {
  1597. check_tcl_chon(dcc[i].nick, dcc[i].sock);
  1598. check_tcl_chjn(botnetnick, dcc[i].nick, dcc[i].u.chat->channel,
  1599. geticon(i), dcc[i].sock, dcc[i].host);
  1600. }
  1601. }
  1602. for (i = 0; i < parties; i++) {
  1603. check_tcl_chjn(party[i].bot, party[i].nick, party[i].chan,
  1604. party[i].flag, party[i].sock, party[i].from);
  1605. }
  1606. }
  1607. static int get_role(char *bot)
  1608. {
  1609. int rl,
  1610. i;
  1611. struct bot_addr *ba;
  1612. int r[5] = { 0, 0, 0, 0, 0 };
  1613. struct userrec *u,
  1614. *u2;
  1615. u2 = get_user_by_handle(userlist, bot);
  1616. if (!u2)
  1617. return 1;
  1618. for (u = userlist; u; u = u->next) {
  1619. if (u->flags & USER_BOT) {
  1620. if (strcmp(u->handle, bot)) {
  1621. ba = get_user(&USERENTRY_BOTADDR, u);
  1622. if ((nextbot(u->handle) >= 0) && (ba) && (ba->roleid > 0)
  1623. && (ba->roleid < 5))
  1624. r[(ba->roleid - 1)]++;
  1625. }
  1626. }
  1627. }
  1628. rl = 0;
  1629. for (i = 1; i <= 4; i++)
  1630. if (r[i] < r[rl])
  1631. rl = i;
  1632. rl++;
  1633. ba = get_user(&USERENTRY_BOTADDR, u2);
  1634. if (ba)
  1635. ba->roleid = rl;
  1636. return rl;
  1637. }
  1638. void lower_bot_linked(int idx)
  1639. {
  1640. char tmp[6];
  1641. sprintf(tmp, STR("rl %d"), get_role(dcc[idx].nick));
  1642. botnet_send_zapf(nextbot(dcc[idx].nick), botnetnick, dcc[idx].nick, tmp);
  1643. }
  1644. void higher_bot_linked(int idx)
  1645. {
  1646. }