notes.c 19 KB

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