notes.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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. #include "notes.h"
  10. #include "src/common.h"
  11. #include "src/chanprog.h"
  12. #include "src/main.h"
  13. #include "src/botnet.h"
  14. #include "src/userrec.h"
  15. #include "src/userent.h"
  16. #include "src/misc_file.h"
  17. #include "src/misc.h"
  18. #include "src/users.h"
  19. #include "src/egg_timer.h"
  20. #include "src/tandem.h"
  21. #include "src/tclhash.h"
  22. #include "src/botmsg.h" /* NOTE DEFINES */
  23. #include <fcntl.h>
  24. #include <sys/stat.h> /* chmod(..) */
  25. static int maxnotes = 50; /* Maximum number of notes to allow stored
  26. * for each user */
  27. static int note_life = 60; /* Number of DAYS a note lives */
  28. static char notefile[121] = ".n"; /* Name of the notefile */
  29. static int allow_fwd = 1; /* Allow note forwarding */
  30. static int notify_users = 1; /* Notify users they have notes every hour? */
  31. static struct user_entry_type USERENTRY_FWD =
  32. {
  33. NULL, /* always 0 ;) */
  34. NULL,
  35. NULL,
  36. #ifdef HUB
  37. NULL,
  38. #endif /* HUB */
  39. NULL,
  40. NULL,
  41. NULL,
  42. fwd_display,
  43. "FWD"
  44. };
  45. #include "cmdsnote.c"
  46. void fwd_display(int idx, struct user_entry *e, struct userrec *u)
  47. {
  48. if (dcc[idx].user && (dcc[idx].user->flags & USER_MASTER))
  49. dprintf(idx, NOTES_FORWARD_TO, e->u.string);
  50. }
  51. /* Determine how many notes are waiting for a user.
  52. */
  53. int num_notes(const char *user)
  54. {
  55. int tot = 0;
  56. FILE *f = NULL;
  57. char s[513] = "", *to = NULL, *s1 = NULL;
  58. if (!notefile[0])
  59. return 0;
  60. f = fopen(notefile, "r");
  61. if (f == NULL)
  62. return 0;
  63. while (!feof(f)) {
  64. fgets(s, 512, f);
  65. if (!feof(f)) {
  66. if (s[strlen(s) - 1] == '\n')
  67. s[strlen(s) - 1] = 0;
  68. rmspace(s);
  69. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  70. s1 = s;
  71. to = newsplit(&s1);
  72. if (!egg_strcasecmp(to, user))
  73. tot++;
  74. }
  75. }
  76. }
  77. fclose(f);
  78. return tot;
  79. }
  80. /* Change someone's handle.
  81. */
  82. static void notes_change(const char *oldnick, const char *newnick)
  83. {
  84. FILE *f = NULL, *g = NULL;
  85. char s[513] = "", *to = NULL, *s1 = NULL;
  86. int tot = 0;
  87. if (!egg_strcasecmp(oldnick, newnick))
  88. return;
  89. if (!notefile[0])
  90. return;
  91. f = fopen(notefile, "r");
  92. if (f == NULL)
  93. return;
  94. sprintf(s, "%s~new", notefile);
  95. g = fopen(s, "w");
  96. if (g == NULL) {
  97. fclose(f);
  98. return;
  99. }
  100. fixmod(s);
  101. while (!feof(f)) {
  102. fgets(s, 512, f);
  103. if (!feof(f)) {
  104. if (s[strlen(s) - 1] == '\n')
  105. s[strlen(s) - 1] = 0;
  106. rmspace(s);
  107. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  108. s1 = s;
  109. to = newsplit(&s1);
  110. if (!egg_strcasecmp(to, oldnick)) {
  111. tot++;
  112. fprintf(g, "%s %s\n", newnick, s1);
  113. } else
  114. fprintf(g, "%s %s\n", to, s1);
  115. } else
  116. fprintf(g, "%s\n", s);
  117. }
  118. }
  119. fclose(f);
  120. fclose(g);
  121. unlink(notefile);
  122. sprintf(s, "%s~new", notefile);
  123. movefile(s, notefile);
  124. putlog(LOG_MISC, "*", NOTES_SWITCHED_NOTES, tot, tot == 1 ? "" : "s",
  125. oldnick, newnick);
  126. }
  127. /* Get rid of old useless notes.
  128. */
  129. static void expire_notes()
  130. {
  131. FILE *f = NULL, *g = NULL;
  132. char s[513] = "", *to = NULL, *from = NULL, *ts = NULL, *s1 = NULL;
  133. int tot = 0, lapse;
  134. if (!notefile[0])
  135. return;
  136. f = fopen(notefile, "r");
  137. if (f == NULL)
  138. return;
  139. sprintf(s, "%s~new", notefile);
  140. g = fopen(s, "w");
  141. if (g == NULL) {
  142. fclose(f);
  143. return;
  144. }
  145. fixmod(s);
  146. while (!feof(f)) {
  147. fgets(s, 512, f);
  148. if (!feof(f)) {
  149. if (s[strlen(s) - 1] == '\n')
  150. s[strlen(s) - 1] = 0;
  151. rmspace(s);
  152. if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */
  153. s1 = s;
  154. to = newsplit(&s1);
  155. from = newsplit(&s1);
  156. ts = newsplit(&s1);
  157. lapse = (now - (time_t) atoi(ts)) / 86400;
  158. if (lapse > note_life)
  159. tot++;
  160. else if (!get_user_by_handle(userlist, to))
  161. tot++;
  162. else
  163. fprintf(g, "%s %s %s %s\n", to, from, ts, s1);
  164. } else
  165. fprintf(g, "%s\n", s);
  166. }
  167. }
  168. fclose(f);
  169. fclose(g);
  170. unlink(notefile);
  171. sprintf(s, "%s~new", notefile);
  172. movefile(s, notefile);
  173. if (tot > 0)
  174. putlog(LOG_MISC, "*", NOTES_EXPIRED, tot, tot == 1 ? "" : "s");
  175. }
  176. /* Add note to notefile.
  177. */
  178. int storenote(char *argv1, char *argv2, char *argv3, int idx, char *who, int bufsize)
  179. {
  180. FILE *f = NULL;
  181. char u[20] = "", *f1 = NULL, *to = NULL, work[1024] = "";
  182. struct userrec *ur = NULL, *ur2 = NULL;
  183. if (who && bufsize > 0) who[0] = 0;
  184. ur = get_user_by_handle(userlist, argv2);
  185. if (ur && allow_fwd && (f1 = get_user(&USERENTRY_FWD, ur))) {
  186. char fwd[161] = "", fwd2[161] = "", *f2 = NULL, *p = NULL, *q = NULL, *r = NULL;
  187. int ok = 1;
  188. /* User is valid & has a valid forwarding address */
  189. strcpy(fwd, f1); /* Only 40 bytes are stored in the userfile */
  190. p = strchr(fwd, '@');
  191. if (p && !egg_strcasecmp(p + 1, conf.bot->nick)) {
  192. *p = 0;
  193. if (!egg_strcasecmp(fwd, argv2))
  194. /* They're forwarding to themselves on the same bot, llama's */
  195. ok = 0;
  196. strcpy(fwd2, fwd);
  197. splitc(fwd2, fwd2, '@');
  198. /* Get the user record of the user that we're forwarding to locally */
  199. ur2 = get_user_by_handle(userlist, fwd2);
  200. if (!ur2)
  201. ok = 0;
  202. if ((f2 = get_user(&USERENTRY_FWD, ur2))) {
  203. strcpy(fwd2, f2);
  204. splitc(fwd2, fwd2, '@');
  205. if (!egg_strcasecmp(fwd2, argv2))
  206. /* They're forwarding to someone who forwards back to them! */
  207. ok = 0;
  208. }
  209. p = NULL;
  210. }
  211. if ((argv1[0] != '@') && ((argv3[0] == '<') || (argv3[0] == '>')))
  212. ok = 0; /* Probablly fake pre 1.3 hax0r */
  213. if (ok && (!p || in_chain(p + 1))) {
  214. if (p)
  215. p++;
  216. q = argv3;
  217. while (ok && q && (q = strchr(q, '<'))) {
  218. q++;
  219. if ((r = strchr(q, ' '))) {
  220. *r = 0;
  221. if (!egg_strcasecmp(fwd, q))
  222. ok = 0;
  223. *r = ' ';
  224. }
  225. }
  226. if (ok) {
  227. if (p && strchr(argv1, '@')) {
  228. simple_sprintf(work, "<%s@%s >%s %s", argv2, conf.bot->nick,
  229. argv1, argv3);
  230. simple_sprintf(u, "@%s", conf.bot->nick);
  231. p = u;
  232. } else {
  233. simple_sprintf(work, "<%s@%s %s", argv2, conf.bot->nick,
  234. argv3);
  235. p = argv1;
  236. }
  237. }
  238. } else
  239. ok = 0;
  240. if (ok) {
  241. if ((add_note(fwd, p, work, idx, 0) == NOTE_OK) && (idx >= 0))
  242. dprintf(idx, "Not online; forwarded to %s.\n", f1);
  243. if (who) strncpy(who, f1, bufsize);
  244. to = NULL;
  245. } else {
  246. strcpy(work, argv3);
  247. to = argv2;
  248. }
  249. } else
  250. to = argv2;
  251. if (to) {
  252. if (notefile[0] == 0) {
  253. if (idx >= 0)
  254. dprintf(idx, "%s\n", "Notes are not supported by this bot.");
  255. } else if (num_notes(to) >= maxnotes) {
  256. if (idx >= 0)
  257. dprintf(idx, "%s\n", "Sorry, that user has too many notes already.");
  258. } else { /* Time to unpack it meaningfully */
  259. f = fopen(notefile, "a");
  260. if (f == NULL)
  261. f = fopen(notefile, "w");
  262. if (f == NULL) {
  263. if (idx >= 0)
  264. dprintf(idx, "%s\n", "Cant create notefile. Sorry.");
  265. putlog(LOG_MISC, "*", "%s", "Notefile unreachable!");
  266. } else {
  267. char *p = NULL, *from = argv1;
  268. size_t len = 0;
  269. fixmod(notefile);
  270. while ((argv3[0] == '<') || (argv3[0] == '>')) {
  271. p = newsplit(&(argv3));
  272. if (*p == '<')
  273. len += simple_sprintf(work + len, "via %s, ", p + 1);
  274. else if (argv1[0] == '@')
  275. from = p + 1;
  276. }
  277. fprintf(f, "%s %s %li %s%s\n", to, from, now, len ? 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[], const 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. void notes_read(const char *hand, const char *nick, const char *srd, int idx)
  337. {
  338. FILE *f = NULL;
  339. char s[601] = "", *to = NULL, *dt = NULL, *from = NULL, *s1 = NULL, 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. void notes_del(const char *hand, const char *nick, const char *sdl, int idx)
  446. {
  447. FILE *f = NULL, *g = NULL;
  448. char s[513] = "", *to = NULL, *s1 = NULL;
  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. fixmod(s);
  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 = NULL, *fcn = NULL;
  538. if (!u)
  539. return 0;
  540. if (u->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 = NULL;
  572. int i;
  573. FILE *f = NULL;
  574. struct userrec *u2 = NULL;
  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. fixmod(notefile);
  619. fprintf(f, "%s %s %li %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 = NULL;
  635. register memberlist *m = NULL;
  636. int k;
  637. register int l;
  638. char s1[256] = "";
  639. struct userrec *u = NULL;
  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 idx, char *msg)
  671. {
  672. if (egg_strcasecmp(bot, conf.bot->nick))
  673. return;
  674. if (msg && msg[0])
  675. dprintf(idx, "%s\n", NOTES_STORED);
  676. else
  677. notes_read(dcc[idx].nick, 0, "+", idx);
  678. }
  679. int chon_notes(int idx)
  680. {
  681. if (dcc[idx].type == &DCC_CHAT)
  682. notes_read(dcc[idx].nick, 0, "+", idx);
  683. return 0;
  684. }
  685. static cmd_t notes_nkch[] =
  686. {
  687. {"*", "", (Function) notes_change, "notes"},
  688. {NULL, NULL, NULL, NULL}
  689. };
  690. static cmd_t notes_away[] =
  691. {
  692. {"*", "", (Function) away_notes, "notes"},
  693. {NULL, NULL, NULL, NULL}
  694. };
  695. static cmd_t notes_msgs[] =
  696. {
  697. {"notes", "", (Function) msg_notes, NULL},
  698. {NULL, NULL, NULL, NULL}
  699. };
  700. static int notes_server_setup(char *mod)
  701. {
  702. add_builtins("msg", notes_msgs);
  703. return 0;
  704. }
  705. void notes_report(int idx, int details)
  706. {
  707. if (details) {
  708. if (notefile[0])
  709. dprintf(idx, " Notes can be stored, in: %s\n", notefile);
  710. else
  711. dprintf(idx, " Notes can not be stored.\n");
  712. }
  713. }
  714. void notes_init()
  715. {
  716. timer_create_secs(3600, "notes_hourly", (Function) notes_hourly);
  717. add_builtins("dcc", notes_cmds);
  718. add_builtins("away", notes_away);
  719. add_builtins("nkch", notes_nkch);
  720. notes_server_setup(0);
  721. egg_memcpy(&USERENTRY_FWD, &USERENTRY_INFO, sizeof(void *) * 12);
  722. add_entry_type(&USERENTRY_FWD);
  723. }