notes.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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. #undef MAKING_MODS
  10. #include "notes.h"
  11. #include "src/common.h"
  12. #include "src/chanprog.h"
  13. #include "src/main.h"
  14. #include "src/botnet.h"
  15. #include "src/userrec.h"
  16. #include "src/userent.h"
  17. #include "src/misc_file.h"
  18. #include "src/modules.h"
  19. #include "src/misc.h"
  20. #include "src/users.h"
  21. #include "src/egg_timer.h"
  22. #include "src/tandem.h"
  23. #include "src/tclhash.h"
  24. #include "src/botmsg.h" /* NOTE DEFINES */
  25. #include <fcntl.h>
  26. #include <sys/stat.h> /* chmod(..) */
  27. static int maxnotes = 50; /* Maximum number of notes to allow stored
  28. * for each user */
  29. static int note_life = 60; /* Number of DAYS a note lives */
  30. static char notefile[121] = ".n"; /* Name of the notefile */
  31. static int allow_fwd = 1; /* Allow note forwarding */
  32. static int notify_users = 1; /* Notify users they have notes every hour? */
  33. static struct user_entry_type USERENTRY_FWD =
  34. {
  35. NULL, /* always 0 ;) */
  36. NULL,
  37. NULL,
  38. NULL,
  39. NULL,
  40. NULL,
  41. NULL,
  42. NULL,
  43. NULL,
  44. fwd_display,
  45. "FWD"
  46. };
  47. #include "cmdsnote.c"
  48. void fwd_display(int idx, struct user_entry *e, struct userrec *u)
  49. {
  50. if (dcc[idx].user && (dcc[idx].user->flags & USER_MASTER))
  51. dprintf(idx, NOTES_FORWARD_TO, e->u.string);
  52. }
  53. /* Determine how many notes are waiting for a user.
  54. */
  55. int num_notes(char *user)
  56. {
  57. int tot = 0;
  58. FILE *f = NULL;
  59. char s[513] = "", *to = NULL, *s1 = NULL;
  60. if (!notefile[0])
  61. return 0;
  62. f = fopen(notefile, "r");
  63. if (f == NULL)
  64. return 0;
  65. while (!feof(f)) {
  66. fgets(s, 512, f);
  67. if (!feof(f)) {
  68. if (s[strlen(s) - 1] == '\n')
  69. s[strlen(s) - 1] = 0;
  70. rmspace(s);
  71. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  72. s1 = s;
  73. to = newsplit(&s1);
  74. if (!egg_strcasecmp(to, user))
  75. tot++;
  76. }
  77. }
  78. }
  79. fclose(f);
  80. return tot;
  81. }
  82. /* Change someone's handle.
  83. */
  84. static void notes_change(char *oldnick, char *newnick)
  85. {
  86. FILE *f = NULL, *g = NULL;
  87. char s[513] = "", *to = NULL, *s1 = NULL;
  88. int tot = 0;
  89. if (!egg_strcasecmp(oldnick, newnick))
  90. return;
  91. if (!notefile[0])
  92. return;
  93. f = fopen(notefile, "r");
  94. if (f == NULL)
  95. return;
  96. sprintf(s, "%s~new", notefile);
  97. g = fopen(s, "w");
  98. if (g == NULL) {
  99. fclose(f);
  100. return;
  101. }
  102. chmod(s, userfile_perm); /* Use userfile permissions. */
  103. while (!feof(f)) {
  104. fgets(s, 512, f);
  105. if (!feof(f)) {
  106. if (s[strlen(s) - 1] == '\n')
  107. s[strlen(s) - 1] = 0;
  108. rmspace(s);
  109. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  110. s1 = s;
  111. to = newsplit(&s1);
  112. if (!egg_strcasecmp(to, oldnick)) {
  113. tot++;
  114. fprintf(g, "%s %s\n", newnick, s1);
  115. } else
  116. fprintf(g, "%s %s\n", to, s1);
  117. } else
  118. fprintf(g, "%s\n", s);
  119. }
  120. }
  121. fclose(f);
  122. fclose(g);
  123. unlink(notefile);
  124. sprintf(s, "%s~new", notefile);
  125. movefile(s, notefile);
  126. putlog(LOG_MISC, "*", NOTES_SWITCHED_NOTES, tot, tot == 1 ? "" : "s",
  127. oldnick, newnick);
  128. }
  129. /* Get rid of old useless notes.
  130. */
  131. static void expire_notes()
  132. {
  133. FILE *f = NULL, *g = NULL;
  134. char s[513] = "", *to = NULL, *from = NULL, *ts = NULL, *s1 = NULL;
  135. int tot = 0, lapse;
  136. if (!notefile[0])
  137. return;
  138. f = fopen(notefile, "r");
  139. if (f == NULL)
  140. return;
  141. sprintf(s, "%s~new", notefile);
  142. g = fopen(s, "w");
  143. if (g == NULL) {
  144. fclose(f);
  145. return;
  146. }
  147. chmod(s, userfile_perm); /* Use userfile permissions. */
  148. while (!feof(f)) {
  149. fgets(s, 512, f);
  150. if (!feof(f)) {
  151. if (s[strlen(s) - 1] == '\n')
  152. s[strlen(s) - 1] = 0;
  153. rmspace(s);
  154. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  155. s1 = s;
  156. to = newsplit(&s1);
  157. from = newsplit(&s1);
  158. ts = newsplit(&s1);
  159. lapse = (now - (time_t) atoi(ts)) / 86400;
  160. if (lapse > note_life)
  161. tot++;
  162. else if (!get_user_by_handle(userlist, to))
  163. tot++;
  164. else
  165. fprintf(g, "%s %s %s %s\n", to, from, ts, s1);
  166. } else
  167. fprintf(g, "%s\n", s);
  168. }
  169. }
  170. fclose(f);
  171. fclose(g);
  172. unlink(notefile);
  173. sprintf(s, "%s~new", notefile);
  174. movefile(s, notefile);
  175. if (tot > 0)
  176. putlog(LOG_MISC, "*", NOTES_EXPIRED, tot, tot == 1 ? "" : "s");
  177. }
  178. /* Add note to notefile.
  179. */
  180. int storenote(char *argv1, char *argv2, char *argv3, int idx, char *who, int bufsize)
  181. {
  182. FILE *f = NULL;
  183. char u[20] = "", *f1 = NULL, *to = NULL, work[1024] = "";
  184. struct userrec *ur = NULL, *ur2 = NULL;
  185. if (who && bufsize > 0) who[0] = 0;
  186. ur = get_user_by_handle(userlist, argv2);
  187. if (ur && allow_fwd && (f1 = get_user(&USERENTRY_FWD, ur))) {
  188. char fwd[161] = "", fwd2[161] = "", *f2 = NULL, *p = NULL, *q = NULL, *r = NULL;
  189. int ok = 1;
  190. /* User is valid & has a valid forwarding address */
  191. strcpy(fwd, f1); /* Only 40 bytes are stored in the userfile */
  192. p = strchr(fwd, '@');
  193. if (p && !egg_strcasecmp(p + 1, conf.bot->nick)) {
  194. *p = 0;
  195. if (!egg_strcasecmp(fwd, argv2))
  196. /* They're forwarding to themselves on the same bot, llama's */
  197. ok = 0;
  198. strcpy(fwd2, fwd);
  199. splitc(fwd2, fwd2, '@');
  200. /* Get the user record of the user that we're forwarding to locally */
  201. ur2 = get_user_by_handle(userlist, fwd2);
  202. if (!ur2)
  203. ok = 0;
  204. if ((f2 = get_user(&USERENTRY_FWD, ur2))) {
  205. strcpy(fwd2, f2);
  206. splitc(fwd2, fwd2, '@');
  207. if (!egg_strcasecmp(fwd2, argv2))
  208. /* They're forwarding to someone who forwards back to them! */
  209. ok = 0;
  210. }
  211. p = NULL;
  212. }
  213. if ((argv1[0] != '@') && ((argv3[0] == '<') || (argv3[0] == '>')))
  214. ok = 0; /* Probablly fake pre 1.3 hax0r */
  215. if (ok && (!p || in_chain(p + 1))) {
  216. if (p)
  217. p++;
  218. q = argv3;
  219. while (ok && q && (q = strchr(q, '<'))) {
  220. q++;
  221. if ((r = strchr(q, ' '))) {
  222. *r = 0;
  223. if (!egg_strcasecmp(fwd, q))
  224. ok = 0;
  225. *r = ' ';
  226. }
  227. }
  228. if (ok) {
  229. if (p && strchr(argv1, '@')) {
  230. simple_sprintf(work, "<%s@%s >%s %s", argv2, conf.bot->nick,
  231. argv1, argv3);
  232. simple_sprintf(u, "@%s", conf.bot->nick);
  233. p = u;
  234. } else {
  235. simple_sprintf(work, "<%s@%s %s", argv2, conf.bot->nick,
  236. argv3);
  237. p = argv1;
  238. }
  239. }
  240. } else
  241. ok = 0;
  242. if (ok) {
  243. if ((add_note(fwd, p, work, idx, 0) == NOTE_OK) && (idx >= 0))
  244. dprintf(idx, "Not online; forwarded to %s.\n", f1);
  245. if (who) strncpy(who, f1, bufsize);
  246. to = NULL;
  247. } else {
  248. strcpy(work, argv3);
  249. to = argv2;
  250. }
  251. } else
  252. to = argv2;
  253. if (to) {
  254. if (notefile[0] == 0) {
  255. if (idx >= 0)
  256. dprintf(idx, "%s\n", "Notes are not supported by this bot.");
  257. } else if (num_notes(to) >= maxnotes) {
  258. if (idx >= 0)
  259. dprintf(idx, "%s\n", "Sorry, that user has too many notes already.");
  260. } else { /* Time to unpack it meaningfully */
  261. f = fopen(notefile, "a");
  262. if (f == NULL)
  263. f = fopen(notefile, "w");
  264. if (f == NULL) {
  265. if (idx >= 0)
  266. dprintf(idx, "%s\n", "Cant create notefile. Sorry.");
  267. putlog(LOG_MISC, "*", "%s", "Notefile unreachable!");
  268. } else {
  269. char *p, *from = argv1;
  270. int l = 0;
  271. chmod(notefile, userfile_perm); /* Use userfile permissions. */
  272. while ((argv3[0] == '<') || (argv3[0] == '>')) {
  273. p = newsplit(&(argv3));
  274. if (*p == '<')
  275. l += simple_sprintf(work + l, "via %s, ", p + 1);
  276. else if (argv1[0] == '@')
  277. from = p + 1;
  278. }
  279. fprintf(f, "%s %s %lu %s%s\n", to, from, now,
  280. l ? work : "", argv3);
  281. fclose(f);
  282. if (idx >= 0)
  283. dprintf(idx, "%s.\n", "Stored message");
  284. }
  285. }
  286. }
  287. return 0;
  288. }
  289. /* Convert a string like "2-4;8;16-"
  290. * in an array {2, 4, 8, 8, 16, maxnotes, -1}
  291. */
  292. static void notes_parse(int dl[], char *s)
  293. {
  294. int i = 0;
  295. int idl = 0;
  296. do {
  297. while (s[i] == ';')
  298. i++;
  299. if (s[i]) {
  300. if (s[i] == '-')
  301. dl[idl] = 1;
  302. else
  303. dl[idl] = atoi(s + i);
  304. idl++;
  305. while ((s[i]) && (s[i] != '-') && (s[i] != ';'))
  306. i++;
  307. if (s[i] == '-') {
  308. dl[idl] = atoi(s + i + 1); /* Will be 0 if not a number */
  309. if (dl[idl] == 0)
  310. dl[idl] = maxnotes;
  311. } else
  312. dl[idl] = dl[idl - 1];
  313. idl++;
  314. while ((s[i]) && (s[i] != ';'))
  315. i++;
  316. }
  317. }
  318. while ((s[i]) && (idl < 124));
  319. dl[idl] = -1;
  320. }
  321. /* Return true if 'in' is in intervals of 'dl'
  322. */
  323. static int notes_in(int dl[], int in)
  324. {
  325. int i = 0;
  326. while (dl[i] != -1) {
  327. if ((dl[i] <= in) && (in <= dl[i + 1]))
  328. return 1;
  329. i += 2;
  330. }
  331. return 0;
  332. }
  333. /*
  334. * srd="+" : index
  335. * srd="-" : read all msgs
  336. * else : read msg in list : (ex: .notes read 5-9;12;13;18-)
  337. * idx=-1 : /msg
  338. */
  339. void notes_read(char *hand, char *nick, char *srd, int idx)
  340. {
  341. FILE *f = NULL;
  342. char s[601] = "", *to = NULL, *dt = NULL, *from = NULL, *s1 = NULL, wt[100] = "";
  343. time_t tt;
  344. int ix = 1;
  345. int ir = 0;
  346. int rd[128]; /* Is it enough ? */
  347. int i;
  348. if (srd[0] == 0)
  349. srd = "-";
  350. if (!notefile[0]) {
  351. if (idx >= 0)
  352. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  353. else
  354. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  355. return;
  356. }
  357. f = fopen(notefile, "r");
  358. if (f == NULL) {
  359. if (idx >= 0)
  360. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  361. else
  362. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  363. return;
  364. }
  365. notes_parse(rd, srd);
  366. while (!feof(f)) {
  367. fgets(s, 600, f);
  368. i = strlen(s);
  369. if (i > 0 && s[i - 1] == '\n')
  370. s[i - 1] = 0;
  371. if (!feof(f)) {
  372. rmspace(s);
  373. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  374. s1 = s;
  375. to = newsplit(&s1);
  376. if (!egg_strcasecmp(to, hand)) {
  377. int lapse;
  378. from = newsplit(&s1);
  379. dt = newsplit(&s1);
  380. tt = atoi(dt);
  381. #ifdef S_UTCTIME
  382. egg_strftime(wt, sizeof wt, "%b %d %H:%M %Z", gmtime(&tt));
  383. #else /* !S_UTCTIME */
  384. egg_strftime(wt, sizeof wt, "%b %d %H:%M %Z", localtime(&tt));
  385. #endif /* S_UTCTIME */
  386. dt = wt;
  387. lapse = (int) ((now - tt) / 86400);
  388. if (lapse > note_life - 7) {
  389. if (lapse >= note_life)
  390. strcat(dt, NOTES_EXPIRE_TODAY);
  391. else
  392. sprintf(&dt[strlen(dt)], NOTES_EXPIRE_XDAYS, note_life - lapse,
  393. (note_life - lapse) == 1 ? "" : "S");
  394. }
  395. if (srd[0] == '+') {
  396. if (idx >= 0) {
  397. if (ix == 1)
  398. dprintf(idx, "### %s:\n", NOTES_WAITING);
  399. dprintf(idx, " %2d. %s (%s)\n", ix, from, dt);
  400. } else {
  401. dprintf(DP_HELP, "NOTICE %s :%2d. %s (%s)\n",
  402. nick, ix, from, dt);
  403. }
  404. } else if (notes_in(rd, ix)) {
  405. if (idx >= 0)
  406. dprintf(idx, "%2d. %s (%s): %s\n", ix, from, dt, s1);
  407. else
  408. dprintf(DP_HELP, "NOTICE %s :%2d. %s (%s): %s\n",
  409. nick, ix, from, dt, s1);
  410. ir++;
  411. }
  412. ix++;
  413. }
  414. }
  415. }
  416. }
  417. fclose(f);
  418. if ((srd[0] != '+') && (ir == 0) && (ix > 1)) {
  419. if (idx >= 0)
  420. dprintf(idx, "%s.\n", NOTES_NOT_THAT_MANY);
  421. else
  422. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NOT_THAT_MANY);
  423. }
  424. if (srd[0] == '+') {
  425. if (ix == 1) {
  426. if (idx >= 0)
  427. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  428. else
  429. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  430. } else {
  431. if (idx >= 0)
  432. dprintf(idx, "### %s.\n", NOTES_DCC_USAGE_READ);
  433. else
  434. dprintf(DP_HELP, "NOTICE %s :(%d %s)\n", nick, ix - 1, MISC_TOTAL);
  435. }
  436. } else if ((ir == 0) && (ix == 1)) {
  437. if (idx >= 0)
  438. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  439. else
  440. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  441. }
  442. }
  443. /*
  444. * sdl="-" : erase all msgs
  445. * else : erase msg in list : (ex: .notes erase 2-4;8;16-)
  446. * idx=-1 : /msg
  447. */
  448. void notes_del(char *hand, char *nick, char *sdl, int idx)
  449. {
  450. FILE *f = NULL, *g = NULL;
  451. char s[513] = "", *to = NULL, *s1 = NULL;
  452. int in = 1;
  453. int er = 0;
  454. int dl[128]; /* Is it enough ? */
  455. if (sdl[0] == 0)
  456. sdl = "-";
  457. if (!notefile[0]) {
  458. if (idx >= 0)
  459. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  460. else
  461. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  462. return;
  463. }
  464. f = fopen(notefile, "r");
  465. if (f == NULL) {
  466. if (idx >= 0)
  467. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  468. else
  469. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  470. return;
  471. }
  472. sprintf(s, "%s~new", notefile);
  473. g = fopen(s, "w");
  474. if (g == NULL) {
  475. if (idx >= 0)
  476. dprintf(idx, "%s. :(\n", NOTES_FAILED_CHMOD);
  477. else
  478. dprintf(DP_HELP, "NOTICE %s :%s. :(\n", nick, NOTES_FAILED_CHMOD);
  479. fclose(f);
  480. return;
  481. }
  482. chmod(s, userfile_perm); /* Use userfile permissions. */
  483. notes_parse(dl, sdl);
  484. while (!feof(f)) {
  485. fgets(s, 512, f);
  486. if (s[strlen(s) - 1] == '\n')
  487. s[strlen(s) - 1] = 0;
  488. if (!feof(f)) {
  489. rmspace(s);
  490. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  491. s1 = s;
  492. to = newsplit(&s1);
  493. if (!egg_strcasecmp(to, hand)) {
  494. if (!notes_in(dl, in))
  495. fprintf(g, "%s %s\n", to, s1);
  496. else
  497. er++;
  498. in++;
  499. } else
  500. fprintf(g, "%s %s\n", to, s1);
  501. } else
  502. fprintf(g, "%s\n", s);
  503. }
  504. }
  505. fclose(f);
  506. fclose(g);
  507. unlink(notefile);
  508. sprintf(s, "%s~new", notefile);
  509. movefile(s, notefile);
  510. if ((er == 0) && (in > 1)) {
  511. if (idx >= 0)
  512. dprintf(idx, "%s.\n", NOTES_NOT_THAT_MANY);
  513. else
  514. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NOT_THAT_MANY);
  515. } else if (in == 1) {
  516. if (idx >= 0)
  517. dprintf(idx, "%s.\n", NOTES_NO_MESSAGES);
  518. else
  519. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_NO_MESSAGES);
  520. } else {
  521. if (er == (in - 1)) {
  522. if (idx >= 0)
  523. dprintf(idx, "%s.\n", NOTES_ERASED_ALL);
  524. else
  525. dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, NOTES_ERASED_ALL);
  526. } else {
  527. if (idx >= 0)
  528. dprintf(idx, "%s %d note%s; %d %s.\n", NOTES_ERASED, er,
  529. (er != 1) ? "s" : "", in - 1 - er, NOTES_LEFT);
  530. else
  531. dprintf(DP_HELP, "NOTICE %s :%s %d note%s; %d %s.\n", nick, MISC_ERASED,
  532. er, (er != 1) ? "s" : "", in - 1 - er, NOTES_LEFT);
  533. }
  534. }
  535. }
  536. /* notes <pass> <func>
  537. */
  538. static int msg_notes(char *nick, char *host, struct userrec *u, char *par)
  539. {
  540. char *pwd = NULL, *fcn = NULL;
  541. if (!u)
  542. return 0;
  543. if (u->flags & (USER_BOT))
  544. return 1;
  545. if (!par[0]) {
  546. dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> INDEX\n", nick, NOTES_USAGE);
  547. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> TO <hand> <msg>\n", nick);
  548. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> READ <# or ALL>\n", nick);
  549. dprintf(DP_HELP, "NOTICE %s : NOTES <pass> ERASE <# or ALL>\n", nick);
  550. dprintf(DP_HELP, "NOTICE %s : %s\n", nick, NOTES_MAYBE);
  551. dprintf(DP_HELP, "NOTICE %s : ex: NOTES mypass ERASE 2-4;8;16-\n", nick);
  552. return 1;
  553. }
  554. if (!u_pass_match(u, "-")) {
  555. /* they have a password set */
  556. pwd = newsplit(&par);
  557. if (!u_pass_match(u, pwd))
  558. return 0;
  559. }
  560. fcn = newsplit(&par);
  561. if (!egg_strcasecmp(fcn, "INDEX"))
  562. notes_read(u->handle, nick, "+", -1);
  563. else if (!egg_strcasecmp(fcn, "READ")) {
  564. if (!egg_strcasecmp(par, "ALL"))
  565. notes_read(u->handle, nick, "-", -1);
  566. else
  567. notes_read(u->handle, nick, par, -1);
  568. } else if (!egg_strcasecmp(fcn, "ERASE")) {
  569. if (!egg_strcasecmp(par, "ALL"))
  570. notes_del(u->handle, nick, "-", -1);
  571. else
  572. notes_del(u->handle, nick, par, -1);
  573. } else if (!egg_strcasecmp(fcn, "TO")) {
  574. char *to = NULL;
  575. int i;
  576. FILE *f = NULL;
  577. struct userrec *u2 = NULL;
  578. to = newsplit(&par);
  579. if (!par[0]) {
  580. dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> TO <hand> <message>\n",
  581. nick, NOTES_USAGE);
  582. return 0;
  583. }
  584. u2 = get_user_by_handle(userlist, to);
  585. if (!u2) {
  586. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_USERF_UNKNOWN);
  587. return 1;
  588. } else if (is_bot(u2)) {
  589. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_NOTTO_BOT);
  590. return 1;
  591. }
  592. for (i = 0; i < dcc_total; i++) {
  593. if ((!egg_strcasecmp(dcc[i].nick, to)) &&
  594. (dcc[i].type->flags & DCT_GETNOTES)) {
  595. int aok = 1;
  596. if (dcc[i].type->flags & DCT_CHAT)
  597. if (dcc[i].u.chat->away != NULL)
  598. aok = 0;
  599. if (!(dcc[i].type->flags & DCT_CHAT))
  600. aok = 0; /* Assume non dcc-chat == something weird, so
  601. * store notes for later */
  602. if (aok) {
  603. dprintf(i, "\007%s [%s]: %s\n", u->handle, NOTES_OUTSIDE, par);
  604. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED);
  605. return 1;
  606. }
  607. }
  608. }
  609. if (notefile[0] == 0) {
  610. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_UNSUPPORTED);
  611. return 1;
  612. }
  613. f = fopen(notefile, "a");
  614. if (f == NULL)
  615. f = fopen(notefile, "w");
  616. if (f == NULL) {
  617. dprintf(DP_HELP, "NOTICE %s :%s", nick, NOTES_NOTEFILE_FAILED);
  618. putlog(LOG_MISC, "*", "* %s", NOTES_NOTEFILE_UNREACHABLE);
  619. return 1;
  620. }
  621. chmod(notefile, userfile_perm); /* Use userfile permissions. */
  622. fprintf(f, "%s %s %lu %s\n", to, u->handle, now, par);
  623. fclose(f);
  624. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED);
  625. return 1;
  626. } else
  627. dprintf(DP_HELP, "NOTICE %s :%s INDEX, READ, ERASE, TO\n",
  628. nick, NOTES_DCC_USAGE_READ);
  629. putlog(LOG_CMDS, "*", "(%s!%s) !%s! NOTES %s %s", nick, host, u->handle, fcn,
  630. par[0] ? "..." : "");
  631. return 1;
  632. }
  633. static void notes_hourly()
  634. {
  635. expire_notes();
  636. if (notify_users) {
  637. register struct chanset_t *chan = NULL;
  638. register memberlist *m = NULL;
  639. int k;
  640. register int l;
  641. char s1[256] = "";
  642. struct userrec *u = NULL;
  643. for (chan = chanset; chan; chan = chan->next) {
  644. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  645. sprintf(s1, "%s!%s", m->nick, m->userhost);
  646. u = get_user_by_host(s1);
  647. if (u) {
  648. k = num_notes(u->handle);
  649. for (l = 0; l < dcc_total; l++)
  650. if ((dcc[l].type->flags & DCT_CHAT) &&
  651. !egg_strcasecmp(dcc[l].nick, u->handle)) {
  652. k = 0; /* They already know they have notes */
  653. break;
  654. }
  655. if (k) {
  656. dprintf(DP_HELP, "NOTICE %s :You have %d note%s waiting on %s.\n",
  657. m->nick, k, k == 1 ? "" : "s", botname);
  658. dprintf(DP_HELP, "NOTICE %s :%s /MSG %s NOTES <pass> INDEX\n",
  659. m->nick, NOTES_FORLIST, botname);
  660. }
  661. }
  662. }
  663. }
  664. for (l = 0; l < dcc_total; l++) {
  665. k = num_notes(dcc[l].nick);
  666. if ((k > 0) && (dcc[l].type->flags & DCT_CHAT)) {
  667. dprintf(l, NOTES_WAITING2, k, k == 1 ? "" : "s");
  668. dprintf(l, NOTES_DCC_USAGE_READ2);
  669. }
  670. }
  671. }
  672. }
  673. static void away_notes(char *bot, int idx, char *msg)
  674. {
  675. if (egg_strcasecmp(bot, conf.bot->nick))
  676. return;
  677. if (msg && msg[0])
  678. dprintf(idx, "%s\n", NOTES_STORED);
  679. else
  680. notes_read(dcc[idx].nick, 0, "+", idx);
  681. }
  682. static int chon_notes(char *nick, int idx)
  683. {
  684. if (dcc[idx].type == &DCC_CHAT)
  685. notes_read(nick, 0, "+", idx);
  686. return 0;
  687. }
  688. static cmd_t notes_nkch[] =
  689. {
  690. {"*", "", (Function) notes_change, "notes"},
  691. {NULL, NULL, NULL, NULL}
  692. };
  693. static cmd_t notes_away[] =
  694. {
  695. {"*", "", (Function) away_notes, "notes"},
  696. {NULL, NULL, NULL, NULL}
  697. };
  698. static cmd_t notes_chon[] =
  699. {
  700. {"*", "", (Function) chon_notes, "notes"},
  701. {NULL, NULL, NULL, NULL}
  702. };
  703. static cmd_t notes_msgs[] =
  704. {
  705. {"notes", "", (Function) msg_notes, NULL},
  706. {NULL, NULL, NULL, NULL}
  707. };
  708. static int notes_server_setup(char *mod)
  709. {
  710. add_builtins("msg", notes_msgs);
  711. return 0;
  712. }
  713. static cmd_t notes_load[] =
  714. {
  715. {"server", "", notes_server_setup, "notes:server"},
  716. {NULL, NULL, NULL, NULL}
  717. };
  718. void notes_report(int idx, int details)
  719. {
  720. if (details) {
  721. if (notefile[0])
  722. dprintf(idx, " Notes can be stored, in: %s\n", notefile);
  723. else
  724. dprintf(idx, " Notes can not be stored.\n");
  725. }
  726. }
  727. void notes_init()
  728. {
  729. timer_create_secs(3600, "notes_hourly", (Function) notes_hourly);
  730. add_builtins("dcc", notes_cmds);
  731. add_builtins("load", notes_load);
  732. add_builtins("away", notes_away);
  733. add_builtins("chon", notes_chon);
  734. add_builtins("nkch", notes_nkch);
  735. notes_server_setup(0);
  736. egg_memcpy(&USERENTRY_FWD, &USERENTRY_INFO, sizeof(void *) * 12);
  737. add_entry_type(&USERENTRY_FWD);
  738. }