userchan.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613
  1. /*
  2. * userchan.c -- part of channels.mod
  3. *
  4. */
  5. #ifdef S_DCCPASS
  6. extern struct cmd_pass *cmdpass;
  7. #endif
  8. struct chanuserrec *get_chanrec(struct userrec *u, char *chname)
  9. {
  10. struct chanuserrec *ch = NULL;
  11. for (ch = u->chanrec; ch; ch = ch->next)
  12. if (!rfc_casecmp(ch->channel, chname))
  13. return ch;
  14. return NULL;
  15. }
  16. static struct chanuserrec *add_chanrec(struct userrec *u, char *chname)
  17. {
  18. struct chanuserrec *ch = NULL;
  19. if (findchan_by_dname(chname)) {
  20. ch = calloc(1, sizeof(struct chanuserrec));
  21. ch->next = u->chanrec;
  22. u->chanrec = ch;
  23. ch->info = NULL;
  24. ch->flags = 0;
  25. ch->flags_udef = 0;
  26. ch->laston = 0;
  27. strncpy(ch->channel, chname, 81);
  28. ch->channel[80] = 0;
  29. if (!noshare && !(u->flags & USER_UNSHARED))
  30. shareout(findchan_by_dname(chname), "+cr %s %s\n", u->handle, chname);
  31. }
  32. return ch;
  33. }
  34. static void add_chanrec_by_handle(struct userrec *bu, char *hand, char *chname)
  35. {
  36. struct userrec *u = NULL;
  37. u = get_user_by_handle(bu, hand);
  38. if (!u)
  39. return;
  40. if (!get_chanrec(u, chname))
  41. add_chanrec(u, chname);
  42. }
  43. static void get_handle_chaninfo(char *handle, char *chname, char *s)
  44. {
  45. struct userrec *u = NULL;
  46. struct chanuserrec *ch = NULL;
  47. u = get_user_by_handle(userlist, handle);
  48. if (u == NULL) {
  49. s[0] = 0;
  50. return;
  51. }
  52. ch = get_chanrec(u, chname);
  53. if (ch == NULL) {
  54. s[0] = 0;
  55. return;
  56. }
  57. if (ch->info == NULL) {
  58. s[0] = 0;
  59. return;
  60. }
  61. strcpy(s, ch->info);
  62. return;
  63. }
  64. static void set_handle_chaninfo(struct userrec *bu, char *handle,
  65. char *chname, char *info)
  66. {
  67. struct userrec *u = NULL;
  68. struct chanuserrec *ch = NULL;
  69. struct chanset_t *cst = NULL;
  70. u = get_user_by_handle(bu, handle);
  71. if (!u)
  72. return;
  73. ch = get_chanrec(u, chname);
  74. if (!ch) {
  75. add_chanrec_by_handle(bu, handle, chname);
  76. ch = get_chanrec(u, chname);
  77. }
  78. if (info) {
  79. if (strlen(info) > 80)
  80. info[80] = 0;
  81. }
  82. if (ch->info != NULL)
  83. free(ch->info);
  84. if (info && info[0]) {
  85. ch->info = strdup(info);
  86. } else
  87. ch->info = NULL;
  88. cst = findchan_by_dname(chname);
  89. if ((!noshare) && (bu == userlist) && !(u->flags & (USER_UNSHARED | USER_BOT))) {
  90. shareout(cst, "chchinfo %s %s %s\n", handle, chname, info ? info : "");
  91. }
  92. }
  93. static void del_chanrec(struct userrec *u, char *chname)
  94. {
  95. struct chanuserrec *ch = u->chanrec, *lst = NULL;
  96. while (ch) {
  97. if (!rfc_casecmp(chname, ch->channel)) {
  98. if (lst == NULL)
  99. u->chanrec = ch->next;
  100. else
  101. lst->next = ch->next;
  102. if (ch->info != NULL)
  103. free(ch->info);
  104. free(ch);
  105. if (!noshare && !(u->flags & USER_UNSHARED))
  106. shareout(findchan_by_dname(chname), "-cr %s %s\n", u->handle, chname);
  107. return;
  108. }
  109. lst = ch;
  110. ch = ch->next;
  111. }
  112. }
  113. static void set_handle_laston(char *chan, struct userrec *u, time_t n)
  114. {
  115. struct chanuserrec *ch = NULL;
  116. if (!u)
  117. return;
  118. touch_laston(u, chan, n);
  119. ch = get_chanrec(u, chan);
  120. if (!ch)
  121. return;
  122. ch->laston = n;
  123. }
  124. /* Is this mask sticky?
  125. */
  126. static int u_sticky_mask(maskrec *u, char *uhost)
  127. {
  128. for (; u; u = u->next)
  129. if (!rfc_casecmp(u->mask, uhost))
  130. return (u->flags & MASKREC_STICKY);
  131. return 0;
  132. }
  133. /* Set sticky attribute for a mask.
  134. */
  135. static int u_setsticky_mask(struct chanset_t *chan, maskrec *u, char *uhost,
  136. int sticky, char *botcmd)
  137. {
  138. int j;
  139. if (str_isdigit(uhost))
  140. j = atoi(uhost);
  141. else
  142. j = (-1);
  143. while(u) {
  144. if (j >= 0)
  145. j--;
  146. if (!j || ((j < 0) && !rfc_casecmp(u->mask, uhost))) {
  147. if (sticky > 0)
  148. u->flags |= MASKREC_STICKY;
  149. else if (!sticky)
  150. u->flags &= ~MASKREC_STICKY;
  151. else /* We don't actually want to change, just skip over */
  152. return 0;
  153. if (!j)
  154. strcpy(uhost, u->mask);
  155. if (!noshare)
  156. shareout(chan, "%s %s %d %s\n", botcmd, uhost, sticky,
  157. (chan) ? chan->dname : "");
  158. return 1;
  159. }
  160. u = u->next;
  161. }
  162. if (j >= 0)
  163. return -j;
  164. return 0;
  165. }
  166. /* Merge of u_equals_ban(), u_equals_exempt() and u_equals_invite().
  167. *
  168. * Returns:
  169. * 0 not a ban
  170. * 1 temporary ban
  171. * 2 perm ban
  172. */
  173. static int u_equals_mask(maskrec *u, char *mask)
  174. {
  175. for (; u; u = u->next)
  176. if (!rfc_casecmp(u->mask, mask)) {
  177. if (u->flags & MASKREC_PERM)
  178. return 2;
  179. else
  180. return 1;
  181. }
  182. return 0;
  183. }
  184. static int u_match_mask(maskrec *rec, char *mask)
  185. {
  186. for (; rec; rec = rec->next)
  187. if (wild_match(rec->mask, mask))
  188. return 1;
  189. return 0;
  190. }
  191. static int u_delban(struct chanset_t *c, char *who, int doit)
  192. {
  193. int j, i = 0;
  194. maskrec *t = NULL;
  195. maskrec **u = (c) ? &c->bans : &global_bans;
  196. char temp[256] = "";
  197. if (!strchr(who, '!') && str_isdigit(who)) {
  198. j = atoi(who);
  199. j--;
  200. for (; (*u) && j; u = &((*u)->next), j--);
  201. if (*u) {
  202. strncpyz(temp, (*u)->mask, sizeof temp);
  203. i = 1;
  204. } else
  205. return -j - 1;
  206. } else {
  207. /* Find matching host, if there is one */
  208. for (; *u && !i; u = &((*u)->next))
  209. if (!rfc_casecmp((*u)->mask, who)) {
  210. strncpyz(temp, who, sizeof temp);
  211. i = 1;
  212. break;
  213. }
  214. if (!*u)
  215. return 0;
  216. }
  217. if (i && doit) {
  218. if (!noshare) {
  219. char *mask = str_escape(temp, ':', '\\');
  220. if (mask) {
  221. /* Distribute chan bans differently */
  222. if (c)
  223. shareout(c, "-bc %s %s\n", c->dname, mask);
  224. else
  225. shareout(NULL, "-b %s\n", mask);
  226. free(mask);
  227. }
  228. }
  229. if (lastdeletedmask)
  230. free(lastdeletedmask);
  231. lastdeletedmask = strdup((*u)->mask);
  232. free((*u)->mask);
  233. if ((*u)->desc)
  234. free((*u)->desc);
  235. if ((*u)->user)
  236. free((*u)->user);
  237. t = *u;
  238. *u = (*u)->next;
  239. free(t);
  240. }
  241. return i;
  242. }
  243. static int u_delexempt (struct chanset_t * c, char * who, int doit)
  244. {
  245. int j, i = 0;
  246. maskrec *t = NULL;
  247. maskrec **u = c ? &(c->exempts) : &global_exempts;
  248. if (!strchr(who, '!') && str_isdigit(who)) {
  249. j = atoi(who);
  250. j--;
  251. for (;(*u) && j;u=&((*u)->next),j--);
  252. if (*u) {
  253. strcpy(who, (*u)->mask);
  254. i = 1;
  255. } else
  256. return -j-1;
  257. } else {
  258. /* Find matching host, if there is one */
  259. for (;*u && !i;u=&((*u)->next))
  260. if (!rfc_casecmp((*u)->mask,who)) {
  261. i = 1;
  262. break;
  263. }
  264. if (!*u)
  265. return 0;
  266. }
  267. if (i && doit) {
  268. if (!noshare) {
  269. char *mask = str_escape(who, ':', '\\');
  270. if (mask) {
  271. /* Distribute chan exempts differently */
  272. if (c)
  273. shareout(c, "-ec %s %s\n", c->dname, mask);
  274. else
  275. shareout(NULL, "-e %s\n", mask);
  276. free(mask);
  277. }
  278. }
  279. free((*u)->mask);
  280. if ((*u)->desc)
  281. free((*u)->desc);
  282. if ((*u)->user)
  283. free((*u)->user);
  284. t = *u;
  285. *u = (*u)->next;
  286. free(t);
  287. }
  288. return i;
  289. }
  290. static int u_delinvite(struct chanset_t *c, char *who, int doit)
  291. {
  292. int j, i = 0;
  293. maskrec *t = NULL;
  294. maskrec **u = c ? &(c->invites) : &global_invites;
  295. if (!strchr(who, '!') && str_isdigit(who)) {
  296. j = atoi(who);
  297. j--;
  298. for (;(*u) && j;u=&((*u)->next),j--);
  299. if (*u) {
  300. strcpy(who, (*u)->mask);
  301. i = 1;
  302. } else
  303. return -j-1;
  304. } else {
  305. /* Find matching host, if there is one */
  306. for (;*u && !i; u = &((*u)->next))
  307. if (!rfc_casecmp((*u)->mask,who)) {
  308. i = 1;
  309. break;
  310. }
  311. if (!*u)
  312. return 0;
  313. }
  314. if (i && doit) {
  315. if (!noshare) {
  316. char *mask = str_escape(who, ':', '\\');
  317. if (mask) {
  318. /* Distribute chan invites differently */
  319. if (c)
  320. shareout(c, "-invc %s %s\n", c->dname, mask);
  321. else
  322. shareout(NULL, "-inv %s\n", mask);
  323. free(mask);
  324. }
  325. }
  326. free((*u)->mask);
  327. if ((*u)->desc)
  328. free((*u)->desc);
  329. if ((*u)->user)
  330. free((*u)->user);
  331. t = *u;
  332. *u = (*u)->next;
  333. free(t);
  334. }
  335. return i;
  336. }
  337. /* Note: If first char of note is '*' it's a sticky ban.
  338. */
  339. static int u_addban(struct chanset_t *chan, char *ban, char *from, char *note,
  340. time_t expire_time, int flags)
  341. {
  342. char host[1024] = "", s[1024] = "";
  343. maskrec *p = NULL, *l = NULL, **u = chan ? &chan->bans : &global_bans;
  344. module_entry *me = NULL;
  345. strcpy(host, ban);
  346. /* Choke check: fix broken bans (must have '!' and '@') */
  347. if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
  348. strcat(host, "!*@*");
  349. else if (strchr(host, '@') == NULL)
  350. strcat(host, "@*");
  351. else if (strchr(host, '!') == NULL) {
  352. char *i = strchr(host, '@');
  353. strcpy(s, i);
  354. *i = 0;
  355. strcat(host, "!*");
  356. strcat(host, s);
  357. }
  358. if ((me = module_find("server", 0, 0)) && me->funcs)
  359. simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
  360. me->funcs[SERVER_BOTUSERHOST]);
  361. else
  362. simple_sprintf(s, "%s!%s@%s", origbotname, botuser, conf.bot->host);
  363. if (wild_match(host, s)) {
  364. putlog(LOG_MISC, "*", IRC_IBANNEDME);
  365. return 0;
  366. }
  367. if (expire_time == now)
  368. return 1;
  369. for (l = *u; l; l = l->next)
  370. if (!rfc_casecmp(l->mask, host)) {
  371. p = l;
  372. break;
  373. }
  374. /* It shouldn't expire and be sticky also */
  375. if (note[0] == '*') {
  376. flags |= MASKREC_STICKY;
  377. note++;
  378. }
  379. if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
  380. flags |= MASKREC_PERM;
  381. expire_time = 0L;
  382. }
  383. if (p == NULL) {
  384. p = calloc(1, sizeof(maskrec));
  385. p->next = *u;
  386. *u = p;
  387. }
  388. else {
  389. free( p->mask );
  390. free( p->user );
  391. free( p->desc );
  392. }
  393. p->expire = expire_time;
  394. p->added = now;
  395. p->lastactive = 0;
  396. p->flags = flags;
  397. p->mask = strdup(host);
  398. p->user = strdup(from);
  399. p->desc = strdup(note);
  400. if (!noshare) {
  401. char *mask = str_escape(host, ':', '\\');
  402. if (mask) {
  403. if (!chan)
  404. shareout(NULL, "+b %s %lu %s%s %s %s\n", mask, expire_time - now,
  405. (flags & MASKREC_STICKY) ? "s" : "",
  406. (flags & MASKREC_PERM) ? "p" : "-", from, note);
  407. else
  408. shareout(chan, "+bc %s %lu %s %s%s %s %s\n", mask, expire_time - now,
  409. chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
  410. (flags & MASKREC_PERM) ? "p" : "-", from, note);
  411. free(mask);
  412. }
  413. }
  414. return 1;
  415. }
  416. /* Note: If first char of note is '*' it's a sticky invite.
  417. */
  418. static int u_addinvite(struct chanset_t *chan, char *invite, char *from,
  419. char *note, time_t expire_time, int flags)
  420. {
  421. char host[1024] = "", s[1024] = "";
  422. maskrec *p = NULL, *l, **u = chan ? &chan->invites : &global_invites;
  423. module_entry *me = NULL;
  424. strcpy(host, invite);
  425. /* Choke check: fix broken invites (must have '!' and '@') */
  426. if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
  427. strcat(host, "!*@*");
  428. else if (strchr(host, '@') == NULL)
  429. strcat(host, "@*");
  430. else if (strchr(host, '!') == NULL) {
  431. char * i = strchr(host, '@');
  432. strcpy(s, i);
  433. *i = 0;
  434. strcat(host, "!*");
  435. strcat(host, s);
  436. }
  437. if ((me = module_find("server",0,0)) && me->funcs)
  438. simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
  439. me->funcs[SERVER_BOTUSERHOST]);
  440. else
  441. simple_sprintf(s, "%s!%s@%s", origbotname, botuser, conf.bot->host);
  442. for (l = *u; l; l = l->next)
  443. if (!rfc_casecmp(l->mask, host)) {
  444. p = l;
  445. break;
  446. }
  447. /* It shouldn't expire and be sticky also */
  448. if (note[0] == '*') {
  449. flags |= MASKREC_STICKY;
  450. note++;
  451. }
  452. if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
  453. flags |= MASKREC_PERM;
  454. expire_time = 0L;
  455. }
  456. if (p == NULL) {
  457. p = calloc(1, sizeof(maskrec));
  458. p->next = *u;
  459. *u = p;
  460. }
  461. else {
  462. free( p->mask );
  463. free( p->user );
  464. free( p->desc );
  465. }
  466. p->expire = expire_time;
  467. p->added = now;
  468. p->lastactive = 0;
  469. p->flags = flags;
  470. p->mask = strdup(host);
  471. p->user = strdup(from);
  472. p->desc = strdup(note);
  473. if (!noshare) {
  474. char *mask = str_escape(host, ':', '\\');
  475. if (mask) {
  476. if (!chan)
  477. shareout(NULL, "+inv %s %lu %s%s %s %s\n", mask, expire_time - now,
  478. (flags & MASKREC_STICKY) ? "s" : "",
  479. (flags & MASKREC_PERM) ? "p": "-", from, note);
  480. else
  481. shareout(chan, "+invc %s %lu %s %s%s %s %s\n", mask, expire_time - now,
  482. chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
  483. (flags & MASKREC_PERM) ? "p": "-", from, note);
  484. free(mask);
  485. }
  486. }
  487. return 1;
  488. }
  489. /* Note: If first char of note is '*' it's a sticky exempt.
  490. */
  491. static int u_addexempt(struct chanset_t *chan, char *exempt, char *from,
  492. char *note, time_t expire_time, int flags)
  493. {
  494. char host[1024] = "", s[1024] = "";
  495. maskrec *p = NULL, *l, **u = chan ? &chan->exempts : &global_exempts;
  496. module_entry *me = NULL;
  497. strcpy(host, exempt);
  498. /* Choke check: fix broken exempts (must have '!' and '@') */
  499. if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
  500. strcat(host, "!*@*");
  501. else if (strchr(host, '@') == NULL)
  502. strcat(host, "@*");
  503. else if (strchr(host, '!') == NULL) {
  504. char * i = strchr(host, '@');
  505. strcpy(s, i);
  506. *i = 0;
  507. strcat(host, "!*");
  508. strcat(host, s);
  509. }
  510. if ((me = module_find("server",0,0)) && me->funcs)
  511. simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
  512. me->funcs[SERVER_BOTUSERHOST]);
  513. else
  514. simple_sprintf(s, "%s!%s@%s", origbotname, botuser, conf.bot->host);
  515. for (l = *u; l; l = l->next)
  516. if (!rfc_casecmp(l->mask, host)) {
  517. p = l;
  518. break;
  519. }
  520. /* It shouldn't expire and be sticky also */
  521. if (note[0] == '*') {
  522. flags |= MASKREC_STICKY;
  523. note++;
  524. }
  525. if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
  526. flags |= MASKREC_PERM;
  527. expire_time = 0L;
  528. }
  529. if (p == NULL) {
  530. p = calloc(1, sizeof(maskrec));
  531. p->next = *u;
  532. *u = p;
  533. }
  534. else {
  535. free( p->mask );
  536. free( p->user );
  537. free( p->desc );
  538. }
  539. p->expire = expire_time;
  540. p->added = now;
  541. p->lastactive = 0;
  542. p->flags = flags;
  543. p->mask = strdup(host);
  544. p->user = strdup(from);
  545. p->desc = strdup(note);
  546. if (!noshare) {
  547. char *mask = str_escape(host, ':', '\\');
  548. if (mask) {
  549. if (!chan)
  550. shareout(NULL, "+e %s %lu %s%s %s %s\n", mask, expire_time - now,
  551. (flags & MASKREC_STICKY) ? "s" : "",
  552. (flags & MASKREC_PERM) ? "p": "-", from, note);
  553. else
  554. shareout(chan, "+ec %s %lu %s %s%s %s %s\n", mask, expire_time - now,
  555. chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
  556. (flags & MASKREC_PERM) ? "p": "-", from, note);
  557. free(mask);
  558. }
  559. }
  560. return 1;
  561. }
  562. /* Take host entry from ban list and display it ban-style.
  563. */
  564. static void display_ban(int idx, int number, maskrec *ban, struct chanset_t *chan, int show_inact)
  565. {
  566. char dates[81] = "", s[41] = "";
  567. if (ban->added) {
  568. daysago(now, ban->added, s);
  569. sprintf(dates, "%s %s", MODES_CREATED, s);
  570. if (ban->added < ban->lastactive) {
  571. strcat(dates, ", ");
  572. strcat(dates, MODES_LASTUSED);
  573. strcat(dates, " ");
  574. daysago(now, ban->lastactive, s);
  575. strcat(dates, s);
  576. }
  577. } else
  578. dates[0] = 0;
  579. if (ban->flags & MASKREC_PERM)
  580. strcpy(s, "(perm)");
  581. else {
  582. char s1[41] = "";
  583. days(ban->expire, now, s1);
  584. sprintf(s, "(expires %s)", s1);
  585. }
  586. if (ban->flags & MASKREC_STICKY)
  587. strcat(s, " (sticky)");
  588. if (!chan || ischanban(chan, ban->mask)) {
  589. if (number >= 0) {
  590. dprintf(idx, " [%3d] %s %s\n", number, ban->mask, s);
  591. } else {
  592. dprintf(idx, "BAN: %s %s\n", ban->mask, s);
  593. }
  594. } else if (show_inact) {
  595. if (number >= 0) {
  596. dprintf(idx, "! [%3d] %s %s\n", number, ban->mask, s);
  597. } else {
  598. dprintf(idx, "BAN (%s): %s %s\n", MODES_INACTIVE, ban->mask, s);
  599. }
  600. } else
  601. return;
  602. dprintf(idx, " %s: %s\n", ban->user, ban->desc);
  603. if (dates[0])
  604. dprintf(idx, " %s\n", dates);
  605. }
  606. /* Take host entry from exempt list and display it ban-style.
  607. */
  608. static void display_exempt(int idx, int number, maskrec *exempt, struct chanset_t *chan, int show_inact)
  609. {
  610. char dates[81] = "", s[41] = "";
  611. if (exempt->added) {
  612. daysago(now, exempt->added, s);
  613. sprintf(dates, "%s %s", MODES_CREATED, s);
  614. if (exempt->added < exempt->lastactive) {
  615. strcat(dates, ", ");
  616. strcat(dates, MODES_LASTUSED);
  617. strcat(dates, " ");
  618. daysago(now, exempt->lastactive, s);
  619. strcat(dates, s);
  620. }
  621. } else
  622. dates[0] = 0;
  623. if (exempt->flags & MASKREC_PERM)
  624. strcpy(s, "(perm)");
  625. else {
  626. char s1[41] = "";
  627. days(exempt->expire, now, s1);
  628. sprintf(s, "(expires %s)", s1);
  629. }
  630. if (exempt->flags & MASKREC_STICKY)
  631. strcat(s, " (sticky)");
  632. if (!chan || ischanexempt(chan, exempt->mask)) {
  633. if (number >= 0) {
  634. dprintf(idx, " [%3d] %s %s\n", number, exempt->mask, s);
  635. } else {
  636. dprintf(idx, "EXEMPT: %s %s\n", exempt->mask, s);
  637. }
  638. } else if (show_inact) {
  639. if (number >= 0) {
  640. dprintf(idx, "! [%3d] %s %s\n", number, exempt->mask, s);
  641. } else {
  642. dprintf(idx, "EXEMPT (%s): %s %s\n", MODES_INACTIVE, exempt->mask, s);
  643. }
  644. } else
  645. return;
  646. dprintf(idx, " %s: %s\n", exempt->user, exempt->desc);
  647. if (dates[0])
  648. dprintf(idx, " %s\n", dates);
  649. }
  650. /* Take host entry from invite list and display it ban-style.
  651. */
  652. static void display_invite (int idx, int number, maskrec *invite, struct chanset_t *chan, int show_inact)
  653. {
  654. char dates[81] = "", s[41] = "";
  655. if (invite->added) {
  656. daysago(now, invite->added, s);
  657. sprintf(dates, "%s %s", MODES_CREATED, s);
  658. if (invite->added < invite->lastactive) {
  659. strcat(dates, ", ");
  660. strcat(dates, MODES_LASTUSED);
  661. strcat(dates, " ");
  662. daysago(now, invite->lastactive, s);
  663. strcat(dates, s);
  664. }
  665. } else
  666. dates[0] = 0;
  667. if (invite->flags & MASKREC_PERM)
  668. strcpy(s, "(perm)");
  669. else {
  670. char s1[41] = "";
  671. days(invite->expire, now, s1);
  672. sprintf(s, "(expires %s)", s1);
  673. }
  674. if (invite->flags & MASKREC_STICKY)
  675. strcat(s, " (sticky)");
  676. if (!chan || ischaninvite(chan, invite->mask)) {
  677. if (number >= 0) {
  678. dprintf(idx, " [%3d] %s %s\n", number, invite->mask, s);
  679. } else {
  680. dprintf(idx, "INVITE: %s %s\n", invite->mask, s);
  681. }
  682. } else if (show_inact) {
  683. if (number >= 0) {
  684. dprintf(idx, "! [%3d] %s %s\n", number, invite->mask, s);
  685. } else {
  686. dprintf(idx, "INVITE (%s): %s %s\n", MODES_INACTIVE, invite->mask, s);
  687. }
  688. } else
  689. return;
  690. dprintf(idx, " %s: %s\n", invite->user, invite->desc);
  691. if (dates[0])
  692. dprintf(idx, " %s\n", dates);
  693. }
  694. static void tell_bans(int idx, int show_inact, char *match)
  695. {
  696. int k = 1;
  697. char *chname = NULL;
  698. struct chanset_t *chan = NULL;
  699. maskrec *u = NULL;
  700. /* Was a channel given? */
  701. if (match[0]) {
  702. chname = newsplit(&match);
  703. if (chname[0] && (strchr(CHANMETA, chname[0]))) {
  704. chan = findchan_by_dname(chname);
  705. if (!chan) {
  706. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  707. return;
  708. }
  709. } else
  710. match = chname;
  711. }
  712. /* don't return here, we want to show global bans even if no chan */
  713. if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan)) &&
  714. !(chan = chanset))
  715. chan = NULL;
  716. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  717. if (private(user, chan, PRIV_OP)) {
  718. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  719. return;
  720. }
  721. if (chan && show_inact)
  722. dprintf(idx, "%s: (! = %s %s)\n", BANS_GLOBAL,
  723. MODES_NOTACTIVE, chan->dname);
  724. else
  725. dprintf(idx, "%s:\n", BANS_GLOBAL);
  726. for (u = global_bans; u; u = u->next) {
  727. if (match[0]) {
  728. if ((wild_match(match, u->mask)) ||
  729. (wild_match(match, u->desc)) ||
  730. (wild_match(match, u->user)))
  731. display_ban(idx, k, u, chan, 1);
  732. k++;
  733. } else
  734. display_ban(idx, k++, u, chan, show_inact);
  735. }
  736. if (chan) {
  737. if (show_inact)
  738. dprintf(idx, "%s %s: (! = %s, * = %s)\n",
  739. BANS_BYCHANNEL, chan->dname,
  740. MODES_NOTACTIVE2, MODES_NOTBYBOT);
  741. else
  742. dprintf(idx, "%s %s: (* = %s)\n",
  743. BANS_BYCHANNEL, chan->dname,
  744. MODES_NOTBYBOT);
  745. for (u = chan->bans; u; u = u->next) {
  746. if (match[0]) {
  747. if ((wild_match(match, u->mask)) ||
  748. (wild_match(match, u->desc)) ||
  749. (wild_match(match, u->user)))
  750. display_ban(idx, k, u, chan, 1);
  751. k++;
  752. } else
  753. display_ban(idx, k++, u, chan, show_inact);
  754. }
  755. if (chan->status & CHAN_ACTIVE) {
  756. masklist *b = NULL;
  757. char s[UHOSTLEN] = "", *s1 = NULL, *s2 = NULL, fill[256] = "";
  758. int min, sec;
  759. for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
  760. if ((!u_equals_mask(global_bans, b->mask)) &&
  761. (!u_equals_mask(chan->bans, b->mask))) {
  762. strcpy(s, b->who);
  763. s2 = s;
  764. s1 = splitnick(&s2);
  765. if (s1[0])
  766. sprintf(fill, "%s (%s!%s)", b->mask, s1, s2);
  767. else
  768. sprintf(fill, "%s (server %s)", b->mask, s2);
  769. if (b->timer != 0) {
  770. min = (now - b->timer) / 60;
  771. sec = (now - b->timer) - (min * 60);
  772. sprintf(s, " (active %02d:%02d)", min, sec);
  773. strcat(fill, s);
  774. }
  775. if ((!match[0]) || (wild_match(match, b->mask)))
  776. dprintf(idx, "* [%3d] %s\n", k, fill);
  777. k++;
  778. }
  779. }
  780. }
  781. }
  782. if (k == 1)
  783. dprintf(idx, "(There are no bans, permanent or otherwise.)\n");
  784. if ((!show_inact) && (!match[0]))
  785. dprintf(idx, "%s.\n", BANS_USEBANSALL);
  786. }
  787. static void tell_exempts(int idx, int show_inact, char *match)
  788. {
  789. int k = 1;
  790. char *chname = NULL;
  791. struct chanset_t *chan = NULL;
  792. maskrec *u = NULL;
  793. /* Was a channel given? */
  794. if (match[0]) {
  795. chname = newsplit(&match);
  796. if (chname[0] && strchr(CHANMETA, chname[0])) {
  797. chan = findchan_by_dname(chname);
  798. if (!chan) {
  799. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  800. return;
  801. }
  802. } else
  803. match = chname;
  804. }
  805. /* don't return here, we want to show global exempts even if no chan */
  806. if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan))
  807. && !(chan = chanset))
  808. chan = NULL;
  809. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  810. if (private(user, chan, PRIV_OP)) {
  811. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  812. return;
  813. }
  814. if (chan && show_inact)
  815. dprintf(idx, "%s: (! = %s %s)\n", EXEMPTS_GLOBAL,
  816. MODES_NOTACTIVE, chan->dname);
  817. else
  818. dprintf(idx, "%s:\n", EXEMPTS_GLOBAL);
  819. for (u = global_exempts; u; u = u->next) {
  820. if (match[0]) {
  821. if ((wild_match(match, u->mask)) ||
  822. (wild_match(match, u->desc)) ||
  823. (wild_match(match, u->user)))
  824. display_exempt(idx, k, u, chan, 1);
  825. k++;
  826. } else
  827. display_exempt(idx, k++, u, chan, show_inact);
  828. }
  829. if (chan) {
  830. if (show_inact)
  831. dprintf(idx, "%s %s: (! = %s, * = %s)\n",
  832. EXEMPTS_BYCHANNEL, chan->dname,
  833. MODES_NOTACTIVE2,
  834. MODES_NOTBYBOT);
  835. else
  836. dprintf(idx, "%s %s: (* = %s)\n",
  837. EXEMPTS_BYCHANNEL, chan->dname,
  838. MODES_NOTBYBOT);
  839. for (u = chan->exempts; u; u = u->next) {
  840. if (match[0]) {
  841. if ((wild_match(match, u->mask)) ||
  842. (wild_match(match, u->desc)) ||
  843. (wild_match(match, u->user)))
  844. display_exempt(idx, k, u, chan, 1);
  845. k++;
  846. } else
  847. display_exempt(idx, k++, u, chan, show_inact);
  848. }
  849. if (chan->status & CHAN_ACTIVE) {
  850. masklist *e = NULL;
  851. char s[UHOSTLEN] = "", *s1 = NULL, *s2 = NULL , fill[256] = "";
  852. int min, sec;
  853. for (e = chan->channel.exempt; e && e->mask[0]; e = e->next) {
  854. if ((!u_equals_mask(global_exempts,e->mask)) &&
  855. (!u_equals_mask(chan->exempts, e->mask))) {
  856. strcpy(s, e->who);
  857. s2 = s;
  858. s1 = splitnick(&s2);
  859. if (s1[0])
  860. sprintf(fill, "%s (%s!%s)", e->mask, s1, s2);
  861. else
  862. sprintf(fill, "%s (server %s)", e->mask, s2);
  863. if (e->timer != 0) {
  864. min = (now - e->timer) / 60;
  865. sec = (now - e->timer) - (min * 60);
  866. sprintf(s, " (active %02d:%02d)", min, sec);
  867. strcat(fill, s);
  868. }
  869. if ((!match[0]) || (wild_match(match, e->mask)))
  870. dprintf(idx, "* [%3d] %s\n", k, fill);
  871. k++;
  872. }
  873. }
  874. }
  875. }
  876. if (k == 1)
  877. dprintf(idx, "(There are no ban exempts, permanent or otherwise.)\n");
  878. if ((!show_inact) && (!match[0]))
  879. dprintf(idx, "%s.\n", EXEMPTS_USEEXEMPTSALL);
  880. }
  881. static void tell_invites(int idx, int show_inact, char *match)
  882. {
  883. int k = 1;
  884. char *chname = NULL;
  885. struct chanset_t *chan = NULL;
  886. maskrec *u = NULL;
  887. /* Was a channel given? */
  888. if (match[0]) {
  889. chname = newsplit(&match);
  890. if (chname[0] && strchr(CHANMETA, chname[0])) {
  891. chan = findchan_by_dname(chname);
  892. if (!chan) {
  893. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  894. return;
  895. }
  896. } else
  897. match = chname;
  898. }
  899. /* don't return here, we want to show global invites even if no chan */
  900. if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan))
  901. && !(chan = chanset))
  902. chan = NULL;
  903. get_user_flagrec(dcc[idx].user, &user, chan->dname);
  904. if (private(user, chan, PRIV_OP)) {
  905. dprintf(idx, "%s.\n", CHAN_NOSUCH);
  906. return;
  907. }
  908. if (chan && show_inact)
  909. dprintf(idx, "%s: (! = %s %s)\n", INVITES_GLOBAL,
  910. MODES_NOTACTIVE, chan->dname);
  911. else
  912. dprintf(idx, "%s:\n", INVITES_GLOBAL);
  913. for (u = global_invites; u; u = u->next) {
  914. if (match[0]) {
  915. if ((wild_match(match, u->mask)) ||
  916. (wild_match(match, u->desc)) ||
  917. (wild_match(match, u->user)))
  918. display_invite(idx, k, u, chan, 1);
  919. k++;
  920. } else
  921. display_invite(idx, k++, u, chan, show_inact);
  922. }
  923. if (chan) {
  924. if (show_inact)
  925. dprintf(idx, "%s %s: (! = %s, * = %s)\n",
  926. INVITES_BYCHANNEL, chan->dname,
  927. MODES_NOTACTIVE2,
  928. MODES_NOTBYBOT);
  929. else
  930. dprintf(idx, "%s %s: (* = %s)\n",
  931. INVITES_BYCHANNEL, chan->dname,
  932. MODES_NOTBYBOT);
  933. for (u = chan->invites; u; u = u->next) {
  934. if (match[0]) {
  935. if ((wild_match(match, u->mask)) ||
  936. (wild_match(match, u->desc)) ||
  937. (wild_match(match, u->user)))
  938. display_invite(idx, k, u, chan, 1);
  939. k++;
  940. } else
  941. display_invite(idx, k++, u, chan, show_inact);
  942. }
  943. if (chan->status & CHAN_ACTIVE) {
  944. masklist *i = NULL;
  945. char s[UHOSTLEN] = "", *s1 = NULL, *s2 = NULL, fill[256] = "";
  946. int min, sec;
  947. for (i = chan->channel.invite; i && i->mask[0]; i = i->next) {
  948. if ((!u_equals_mask(global_invites,i->mask)) &&
  949. (!u_equals_mask(chan->invites, i->mask))) {
  950. strcpy(s, i->who);
  951. s2 = s;
  952. s1 = splitnick(&s2);
  953. if (s1[0])
  954. sprintf(fill, "%s (%s!%s)", i->mask, s1, s2);
  955. else
  956. sprintf(fill, "%s (server %s)", i->mask, s2);
  957. if (i->timer != 0) {
  958. min = (now - i->timer) / 60;
  959. sec = (now - i->timer) - (min * 60);
  960. sprintf(s, " (active %02d:%02d)", min, sec);
  961. strcat(fill, s);
  962. }
  963. if ((!match[0]) || (wild_match(match, i->mask)))
  964. dprintf(idx, "* [%3d] %s\n", k, fill);
  965. k++;
  966. }
  967. }
  968. }
  969. }
  970. if (k == 1)
  971. dprintf(idx, "(There are no invites, permanent or otherwise.)\n");
  972. if ((!show_inact) && (!match[0]))
  973. dprintf(idx, "%s.\n", INVITES_USEINVITESALL);
  974. }
  975. static int write_config(FILE *f, int idx)
  976. {
  977. int i = 0;
  978. #ifdef S_DCCPASS
  979. struct cmd_pass *cp = NULL;
  980. #endif
  981. putlog(LOG_DEBUG, "@", "Writing config entries...");
  982. if (lfprintf(f, CONFIG_NAME " - -\n") == EOF) /* Daemus */
  983. return 0;
  984. for (i = 0; i < cfg_count; i++) {
  985. if ((cfg[i]->flags & CFGF_GLOBAL) && (cfg[i]->gdata)) {
  986. if (lfprintf(f, "@ %s %s\n", cfg[i]->name, cfg[i]->gdata ? cfg[i]->gdata : "") == EOF)
  987. return 0;
  988. }
  989. }
  990. #ifdef S_DCCPASS
  991. for (cp = cmdpass; cp; cp = cp->next)
  992. if (lfprintf(f, "- %s %s\n", cp->name, cp->pass) == EOF)
  993. return 0;
  994. #endif
  995. return 1;
  996. }
  997. /* Write the ban lists and the ignore list to a file.
  998. */
  999. static int write_bans(FILE *f, int idx)
  1000. {
  1001. struct chanset_t *chan = NULL;
  1002. maskrec *b = NULL;
  1003. struct igrec *i = NULL;
  1004. char *mask = NULL;
  1005. if (global_ign)
  1006. if (lfprintf(f, IGNORE_NAME " - -\n") == EOF) /* Daemus */
  1007. return 0;
  1008. for (i = global_ign; i; i = i->next) {
  1009. mask = str_escape(i->igmask, ':', '\\');
  1010. if (!mask ||
  1011. lfprintf(f, "- %s:%s%lu:%s:%lu:%s\n", mask,
  1012. (i->flags & IGREC_PERM) ? "+" : "", i->expire,
  1013. i->user ? i->user : conf.bot->nick, i->added,
  1014. i->msg ? i->msg : "") == EOF) {
  1015. if (mask)
  1016. free(mask);
  1017. return 0;
  1018. }
  1019. free(mask);
  1020. }
  1021. if (global_bans)
  1022. if (lfprintf(f, BAN_NAME " - -\n") == EOF) /* Daemus */
  1023. return 0;
  1024. for (b = global_bans; b; b = b->next) {
  1025. mask = str_escape(b->mask, ':', '\\');
  1026. if (!mask ||
  1027. lfprintf(f, "- %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
  1028. (b->flags & MASKREC_PERM) ? "+" : "", b->expire,
  1029. (b->flags & MASKREC_STICKY) ? "*" : "", b->added,
  1030. b->lastactive, b->user ? b->user : conf.bot->nick,
  1031. b->desc ? b->desc : "requested") == EOF) {
  1032. if (mask)
  1033. free(mask);
  1034. return 0;
  1035. }
  1036. free(mask);
  1037. }
  1038. for (chan = chanset; chan; chan = chan->next)
  1039. if ((idx < 0) || 1) {
  1040. struct flag_record fr = {FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0};
  1041. if (idx >= 0)
  1042. get_user_flagrec(dcc[idx].user, &fr, chan->dname);
  1043. else
  1044. fr.chan = BOT_SHARE;
  1045. if (lfprintf(f, "::%s bans\n", chan->dname) == EOF)
  1046. return 0;
  1047. for (b = chan->bans; b; b = b->next) {
  1048. mask = str_escape(b->mask, ':', '\\');
  1049. if (!mask ||
  1050. lfprintf(f, "- %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
  1051. (b->flags & MASKREC_PERM) ? "+" : "", b->expire,
  1052. (b->flags & MASKREC_STICKY) ? "*" : "", b->added,
  1053. b->lastactive, b->user ? b->user : conf.bot->nick,
  1054. b->desc ? b->desc : "requested") == EOF) {
  1055. if (mask)
  1056. free(mask);
  1057. return 0;
  1058. }
  1059. free(mask);
  1060. }
  1061. }
  1062. return 1;
  1063. }
  1064. /* Write the exemptlists to a file.
  1065. */
  1066. static int write_exempts(FILE *f, int idx)
  1067. {
  1068. struct chanset_t *chan = NULL;
  1069. maskrec *e = NULL;
  1070. char *mask = NULL;
  1071. if (global_exempts)
  1072. if (lfprintf(f, EXEMPT_NAME " - -\n") == EOF) /* Daemus */
  1073. return 0;
  1074. for (e = global_exempts; e; e = e->next) {
  1075. mask = str_escape(e->mask, ':', '\\');
  1076. if (!mask ||
  1077. lfprintf(f, "%s %s:%s%lu%s:+%lu:%lu:%s:%s\n", "%", mask,
  1078. (e->flags & MASKREC_PERM) ? "+" : "", e->expire,
  1079. (e->flags & MASKREC_STICKY) ? "*" : "", e->added,
  1080. e->lastactive, e->user ? e->user : conf.bot->nick,
  1081. e->desc ? e->desc : "requested") == EOF) {
  1082. if (mask)
  1083. free(mask);
  1084. return 0;
  1085. }
  1086. free(mask);
  1087. }
  1088. for (chan = chanset;chan;chan=chan->next)
  1089. if ((idx < 0) || 1) {
  1090. struct flag_record fr = {FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0};
  1091. if (idx >= 0)
  1092. get_user_flagrec(dcc[idx].user,&fr,chan->dname);
  1093. else
  1094. fr.chan = BOT_SHARE;
  1095. if (lfprintf(f, "&&%s exempts\n", chan->dname) == EOF)
  1096. return 0;
  1097. for (e = chan->exempts; e; e = e->next) {
  1098. mask = str_escape(e->mask, ':', '\\');
  1099. if (!mask ||
  1100. lfprintf(f,"%s %s:%s%lu%s:+%lu:%lu:%s:%s\n","%", mask,
  1101. (e->flags & MASKREC_PERM) ? "+" : "", e->expire,
  1102. (e->flags & MASKREC_STICKY) ? "*" : "", e->added,
  1103. e->lastactive, e->user ? e->user : conf.bot->nick,
  1104. e->desc ? e->desc : "requested") == EOF) {
  1105. if (mask)
  1106. free(mask);
  1107. return 0;
  1108. }
  1109. free(mask);
  1110. }
  1111. }
  1112. return 1;
  1113. }
  1114. /* Write the invitelists to a file.
  1115. */
  1116. static int write_invites(FILE *f, int idx)
  1117. {
  1118. struct chanset_t *chan = NULL;
  1119. maskrec *ir = NULL;
  1120. char *mask = NULL;
  1121. if (global_invites)
  1122. if (lfprintf(f, INVITE_NAME " - -\n") == EOF) /* Daemus */
  1123. return 0;
  1124. for (ir = global_invites; ir; ir = ir->next) {
  1125. mask = str_escape(ir->mask, ':', '\\');
  1126. if (!mask ||
  1127. lfprintf(f,"@ %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
  1128. (ir->flags & MASKREC_PERM) ? "+" : "", ir->expire,
  1129. (ir->flags & MASKREC_STICKY) ? "*" : "", ir->added,
  1130. ir->lastactive, ir->user ? ir->user : conf.bot->nick,
  1131. ir->desc ? ir->desc : "requested") == EOF) {
  1132. if (mask)
  1133. free(mask);
  1134. return 0;
  1135. }
  1136. free(mask);
  1137. }
  1138. for (chan = chanset; chan; chan = chan->next)
  1139. if ((idx < 0) || (1)) {
  1140. struct flag_record fr = {FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0};
  1141. if (idx >= 0)
  1142. get_user_flagrec(dcc[idx].user,&fr,chan->dname);
  1143. else
  1144. fr.chan = BOT_SHARE;
  1145. if (lfprintf(f, "$$%s invites\n", chan->dname) == EOF)
  1146. return 0;
  1147. for (ir = chan->invites; ir; ir = ir->next) {
  1148. mask = str_escape(ir->mask, ':', '\\');
  1149. if (!mask ||
  1150. lfprintf(f,"@ %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
  1151. (ir->flags & MASKREC_PERM) ? "+" : "", ir->expire,
  1152. (ir->flags & MASKREC_STICKY) ? "*" : "", ir->added,
  1153. ir->lastactive, ir->user ? ir->user : conf.bot->nick,
  1154. ir->desc ? ir->desc : "requested") == EOF) {
  1155. if (mask)
  1156. free(mask);
  1157. return 0;
  1158. }
  1159. free(mask);
  1160. }
  1161. }
  1162. return 1;
  1163. }
  1164. /* Write the channels to the userfile
  1165. */
  1166. static int write_chans(FILE *f, int idx)
  1167. {
  1168. char w[1024] = "", w2[1024] = "", name[163] = "";
  1169. /* char udefs[2048] = "", buf[2048]; */
  1170. /* Chanchar template
  1171. *char temp[121];
  1172. */
  1173. struct chanset_t *chan = NULL;
  1174. /* struct udef_struct *ul; */
  1175. putlog(LOG_DEBUG, "*", "Writing channels..");
  1176. if (lfprintf(f, CHANS_NAME " - -\n") == EOF) /* Daemus */
  1177. return 0;
  1178. for (chan = chanset; chan; chan = chan->next) {
  1179. if ((idx < 0) || (1)) {
  1180. struct flag_record fr = {FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0};
  1181. if (idx >= 0)
  1182. get_user_flagrec(dcc[idx].user,&fr,chan->dname);
  1183. else
  1184. fr.chan = BOT_SHARE;
  1185. putlog(LOG_DEBUG, "*", "writing channel %s to userfile..", chan->dname);
  1186. /* egg_memset(udefs,'\0',2048); */
  1187. convert_element(chan->dname, name);
  1188. get_mode_protect(chan, w);
  1189. convert_element(w, w2);
  1190. /* Chanchar template
  1191. * convert_element(chan->temp, temp);
  1192. */
  1193. /* fuck these for now
  1194. for (ul = udef; ul; ul = ul->next) { //put the udefs into one string
  1195. egg_memset(buf,'\0',2048);
  1196. if (ul->defined && ul->name) {
  1197. if (ul->type == UDEF_FLAG)
  1198. sprintf(buf, "%c%s%s ", getudef(ul->values, chan->dname) ? '+' : '-', "udef-flag-", ul->name);
  1199. else if (ul->type == UDEF_INT)
  1200. sprintf(buf, "%s%s %d ", "udef-int-", ul->name, getudef(ul->values, chan->dname));
  1201. else
  1202. debug1("UDEF-ERROR: unknown type %d", ul->type);
  1203. strcat(udefs,buf);
  1204. }
  1205. }
  1206. */
  1207. if (lfprintf(f, "+ channel add %s { chanmode %s addedby %s addedts %lu idle-kick %d limit %d stopnethack-mode %d \
  1208. revenge-mode %d \
  1209. flood-chan %d:%d flood-ctcp %d:%d flood-join %d:%d \
  1210. flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d \
  1211. closed-ban %d \
  1212. ban-time %d exempt-time %d invite-time %d \
  1213. %cenforcebans %cdynamicbans %cuserbans %cbitch \
  1214. %cprotectops %crevenge %crevengebot \
  1215. %cprivate %ccycle %cinactive %cdynamicexempts \
  1216. %cuserexempts %cdynamicinvites %cuserinvites \
  1217. %cnodesynch %cclosed %ctake %cmanop %cvoice \
  1218. %cfastop }\n",
  1219. name,
  1220. w2,
  1221. chan->added_by,
  1222. chan->added_ts,
  1223. /* Chanchar template
  1224. * temp,
  1225. * also include temp %s in dprintf.
  1226. */
  1227. chan->idle_kick, /* idle-kick 0 is same as dont-idle-kick (lcode)*/
  1228. chan->limitraise,
  1229. chan->stopnethack_mode,
  1230. chan->revenge_mode,
  1231. chan->flood_pub_thr, chan->flood_pub_time,
  1232. chan->flood_ctcp_thr, chan->flood_ctcp_time,
  1233. chan->flood_join_thr, chan->flood_join_time,
  1234. chan->flood_kick_thr, chan->flood_kick_time,
  1235. chan->flood_deop_thr, chan->flood_deop_time,
  1236. chan->flood_nick_thr, chan->flood_nick_time,
  1237. chan->closed_ban,
  1238. /* Chanint template
  1239. * chan->temp,
  1240. * also include temp %d in dprintf
  1241. */
  1242. chan->ban_time,
  1243. chan->exempt_time,
  1244. chan->invite_time,
  1245. PLSMNS(channel_enforcebans(chan)),
  1246. PLSMNS(channel_dynamicbans(chan)),
  1247. PLSMNS(!channel_nouserbans(chan)),
  1248. PLSMNS(channel_bitch(chan)),
  1249. PLSMNS(channel_protectops(chan)),
  1250. PLSMNS(channel_revenge(chan)),
  1251. PLSMNS(channel_revengebot(chan)),
  1252. PLSMNS(channel_private(chan)),
  1253. PLSMNS(channel_cycle(chan)),
  1254. PLSMNS(channel_inactive(chan)),
  1255. PLSMNS(channel_dynamicexempts(chan)),
  1256. PLSMNS(!channel_nouserexempts(chan)),
  1257. PLSMNS(channel_dynamicinvites(chan)),
  1258. PLSMNS(!channel_nouserinvites(chan)),
  1259. PLSMNS(channel_nodesynch(chan)),
  1260. PLSMNS(channel_closed(chan)),
  1261. PLSMNS(channel_take(chan)),
  1262. PLSMNS(channel_manop(chan)),
  1263. PLSMNS(channel_voice(chan)),
  1264. PLSMNS(channel_fastop(chan))
  1265. /* Chanflag template
  1266. * also include a %ctemp above.
  1267. * PLSMNS(channel_temp(chan)),
  1268. */
  1269. ) == EOF)
  1270. return 0;
  1271. }
  1272. }
  1273. return 1;
  1274. }
  1275. static void channels_writeuserfile(void)
  1276. {
  1277. #ifdef HUB
  1278. char s[1024] = "";
  1279. FILE *f = NULL;
  1280. int ret = 0;
  1281. putlog(LOG_DEBUG, "@", "Writing channel/ban/exempt/invite entries.");
  1282. simple_sprintf(s, "%s~new", userfile);
  1283. f = fopen(s, "a");
  1284. if (f) {
  1285. ret = write_chans(f, -1);
  1286. ret += write_config(f, -1);
  1287. ret += write_bans(f, -1);
  1288. ret += write_exempts(f, -1);
  1289. ret += write_invites(f, -1);
  1290. fclose(f);
  1291. }
  1292. if (ret < 5)
  1293. putlog(LOG_MISC, "*", USERF_ERRWRITE);
  1294. #endif /* HUB */
  1295. }
  1296. /* Expire mask originally set by `who' on `chan'?
  1297. *
  1298. * We might not want to expire masks in all cases, as other bots
  1299. * often tend to immediately reset masks they've listed in their
  1300. * internal ban list, making it quite senseless for us to remove
  1301. * them in the first place.
  1302. *
  1303. * Returns 1 if a mask on `chan' by `who' may be expired and 0 if
  1304. * not.
  1305. */
  1306. static int expired_mask(struct chanset_t *chan, char *who)
  1307. {
  1308. memberlist *m = NULL, *m2 = NULL;
  1309. char buf[UHOSTLEN] = "", *snick = NULL, *sfrom = NULL;
  1310. struct userrec *u = NULL;
  1311. /* Always expire masks, regardless of who set it? */
  1312. if (force_expire)
  1313. return 1;
  1314. strcpy(buf, who);
  1315. sfrom = buf;
  1316. snick = splitnick(&sfrom);
  1317. if (!snick[0])
  1318. return 1;
  1319. m = ismember(chan, snick);
  1320. if (!m)
  1321. for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
  1322. if (!egg_strcasecmp(sfrom, m2->userhost)) {
  1323. m = m2;
  1324. break;
  1325. }
  1326. if (!m || !chan_hasop(m) || !rfc_casecmp(m->nick, botname))
  1327. return 1;
  1328. /* At this point we know the person/bot who set the mask is currently
  1329. * present in the channel and has op.
  1330. */
  1331. if (m->user)
  1332. u = m->user;
  1333. else {
  1334. simple_sprintf(buf, "%s!%s", m->nick, m->userhost);
  1335. u = get_user_by_host(buf);
  1336. }
  1337. /* Do not expire masks set by bots. */
  1338. if (u && u->flags & USER_BOT)
  1339. return 0;
  1340. else
  1341. return 1;
  1342. }
  1343. /* Check for expired timed-bans.
  1344. */
  1345. static void check_expired_bans(void)
  1346. {
  1347. maskrec *u = NULL, *u2 = NULL;
  1348. struct chanset_t *chan = NULL;
  1349. masklist *b = NULL;
  1350. for (u = global_bans; u; u = u2) {
  1351. u2 = u->next;
  1352. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1353. putlog(LOG_MISC, "*", "%s %s (%s)", BANS_NOLONGER,
  1354. u->mask, MISC_EXPIRED);
  1355. for (chan = chanset; chan; chan = chan->next)
  1356. for (b = chan->channel.ban; b->mask[0]; b = b->next)
  1357. if (!rfc_casecmp(b->mask, u->mask) &&
  1358. expired_mask(chan, b->who) && b->timer != now) {
  1359. add_mode(chan, '-', 'b', u->mask);
  1360. b->timer = now;
  1361. }
  1362. u_delban(NULL, u->mask, 1);
  1363. }
  1364. }
  1365. /* Check for specific channel-domain bans expiring */
  1366. for (chan = chanset; chan; chan = chan->next) {
  1367. for (u = chan->bans; u; u = u2) {
  1368. u2 = u->next;
  1369. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1370. putlog(LOG_MISC, "*", "%s %s %s %s (%s)", BANS_NOLONGER,
  1371. u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
  1372. for (b = chan->channel.ban; b->mask[0]; b = b->next)
  1373. if (!rfc_casecmp(b->mask, u->mask) &&
  1374. expired_mask(chan, b->who) && b->timer != now) {
  1375. add_mode(chan, '-', 'b', u->mask);
  1376. b->timer = now;
  1377. }
  1378. u_delban(chan, u->mask, 1);
  1379. }
  1380. }
  1381. }
  1382. }
  1383. /* Check for expired timed-exemptions
  1384. */
  1385. static void check_expired_exempts(void)
  1386. {
  1387. maskrec *u = NULL, *u2 = NULL;
  1388. struct chanset_t *chan = NULL;
  1389. masklist *b = NULL, *e = NULL;
  1390. int match;
  1391. if (!use_exempts)
  1392. return;
  1393. for (u = global_exempts; u; u = u2) {
  1394. u2 = u->next;
  1395. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1396. putlog(LOG_MISC, "*", "%s %s (%s)", EXEMPTS_NOLONGER,
  1397. u->mask, MISC_EXPIRED);
  1398. for (chan = chanset; chan; chan = chan->next) {
  1399. match = 0;
  1400. b = chan->channel.ban;
  1401. while (b->mask[0] && !match) {
  1402. if (wild_match(b->mask, u->mask) ||
  1403. wild_match(u->mask, b->mask))
  1404. match = 1;
  1405. else
  1406. b = b->next;
  1407. }
  1408. if (match)
  1409. putlog(LOG_MISC, chan->dname,
  1410. "Exempt not expired on channel %s. Ban still set!",
  1411. chan->dname);
  1412. else
  1413. for (e = chan->channel.exempt; e->mask[0]; e = e->next)
  1414. if (!rfc_casecmp(e->mask, u->mask) &&
  1415. expired_mask(chan, e->who) && e->timer != now) {
  1416. add_mode(chan, '-', 'e', u->mask);
  1417. e->timer = now;
  1418. }
  1419. }
  1420. u_delexempt(NULL, u->mask,1);
  1421. }
  1422. }
  1423. /* Check for specific channel-domain exempts expiring */
  1424. for (chan = chanset; chan; chan = chan->next) {
  1425. for (u = chan->exempts; u; u = u2) {
  1426. u2 = u->next;
  1427. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1428. match=0;
  1429. b = chan->channel.ban;
  1430. while (b->mask[0] && !match) {
  1431. if (wild_match(b->mask, u->mask) ||
  1432. wild_match(u->mask, b->mask))
  1433. match=1;
  1434. else
  1435. b = b->next;
  1436. }
  1437. if (match)
  1438. putlog(LOG_MISC, chan->dname,
  1439. "Exempt not expired on channel %s. Ban still set!",
  1440. chan->dname);
  1441. else {
  1442. putlog(LOG_MISC, "*", "%s %s %s %s (%s)", EXEMPTS_NOLONGER,
  1443. u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
  1444. for (e = chan->channel.exempt; e->mask[0]; e = e->next)
  1445. if (!rfc_casecmp(e->mask, u->mask) &&
  1446. expired_mask(chan, e->who) && e->timer != now) {
  1447. add_mode(chan, '-', 'e', u->mask);
  1448. e->timer = now;
  1449. }
  1450. u_delexempt(chan, u->mask, 1);
  1451. }
  1452. }
  1453. }
  1454. }
  1455. }
  1456. /* Check for expired timed-invites.
  1457. */
  1458. static void check_expired_invites(void)
  1459. {
  1460. maskrec *u = NULL, *u2 = NULL;
  1461. struct chanset_t *chan = NULL;
  1462. masklist *b = NULL;
  1463. if (!use_invites)
  1464. return;
  1465. for (u = global_invites; u; u = u2) {
  1466. u2 = u->next;
  1467. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1468. putlog(LOG_MISC, "*", "%s %s (%s)", INVITES_NOLONGER,
  1469. u->mask, MISC_EXPIRED);
  1470. for (chan = chanset; chan; chan = chan->next)
  1471. if (!(chan->channel.mode & CHANINV))
  1472. for (b = chan->channel.invite; b->mask[0]; b = b->next)
  1473. if (!rfc_casecmp(b->mask, u->mask) &&
  1474. expired_mask(chan, b->who) && b->timer != now) {
  1475. add_mode(chan, '-', 'I', u->mask);
  1476. b->timer = now;
  1477. }
  1478. u_delinvite(NULL, u->mask,1);
  1479. }
  1480. }
  1481. /* Check for specific channel-domain invites expiring */
  1482. for (chan = chanset; chan; chan = chan->next) {
  1483. for (u = chan->invites; u; u = u2) {
  1484. u2 = u->next;
  1485. if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
  1486. putlog(LOG_MISC, "*", "%s %s %s %s (%s)", INVITES_NOLONGER,
  1487. u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
  1488. if (!(chan->channel.mode & CHANINV))
  1489. for (b = chan->channel.invite; b->mask[0]; b = b->next)
  1490. if (!rfc_casecmp(b->mask, u->mask) &&
  1491. expired_mask(chan, b->who) && b->timer != now) {
  1492. add_mode(chan, '-', 'I', u->mask);
  1493. b->timer = now;
  1494. }
  1495. u_delinvite(chan, u->mask, 1);
  1496. }
  1497. }
  1498. }
  1499. }