notes.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. /*
  2. * notes.c -- part of notes.mod
  3. * reading and sending notes
  4. * killing old notes and changing the destinations
  5. * note cmds
  6. * note ignores
  7. *
  8. */
  9. #define MODULE_NAME "notes"
  10. #define MAKING_NOTES
  11. #include <fcntl.h>
  12. #include <sys/stat.h> /* chmod(..) */
  13. #include "src/mod/module.h"
  14. #include "src/tandem.h"
  15. #undef global
  16. #include "notes.h"
  17. static int maxnotes = 50; /* Maximum number of notes to allow stored
  18. * for each user */
  19. static int note_life = 60; /* Number of DAYS a note lives */
  20. static char notefile[121] = ".n"; /* Name of the notefile */
  21. static int allow_fwd = 1; /* Allow note forwarding */
  22. static int notify_users = 1; /* Notify users they have notes every hour? */
  23. static Function *global = NULL; /* DAMN fcntl.h */
  24. static bind_table_t *BT_dcc, *BT_load, *BT_away, *BT_nkch, *BT_chon;
  25. static struct user_entry_type USERENTRY_FWD =
  26. {
  27. NULL, /* always 0 ;) */
  28. NULL,
  29. NULL,
  30. NULL,
  31. NULL,
  32. NULL,
  33. NULL,
  34. NULL,
  35. NULL,
  36. NULL,
  37. NULL,
  38. NULL,
  39. fwd_display,
  40. "FWD"
  41. };
  42. #include "cmdsnote.c"
  43. static void fwd_display(int idx, struct user_entry *e, struct userrec *u)
  44. {
  45. if (dcc[idx].user && (dcc[idx].user->flags & USER_MASTER))
  46. dprintf(idx, NOTES_FORWARD_TO, e->u.string);
  47. }
  48. /* Determine how many notes are waiting for a user.
  49. */
  50. static int num_notes(char *user)
  51. {
  52. int tot = 0;
  53. FILE *f;
  54. char s[513], *to, *s1;
  55. if (!notefile[0])
  56. return 0;
  57. f = fopen(notefile, "r");
  58. if (f == NULL)
  59. return 0;
  60. while (!feof(f)) {
  61. fgets(s, 512, f);
  62. if (!feof(f)) {
  63. if (s[strlen(s) - 1] == '\n')
  64. s[strlen(s) - 1] = 0;
  65. rmspace(s);
  66. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  67. s1 = s;
  68. to = newsplit(&s1);
  69. if (!egg_strcasecmp(to, user))
  70. tot++;
  71. }
  72. }
  73. }
  74. fclose(f);
  75. return tot;
  76. }
  77. /* Change someone's handle.
  78. */
  79. static void notes_change(char *oldnick, char *newnick)
  80. {
  81. FILE *f, *g;
  82. char s[513], *to, *s1;
  83. int tot = 0;
  84. if (!egg_strcasecmp(oldnick, newnick))
  85. return;
  86. if (!notefile[0])
  87. return;
  88. f = fopen(notefile, "r");
  89. if (f == NULL)
  90. return;
  91. sprintf(s, "%s~new", notefile);
  92. g = fopen(s, "w");
  93. if (g == NULL) {
  94. fclose(f);
  95. return;
  96. }
  97. chmod(s, userfile_perm); /* Use userfile permissions. */
  98. while (!feof(f)) {
  99. fgets(s, 512, f);
  100. if (!feof(f)) {
  101. if (s[strlen(s) - 1] == '\n')
  102. s[strlen(s) - 1] = 0;
  103. rmspace(s);
  104. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  105. s1 = s;
  106. to = newsplit(&s1);
  107. if (!egg_strcasecmp(to, oldnick)) {
  108. tot++;
  109. fprintf(g, "%s %s\n", newnick, s1);
  110. } else
  111. fprintf(g, "%s %s\n", to, s1);
  112. } else
  113. fprintf(g, "%s\n", s);
  114. }
  115. }
  116. fclose(f);
  117. fclose(g);
  118. unlink(notefile);
  119. sprintf(s, "%s~new", notefile);
  120. movefile(s, notefile);
  121. putlog(LOG_MISC, "*", NOTES_SWITCHED_NOTES, tot, tot == 1 ? "" : "s",
  122. oldnick, newnick);
  123. }
  124. /* Get rid of old useless notes.
  125. */
  126. static void expire_notes()
  127. {
  128. FILE *f, *g;
  129. char s[513], *to, *from, *ts, *s1;
  130. int tot = 0, lapse;
  131. if (!notefile[0])
  132. return;
  133. f = fopen(notefile, "r");
  134. if (f == NULL)
  135. return;
  136. sprintf(s, "%s~new", notefile);
  137. g = fopen(s, "w");
  138. if (g == NULL) {
  139. fclose(f);
  140. return;
  141. }
  142. chmod(s, userfile_perm); /* Use userfile permissions. */
  143. while (!feof(f)) {
  144. fgets(s, 512, f);
  145. if (!feof(f)) {
  146. if (s[strlen(s) - 1] == '\n')
  147. s[strlen(s) - 1] = 0;
  148. rmspace(s);
  149. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  150. s1 = s;
  151. to = newsplit(&s1);
  152. from = newsplit(&s1);
  153. ts = newsplit(&s1);
  154. lapse = (now - (time_t) atoi(ts)) / 86400;
  155. if (lapse > note_life)
  156. tot++;
  157. else if (!get_user_by_handle(userlist, to))
  158. tot++;
  159. else
  160. fprintf(g, "%s %s %s %s\n", to, from, ts, s1);
  161. } else
  162. fprintf(g, "%s\n", s);
  163. }
  164. }
  165. fclose(f);
  166. fclose(g);
  167. unlink(notefile);
  168. sprintf(s, "%s~new", notefile);
  169. movefile(s, notefile);
  170. if (tot > 0)
  171. putlog(LOG_MISC, "*", NOTES_EXPIRED, tot, tot == 1 ? "" : "s");
  172. }
  173. /* Add note to notefile.
  174. */
  175. static int storenote(char *argv1, char *argv2, char *argv3, int idx, char *who, int bufsize)
  176. {
  177. FILE *f;
  178. char u[20], *f1, *to = NULL, work[1024];
  179. struct userrec *ur;
  180. struct userrec *ur2;
  181. idx = findanyidx(idx);
  182. if (who && bufsize > 0) who[0] = 0;
  183. ur = get_user_by_handle(userlist, argv2);
  184. if (ur && allow_fwd && (f1 = get_user(&USERENTRY_FWD, ur))) {
  185. char fwd[161], fwd2[161], *f2, *p, *q, *r;
  186. int ok = 1;
  187. /* User is valid & has a valid forwarding address */
  188. strcpy(fwd, f1); /* Only 40 bytes are stored in the userfile */
  189. p = strchr(fwd, '@');
  190. if (p && !egg_strcasecmp(p + 1, botnetnick)) {
  191. *p = 0;
  192. if (!egg_strcasecmp(fwd, argv2))
  193. /* They're forwarding to themselves on the same bot, llama's */
  194. ok = 0;
  195. strcpy(fwd2, fwd);
  196. splitc(fwd2, fwd2, '@');
  197. /* Get the user record of the user that we're forwarding to locally */
  198. ur2 = get_user_by_handle(userlist, fwd2);
  199. if (!ur2)
  200. ok = 0;
  201. if ((f2 = get_user(&USERENTRY_FWD, ur2))) {
  202. strcpy(fwd2, f2);
  203. splitc(fwd2, fwd2, '@');
  204. if (!egg_strcasecmp(fwd2, argv2))
  205. /* They're forwarding to someone who forwards back to them! */
  206. ok = 0;
  207. }
  208. p = NULL;
  209. }
  210. if ((argv1[0] != '@') && ((argv3[0] == '<') || (argv3[0] == '>')))
  211. ok = 0; /* Probablly fake pre 1.3 hax0r */
  212. if (ok && (!p || in_chain(p + 1))) {
  213. if (p)
  214. p++;
  215. q = argv3;
  216. while (ok && q && (q = strchr(q, '<'))) {
  217. q++;
  218. if ((r = strchr(q, ' '))) {
  219. *r = 0;
  220. if (!egg_strcasecmp(fwd, q))
  221. ok = 0;
  222. *r = ' ';
  223. }
  224. }
  225. if (ok) {
  226. if (p && strchr(argv1, '@')) {
  227. simple_sprintf(work, "<%s@%s >%s %s", argv2, botnetnick,
  228. argv1, argv3);
  229. simple_sprintf(u, "@%s", botnetnick);
  230. p = u;
  231. } else {
  232. simple_sprintf(work, "<%s@%s %s", argv2, botnetnick,
  233. argv3);
  234. p = argv1;
  235. }
  236. }
  237. } else
  238. ok = 0;
  239. if (ok) {
  240. if ((add_note(fwd, p, work, idx, 0) == NOTE_OK) && (idx >= 0))
  241. dprintf(idx, "Not online; forwarded to %s.\n", f1);
  242. if (who) strncpy(who, f1, bufsize);
  243. to = NULL;
  244. } else {
  245. strcpy(work, argv3);
  246. to = argv2;
  247. }
  248. } else
  249. to = argv2;
  250. if (to) {
  251. if (notefile[0] == 0) {
  252. if (idx >= 0)
  253. dprintf(idx, "%s\n", "Notes are not supported by this bot.");
  254. } else if (num_notes(to) >= maxnotes) {
  255. if (idx >= 0)
  256. dprintf(idx, "%s\n", "Sorry, that user has too many notes already.");
  257. } else { /* Time to unpack it meaningfully */
  258. f = fopen(notefile, "a");
  259. if (f == NULL)
  260. f = fopen(notefile, "w");
  261. if (f == NULL) {
  262. if (idx >= 0)
  263. dprintf(idx, "%s\n", "Cant create notefile. Sorry.");
  264. putlog(LOG_MISC, "*", "%s", "Notefile unreachable!");
  265. } else {
  266. char *p, *from = argv1;
  267. int l = 0;
  268. chmod(notefile, userfile_perm); /* Use userfile permissions. */
  269. while ((argv3[0] == '<') || (argv3[0] == '>')) {
  270. p = newsplit(&(argv3));
  271. if (*p == '<')
  272. l += simple_sprintf(work + l, "via %s, ", p + 1);
  273. else if (argv1[0] == '@')
  274. from = p + 1;
  275. }
  276. fprintf(f, "%s %s %lu %s%s\n", to, from, now,
  277. l ? work : "", argv3);
  278. fclose(f);
  279. if (idx >= 0)
  280. dprintf(idx, "%s.\n", "Stored message");
  281. }
  282. }
  283. }
  284. return 0;
  285. }
  286. /* Convert a string like "2-4;8;16-"
  287. * in an array {2, 4, 8, 8, 16, maxnotes, -1}
  288. */
  289. static void notes_parse(int dl[], char *s)
  290. {
  291. int i = 0;
  292. int idl = 0;
  293. do {
  294. while (s[i] == ';')
  295. i++;
  296. if (s[i]) {
  297. if (s[i] == '-')
  298. dl[idl] = 1;
  299. else
  300. dl[idl] = atoi(s + i);
  301. idl++;
  302. while ((s[i]) && (s[i] != '-') && (s[i] != ';'))
  303. i++;
  304. if (s[i] == '-') {
  305. dl[idl] = atoi(s + i + 1); /* Will be 0 if not a number */
  306. if (dl[idl] == 0)
  307. dl[idl] = maxnotes;
  308. } else
  309. dl[idl] = dl[idl - 1];
  310. idl++;
  311. while ((s[i]) && (s[i] != ';'))
  312. i++;
  313. }
  314. }
  315. while ((s[i]) && (idl < 124));
  316. dl[idl] = -1;
  317. }
  318. /* Return true if 'in' is in intervals of 'dl'
  319. */
  320. static int notes_in(int dl[], int in)
  321. {
  322. int i = 0;
  323. while (dl[i] != -1) {
  324. if ((dl[i] <= in) && (in <= dl[i + 1]))
  325. return 1;
  326. i += 2;
  327. }
  328. return 0;
  329. }
  330. /*
  331. * srd="+" : index
  332. * srd="-" : read all msgs
  333. * else : read msg in list : (ex: .notes read 5-9;12;13;18-)
  334. * idx=-1 : /msg
  335. */
  336. static void notes_read(char *hand, char *nick, char *srd, int idx)
  337. {
  338. FILE *f;
  339. char s[601], *to, *dt, *from, *s1, wt[100];
  340. time_t tt;
  341. int ix = 1;
  342. int ir = 0;
  343. int rd[128]; /* Is it enough ? */
  344. int i;
  345. if (srd[0] == 0)
  346. srd = "-";
  347. if (!notefile[0]) {
  348. if (idx >= 0)
  349. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  350. else
  351. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  352. return;
  353. }
  354. f = fopen(notefile, "r");
  355. if (f == NULL) {
  356. if (idx >= 0)
  357. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  358. else
  359. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  360. return;
  361. }
  362. notes_parse(rd, srd);
  363. while (!feof(f)) {
  364. fgets(s, 600, f);
  365. i = strlen(s);
  366. if (i > 0 && s[i - 1] == '\n')
  367. s[i - 1] = 0;
  368. if (!feof(f)) {
  369. rmspace(s);
  370. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  371. s1 = s;
  372. to = newsplit(&s1);
  373. if (!egg_strcasecmp(to, hand)) {
  374. int lapse;
  375. from = newsplit(&s1);
  376. dt = newsplit(&s1);
  377. tt = atoi(dt);
  378. #ifdef S_UTCTIME
  379. egg_strftime(wt, sizeof wt, "%b %d %H:%M %Z", gmtime(&tt));
  380. #else /* !S_UTCTIME */
  381. egg_strftime(wt, sizeof wt, "%b %d %H:%M %Z", localtime(&tt));
  382. #endif /* S_UTCTIME */
  383. dt = wt;
  384. lapse = (int) ((now - tt) / 86400);
  385. if (lapse > note_life - 7) {
  386. if (lapse >= note_life)
  387. strcat(dt, NOTES_EXPIRE_TODAY);
  388. else
  389. sprintf(&dt[strlen(dt)], NOTES_EXPIRE_XDAYS, note_life - lapse,
  390. (note_life - lapse) == 1 ? "" : "S");
  391. }
  392. if (srd[0] == '+') {
  393. if (idx >= 0) {
  394. if (ix == 1)
  395. dprintf(idx, "### %s:\n", NOTES_WAITING);
  396. dprintf(idx, " %2d. %s (%s)\n", ix, from, dt);
  397. } else {
  398. dprintf(DP_HELP, "NOTICE %s :%2d. %s (%s)\n",
  399. nick, ix, from, dt);
  400. }
  401. } else if (notes_in(rd, ix)) {
  402. if (idx >= 0)
  403. dprintf(idx, "%2d. %s (%s): %s\n", ix, from, dt, s1);
  404. else
  405. dprintf(DP_HELP, "NOTICE %s :%2d. %s (%s): %s\n",
  406. nick, ix, from, dt, s1);
  407. ir++;
  408. }
  409. ix++;
  410. }
  411. }
  412. }
  413. }
  414. fclose(f);
  415. if ((srd[0] != '+') && (ir == 0) && (ix > 1)) {
  416. if (idx >= 0)
  417. dprintf(idx, "%s.\n", NOTES_NOT_THAT_MANY);
  418. else
  419. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NOT_THAT_MANY);
  420. }
  421. if (srd[0] == '+') {
  422. if (ix == 1) {
  423. if (idx >= 0)
  424. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  425. else
  426. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  427. } else {
  428. if (idx >= 0)
  429. dprintf(idx, "### %s.\n", NOTES_DCC_USAGE_READ);
  430. else
  431. dprintf(DP_HELP, "NOTICE %s :(%d %s)\n", nick, ix - 1, MISC_TOTAL);
  432. }
  433. } else if ((ir == 0) && (ix == 1)) {
  434. if (idx >= 0)
  435. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  436. else
  437. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  438. }
  439. }
  440. /*
  441. * sdl="-" : erase all msgs
  442. * else : erase msg in list : (ex: .notes erase 2-4;8;16-)
  443. * idx=-1 : /msg
  444. */
  445. static void notes_del(char *hand, char *nick, char *sdl, int idx)
  446. {
  447. FILE *f, *g;
  448. char s[513], *to, *s1;
  449. int in = 1;
  450. int er = 0;
  451. int dl[128]; /* Is it enough ? */
  452. if (sdl[0] == 0)
  453. sdl = "-";
  454. if (!notefile[0]) {
  455. if (idx >= 0)
  456. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  457. else
  458. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  459. return;
  460. }
  461. f = fopen(notefile, "r");
  462. if (f == NULL) {
  463. if (idx >= 0)
  464. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  465. else
  466. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  467. return;
  468. }
  469. sprintf(s, "%s~new", notefile);
  470. g = fopen(s, "w");
  471. if (g == NULL) {
  472. if (idx >= 0)
  473. dprintf(idx, "%s. :(\n", NOTES_FAILED_CHMOD);
  474. else
  475. dprintf(DP_HELP, "NOTICE %s :%s. :(\n", nick, NOTES_FAILED_CHMOD);
  476. fclose(f);
  477. return;
  478. }
  479. chmod(s, userfile_perm); /* Use userfile permissions. */
  480. notes_parse(dl, sdl);
  481. while (!feof(f)) {
  482. fgets(s, 512, f);
  483. if (s[strlen(s) - 1] == '\n')
  484. s[strlen(s) - 1] = 0;
  485. if (!feof(f)) {
  486. rmspace(s);
  487. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  488. s1 = s;
  489. to = newsplit(&s1);
  490. if (!egg_strcasecmp(to, hand)) {
  491. if (!notes_in(dl, in))
  492. fprintf(g, "%s %s\n", to, s1);
  493. else
  494. er++;
  495. in++;
  496. } else
  497. fprintf(g, "%s %s\n", to, s1);
  498. } else
  499. fprintf(g, "%s\n", s);
  500. }
  501. }
  502. fclose(f);
  503. fclose(g);
  504. unlink(notefile);
  505. sprintf(s, "%s~new", notefile);
  506. movefile(s, notefile);
  507. if ((er == 0) && (in > 1)) {
  508. if (idx >= 0)
  509. dprintf(idx, "%s.\n", NOTES_NOT_THAT_MANY);
  510. else
  511. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NOT_THAT_MANY);
  512. } else if (in == 1) {
  513. if (idx >= 0)
  514. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  515. else
  516. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  517. } else {
  518. if (er == (in - 1)) {
  519. if (idx >= 0)
  520. dprintf(idx, "%s.\n", NOTES_ERASED_ALL);
  521. else
  522. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_ERASED_ALL);
  523. } else {
  524. if (idx >= 0)
  525. dprintf(idx, "%s %d note%s; %d %s.\n", NOTES_ERASED, er,
  526. (er != 1) ? "s" : "", in - 1 - er, NOTES_LEFT);
  527. else
  528. dprintf(DP_HELP, "NOTICE %s :%s %d note%s; %d %s.\n", nick, MISC_ERASED,
  529. er, (er != 1) ? "s" : "", in - 1 - er, NOTES_LEFT);
  530. }
  531. }
  532. }
  533. /* notes <pass> <func>
  534. */
  535. static int msg_notes(char *nick, char *host, struct userrec *u, char *par)
  536. {
  537. char *pwd, *fcn;
  538. if (!u)
  539. return 0;
  540. if (u->flags & (USER_BOT))
  541. return 1;
  542. if (!par[0]) {
  543. dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> INDEX\n", nick, NOTES_USAGE);
  544. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> TO <hand> <msg>\n", nick);
  545. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> READ <# or ALL>\n", nick);
  546. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> ERASE <# or ALL>\n", nick);
  547. dprintf(DP_HELP, "NOTICE %s : %s\n", nick, NOTES_MAYBE);
  548. dprintf(DP_HELP, "NOTICE %s : ex: NOTES mypass ERASE 2-4;8;16-\n", nick);
  549. return 1;
  550. }
  551. if (!u_pass_match(u, "-")) {
  552. /* they have a password set */
  553. pwd = newsplit(&par);
  554. if (!u_pass_match(u, pwd))
  555. return 0;
  556. }
  557. fcn = newsplit(&par);
  558. if (!egg_strcasecmp(fcn, "INDEX"))
  559. notes_read(u->handle, nick, "+", -1);
  560. else if (!egg_strcasecmp(fcn, "READ")) {
  561. if (!egg_strcasecmp(par, "ALL"))
  562. notes_read(u->handle, nick, "-", -1);
  563. else
  564. notes_read(u->handle, nick, par, -1);
  565. } else if (!egg_strcasecmp(fcn, "ERASE")) {
  566. if (!egg_strcasecmp(par, "ALL"))
  567. notes_del(u->handle, nick, "-", -1);
  568. else
  569. notes_del(u->handle, nick, par, -1);
  570. } else if (!egg_strcasecmp(fcn, "TO")) {
  571. char *to;
  572. int i;
  573. FILE *f;
  574. struct userrec *u2;
  575. to = newsplit(&par);
  576. if (!par[0]) {
  577. dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> TO <hand> <message>\n",
  578. nick, NOTES_USAGE);
  579. return 0;
  580. }
  581. u2 = get_user_by_handle(userlist, to);
  582. if (!u2) {
  583. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_USERF_UNKNOWN);
  584. return 1;
  585. } else if (is_bot(u2)) {
  586. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_NOTTO_BOT);
  587. return 1;
  588. }
  589. for (i = 0; i < dcc_total; i++) {
  590. if ((!egg_strcasecmp(dcc[i].nick, to)) &&
  591. (dcc[i].type->flags & DCT_GETNOTES)) {
  592. int aok = 1;
  593. if (dcc[i].type->flags & DCT_CHAT)
  594. if (dcc[i].u.chat->away != NULL)
  595. aok = 0;
  596. if (!(dcc[i].type->flags & DCT_CHAT))
  597. aok = 0; /* Assume non dcc-chat == something weird, so
  598. * store notes for later */
  599. if (aok) {
  600. dprintf(i, "\007%s [%s]: %s\n", u->handle, NOTES_OUTSIDE, par);
  601. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED);
  602. return 1;
  603. }
  604. }
  605. }
  606. if (notefile[0] == 0) {
  607. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_UNSUPPORTED);
  608. return 1;
  609. }
  610. f = fopen(notefile, "a");
  611. if (f == NULL)
  612. f = fopen(notefile, "w");
  613. if (f == NULL) {
  614. dprintf(DP_HELP, "NOTICE %s :%s", nick, NOTES_NOTEFILE_FAILED);
  615. putlog(LOG_MISC, "*", "* %s", NOTES_NOTEFILE_UNREACHABLE);
  616. return 1;
  617. }
  618. chmod(notefile, userfile_perm); /* Use userfile permissions. */
  619. fprintf(f, "%s %s %lu %s\n", to, u->handle, now, par);
  620. fclose(f);
  621. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED);
  622. return 1;
  623. } else
  624. dprintf(DP_HELP, "NOTICE %s :%s INDEX, READ, ERASE, TO\n",
  625. nick, NOTES_DCC_USAGE_READ);
  626. putlog(LOG_CMDS, "*", "(%s!%s) !%s! NOTES %s %s", nick, host, u->handle, fcn,
  627. par[0] ? "..." : "");
  628. return 1;
  629. }
  630. static void notes_hourly()
  631. {
  632. expire_notes();
  633. if (notify_users) {
  634. register struct chanset_t *chan;
  635. register memberlist *m;
  636. int k;
  637. register int l;
  638. char s1[256];
  639. struct userrec *u;
  640. for (chan = chanset; chan; chan = chan->next) {
  641. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  642. sprintf(s1, "%s!%s", m->nick, m->userhost);
  643. u = get_user_by_host(s1);
  644. if (u) {
  645. k = num_notes(u->handle);
  646. for (l = 0; l < dcc_total; l++)
  647. if ((dcc[l].type->flags & DCT_CHAT) &&
  648. !egg_strcasecmp(dcc[l].nick, u->handle)) {
  649. k = 0; /* They already know they have notes */
  650. break;
  651. }
  652. if (k) {
  653. dprintf(DP_HELP, "NOTICE %s :You have %d note%s waiting on %s.\n",
  654. m->nick, k, k == 1 ? "" : "s", botname);
  655. dprintf(DP_HELP, "NOTICE %s :%s /MSG %s NOTES <pass> INDEX\n",
  656. m->nick, NOTES_FORLIST, botname);
  657. }
  658. }
  659. }
  660. }
  661. for (l = 0; l < dcc_total; l++) {
  662. k = num_notes(dcc[l].nick);
  663. if ((k > 0) && (dcc[l].type->flags & DCT_CHAT)) {
  664. dprintf(l, NOTES_WAITING2, k, k == 1 ? "" : "s");
  665. dprintf(l, NOTES_DCC_USAGE_READ2);
  666. }
  667. }
  668. }
  669. }
  670. static void away_notes(char *bot, int sock, char *msg)
  671. {
  672. int idx = findanyidx(sock);
  673. if (egg_strcasecmp(bot, botnetnick))
  674. return;
  675. if (msg && msg[0])
  676. dprintf(idx, "%s\n", NOTES_STORED);
  677. else
  678. notes_read(dcc[idx].nick, 0, "+", idx);
  679. }
  680. static int chon_notes(char *nick, int idx)
  681. {
  682. if (dcc[idx].type == &DCC_CHAT)
  683. notes_read(nick, 0, "+", idx);
  684. return 0;
  685. }
  686. /* Return either NULL or a pointer to the xtra_key structure
  687. * where the not ignores are kept.
  688. */
  689. static struct xtra_key *getnotesentry(struct userrec *u)
  690. {
  691. struct user_entry *ue = find_user_entry(&USERENTRY_XTRA, u);
  692. struct xtra_key *xk, *nxk = NULL;
  693. if (!ue)
  694. return NULL;
  695. /* Search for the notes ignore list entry */
  696. for (xk = ue->u.extra; xk; xk = xk->next)
  697. if (xk->key && !egg_strcasecmp(xk->key, NOTES_IGNKEY)) {
  698. nxk = xk;
  699. break;
  700. }
  701. if (!nxk || !nxk->data || !(nxk->data[0]))
  702. return NULL;
  703. return nxk;
  704. }
  705. /* Parse the NOTES_IGNKEY xtra field. You must free the memory allocated
  706. * in here: the buffer 'ignores[0]' and the array 'ignores'.
  707. */
  708. int get_note_ignores(struct userrec *u, char ***ignores)
  709. {
  710. struct xtra_key *xk;
  711. char *buf, *p;
  712. int ignoresn;
  713. /* Hullo? sanity? */
  714. if (!u)
  715. return 0;
  716. xk = getnotesentry(u);
  717. if (!xk)
  718. return 0;
  719. rmspace(xk->data);
  720. buf = user_malloc(strlen(xk->data) + 1);
  721. strcpy(buf, xk->data);
  722. p = buf;
  723. /* Split up the string into small parts */
  724. *ignores = nmalloc(sizeof(char *) + 100);
  725. **ignores = p;
  726. ignoresn = 1;
  727. while ((p = strchr(p, ' ')) != NULL) {
  728. *ignores = nrealloc(*ignores, sizeof(char *) * (ignoresn+1));
  729. (*ignores)[ignoresn] = p + 1;
  730. ignoresn++;
  731. *p = 0;
  732. p++;
  733. }
  734. return ignoresn;
  735. }
  736. int add_note_ignore(struct userrec *u, char *mask)
  737. {
  738. struct xtra_key *xk;
  739. char **ignores;
  740. int ignoresn, i;
  741. ignoresn = get_note_ignores(u, &ignores);
  742. if (ignoresn > 0) {
  743. /* Search for existing mask */
  744. for (i = 0; i < ignoresn; i++)
  745. if (!strcmp(ignores[i], mask)) {
  746. nfree(ignores[0]); /* Free the string buffer */
  747. nfree(ignores); /* Free the ptr array */
  748. /* The mask already exists, exit. */
  749. return 0;
  750. }
  751. nfree(ignores[0]); /* Free the string buffer */
  752. nfree(ignores); /* Free the ptr array */
  753. }
  754. xk = getnotesentry(u);
  755. /* First entry? */
  756. if (!xk) {
  757. struct xtra_key *mxk = user_malloc(sizeof(struct xtra_key));
  758. struct user_entry *ue = find_user_entry(&USERENTRY_XTRA, u);
  759. if (!ue)
  760. return 0;
  761. mxk->next = 0;
  762. mxk->data = user_malloc(strlen(mask) + 1);
  763. strcpy(mxk->data, mask);
  764. mxk->key = user_malloc(strlen(NOTES_IGNKEY) + 1);
  765. strcpy(mxk->key, NOTES_IGNKEY);
  766. xtra_set(u, ue, mxk);
  767. } else { /* ... else, we already have other entries. */
  768. xk->data = user_realloc(xk->data, strlen(xk->data) + strlen(mask) + 2);
  769. strcat(xk->data, " ");
  770. strcat(xk->data, mask);
  771. }
  772. return 1;
  773. }
  774. int del_note_ignore(struct userrec *u, char *mask)
  775. {
  776. struct user_entry *ue;
  777. struct xtra_key *xk;
  778. char **ignores, *buf = NULL;
  779. int ignoresn, i, size = 0, foundit = 0;
  780. ignoresn = get_note_ignores(u, &ignores);
  781. if (!ignoresn)
  782. return 0;
  783. buf = user_malloc(1);
  784. buf[0] = 0;
  785. for (i = 0; i < ignoresn; i++) {
  786. if (strcmp(ignores[i], mask)) {
  787. size += strlen(ignores[i]);
  788. if (buf[0])
  789. size++;
  790. buf = user_realloc(buf, size+1);
  791. if (buf[0])
  792. strcat(buf, " ");
  793. strcat(buf, ignores[i]);
  794. } else
  795. foundit = 1;
  796. }
  797. nfree(ignores[0]); /* Free the string buffer */
  798. nfree(ignores); /* Free the ptr array */
  799. /* Entry not found */
  800. if (!foundit) {
  801. nfree(buf);
  802. return 0;
  803. }
  804. ue = find_user_entry(&USERENTRY_XTRA, u);
  805. /* Delete the entry if the buffer is empty */
  806. xk = user_malloc(sizeof(struct xtra_key));
  807. xk->key = user_malloc(strlen(NOTES_IGNKEY)+1);
  808. xk->next = 0;
  809. if (!buf[0]) {
  810. nfree(buf); /* The allocated byte needs to be free'd too */
  811. strcpy(xk->key, NOTES_IGNKEY);
  812. xk->data = 0;
  813. } else {
  814. xk->data = buf;
  815. strcpy(xk->key, NOTES_IGNKEY);
  816. }
  817. xtra_set(u, ue, xk);
  818. return 1;
  819. }
  820. /* Returns 1 if the user u has an note ignore which
  821. * matches from
  822. */
  823. int match_note_ignore(struct userrec *u, char *from)
  824. {
  825. char **ignores;
  826. int ignoresn, i;
  827. ignoresn = get_note_ignores(u, &ignores);
  828. if (!ignoresn)
  829. return 0;
  830. for (i = 0; i < ignoresn; i++)
  831. if (wild_match(ignores[i], from)) {
  832. nfree(ignores[0]);
  833. nfree(ignores);
  834. return 1;
  835. }
  836. nfree(ignores[0]); /* Free the string buffer */
  837. nfree(ignores); /* Free the ptr array */
  838. return 0;
  839. }
  840. static cmd_t notes_nkch[] =
  841. {
  842. {"*", "", (Function) notes_change, "notes"},
  843. {NULL, NULL, NULL, NULL}
  844. };
  845. static cmd_t notes_away[] =
  846. {
  847. {"*", "", (Function) away_notes, "notes"},
  848. {NULL, NULL, NULL, NULL}
  849. };
  850. static cmd_t notes_chon[] =
  851. {
  852. {"*", "", (Function) chon_notes, "notes"},
  853. {NULL, NULL, NULL, NULL}
  854. };
  855. static cmd_t notes_msgs[] =
  856. {
  857. {"notes", "", (Function) msg_notes, NULL},
  858. {NULL, NULL, NULL, NULL}
  859. };
  860. static tcl_ints notes_ints[] =
  861. {
  862. {"note-life", &note_life},
  863. {"max-notes", &maxnotes},
  864. {"allow-fwd", &allow_fwd},
  865. {"notify-users", &notify_users},
  866. {NULL, NULL}
  867. };
  868. static tcl_strings notes_strings[] =
  869. {
  870. {"notefile", notefile, 120, 0},
  871. {NULL, NULL, 0, 0}
  872. };
  873. static int notes_server_setup(char *mod)
  874. {
  875. bind_table_t *table;
  876. if ((table = find_bind_table2("msg")))
  877. add_builtins2(table, notes_msgs);
  878. return 0;
  879. }
  880. static cmd_t notes_load[] =
  881. {
  882. {"server", "", notes_server_setup, "notes:server"},
  883. {NULL, NULL, NULL, NULL}
  884. };
  885. static int notes_expmem()
  886. {
  887. return 0;
  888. }
  889. static void notes_report(int idx, int details)
  890. {
  891. if (details) {
  892. if (notefile[0])
  893. dprintf(idx, " Notes can be stored, in: %s\n", notefile);
  894. else
  895. dprintf(idx, " Notes can not be stored.\n");
  896. }
  897. }
  898. EXPORT_SCOPE char *notes_start();
  899. static Function notes_table[] =
  900. {
  901. (Function) notes_start,
  902. (Function) NULL,
  903. (Function) notes_expmem,
  904. (Function) notes_report,
  905. (Function) cmd_note,
  906. };
  907. char *notes_start(Function * global_funcs)
  908. {
  909. global = global_funcs;
  910. notefile[0] = 0;
  911. module_register(MODULE_NAME, notes_table, 2, 1);
  912. add_hook(HOOK_HOURLY, (Function) notes_hourly);
  913. add_hook(HOOK_MATCH_NOTEREJ, (Function) match_note_ignore);
  914. add_hook(HOOK_STORENOTE, (Function) storenote);
  915. add_tcl_ints(notes_ints);
  916. add_tcl_strings(notes_strings);
  917. BT_dcc = find_bind_table2("dcc");
  918. BT_load = find_bind_table2("load");
  919. BT_away = find_bind_table2("away");
  920. BT_nkch = find_bind_table2("nkch");
  921. BT_chon = find_bind_table2("chon");
  922. if (BT_dcc) add_builtins2(BT_dcc, notes_cmds);
  923. if (BT_load) add_builtins2(BT_load, notes_load);
  924. if (BT_away) add_builtins2(BT_away, notes_away);
  925. if (BT_chon) add_builtins2(BT_chon, notes_chon);
  926. if (BT_nkch) add_builtins2(BT_nkch, notes_nkch);
  927. notes_server_setup(0);
  928. my_memcpy(&USERENTRY_FWD, &USERENTRY_INFO, sizeof(void *) * 12);
  929. add_entry_type(&USERENTRY_FWD);
  930. return NULL;
  931. }