PageRenderTime 30ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 1ms

/src/scriptcmd.cpp

https://gitlab.com/b0nk/mbot
C++ | 1275 lines | 1132 code | 65 blank | 78 comment | 341 complexity | 428b0389d6c5e4b0f13395075eb43670 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. This file is part of mbot.
  3. mbot is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at
  6. your option) any later version.
  7. mbot is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with mbot; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "scriptcmd.h"
  16. #define SOURCE s->script.source
  17. #define DEST s->script.dest
  18. #define BUF s->script.buf
  19. #define SEND_TEXT s->script.send_text
  20. // !modlist
  21. void
  22. scriptcmd_modlist (NetServer *s)
  23. {
  24. if (bot->modules.count () == 0)
  25. {
  26. SEND_TEXT (DEST, "No modules loaded.");
  27. return;
  28. }
  29. Module *m;
  30. StringFixed tmp (MSG_SIZE);
  31. bot->modules.rewind ();
  32. while ((m = (Module *)bot->modules.next ()) != NULL)
  33. {
  34. tmp += (c_char)*m;
  35. tmp += " ";
  36. }
  37. SEND_TEXT (DEST, "Loaded Modules: %s", (c_char)tmp);
  38. }
  39. // !modadd path
  40. void
  41. scriptcmd_modadd (NetServer *s)
  42. {
  43. strsplit (CMD[3], BUF, 1);
  44. if (BUF[1][0] == 0)
  45. {
  46. SEND_TEXT (DEST, "%s", HELP_MODADD);
  47. return;
  48. }
  49. Module *mod = bot->add_module (BUF[1]);
  50. if (mod == NULL)
  51. {
  52. SEND_TEXT (DEST, "Failed to load module.");
  53. return;
  54. }
  55. NetServer *server = NULL;
  56. const char *bufline;
  57. int server_cur = -1;
  58. bot->line = 0;
  59. bot->conf.rewind_text ();
  60. while ( (bufline = bot->conf.get_line ()) != NULL)
  61. {
  62. bot->line++;
  63. if (bufline[0] == 0 || bufline[0] == '#' || bufline[0] == 10)
  64. continue;
  65. strsplit (bufline, BUF, 2);
  66. if (strcasecmp (BUF[0], "bot") == 0)
  67. {
  68. server_cur++;
  69. if (server_cur < bot->server_num)
  70. server = bot->servers[server_cur];
  71. }
  72. if (server == NULL)
  73. continue;
  74. if (strcasecmp (BUF[0], "set") == 0)
  75. {
  76. if (!server->vars.var_set (BUF[1], BUF[2]))
  77. {
  78. snprintf (BUF[3], MSG_SIZE, "inexistant variable \"%s\".", BUF[1]);
  79. bot->conf_warn (BUF[3]);
  80. }
  81. }
  82. mod->conf (server, bufline);
  83. }
  84. SEND_TEXT (DEST, "Module loaded.");
  85. }
  86. // !moddel name
  87. void
  88. scriptcmd_moddel (NetServer *s)
  89. {
  90. strsplit (CMD[3], BUF, 1);
  91. if (BUF[1][0] == 0)
  92. {
  93. SEND_TEXT (DEST, "%s", HELP_MODDEL);
  94. return;
  95. }
  96. if (bot->del_module (BUF[1]))
  97. SEND_TEXT (DEST, "Module unloaded.");
  98. else
  99. SEND_TEXT (DEST, "Failed to unload module.");
  100. }
  101. // !quit [reason]
  102. void
  103. scriptcmd_quit (NetServer *s)
  104. {
  105. strsplit (CMD[3], BUF, 1);
  106. for (int i = 0; i < bot->server_num; i++)
  107. if (BUF[1][0] == 0)
  108. bot->servers[i]->irc_quit (NULL);
  109. else
  110. bot->servers[i]->irc_quit (BUF[1]);
  111. mbot_exit ();
  112. }
  113. // !server next | <hostname [<port> [<password>]]>
  114. void
  115. scriptcmd_server (NetServer *s)
  116. {
  117. strsplit (CMD[3], BUF, 3);
  118. if (BUF[1][0] == 0)
  119. {
  120. SEND_TEXT (DEST, "%s", HELP_SERVER);
  121. return;
  122. }
  123. if (strcasecmp (BUF[1], "next") != 0) // a hostname was specified
  124. {
  125. s->host_current = s->host_add (s->hosts, BUF[1],
  126. BUF[2][0] == 0 ? 6667 : atoi (BUF[2]),
  127. BUF[3][0] == 0 ? NULL : BUF[3]);
  128. }
  129. s->script.server_jumped = true;
  130. s->irc_quit ("switching servers");
  131. }
  132. // !set option [value]
  133. void
  134. scriptcmd_set (NetServer *s)
  135. {
  136. strsplit (CMD[3], BUF, 2);
  137. if (BUF[1][0] == 0)
  138. {
  139. SEND_TEXT (DEST, "%s", HELP_SET);
  140. return;
  141. }
  142. if (BUF[2][0] != 0)
  143. {
  144. if (s->vars.var_set (BUF[1], BUF[2]))
  145. {
  146. s->vars.var_get (BUF[1], BUF[2], MSG_SIZE);
  147. SEND_TEXT (DEST, "Value of \002%s\002 changed to \"%s\".", BUF[1], BUF[2]);
  148. return;
  149. }
  150. }
  151. else if (s->vars.var_get (BUF[1], BUF[2], MSG_SIZE))
  152. {
  153. SEND_TEXT (DEST, "Value of \002%s\002 is \"%s\".", BUF[1], BUF[2]);
  154. return;
  155. }
  156. SEND_TEXT (DEST, "Inexistant variable \002%s\002.", BUF[1]);
  157. }
  158. // !loadconf
  159. void
  160. scriptcmd_loadconf (NetServer *s)
  161. {
  162. strsplit (CMD[3], BUF, 2);
  163. if (BUF[1][0] != 0)
  164. {
  165. bot->conf_file = BUF[1];
  166. SEND_TEXT (DEST, "Configuration file set to \"%s\".", (c_char)bot->conf_file);
  167. }
  168. bot->conf.delete_lines ();
  169. if (bot->conf.read_file (bot->conf_file))
  170. SEND_TEXT (DEST, "Configuration loaded.");
  171. else
  172. SEND_TEXT (DEST, "Couldn't load configuration!");
  173. }
  174. // !away [msg]
  175. void
  176. scriptcmd_away (NetServer *s)
  177. {
  178. strsplit (CMD[3], BUF, 1);
  179. s->away = BUF[1];
  180. s->irc_away (s->away);
  181. }
  182. // !nick nick
  183. void
  184. scriptcmd_nick (NetServer *s)
  185. {
  186. strsplit (CMD[3], BUF, 2);
  187. if (BUF[1][0] == 0)
  188. SEND_TEXT(DEST, "%s", HELP_NICK);
  189. else
  190. s->irc_nick (BUF[1]);
  191. }
  192. // !unbind !command
  193. void
  194. scriptcmd_unbind (NetServer *s)
  195. {
  196. strsplit (CMD[3], BUF, 2);
  197. if (BUF[1][0] == 0)
  198. {
  199. SEND_TEXT (DEST, "%s", HELP_UNBIND);
  200. return;
  201. }
  202. if (s->script.cmd_unbind (BUF[1]))
  203. SEND_TEXT (DEST, "Command unbinded.");
  204. else
  205. SEND_TEXT (DEST, "Command \002%s\002 does not exist.", BUF[1]);
  206. }
  207. // !cmdlevel !command level
  208. void
  209. scriptcmd_cmdlevel (NetServer *s)
  210. {
  211. strsplit (CMD[3], BUF, 3);
  212. if (BUF[2][0] == 0)
  213. {
  214. SEND_TEXT (DEST, "%s", HELP_CMDLEVEL);
  215. return;
  216. }
  217. Script::cmd_type *c = s->script.cmd_get (BUF[1]);
  218. if (c == NULL)
  219. {
  220. SEND_TEXT (DEST, "Command \002%s\002 does not exist.", BUF[1]);
  221. return;
  222. }
  223. int level = atoi (BUF[2]);
  224. if (level > LEVEL_MAX)
  225. c->level = LEVEL_MAX;
  226. else if (level < 0)
  227. c->level = 0;
  228. else
  229. c->level = level;
  230. SEND_TEXT (DEST, "Command \002%s\002's level set to \002%d\002.", BUF[1], c->level);
  231. }
  232. // !join #channel [key]
  233. void
  234. scriptcmd_join (NetServer *s)
  235. {
  236. strsplit (CMD[3], BUF, 3);
  237. if (BUF[1][0] == 0)
  238. {
  239. SEND_TEXT (DEST, "%s", HELP_JOIN);
  240. return;
  241. }
  242. int chan_num = CHANNEL_INDEX (BUF[1]);
  243. if (chan_num != -1) // if not already in the channel
  244. {
  245. SEND_TEXT (DEST, "I'm already on \002%s\002.", BUF[1]);
  246. return;
  247. }
  248. if (!s->channel_add (BUF[1], BUF[2]))
  249. {
  250. SEND_TEXT (DEST, "Maximum channels reached.");
  251. return;
  252. }
  253. chan_num = CHANNEL_INDEX (BUF[1]); // search it's position again
  254. CHANNELS[chan_num]->irc_join (); // join it
  255. }
  256. // !part #channel
  257. void
  258. scriptcmd_part (NetServer *s)
  259. {
  260. strsplit (CMD[3], BUF, 2);
  261. if (BUF[1][0] == 0)
  262. {
  263. SEND_TEXT (DEST, "%s", HELP_PART);
  264. return;
  265. }
  266. int i = CHANNEL_INDEX (BUF[1]);
  267. if (i != -1)
  268. {
  269. CHANNELS[i]->irc_part ();
  270. s->channel_del (BUF[1]);
  271. }
  272. else
  273. SEND_TEXT (DEST, "I'm not on \002%s\002.", BUF[1]);
  274. }
  275. // !status
  276. void
  277. scriptcmd_status (NetServer *s)
  278. {
  279. SEND_TEXT (DEST,
  280. "Status: %s - %s:%d - %s!%s (%s) - %d users, %d/%d channels, %d bytes read, %d written. Up since %s, running on %s (%d bits)",
  281. VERSION_STRING, (c_char)s->host_current->host,
  282. s->host_current->port, (c_char)s->nick, (c_char)s->user,
  283. (c_char)s->name, USERS.count (), s->channel_num, CHANNEL_MAX,
  284. s->bytesin, s->bytesout,
  285. get_asctime (s->uptime, BUF[2], MSG_SIZE),
  286. HOST, 8*sizeof (int *));
  287. }
  288. // !topic [#channel] text
  289. void
  290. scriptcmd_topic (NetServer *s)
  291. {
  292. strsplit (CMD[3], BUF, 1);
  293. if (BUF[1][0] == 0)
  294. {
  295. SEND_TEXT (DEST, "%s", HELP_TOPIC);
  296. return;
  297. }
  298. int i;
  299. if (BUF[1][0] != '#')
  300. {
  301. i = CHANNEL_INDEX (CMD[2]);
  302. if (i != -1)
  303. CHANNELS[i]->irc_topic (BUF[1]);
  304. else
  305. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  306. }
  307. else
  308. {
  309. strsplit (CMD[3], BUF, 2);
  310. i = CHANNEL_INDEX (BUF[1]);
  311. if (i != -1)
  312. CHANNELS[i]->irc_topic (BUF[2]);
  313. else
  314. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  315. }
  316. }
  317. // !opme
  318. void
  319. scriptcmd_opme (NetServer *s)
  320. {
  321. if (CMD[2][0] != '#')
  322. {
  323. SEND_TEXT (DEST, "This command only works inside channels.");
  324. return;
  325. }
  326. mask2nick (CMD[0], BUF[0]);
  327. int i = CHANNEL_INDEX (CMD[2]);
  328. if (i != -1)
  329. CHANNELS[i]->irc_op (BUF[0]);
  330. else
  331. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  332. }
  333. // !op nick [#channel]
  334. void
  335. scriptcmd_op (NetServer *s)
  336. {
  337. strsplit (CMD[3], BUF, 3);
  338. if (BUF[1][0] == 0)
  339. {
  340. SEND_TEXT (DEST, "%s", HELP_OP);
  341. return;
  342. }
  343. if (BUF[2][0] != '#')
  344. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  345. int i = CHANNEL_INDEX (BUF[2]);
  346. if (i != -1)
  347. CHANNELS[i]->irc_op (BUF[1]);
  348. else
  349. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  350. }
  351. // !deop nick [#channel]
  352. void
  353. scriptcmd_deop (NetServer *s)
  354. {
  355. strsplit (CMD[3], BUF, 3);
  356. if (BUF[1][0] == 0)
  357. {
  358. SEND_TEXT (DEST, "%s", HELP_DEOP);
  359. return;
  360. }
  361. if (BUF[2][0] != '#')
  362. strncpy (BUF[2], CMD[2], MSG_SIZE);
  363. if (strcasecmp (BUF[1], s->nick) != 0)
  364. {
  365. int i = CHANNEL_INDEX (BUF[2]);
  366. if (i != -1)
  367. CHANNELS[i]->irc_deop (BUF[1]);
  368. else
  369. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  370. }
  371. else
  372. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  373. }
  374. // !kick nick [#channel] [reason]
  375. void
  376. scriptcmd_kick (NetServer *s)
  377. {
  378. strsplit (CMD[3], BUF, 2);
  379. if (BUF[1][0] == 0)
  380. {
  381. SEND_TEXT (DEST, "%s", HELP_KICK);
  382. return;
  383. }
  384. if (strcasecmp (BUF[1], s->nick) == 0) // doesn't kick the bot
  385. {
  386. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  387. return;
  388. }
  389. int i;
  390. if (BUF[2][0] != '#')
  391. {
  392. i = CHANNEL_INDEX(CMD[2]);
  393. if (i != -1)
  394. CHANNELS[i]->irc_kick (BUF[1], BUF[2]);
  395. else
  396. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  397. }
  398. else
  399. {
  400. strsplit (CMD[3], BUF, 3);
  401. i = CHANNEL_INDEX (BUF[2]);
  402. if (i != -1)
  403. CHANNELS[i]->irc_kick (BUF[1], BUF[3]);
  404. else
  405. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  406. }
  407. }
  408. // !ban nick | mask [#channel]
  409. void
  410. scriptcmd_ban (NetServer *s)
  411. {
  412. strsplit (CMD[3], BUF, 3);
  413. if (BUF[1][0] == 0)
  414. {
  415. SEND_TEXT(DEST, "%s", HELP_BAN);
  416. return;
  417. }
  418. if (BUF[2][0] != '#')
  419. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  420. int i;
  421. if (strchr (BUF[1], '@') != NULL) // check if it's a mask
  422. {
  423. i = CHANNEL_INDEX (BUF[2]);
  424. if (i != -1)
  425. CHANNELS[i]->irc_ban_mask (BUF[1]);
  426. else
  427. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  428. return;
  429. }
  430. if (strcasecmp (BUF[1], s->nick) != 0) // doesn't ban the bot
  431. {
  432. i = CHANNEL_INDEX (BUF[2]);
  433. if (i != -1)
  434. CHANNELS[i]->irc_ban_nick (BUF[1]);
  435. else
  436. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  437. }
  438. else
  439. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  440. }
  441. // !unban nick | mask [#channel]
  442. void
  443. scriptcmd_unban (NetServer *s)
  444. {
  445. strsplit (CMD[3], BUF, 3);
  446. if (BUF[1][0] == 0)
  447. {
  448. SEND_TEXT (DEST, "%s", HELP_UNBAN);
  449. return;
  450. }
  451. if (BUF[2][0] != '#')
  452. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  453. int i;
  454. if (strchr (BUF[1], '@') != NULL) // check if it's a mask
  455. {
  456. i = CHANNEL_INDEX (BUF[2]);
  457. if (i != -1)
  458. CHANNELS[i]->irc_unban_mask (BUF[1]);
  459. else
  460. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  461. return;
  462. }
  463. i = CHANNEL_INDEX (BUF[2]);
  464. if (i != -1)
  465. CHANNELS[i]->irc_unban_nick (BUF[1]);
  466. else
  467. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  468. }
  469. // !bk nick [#channel] [reason]
  470. void
  471. scriptcmd_bk (NetServer *s)
  472. {
  473. strsplit (CMD[3], BUF, 2);
  474. if (BUF[1][0] == 0)
  475. {
  476. SEND_TEXT(DEST, "%s", HELP_BK);
  477. return;
  478. }
  479. if (strcasecmp (BUF[1], s->nick) == 0) // doesn't bk the bot
  480. {
  481. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  482. return;
  483. }
  484. if (BUF[2][0] != '#') // if the channel was not specified
  485. {
  486. my_strncpy (BUF[3], BUF[2], MSG_SIZE); // reason
  487. my_strncpy (BUF[2], CMD[2], MSG_SIZE); // channel
  488. }
  489. else
  490. strsplit (CMD[3], BUF, 3);
  491. int i = CHANNEL_INDEX (BUF[2]);
  492. if (i == -1) // if the channel exists
  493. {
  494. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  495. return;
  496. }
  497. int i2 = CHANNELS[i]->user_index (BUF[1]);
  498. if (i2 != -1) // and the user too
  499. {
  500. // make mask
  501. make_generic_mask (CHANNELS[i]->users[i2]->mask, BUF[4]);
  502. // deop/ban
  503. CHANNELS[i]->irc_deopban (BUF[1], BUF[4]);
  504. // kick
  505. CHANNELS[i]->irc_kick (BUF[1], BUF[3][0] == 0 ? NULL : BUF[3]);
  506. }
  507. else
  508. SEND_TEXT (DEST, "Nick %s is not inside %s.", BUF[1], BUF[2]);
  509. }
  510. // !invite nick [#channel]
  511. void
  512. scriptcmd_invite (NetServer *s)
  513. {
  514. strsplit (CMD[3], BUF, 3);
  515. if (BUF[1][0] == 0)
  516. {
  517. SEND_TEXT (DEST, "%s", HELP_INVITE);
  518. return;
  519. }
  520. if (BUF[2][0] != '#')
  521. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  522. int i = CHANNEL_INDEX (BUF[2]);
  523. if (i != -1)
  524. CHANNELS[i]->irc_invite (BUF[1]);
  525. else
  526. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  527. }
  528. // !voice nick [#channel]
  529. void
  530. scriptcmd_voice (NetServer *s)
  531. {
  532. strsplit (CMD[3], BUF, 3);
  533. if (BUF[1][0] == 0)
  534. {
  535. SEND_TEXT (DEST, "%s", HELP_VOICE);
  536. return;
  537. }
  538. if (BUF[2][0] != '#')
  539. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  540. int i = CHANNEL_INDEX (BUF[2]);
  541. if (i != -1)
  542. CHANNELS[i]->irc_voice (BUF[1]);
  543. else
  544. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  545. }
  546. // !devoice nick [#channel]
  547. void
  548. scriptcmd_devoice (NetServer *s)
  549. {
  550. strsplit (CMD[3], BUF, 3);
  551. if (BUF[1][0] == 0)
  552. {
  553. SEND_TEXT(DEST, "%s", HELP_DEVOICE);
  554. return;
  555. }
  556. if (BUF[2][0] != '#')
  557. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  558. if (strcasecmp (BUF[1], s->nick) != 0)
  559. {
  560. int i = CHANNEL_INDEX (BUF[2]);
  561. if (i != -1)
  562. CHANNELS[i]->irc_devoice (BUF[1]);
  563. else
  564. SEND_TEXT (DEST, "%s", SCRIPT_INVALID_CHAN);
  565. }
  566. else
  567. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  568. }
  569. // !say [#channel | $nick] text
  570. void
  571. scriptcmd_say (NetServer *s)
  572. {
  573. strsplit (CMD[3], BUF, 1);
  574. if (BUF[1][0] == 0)
  575. {
  576. SEND_TEXT (DEST, "%s", HELP_SAY);
  577. return;
  578. }
  579. if (BUF[1][0] == '#')
  580. {
  581. int i = 0;
  582. while (BUF[1][i] != ' ' && BUF[1][i] != 0)
  583. i++;
  584. my_strncpy (DEST, BUF[1], i);
  585. my_strncpy (BUF[2], BUF[1] + i + num_spaces (BUF[1]+i), MSG_SIZE);
  586. my_strncpy (BUF[1], BUF[2], MSG_SIZE);
  587. }
  588. else if (BUF[1][0] == '$')
  589. {
  590. int i = 0;
  591. while (BUF[1][i] != ' ' && BUF[1][i] != 0)
  592. i++;
  593. my_strncpy (DEST, BUF[1], i);
  594. my_strncpy (DEST, DEST+1, CHANNEL_SIZE);
  595. if (strcasecmp (NICKSERV, DEST) == 0
  596. || strcasecmp (CHANSERV, DEST) == 0
  597. || strcasecmp (MEMOSERV, DEST) == 0
  598. || strcasecmp (OPERSERV, DEST) == 0)
  599. {
  600. SEND_TEXT (SOURCE, "Cannot send to IRC Services.");
  601. return;
  602. }
  603. my_strncpy (BUF[2], BUF[1] + i + num_spaces (BUF[1] + i), MSG_SIZE);
  604. my_strncpy (BUF[1], BUF[2], MSG_SIZE);
  605. }
  606. SEND_TEXT (DEST, "%s", BUF[1]);
  607. }
  608. // !help
  609. void
  610. scriptcmd_help (NetServer *s)
  611. {
  612. int level = USERS.match_mask_level (CMD[0]);
  613. Script::cmd_type *c;
  614. strsplit (CMD[3], BUF, 1);
  615. if (BUF[1][0] != 0) // a command was specified
  616. {
  617. c = s->script.cmd_get (BUF[1]);
  618. if (c == NULL || c->level > level)
  619. {
  620. SEND_TEXT (SOURCE, "Unknown command \002%s\002. Try \002!help\002 for a list of available commands.", BUF[1]);
  621. return;
  622. }
  623. if (c->help == NULL)
  624. {
  625. SEND_TEXT (SOURCE, "No help available for \002%s\002.", BUF[1]);
  626. return;
  627. }
  628. SEND_TEXT (SOURCE, "%s", c->help);
  629. return;
  630. }
  631. bool has_help;
  632. SEND_TEXT (SOURCE, "Commands (do \002!help command\002 to see help on it):");
  633. for (int i = level; i >= 0; i--)
  634. {
  635. snprintf (BUF[1], MSG_SIZE, "\002Level %d\002:", i);
  636. has_help = 0;
  637. s->script.cmds.rewind ();
  638. while ((c = (Script::cmd_type *)s->script.cmds.next ()) != NULL)
  639. if (c->level == i && (c_char)c->help != NULL)
  640. {
  641. has_help = 1;
  642. snprintf (BUF[1] + strlen (BUF[1]), MSG_SIZE, " %s", (c_char)c->name);
  643. }
  644. if (has_help)
  645. SEND_TEXT (SOURCE, "%s", BUF[1]);
  646. }
  647. }
  648. // !dcckill dcc_index
  649. void
  650. scriptcmd_dcckill (NetServer *s)
  651. {
  652. strsplit (CMD[3], BUF, 1);
  653. if (BUF[1][0] == 0)
  654. {
  655. SEND_TEXT (DEST, "%s", HELP_DCCKILL);
  656. return;
  657. }
  658. int dcc_index = atoi (BUF[1]);
  659. if (dcc_index < 0 || dcc_index > DCC_NUM - 1)
  660. {
  661. SEND_TEXT (DEST, "Invalid DCC index.");
  662. return;
  663. }
  664. if (DCCS[dcc_index]->status == 5)
  665. s->script.send_partyline ("%s killed %s.", SOURCE, DCCS[dcc_index]->nick);
  666. DCCS[dcc_index]->dcc_stop ();
  667. }
  668. // !dcclist
  669. void
  670. scriptcmd_dcclist (NetServer *s)
  671. {
  672. if (DCC_NUM == 0)
  673. {
  674. SEND_TEXT (DEST, "No DCCs running.");
  675. return;
  676. }
  677. for (int i = 0; i < DCC_NUM; i++)
  678. {
  679. switch (DCCS[i]->status)
  680. {
  681. case DCC_STOP:
  682. my_strncpy (BUF[1], "closing", MSG_SIZE);
  683. break;
  684. case DCC_SEND_INIT:
  685. my_strncpy (BUF[1], "Send (not connected)", MSG_SIZE);
  686. break;
  687. case DCC_SEND:
  688. my_strncpy (BUF[1], "Send", MSG_SIZE);
  689. break;
  690. case DCC_CHAT_INIT:
  691. my_strncpy (BUF[1], "Chat (not connected)", MSG_SIZE);
  692. break;
  693. case DCC_CHAT_AUTH:
  694. my_strncpy (BUF[1], "Chat (authenticating)", MSG_SIZE);
  695. break;
  696. case DCC_CHAT:
  697. my_strncpy (BUF[1], "Chat", MSG_SIZE);
  698. break;
  699. default:
  700. my_strncpy (BUF[1], "unknown", MSG_SIZE);
  701. }
  702. SEND_TEXT (DEST, "%d: DCC %s with %s", i, BUF[1], (c_char)DCCS[i]->mask);
  703. }
  704. }
  705. // !chat
  706. void
  707. scriptcmd_chat (NetServer *s)
  708. {
  709. if (USERS.match_mask_level (CMD[0]) < 1)
  710. {
  711. SEND_TEXT (SOURCE, "Sorry, you don't have access.");
  712. return;
  713. }
  714. for (int i = 0; i < DCC_NUM; i++)
  715. if (strcasecmp (DCCS[i]->nick, SOURCE) == 0
  716. && DCCS[i]->status >= 3 && DCCS[i]->status <= 5)
  717. {
  718. SEND_TEXT (SOURCE, "Another DCC Chat is in progress for you.");
  719. return;
  720. }
  721. if (DCC_NUM == DCC_MAX)
  722. {
  723. SEND_TEXT (SOURCE, "No free DCC slots available, please try later.");
  724. return;
  725. }
  726. int dcc_index = ((CMD[2][0] >= '0' && CMD[2][0] <= '9') ? atoi (CMD[2]) : -1);
  727. DCCS[DCC_NUM] = new NetDCC (s, CMD[0], DCC_NUM, dcc_index);
  728. // if it gives error, work()'ll delete it
  729. if (DCCS[DCC_NUM]->dcc_chat_start ())
  730. SEND_TEXT (SOURCE, DCCS[DCC_NUM]->dcc_make_ctcp_chat (BUF[3], MSG_SIZE));
  731. DCC_NUM++;
  732. }
  733. // !get [file]
  734. void
  735. scriptcmd_get (NetServer *s)
  736. {
  737. ifstream f ((c_char)s->dcc_file, ios::in | IOS_NOCREATE);
  738. if (!f)
  739. {
  740. SEND_TEXT (SOURCE, "Error opening configuration file \002%s\002: %s", (c_char)s->dcc_file, strerror (errno));
  741. s->write_botlog ("error opening configuration file %s: %s", (c_char)s->dcc_file, strerror (errno));
  742. return;
  743. }
  744. strsplit (CMD[3], BUF, 1);
  745. if (BUF[1][0] == 0) // if none specified, show help
  746. {
  747. while (f.getline (BUF[0], MSG_SIZE))
  748. if (BUF[0][0] == ':') // if it's help
  749. SEND_TEXT (SOURCE, "%s", BUF[0]+1); // +1 to remove the ':'
  750. return;
  751. }
  752. for (int i = 0; i < DCC_NUM; i++)
  753. if (strcasecmp (DCCS[i]->nick, SOURCE) == 0 &&
  754. (DCCS[i]->status == 1 || DCCS[i]->status == 2))
  755. {
  756. SEND_TEXT (SOURCE, "Another DCC Send is in progress for you.");
  757. return;
  758. }
  759. if (DCC_NUM == DCC_MAX)
  760. {
  761. SEND_TEXT (SOURCE, "No free DCC slots available, please try later.");
  762. return;
  763. }
  764. String file (BUF[1], PATH_MAX); // because BUF will be destroyed
  765. while (f.getline (BUF[7], MSG_SIZE))
  766. {
  767. if (BUF[7][0] == ':' || BUF[7][0] == '#') // ignore comments
  768. continue;
  769. strip_crlf (BUF[7]);
  770. strsplit (BUF[7], BUF, 2);
  771. if (strcasecmp (BUF[0], file) != 0) // it's not this one
  772. continue;
  773. int dcc_index = ((CMD[2][0] >= '0' && CMD[2][0] <= '9') ? atoi (CMD[2]) : -1);
  774. // create the dcc
  775. DCCS[DCC_NUM] = new NetDCC (s, CMD[0], DCC_NUM, dcc_index);
  776. // if it gave error, work()'ll delete it
  777. if (DCCS[DCC_NUM]->dcc_send_start (BUF[1]))
  778. SEND_TEXT (SOURCE, "%s", DCCS[DCC_NUM]->dcc_make_ctcp_send (BUF[1], MSG_SIZE));
  779. DCC_NUM++;
  780. return;
  781. }
  782. SEND_TEXT (SOURCE, "Unknown file \002%s\002.", (c_char)file);
  783. }
  784. // look for ctcp dcc chat on privmsg
  785. void
  786. scriptcmd_dcc_event (NetServer *s)
  787. {
  788. if (CMD[3][0] == '' && strcmp(CMD[1], "PRIVMSG") == 0)
  789. {
  790. mask2nick (CMD[0], DEST);
  791. if (strncmp (CMD[3], "DCC CHAT", 9) == 0)
  792. {
  793. s->irc_notice (DEST, "DCC REJECT CHAT chat");
  794. SEND_TEXT (DEST, "Please use the \002!chat\002 command to start a DCC Chat.");
  795. }
  796. }
  797. }
  798. // !randkick's reason, change at will
  799. #define RANDKICK_REASON "9 out of 10 people really hate this kick. how about you?"
  800. // !randkick
  801. void
  802. scriptcmd_randkick (NetServer *s)
  803. {
  804. if (strcasecmp (CMD[2], s->nick) == 0)
  805. {
  806. SEND_TEXT(DEST, "\002!randkick\002 can only be used inside channels.");
  807. return;
  808. }
  809. int i = CHANNEL_INDEX (CMD[2]);
  810. if (i == -1)
  811. return;
  812. struct Channel::user_type *list[C_USERS_MAX];
  813. int user_num, list_num = 0;
  814. // build non-ops list
  815. for (user_num = 0; user_num < CHANNELS[i]->user_num; user_num++)
  816. if ( ! (CHANNELS[i]->users[user_num]->is_op) )
  817. list[list_num++] = CHANNELS[i]->users[user_num];
  818. // if there's at least one
  819. if (list_num != 0)
  820. {
  821. int rand_user = random_num (list_num);
  822. CHANNELS[i]->irc_kick (list[rand_user]->nick, RANDKICK_REASON);
  823. }
  824. else
  825. SEND_TEXT (DEST, "There's no one to kick.");
  826. }
  827. // !time
  828. void
  829. scriptcmd_time (NetServer *s)
  830. {
  831. SEND_TEXT (DEST, "%s", get_asctime (s->time_now, s->script.BUF[0], MSG_SIZE));
  832. }
  833. // !rose nick
  834. void
  835. scriptcmd_rose (NetServer *s)
  836. {
  837. strsplit (CMD[3], BUF, 1);
  838. if (BUF[1][0] == 0)
  839. SEND_TEXT (DEST, "%s", HELP_ROSE);
  840. else
  841. SEND_TEXT (DEST, "ACTION \002%s\002 offers this 7@3}-,-'-- to the beautiful \002%s\002 :)",
  842. SOURCE, BUF[1]);
  843. }
  844. // !reverse text
  845. void
  846. scriptcmd_reverse (NetServer *s)
  847. {
  848. strsplit (CMD[3], BUF, 1);
  849. if (BUF[1][0] == 0)
  850. {
  851. SEND_TEXT (DEST, "%s", HELP_REVERSE);
  852. return;
  853. }
  854. char c;
  855. size_t len = strlen (BUF[1]);
  856. for (size_t i = 0; i < len/2; i++)
  857. {
  858. c = BUF[1][i];
  859. BUF[1][i] = BUF[1][len-i-1];
  860. BUF[1][len-i-1] = c;
  861. }
  862. SEND_TEXT (DEST, "%s", BUF[1]);
  863. }
  864. // !cop nick [#channel]
  865. void
  866. scriptcmd_cop (NetServer *s)
  867. {
  868. strsplit (CMD[3], BUF, 3);
  869. if (BUF[1][0] == 0)
  870. {
  871. SEND_TEXT (DEST, "%s", HELP_COP);
  872. return;
  873. }
  874. if (BUF[2][0] == 0)
  875. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  876. s->services.chan_op (BUF[2], BUF[1]);
  877. }
  878. // !cdeop nick [#channel]
  879. void
  880. scriptcmd_cdeop (NetServer *s)
  881. {
  882. strsplit (CMD[3], BUF, 3);
  883. if (BUF[1][0] == 0)
  884. {
  885. SEND_TEXT (DEST, "%s", HELP_CDEOP);
  886. return;
  887. }
  888. if (BUF[2][0] == 0)
  889. my_strncpy (BUF[2], CMD[2], MSG_SIZE);
  890. if (strcasecmp (BUF[1], s->nick) != 0)
  891. s->services.chan_deop (BUF[2], BUF[1]);
  892. else
  893. SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  894. }
  895. // !useradd mask level [msg]
  896. void
  897. scriptcmd_useradd (NetServer *s)
  898. {
  899. strsplit (CMD[3], BUF, 3);
  900. if (BUF[2][0] == 0)
  901. {
  902. SEND_TEXT (DEST, "%s", HELP_USERADD);
  903. return;
  904. }
  905. if (USERS.abs_mask2user (BUF[1]) != NULL)
  906. {
  907. SEND_TEXT (DEST, "A user with mask \002%s\002 already exists.", BUF[1]);
  908. return;
  909. }
  910. if (USERS.match_mask_level (CMD[0]) > USERS.match_mask_reallevel (BUF[1]) &&
  911. USERS.match_mask_level (CMD[0]) > atoi (BUF[2]))
  912. {
  913. if (USERS.add_user (BUF[1], NULL, atoi (BUF[2]), BUF[3]))
  914. SEND_TEXT (DEST, "User added.");
  915. else
  916. SEND_TEXT (DEST, "Error adding user.");
  917. }
  918. else
  919. SEND_TEXT (DEST, "Not enough access level.");
  920. }
  921. // !userdel mask
  922. void
  923. scriptcmd_userdel (NetServer *s)
  924. {
  925. strsplit (CMD[3], BUF, 2);
  926. if (BUF[1][0] == 0)
  927. {
  928. SEND_TEXT (DEST, "%s", HELP_USERDEL);
  929. return;
  930. }
  931. struct ListUsers::user_type *u = USERS.abs_mask2user (BUF[1]);
  932. if (u == NULL)
  933. {
  934. SEND_TEXT (DEST, "User does not exist.");
  935. return;
  936. }
  937. if (USERS.match_mask_level (CMD[0]) > u->level)
  938. {
  939. if (USERS.del_user (BUF[1]))
  940. SEND_TEXT (DEST, "User deleted.");
  941. else
  942. SEND_TEXT (DEST, "Error deleting user.");
  943. }
  944. else
  945. SEND_TEXT (DEST, "Not enough access level.");
  946. }
  947. // !userpass mask pass
  948. void
  949. scriptcmd_userpass (NetServer *s)
  950. {
  951. strsplit (CMD[3], BUF, 3);
  952. if (BUF[2][0] == 0)
  953. {
  954. SEND_TEXT (DEST, "%s", HELP_USERPASS);
  955. return;
  956. }
  957. struct ListUsers::user_type *u = USERS.abs_mask2user (BUF[1]);
  958. if (u == NULL)
  959. {
  960. SEND_TEXT (DEST, "User does not exist.");
  961. return;
  962. }
  963. if (USERS.match_mask_level (CMD[0]) > u->level )
  964. {
  965. USERS.abs_set_pass (BUF[1], BUF[2]);
  966. SEND_TEXT (DEST, "Password of \002%s\002 set to \002%s\002.", BUF[1], BUF[2]);
  967. }
  968. else
  969. SEND_TEXT (DEST, "Not enough access level.");
  970. }
  971. // !usermsg mask msg|<none>
  972. void
  973. scriptcmd_usermsg (NetServer *s)
  974. {
  975. strsplit (CMD[3], BUF, 2);
  976. if (BUF[2][0] == 0)
  977. {
  978. SEND_TEXT (DEST, "%s", HELP_USERMSG);
  979. return;
  980. }
  981. struct ListUsers::user_type *u = USERS.abs_mask2user (BUF[1]);
  982. if (u == NULL)
  983. {
  984. SEND_TEXT (DEST, "User does not exist.");
  985. return;
  986. }
  987. if (USERS.match_mask_level (CMD[0]) > u->level)
  988. {
  989. if (strcasecmp (BUF[2], "<none>") == 0)
  990. {
  991. USERS.abs_set_msg (BUF[1], "");
  992. SEND_TEXT (DEST, "Message \002disabled\002.");
  993. }
  994. else
  995. {
  996. USERS.abs_set_msg (BUF[1], BUF[2]);
  997. SEND_TEXT (DEST, "Message of \002%s\002 set to \002%s\002.", BUF[1], BUF[2]);
  998. }
  999. }
  1000. else
  1001. SEND_TEXT (DEST, "Not enough access level.");
  1002. }
  1003. // !usermask mask newmask
  1004. void
  1005. scriptcmd_usermask (NetServer *s)
  1006. {
  1007. strsplit (CMD[3], BUF, 3);
  1008. if (BUF[2][0] == 0)
  1009. {
  1010. SEND_TEXT (DEST, "%s", HELP_USERMASK);
  1011. return;
  1012. }
  1013. struct ListUsers::user_type *u = USERS.abs_mask2user (BUF[1]);
  1014. if (u == NULL)
  1015. {
  1016. SEND_TEXT (DEST, "User does not exist.");
  1017. return;
  1018. }
  1019. if (USERS.match_mask_level (CMD[0]) > u->level)
  1020. {
  1021. USERS.abs_set_mask (BUF[1], BUF[2]);
  1022. SEND_TEXT (DEST, "Mask \002%s\002 changed to \002%s\002.", BUF[1], BUF[2]);
  1023. }
  1024. else
  1025. SEND_TEXT (DEST, "Not enough access level.");
  1026. }
  1027. // !userlevel mask level
  1028. void
  1029. scriptcmd_userlevel (NetServer *s)
  1030. {
  1031. strsplit (CMD[3], BUF, 3);
  1032. if (BUF[2][0] == 0)
  1033. {
  1034. SEND_TEXT (DEST, "%s", HELP_USERLEVEL);
  1035. return;
  1036. }
  1037. struct ListUsers::user_type *u = USERS.abs_mask2user (BUF[1]);
  1038. if (u == NULL)
  1039. {
  1040. SEND_TEXT (DEST, "User does not exist.");
  1041. return;
  1042. }
  1043. if (atoi (BUF[2]) >= LEVEL_MIN && atoi (BUF[2]) <= LEVEL_MAX)
  1044. {
  1045. if (USERS.match_mask_level (CMD[0]) > u->level
  1046. && USERS.match_mask_level (CMD[0]) > atoi (BUF[2]))
  1047. {
  1048. USERS.abs_set_level (BUF[1], atoi (BUF[2]));
  1049. SEND_TEXT (DEST, "Level of \002%s\002 set to \002%s\002.", BUF[1], BUF[2]);
  1050. }
  1051. else
  1052. SEND_TEXT (DEST, "Not enough access level.");
  1053. }
  1054. else
  1055. SEND_TEXT (DEST, "Invalid level.");
  1056. }
  1057. // !id
  1058. void
  1059. scriptcmd_id (NetServer *s)
  1060. {
  1061. StringFixed str (MSG_SIZE);
  1062. struct ListUsers::user_type *u;
  1063. USERS.rewind ();
  1064. while ((u = (struct ListUsers::user_type *)USERS.next ()) != NULL)
  1065. {
  1066. str += " ";
  1067. str += u->cur_mask;
  1068. }
  1069. SEND_TEXT (DEST, "Identified users:%s", (c_char)str);
  1070. }
  1071. // !userlist
  1072. void
  1073. scriptcmd_userlist (NetServer *s)
  1074. {
  1075. bool has_user;
  1076. struct ListUsers::user_type *u;
  1077. SEND_TEXT (SOURCE, "Users:");
  1078. for (int i = LEVEL_MAX; i >= LEVEL_MIN; i--)
  1079. {
  1080. has_user = 0;
  1081. snprintf (BUF[1], MSG_SIZE, "\002Level %d\002:", i);
  1082. USERS.rewind ();
  1083. while ((u = (struct ListUsers::user_type *)USERS.next ()) != NULL)
  1084. if (u->level == i)
  1085. if (strlen (BUF[1]) + u->mask.getlen () > MSG_SIZE)
  1086. {
  1087. SEND_TEXT (SOURCE, "%s", BUF[1]);
  1088. my_strncpy (BUF[1], u->mask, MSG_SIZE);
  1089. }
  1090. else
  1091. {
  1092. snprintf (BUF[1] + strlen (BUF[1]), MSG_SIZE - strlen (BUF[1]),
  1093. " %s", (c_char)u->mask);
  1094. has_user = 1;
  1095. }
  1096. if (has_user)
  1097. SEND_TEXT (SOURCE, "%s", BUF[1]);
  1098. }
  1099. }
  1100. // !setpass password
  1101. void
  1102. scriptcmd_setpass (NetServer *s)
  1103. {
  1104. if (DEST[0] == '#')
  1105. {
  1106. SEND_TEXT (DEST, "Do \002not\002 use this command on a channel.");
  1107. return;
  1108. }
  1109. strsplit (CMD[3], BUF, 2);
  1110. if (BUF[1][0] == 0)
  1111. SEND_TEXT (DEST, "%s", HELP_SETPASS);
  1112. else
  1113. {
  1114. USERS.match_set_pass (CMD[0], BUF[1]);
  1115. SEND_TEXT (DEST, "Password set to \002%s\002 - remember it for later use.", BUF[1]);
  1116. }
  1117. }
  1118. // !setmsg msg | <none>
  1119. void
  1120. scriptcmd_setmsg (NetServer *s)
  1121. {
  1122. strsplit (CMD[3], BUF, 1);
  1123. if (BUF[1][0] == 0)
  1124. {
  1125. SEND_TEXT (DEST, "%s", HELP_SETMSG);
  1126. return;
  1127. }
  1128. if (strcasecmp (BUF[1], "<none>") == 0)
  1129. {
  1130. USERS.match_set_msg (CMD[0], "");
  1131. SEND_TEXT (DEST, "Message \002disabled\002.");
  1132. }
  1133. else
  1134. {
  1135. USERS.match_set_msg (CMD[0], BUF[1]);
  1136. SEND_TEXT (DEST, "Message set to '%s'.", BUF[1]);
  1137. }
  1138. }
  1139. // !pass password
  1140. void
  1141. scriptcmd_pass (NetServer *s)
  1142. {
  1143. if (DEST[0] == '#')
  1144. {
  1145. SEND_TEXT (DEST, "Do \002not\002 use this command on a channel.");
  1146. return;
  1147. }
  1148. strsplit (CMD[3], BUF, 1);
  1149. if (BUF[1][0] == 0)
  1150. {
  1151. SEND_TEXT (DEST, "%s", HELP_PASS);
  1152. return;
  1153. }
  1154. if (USERS.match_check_pass (CMD[0], BUF[1]))
  1155. {
  1156. USERS.match_set_id (CMD[0], 1);
  1157. mask2nick (CMD[0], BUF[2]);
  1158. s->irc_watch (BUF[2], 1);
  1159. SEND_TEXT (DEST, "Password correct.");
  1160. }
  1161. else
  1162. SEND_TEXT (DEST, "Password \002in\002correct.");
  1163. }
  1164. // !level
  1165. void
  1166. scriptcmd_level (NetServer *s)
  1167. {
  1168. snprintf (BUF[1], MSG_SIZE, "Your access level is \002%d\002",
  1169. USERS.match_mask_reallevel (CMD[0]));
  1170. if (USERS.match_mask_reallevel (CMD[0]) >= 1)
  1171. {
  1172. if (USERS.match_mask_level (CMD[0]) > 1)
  1173. snprintf (BUF[1] + strlen (BUF[1]), MSG_SIZE - strlen (BUF[1]),
  1174. ", identified");
  1175. else
  1176. snprintf (BUF[1] + strlen (BUF[1]), MSG_SIZE - strlen (BUF[1]),
  1177. ", \002un\002identified");
  1178. }
  1179. SEND_TEXT (DEST, "%s.", BUF[1]);
  1180. }
  1181. void
  1182. scriptcmd_ctcp_var (NetServer *s, c_char name, char *data, size_t n)
  1183. {
  1184. if (strcasecmp (name, "ctcp_version") == 0)
  1185. {
  1186. if (n != 0)
  1187. my_strncpy (data, s->script.ctcp_version, n);
  1188. else
  1189. s->script.ctcp_version = data;
  1190. }
  1191. else if (strcasecmp (name, "ctcp_finger") == 0)
  1192. {
  1193. if (n != 0)
  1194. my_strncpy (data, s->script.ctcp_finger, n);
  1195. else
  1196. s->script.ctcp_finger = data;
  1197. }
  1198. else if (strcasecmp (name, "ctcp_source") == 0)
  1199. {
  1200. if (n != 0)
  1201. my_strncpy (data, s->script.ctcp_source, n);
  1202. else
  1203. s->script.ctcp_source = data;
  1204. }
  1205. }