tcluser.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * tcluser.c -- handles:
  3. * Tcl stubs for the user-record-oriented commands
  4. *
  5. */
  6. #include "main.h"
  7. #include "users.h"
  8. #include "chan.h"
  9. #include "tandem.h"
  10. #include "modules.h"
  11. extern Tcl_Interp *interp;
  12. extern struct userrec *userlist;
  13. extern int default_flags, dcc_total, ignore_time;
  14. extern struct dcc_t *dcc;
  15. extern char origbotname[], botnetnick[];
  16. extern time_t now;
  17. static int tcl_countusers STDVAR
  18. {
  19. BADARGS(1, 1, "");
  20. Tcl_AppendResult(irp, int_to_base10(count_users(userlist)), NULL);
  21. return TCL_OK;
  22. }
  23. static int tcl_validuser STDVAR
  24. {
  25. BADARGS(2, 2, " handle");
  26. Tcl_AppendResult(irp, get_user_by_handle(userlist, argv[1]) ? "1" : "0",
  27. NULL);
  28. return TCL_OK;
  29. }
  30. static int tcl_finduser STDVAR
  31. {
  32. struct userrec *u;
  33. BADARGS(2, 2, " nick!user@host");
  34. u = get_user_by_host(argv[1]);
  35. Tcl_AppendResult(irp, u ? u->handle : "*", NULL);
  36. return TCL_OK;
  37. }
  38. static int tcl_passwdOk STDVAR
  39. {
  40. struct userrec *u;
  41. BADARGS(3, 3, " handle passwd");
  42. Tcl_AppendResult(irp, ((u = get_user_by_handle(userlist, argv[1])) &&
  43. u_pass_match(u, argv[2])) ? "1" : "0", NULL);
  44. return TCL_OK;
  45. }
  46. static int tcl_chattr STDVAR
  47. {
  48. char *chan, *chg, work[100];
  49. struct flag_record pls, mns, user;
  50. struct userrec *u;
  51. BADARGS(2, 4, " handle ?changes? ?channel?");
  52. if ((argv[1][0] == '*') || !(u = get_user_by_handle(userlist, argv[1]))) {
  53. Tcl_AppendResult(irp, "*", NULL);
  54. return TCL_OK;
  55. }
  56. if (argc == 4) {
  57. user.match = FR_GLOBAL | FR_CHAN;
  58. chan = argv[3];
  59. chg = argv[2];
  60. } else if (argc == 3 && argv[2][0]) {
  61. int ischan = (findchan_by_dname(argv[2]) != NULL);
  62. if (strchr(CHANMETA, argv[2][0]) && !ischan && argv[2][0] != '+' && argv[2][0] != '-') {
  63. Tcl_AppendResult(irp, "no such channel", NULL);
  64. return TCL_ERROR;
  65. } else if (ischan) {
  66. /* Channel exists */
  67. user.match = FR_GLOBAL | FR_CHAN;
  68. chan = argv[2];
  69. chg = NULL;
  70. } else {
  71. /* 3rd possibility... channel doesnt exist, does start with a +.
  72. * In this case we assume the string is flags.
  73. */
  74. user.match = FR_GLOBAL;
  75. chan = NULL;
  76. chg = argv[2];
  77. }
  78. } else {
  79. user.match = FR_GLOBAL;
  80. chan = NULL;
  81. chg = NULL;
  82. }
  83. if (chan && !findchan_by_dname(chan)) {
  84. Tcl_AppendResult(irp, "no such channel", NULL);
  85. return TCL_ERROR;
  86. }
  87. get_user_flagrec(u, &user, chan);
  88. /* Make changes */
  89. if (chg) {
  90. pls.match = user.match;
  91. break_down_flags(chg, &pls, &mns);
  92. /* No-one can change these flags on-the-fly */
  93. pls.global &=~(USER_BOT);
  94. mns.global &=~(USER_BOT);
  95. if (chan) {
  96. pls.chan &= ~(BOT_SHARE);
  97. mns.chan &= ~(BOT_SHARE);
  98. }
  99. user.global = sanity_check((user.global |pls.global) &~mns.global);
  100. user.udef_global = (user.udef_global | pls.udef_global)
  101. & ~mns.udef_global;
  102. if (chan) {
  103. user.chan = chan_sanity_check((user.chan | pls.chan) & ~mns.chan,
  104. user.global);
  105. user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan;
  106. }
  107. set_user_flagrec(u, &user, chan);
  108. }
  109. /* Retrieve current flags and return them */
  110. build_flags(work, &user, NULL);
  111. Tcl_AppendResult(irp, work, NULL);
  112. return TCL_OK;
  113. }
  114. static int tcl_botattr STDVAR
  115. {
  116. char *chan, *chg, work[100];
  117. struct flag_record pls, mns, user;
  118. struct userrec *u;
  119. BADARGS(2, 4, " bot-handle ?changes? ?channel?");
  120. u = get_user_by_handle(userlist, argv[1]);
  121. if ((argv[1][0] == '*') || !u || !(u->flags & USER_BOT)) {
  122. Tcl_AppendResult(irp, "*", NULL);
  123. return TCL_OK;
  124. }
  125. if (argc == 4) {
  126. user.match = FR_BOT | FR_CHAN;
  127. chan = argv[3];
  128. chg = argv[2];
  129. } else if (argc == 3 && argv[2][0] &&
  130. strchr(CHANMETA, argv[2][0]) != NULL) {
  131. /* We need todo extra checking here to stop us mixing up +channel's
  132. * with flags. <cybah>
  133. */
  134. if (!findchan_by_dname(argv[2]) && argv[2][0] != '+') {
  135. /* Channel doesnt exist, and it cant possibly be flags as there
  136. * is no + at the start of the string.
  137. */
  138. Tcl_AppendResult(irp, "no such channel", NULL);
  139. return TCL_ERROR;
  140. } else if(findchan_by_dname(argv[2])) {
  141. /* Channel exists */
  142. user.match = FR_BOT | FR_CHAN;
  143. chan = argv[2];
  144. chg = NULL;
  145. } else {
  146. /* 3rd possibility... channel doesnt exist, does start with a +.
  147. * In this case we assume the string is flags.
  148. */
  149. user.match = FR_BOT;
  150. chan = NULL;
  151. chg = argv[2];
  152. }
  153. } else {
  154. user.match = FR_BOT;
  155. chan = NULL;
  156. if (argc < 3)
  157. chg = NULL;
  158. else
  159. chg = argv[2];
  160. }
  161. if (chan && !findchan_by_dname(chan)) {
  162. Tcl_AppendResult(irp, "no such channel", NULL);
  163. return TCL_ERROR;
  164. }
  165. get_user_flagrec(u, &user, chan);
  166. /* Make changes */
  167. if (chg) {
  168. pls.match = user.match;
  169. break_down_flags(chg, &pls, &mns);
  170. /* No-one can change these flags on-the-fly */
  171. if (chan) {
  172. pls.chan &= BOT_SHARE;
  173. mns.chan &= BOT_SHARE;
  174. }
  175. user.bot = sanity_check((user.bot | pls.bot) & ~mns.bot);
  176. if (chan) {
  177. user.chan = (user.chan | pls.chan) & ~mns.chan;
  178. user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan;
  179. }
  180. set_user_flagrec(u, &user, chan);
  181. }
  182. /* Retrieve current flags and return them */
  183. build_flags(work, &user, NULL);
  184. Tcl_AppendResult(irp, work, NULL);
  185. return TCL_OK;
  186. }
  187. static int tcl_matchattr STDVAR
  188. {
  189. struct userrec *u;
  190. struct flag_record plus, minus, user;
  191. int ok = 0, f;
  192. BADARGS(3, 4, " handle flags ?channel?");
  193. if ((u = get_user_by_handle(userlist, argv[1]))) {
  194. user.match = FR_GLOBAL | (argc == 4 ? FR_CHAN : 0) | FR_BOT;
  195. get_user_flagrec(u, &user, argv[3]);
  196. plus.match = user.match;
  197. break_down_flags(argv[2], &plus, &minus);
  198. f = (minus.global || minus.udef_global || minus.chan ||
  199. minus.udef_chan || minus.bot);
  200. if (flagrec_eq(&plus, &user)) {
  201. if (!f)
  202. ok = 1;
  203. else {
  204. minus.match = plus.match ^ (FR_AND | FR_OR);
  205. if (!flagrec_eq(&minus, &user))
  206. ok = 1;
  207. }
  208. }
  209. }
  210. Tcl_AppendResult(irp, ok ? "1" : "0", NULL);
  211. return TCL_OK;
  212. }
  213. static int tcl_adduser STDVAR
  214. {
  215. BADARGS(2, 3, " handle ?hostmask?");
  216. if (strlen(argv[1]) > HANDLEN)
  217. argv[1][HANDLEN] = 0;
  218. if ((argv[1][0] == '*') || get_user_by_handle(userlist, argv[1]))
  219. Tcl_AppendResult(irp, "0", NULL);
  220. else {
  221. userlist = adduser(userlist, argv[1], argv[2], "-", default_flags);
  222. Tcl_AppendResult(irp, "1", NULL);
  223. }
  224. return TCL_OK;
  225. }
  226. static int tcl_addbot STDVAR
  227. {
  228. struct bot_addr *bi;
  229. char *p, *q;
  230. BADARGS(3, 3, " handle address");
  231. if (strlen(argv[1]) > HANDLEN)
  232. argv[1][HANDLEN] = 0;
  233. if (get_user_by_handle(userlist, argv[1]))
  234. Tcl_AppendResult(irp, "0", NULL);
  235. else if (argv[1][0] == '*')
  236. Tcl_AppendResult(irp, "0", NULL);
  237. else {
  238. userlist = adduser(userlist, argv[1], "none", "-", USER_BOT);
  239. bi = user_malloc(sizeof(struct bot_addr));
  240. q = strchr(argv[2], ':');
  241. if (!q) {
  242. bi->address = user_malloc(strlen(argv[2]) + 1);
  243. strcpy(bi->address, argv[2]);
  244. bi->telnet_port = 3333;
  245. bi->relay_port = 3333;
  246. } else {
  247. bi->address = user_malloc(q - argv[2] + 1);
  248. strncpy(bi->address, argv[2], q - argv[2]);
  249. bi->address[q - argv[2]] = 0;
  250. p = q + 1;
  251. bi->telnet_port = atoi(p);
  252. q = strchr(p, '/');
  253. if (!q)
  254. bi->relay_port = bi->telnet_port;
  255. else
  256. bi->relay_port = atoi(q + 1);
  257. }
  258. set_user(&USERENTRY_BOTADDR, get_user_by_handle(userlist, argv[1]), bi);
  259. Tcl_AppendResult(irp, "1", NULL);
  260. }
  261. return TCL_OK;
  262. }
  263. static int tcl_deluser STDVAR
  264. {
  265. BADARGS(2, 2, " handle");
  266. Tcl_AppendResult(irp, (argv[1][0] == '*') ? "0" :
  267. int_to_base10(deluser(argv[1])), NULL);
  268. return TCL_OK;
  269. }
  270. static int tcl_delhost STDVAR
  271. {
  272. BADARGS(3, 3, " handle hostmask");
  273. if ((!get_user_by_handle(userlist, argv[1])) || (argv[1][0] == '*')) {
  274. Tcl_AppendResult(irp, "non-existent user", NULL);
  275. return TCL_ERROR;
  276. }
  277. Tcl_AppendResult(irp, delhost_by_handle(argv[1], argv[2]) ? "1" : "0",
  278. NULL);
  279. return TCL_OK;
  280. }
  281. static int tcl_userlist STDVAR
  282. {
  283. struct userrec *u;
  284. struct flag_record user, plus, minus;
  285. int ok = 1, f = 0;
  286. BADARGS(1, 3, " ?flags ?channel??");
  287. if (argc == 3 && !findchan_by_dname(argv[2])) {
  288. Tcl_AppendResult(irp, "Invalid channel: ", argv[2], NULL);
  289. return TCL_ERROR;
  290. }
  291. if (argc >= 2) {
  292. plus.match = FR_GLOBAL | FR_CHAN | FR_BOT;
  293. break_down_flags(argv[1], &plus, &minus);
  294. f = (minus.global || minus.udef_global || minus.chan ||
  295. minus.udef_chan || minus.bot);
  296. }
  297. minus.match = plus.match ^ (FR_AND | FR_OR);
  298. for (u = userlist; u; u = u->next) {
  299. if (argc >= 2) {
  300. user.match = FR_GLOBAL | FR_CHAN | FR_BOT | (argc == 3 ? 0 : FR_ANYWH);
  301. if (argc == 3)
  302. get_user_flagrec(u, &user, argv[2]);
  303. else
  304. get_user_flagrec(u, &user, NULL);
  305. if (flagrec_eq(&plus, &user) && !(f && flagrec_eq(&minus, &user)))
  306. ok = 1;
  307. else
  308. ok = 0;
  309. }
  310. if (ok)
  311. Tcl_AppendElement(interp, u->handle);
  312. }
  313. return TCL_OK;
  314. }
  315. #ifdef HUB
  316. static int tcl_save STDVAR
  317. {
  318. write_userfile(-1);
  319. return TCL_OK;
  320. }
  321. static int tcl_reload STDVAR
  322. {
  323. reload();
  324. return TCL_OK;
  325. }
  326. #endif
  327. static int tcl_chhandle STDVAR
  328. {
  329. struct userrec *u;
  330. char newhand[HANDLEN + 1];
  331. int x = 1, i;
  332. BADARGS(3, 3, " oldnick newnick");
  333. u = get_user_by_handle(userlist, argv[1]);
  334. if (!u)
  335. x = 0;
  336. else {
  337. strncpyz(newhand, argv[2], sizeof newhand);
  338. for (i = 0; i < strlen(newhand); i++)
  339. if ((newhand[i] <= 32) || (newhand[i] >= 127) || (newhand[i] == '@'))
  340. newhand[i] = '?';
  341. if (strchr(BADHANDCHARS, newhand[0]) != NULL)
  342. x = 0;
  343. else if (strlen(newhand) < 1)
  344. x = 0;
  345. else if (get_user_by_handle(userlist, newhand))
  346. x = 0;
  347. else if (!egg_strcasecmp(botnetnick, newhand) &&
  348. (!(u->flags & USER_BOT) || nextbot (argv [1]) != -1))
  349. x = 0;
  350. else if (newhand[0] == '*')
  351. x = 0;
  352. }
  353. if (x)
  354. x = change_handle(u, newhand);
  355. Tcl_AppendResult(irp, x ? "1" : "0", NULL);
  356. return TCL_OK;
  357. }
  358. static int tcl_getting_users STDVAR
  359. {
  360. int i;
  361. BADARGS(1, 1, "");
  362. for (i = 0; i < dcc_total; i++) {
  363. if (dcc[i].type == &DCC_BOT && dcc[i].status & STAT_GETTING) {
  364. Tcl_AppendResult(irp, "1", NULL);
  365. return TCL_OK;
  366. }
  367. }
  368. Tcl_AppendResult(irp, "0", NULL);
  369. return TCL_OK;
  370. }
  371. static int tcl_isignore STDVAR
  372. {
  373. BADARGS(2, 2, " nick!user@host");
  374. Tcl_AppendResult(irp, match_ignore(argv[1]) ? "1" : "0", NULL);
  375. return TCL_OK;
  376. }
  377. static int tcl_newignore STDVAR
  378. {
  379. time_t expire_time;
  380. char ign[UHOSTLEN], cmt[66], from[HANDLEN + 1];
  381. BADARGS(4, 5, " hostmask creator comment ?lifetime?");
  382. strncpyz(ign, argv[1], sizeof ign);
  383. strncpyz(from, argv[2], sizeof from);
  384. strncpyz(cmt, argv[3], sizeof cmt);
  385. if (argc == 4)
  386. expire_time = now + (60 * ignore_time);
  387. else {
  388. if (argc == 5 && atol(argv[4]) == 0)
  389. expire_time = 0L;
  390. else
  391. expire_time = now + (60 * atol(argv[4])); /* This is a potential crash. FIXME -poptix */
  392. }
  393. addignore(ign, from, cmt, expire_time);
  394. return TCL_OK;
  395. }
  396. static int tcl_killignore STDVAR
  397. {
  398. BADARGS(2, 2, " hostmask");
  399. Tcl_AppendResult(irp, delignore(argv[1]) ? "1" : "0", NULL);
  400. return TCL_OK;
  401. }
  402. /* { hostmask note expire-time create-time creator }
  403. */
  404. static int tcl_ignorelist STDVAR
  405. {
  406. struct igrec *i;
  407. char expire[11], added[11], *p;
  408. #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8))
  409. CONST char *list[5];
  410. #else
  411. char *list[5];
  412. #endif
  413. BADARGS(1, 1, "");
  414. for (i = global_ign; i; i = i->next) {
  415. list[0] = i->igmask;
  416. list[1] = i->msg;
  417. egg_snprintf(expire, sizeof expire, "%lu", i->expire);
  418. list[2] = expire;
  419. egg_snprintf(added, sizeof added, "%lu", i->added);
  420. list[3] = added;
  421. list[4] = i->user;
  422. p = Tcl_Merge(5, list);
  423. Tcl_AppendElement(irp, p);
  424. Tcl_Free((char *) p);
  425. }
  426. return TCL_OK;
  427. }
  428. static int tcl_getuser STDVAR
  429. {
  430. struct user_entry_type *et;
  431. struct userrec *u;
  432. struct user_entry *e;
  433. BADARGS(3, 999, " handle type");
  434. if (!(et = find_entry_type(argv[2])) && egg_strcasecmp(argv[2], "HANDLE")) {
  435. Tcl_AppendResult(irp, "No such info type: ", argv[2], NULL);
  436. return TCL_ERROR;
  437. }
  438. if (!(u = get_user_by_handle(userlist, argv[1]))) {
  439. if (argv[1][0] != '*') {
  440. Tcl_AppendResult(irp, "No such user.", NULL);
  441. return TCL_ERROR;
  442. } else
  443. return TCL_OK; /* silently ignore user * */
  444. }
  445. if (!egg_strcasecmp(argv[2], "HANDLE")) {
  446. Tcl_AppendResult(irp,u->handle, NULL);
  447. } else {
  448. e = find_user_entry(et, u);
  449. if (e)
  450. return et->tcl_get(irp, u, e, argc, argv);
  451. }
  452. return TCL_OK;
  453. }
  454. static int tcl_setuser STDVAR
  455. {
  456. struct user_entry_type *et;
  457. struct userrec *u;
  458. struct user_entry *e;
  459. int r;
  460. module_entry *me;
  461. BADARGS(3, 999, " handle type ?setting....?");
  462. if (!(et = find_entry_type(argv[2]))) {
  463. Tcl_AppendResult(irp, "No such info type: ", argv[2], NULL);
  464. return TCL_ERROR;
  465. }
  466. if (!(u = get_user_by_handle(userlist, argv[1]))) {
  467. if (argv[1][0] != '*') {
  468. Tcl_AppendResult(irp, "No such user.", NULL);
  469. return TCL_ERROR;
  470. } else
  471. return TCL_OK; /* Silently ignore user * */
  472. }
  473. me = module_find("irc", 0, 0);
  474. if (me && !strcmp(argv[2], "hosts") && argc == 3) {
  475. Function *func = me->funcs;
  476. (func[IRC_CHECK_THIS_USER]) (argv[1], 1, NULL);
  477. }
  478. if (!(e = find_user_entry(et, u))) {
  479. e = user_malloc(sizeof(struct user_entry));
  480. e->type = et;
  481. e->name = NULL;
  482. e->u.list = NULL;
  483. list_insert((&(u->entries)), e);
  484. }
  485. r = et->tcl_set(irp, u, e, argc, argv);
  486. /* Yeah... e is freed, and we read it... (tcl: setuser hand HOSTS none) */
  487. if (!e->u.list) {
  488. if (list_delete((struct list_type **) &(u->entries),
  489. (struct list_type *) e))
  490. nfree(e);
  491. /* else maybe already freed... (entry_type==HOSTS) <drummer> */
  492. }
  493. if (me && !strcmp(argv[2], "hosts") && argc == 4) {
  494. Function *func = me->funcs;
  495. (func[IRC_CHECK_THIS_USER]) (argv[1], 0, NULL);
  496. }
  497. return r;
  498. }
  499. tcl_cmds tcluser_cmds[] =
  500. {
  501. {"countusers", tcl_countusers},
  502. {"validuser", tcl_validuser},
  503. {"finduser", tcl_finduser},
  504. {"passwdok", tcl_passwdOk},
  505. {"chattr", tcl_chattr},
  506. {"botattr", tcl_botattr},
  507. {"matchattr", tcl_matchattr},
  508. {"matchchanattr", tcl_matchattr},
  509. {"adduser", tcl_adduser},
  510. {"addbot", tcl_addbot},
  511. {"deluser", tcl_deluser},
  512. {"delhost", tcl_delhost},
  513. {"userlist", tcl_userlist},
  514. #ifdef HUB
  515. {"save", tcl_save},
  516. {"reload", tcl_reload},
  517. #endif
  518. {"chhandle", tcl_chhandle},
  519. {"chnick", tcl_chhandle},
  520. {"getting-users", tcl_getting_users},
  521. {"isignore", tcl_isignore},
  522. {"newignore", tcl_newignore},
  523. {"killignore", tcl_killignore},
  524. {"ignorelist", tcl_ignorelist},
  525. {"getuser", tcl_getuser},
  526. {"setuser", tcl_setuser},
  527. {NULL, NULL}
  528. };