PageRenderTime 59ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/src/common/outbound.c

https://github.com/tuquito/xchat
C | 4403 lines | 3707 code | 532 blank | 164 comment | 767 complexity | 6d7ca8990a04d46f3a2d711c8fec74d9 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* X-Chat
  2. * Copyright (C) 1998 Peter Zelezny.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  17. */
  18. #define _GNU_SOURCE /* for memrchr */
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <limits.h>
  24. #include <errno.h>
  25. #define WANTSOCKET
  26. #define WANTARPA
  27. #include "inet.h"
  28. #ifndef WIN32
  29. #include <sys/wait.h>
  30. #endif
  31. #include <unistd.h>
  32. #include <time.h>
  33. #include <signal.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #include "xchat.h"
  37. #include "plugin.h"
  38. #include "ignore.h"
  39. #include "util.h"
  40. #include "fe.h"
  41. #include "cfgfiles.h" /* xchat_fopen_file() */
  42. #include "network.h" /* net_ip() */
  43. #include "modes.h"
  44. #include "notify.h"
  45. #include "inbound.h"
  46. #include "text.h"
  47. #include "xchatc.h"
  48. #include "servlist.h"
  49. #include "server.h"
  50. #include "tree.h"
  51. #include "outbound.h"
  52. #ifdef USE_DEBUG
  53. extern int current_mem_usage;
  54. #endif
  55. #define TBUFSIZE 4096
  56. static void help (session *sess, char *tbuf, char *helpcmd, int quiet);
  57. static int cmd_server (session *sess, char *tbuf, char *word[], char *word_eol[]);
  58. static void handle_say (session *sess, char *text, int check_spch);
  59. static void
  60. notj_msg (struct session *sess)
  61. {
  62. PrintText (sess, _("No channel joined. Try /join #<channel>\n"));
  63. }
  64. void
  65. notc_msg (struct session *sess)
  66. {
  67. PrintText (sess, _("Not connected. Try /server <host> [<port>]\n"));
  68. }
  69. static char *
  70. random_line (char *file_name)
  71. {
  72. FILE *fh;
  73. char buf[512];
  74. int lines, ran;
  75. if (!file_name[0])
  76. goto nofile;
  77. fh = xchat_fopen_file (file_name, "r", 0);
  78. if (!fh)
  79. {
  80. nofile:
  81. /* reason is not a file, an actual reason! */
  82. return strdup (file_name);
  83. }
  84. /* count number of lines in file */
  85. lines = 0;
  86. while (fgets (buf, sizeof (buf), fh))
  87. lines++;
  88. if (lines < 1)
  89. goto nofile;
  90. /* go down a random number */
  91. rewind (fh);
  92. ran = RAND_INT (lines);
  93. do
  94. {
  95. fgets (buf, sizeof (buf), fh);
  96. lines--;
  97. }
  98. while (lines > ran);
  99. fclose (fh);
  100. buf[strlen (buf) - 1] = 0; /* remove the trailing '\n' */
  101. return strdup (buf);
  102. }
  103. void
  104. server_sendpart (server * serv, char *channel, char *reason)
  105. {
  106. if (!reason)
  107. {
  108. reason = random_line (prefs.partreason);
  109. serv->p_part (serv, channel, reason);
  110. free (reason);
  111. } else
  112. {
  113. /* reason set by /quit, /close argument */
  114. serv->p_part (serv, channel, reason);
  115. }
  116. }
  117. void
  118. server_sendquit (session * sess)
  119. {
  120. char *rea, *colrea;
  121. if (!sess->quitreason)
  122. {
  123. colrea = strdup (prefs.quitreason);
  124. check_special_chars (colrea, FALSE);
  125. rea = random_line (colrea);
  126. free (colrea);
  127. sess->server->p_quit (sess->server, rea);
  128. free (rea);
  129. } else
  130. {
  131. /* reason set by /quit, /close argument */
  132. sess->server->p_quit (sess->server, sess->quitreason);
  133. }
  134. }
  135. void
  136. process_data_init (char *buf, char *cmd, char *word[],
  137. char *word_eol[], gboolean handle_quotes,
  138. gboolean allow_escape_quotes)
  139. {
  140. int wordcount = 2;
  141. int space = FALSE;
  142. int quote = FALSE;
  143. int j = 0;
  144. int len;
  145. word[0] = "\000\000";
  146. word_eol[0] = "\000\000";
  147. word[1] = (char *)buf;
  148. word_eol[1] = (char *)cmd;
  149. while (1)
  150. {
  151. switch (*cmd)
  152. {
  153. case 0:
  154. buf[j] = 0;
  155. for (j = wordcount; j < PDIWORDS; j++)
  156. {
  157. word[j] = "\000\000";
  158. word_eol[j] = "\000\000";
  159. }
  160. return;
  161. case '\042':
  162. if (!handle_quotes)
  163. goto def;
  164. /* two quotes turn into 1 */
  165. if (allow_escape_quotes && cmd[1] == '\042')
  166. {
  167. cmd++;
  168. goto def;
  169. }
  170. if (quote)
  171. {
  172. quote = FALSE;
  173. space = FALSE;
  174. } else
  175. quote = TRUE;
  176. cmd++;
  177. break;
  178. case ' ':
  179. if (!quote)
  180. {
  181. if (!space)
  182. {
  183. buf[j] = 0;
  184. j++;
  185. if (wordcount < PDIWORDS)
  186. {
  187. word[wordcount] = &buf[j];
  188. word_eol[wordcount] = cmd + 1;
  189. wordcount++;
  190. }
  191. space = TRUE;
  192. }
  193. cmd++;
  194. break;
  195. }
  196. default:
  197. def:
  198. space = FALSE;
  199. len = g_utf8_skip[((unsigned char *)cmd)[0]];
  200. if (len == 1)
  201. {
  202. buf[j] = *cmd;
  203. j++;
  204. cmd++;
  205. } else
  206. {
  207. /* skip past a multi-byte utf8 char */
  208. memcpy (buf + j, cmd, len);
  209. j += len;
  210. cmd += len;
  211. }
  212. }
  213. }
  214. }
  215. static int
  216. cmd_addbutton (struct session *sess, char *tbuf, char *word[],
  217. char *word_eol[])
  218. {
  219. if (*word[2] && *word_eol[3])
  220. {
  221. if (sess->type == SESS_DIALOG)
  222. {
  223. list_addentry (&dlgbutton_list, word_eol[3], word[2]);
  224. fe_dlgbuttons_update (sess);
  225. } else
  226. {
  227. list_addentry (&button_list, word_eol[3], word[2]);
  228. fe_buttons_update (sess);
  229. }
  230. return TRUE;
  231. }
  232. return FALSE;
  233. }
  234. static int
  235. cmd_allchannels (session *sess, char *tbuf, char *word[], char *word_eol[])
  236. {
  237. GSList *list = sess_list;
  238. if (!*word_eol[2])
  239. return FALSE;
  240. while (list)
  241. {
  242. sess = list->data;
  243. if (sess->type == SESS_CHANNEL && sess->channel[0] && sess->server->connected)
  244. {
  245. handle_command (sess, word_eol[2], FALSE);
  246. }
  247. list = list->next;
  248. }
  249. return TRUE;
  250. }
  251. static int
  252. cmd_allchannelslocal (session *sess, char *tbuf, char *word[], char *word_eol[])
  253. {
  254. GSList *list = sess_list;
  255. server *serv = sess->server;
  256. if (!*word_eol[2])
  257. return FALSE;
  258. while (list)
  259. {
  260. sess = list->data;
  261. if (sess->type == SESS_CHANNEL && sess->channel[0] &&
  262. sess->server->connected && sess->server == serv)
  263. {
  264. handle_command (sess, word_eol[2], FALSE);
  265. }
  266. list = list->next;
  267. }
  268. return TRUE;
  269. }
  270. static int
  271. cmd_allservers (struct session *sess, char *tbuf, char *word[],
  272. char *word_eol[])
  273. {
  274. GSList *list;
  275. server *serv;
  276. if (!*word_eol[2])
  277. return FALSE;
  278. list = serv_list;
  279. while (list)
  280. {
  281. serv = list->data;
  282. if (serv->connected)
  283. handle_command (serv->front_session, word_eol[2], FALSE);
  284. list = list->next;
  285. }
  286. return TRUE;
  287. }
  288. static int
  289. cmd_away (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  290. {
  291. GSList *list;
  292. char *reason = word_eol[2];
  293. if (!(*reason))
  294. {
  295. if (sess->server->is_away)
  296. {
  297. if (sess->server->last_away_reason)
  298. PrintTextf (sess, _("Already marked away: %s\n"), sess->server->last_away_reason);
  299. return FALSE;
  300. }
  301. if (sess->server->reconnect_away)
  302. reason = sess->server->last_away_reason;
  303. else
  304. /* must manage memory pointed to by random_line() */
  305. reason = random_line (prefs.awayreason);
  306. }
  307. sess->server->p_set_away (sess->server, reason);
  308. if (prefs.show_away_message)
  309. {
  310. snprintf (tbuf, TBUFSIZE, "me is away: %s", reason);
  311. for (list = sess_list; list; list = list->next)
  312. {
  313. /* am I the right server and not a dialog box */
  314. if (((struct session *) list->data)->server == sess->server
  315. && ((struct session *) list->data)->type == SESS_CHANNEL
  316. && ((struct session *) list->data)->channel[0])
  317. {
  318. handle_command ((session *) list->data, tbuf, TRUE);
  319. }
  320. }
  321. }
  322. if (sess->server->last_away_reason != reason)
  323. {
  324. if (sess->server->last_away_reason)
  325. free (sess->server->last_away_reason);
  326. if (reason == word_eol[2])
  327. sess->server->last_away_reason = strdup (reason);
  328. else
  329. sess->server->last_away_reason = reason;
  330. }
  331. if (!sess->server->connected)
  332. sess->server->reconnect_away = 1;
  333. return TRUE;
  334. }
  335. static int
  336. cmd_back (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  337. {
  338. GSList *list;
  339. unsigned int gone;
  340. if (sess->server->is_away)
  341. {
  342. sess->server->p_set_back (sess->server);
  343. if (prefs.show_away_message)
  344. {
  345. gone = time (NULL) - sess->server->away_time;
  346. sprintf (tbuf, "me is back (gone %.2d:%.2d:%.2d)", gone / 3600,
  347. (gone / 60) % 60, gone % 60);
  348. for (list = sess_list; list; list = list->next)
  349. {
  350. /* am I the right server and not a dialog box */
  351. if (((struct session *) list->data)->server == sess->server
  352. && ((struct session *) list->data)->type == SESS_CHANNEL
  353. && ((struct session *) list->data)->channel[0])
  354. {
  355. handle_command ((session *) list->data, tbuf, TRUE);
  356. }
  357. }
  358. }
  359. }
  360. else
  361. {
  362. PrintText (sess, _("Already marked back.\n"));
  363. }
  364. if (sess->server->last_away_reason)
  365. free (sess->server->last_away_reason);
  366. sess->server->last_away_reason = NULL;
  367. return TRUE;
  368. }
  369. static void
  370. ban (session * sess, char *tbuf, char *mask, char *bantypestr, int deop)
  371. {
  372. int bantype;
  373. struct User *user;
  374. char *at, *dot, *lastdot;
  375. char username[64], fullhost[128], domain[128], *mode, *p2;
  376. server *serv = sess->server;
  377. user = userlist_find (sess, mask);
  378. if (user && user->hostname) /* it's a nickname, let's find a proper ban mask */
  379. {
  380. if (deop)
  381. {
  382. mode = "-o+b ";
  383. p2 = user->nick;
  384. } else
  385. {
  386. mode = "+b";
  387. p2 = "";
  388. }
  389. mask = user->hostname;
  390. at = strchr (mask, '@'); /* FIXME: utf8 */
  391. if (!at)
  392. return; /* can't happen? */
  393. *at = 0;
  394. if (mask[0] == '~' || mask[0] == '+' ||
  395. mask[0] == '=' || mask[0] == '^' || mask[0] == '-')
  396. {
  397. /* the ident is prefixed with something, we replace that sign with an * */
  398. safe_strcpy (username+1, mask+1, sizeof (username)-1);
  399. username[0] = '*';
  400. } else if (at - mask < USERNAMELEN)
  401. {
  402. /* we just add an * in the begining of the ident */
  403. safe_strcpy (username+1, mask, sizeof (username)-1);
  404. username[0] = '*';
  405. } else
  406. {
  407. /* ident might be too long, we just ban what it gives and add an * in the end */
  408. safe_strcpy (username, mask, sizeof (username));
  409. }
  410. *at = '@';
  411. safe_strcpy (fullhost, at + 1, sizeof (fullhost));
  412. dot = strchr (fullhost, '.');
  413. if (dot)
  414. {
  415. safe_strcpy (domain, dot, sizeof (domain));
  416. } else
  417. {
  418. safe_strcpy (domain, fullhost, sizeof (domain));
  419. }
  420. if (*bantypestr)
  421. bantype = atoi (bantypestr);
  422. else
  423. bantype = prefs.bantype;
  424. tbuf[0] = 0;
  425. if (inet_addr (fullhost) != -1) /* "fullhost" is really a IP number */
  426. {
  427. lastdot = strrchr (fullhost, '.');
  428. if (!lastdot)
  429. return; /* can't happen? */
  430. *lastdot = 0;
  431. strcpy (domain, fullhost);
  432. *lastdot = '.';
  433. switch (bantype)
  434. {
  435. case 0:
  436. snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s.*", mode, p2, domain);
  437. break;
  438. case 1:
  439. snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
  440. break;
  441. case 2:
  442. snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s.*", mode, p2, username, domain);
  443. break;
  444. case 3:
  445. snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
  446. break;
  447. }
  448. } else
  449. {
  450. switch (bantype)
  451. {
  452. case 0:
  453. snprintf (tbuf, TBUFSIZE, "%s%s *!*@*%s", mode, p2, domain);
  454. break;
  455. case 1:
  456. snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
  457. break;
  458. case 2:
  459. snprintf (tbuf, TBUFSIZE, "%s%s *!%s@*%s", mode, p2, username, domain);
  460. break;
  461. case 3:
  462. snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
  463. break;
  464. }
  465. }
  466. } else
  467. {
  468. snprintf (tbuf, TBUFSIZE, "+b %s", mask);
  469. }
  470. serv->p_mode (serv, sess->channel, tbuf);
  471. }
  472. static int
  473. cmd_ban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  474. {
  475. char *mask = word[2];
  476. if (*mask)
  477. {
  478. ban (sess, tbuf, mask, word[3], 0);
  479. } else
  480. {
  481. sess->server->p_mode (sess->server, sess->channel, "+b"); /* banlist */
  482. }
  483. return TRUE;
  484. }
  485. static int
  486. cmd_unban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  487. {
  488. /* Allow more than one mask in /unban -- tvk */
  489. int i = 2;
  490. while (1)
  491. {
  492. if (!*word[i])
  493. {
  494. if (i == 2)
  495. return FALSE;
  496. send_channel_modes (sess, tbuf, word, 2, i, '-', 'b', 0);
  497. return TRUE;
  498. }
  499. i++;
  500. }
  501. }
  502. static int
  503. cmd_chanopt (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  504. {
  505. /* chanopt.c */
  506. return chanopt_command (sess, tbuf, word, word_eol);
  507. }
  508. static int
  509. cmd_charset (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  510. {
  511. server *serv = sess->server;
  512. const char *locale = NULL;
  513. int offset = 0;
  514. if (strcmp (word[2], "-quiet") == 0)
  515. offset++;
  516. if (!word[2 + offset][0])
  517. {
  518. g_get_charset (&locale);
  519. PrintTextf (sess, "Current charset: %s\n",
  520. serv->encoding ? serv->encoding : locale);
  521. return TRUE;
  522. }
  523. if (servlist_check_encoding (word[2 + offset]))
  524. {
  525. server_set_encoding (serv, word[2 + offset]);
  526. if (offset < 1)
  527. PrintTextf (sess, "Charset changed to: %s\n", word[2 + offset]);
  528. } else
  529. {
  530. PrintTextf (sess, "\0034Unknown charset:\017 %s\n", word[2 + offset]);
  531. }
  532. return TRUE;
  533. }
  534. static int
  535. cmd_clear (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  536. {
  537. GSList *list = sess_list;
  538. char *reason = word_eol[2];
  539. if (strcasecmp (reason, "HISTORY") == 0)
  540. {
  541. history_free (&sess->history);
  542. return TRUE;
  543. }
  544. if (strncasecmp (reason, "all", 3) == 0)
  545. {
  546. while (list)
  547. {
  548. sess = list->data;
  549. if (!sess->nick_said)
  550. fe_text_clear (list->data, 0);
  551. list = list->next;
  552. }
  553. return TRUE;
  554. }
  555. if (reason[0] != '-' && !isdigit (reason[0]) && reason[0] != 0)
  556. return FALSE;
  557. fe_text_clear (sess, atoi (reason));
  558. return TRUE;
  559. }
  560. static int
  561. cmd_close (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  562. {
  563. GSList *list;
  564. if (strcmp (word[2], "-m") == 0)
  565. {
  566. list = sess_list;
  567. while (list)
  568. {
  569. sess = list->data;
  570. list = list->next;
  571. if (sess->type == SESS_DIALOG)
  572. fe_close_window (sess);
  573. }
  574. } else
  575. {
  576. if (*word_eol[2])
  577. sess->quitreason = word_eol[2];
  578. fe_close_window (sess);
  579. }
  580. return TRUE;
  581. }
  582. static int
  583. cmd_ctcp (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  584. {
  585. int mbl;
  586. char *to = word[2];
  587. if (*to)
  588. {
  589. char *msg = word_eol[3];
  590. if (*msg)
  591. {
  592. unsigned char *cmd = (unsigned char *)msg;
  593. /* make the first word upper case (as per RFC) */
  594. while (1)
  595. {
  596. if (*cmd == ' ' || *cmd == 0)
  597. break;
  598. mbl = g_utf8_skip[*cmd];
  599. if (mbl == 1)
  600. *cmd = toupper (*cmd);
  601. cmd += mbl;
  602. }
  603. sess->server->p_ctcp (sess->server, to, msg);
  604. EMIT_SIGNAL (XP_TE_CTCPSEND, sess, to, msg, NULL, NULL, 0);
  605. return TRUE;
  606. }
  607. }
  608. return FALSE;
  609. }
  610. static int
  611. cmd_country (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  612. {
  613. char *code = word[2];
  614. if (*code)
  615. {
  616. /* search? */
  617. if (strcmp (code, "-s") == 0)
  618. {
  619. country_search (word[3], sess, (void *)PrintTextf);
  620. return TRUE;
  621. }
  622. /* search, but forgot the -s */
  623. if (strchr (code, '*'))
  624. {
  625. country_search (code, sess, (void *)PrintTextf);
  626. return TRUE;
  627. }
  628. sprintf (tbuf, "%s = %s\n", code, country (code));
  629. PrintText (sess, tbuf);
  630. return TRUE;
  631. }
  632. return FALSE;
  633. }
  634. static int
  635. cmd_cycle (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  636. {
  637. char *key = sess->channelkey;
  638. char *chan = word[2];
  639. if (!*chan)
  640. chan = sess->channel;
  641. if (*chan && sess->type == SESS_CHANNEL)
  642. {
  643. sess->server->p_cycle (sess->server, chan, key);
  644. return TRUE;
  645. }
  646. return FALSE;
  647. }
  648. static int
  649. cmd_dcc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  650. {
  651. int goodtype;
  652. struct DCC *dcc = 0;
  653. char *type = word[2];
  654. if (*type)
  655. {
  656. if (!strcasecmp (type, "HELP"))
  657. return FALSE;
  658. if (!strcasecmp (type, "CLOSE"))
  659. {
  660. if (*word[3] && *word[4])
  661. {
  662. goodtype = 0;
  663. if (!strcasecmp (word[3], "SEND"))
  664. {
  665. dcc = find_dcc (word[4], word[5], TYPE_SEND);
  666. dcc_abort (sess, dcc);
  667. goodtype = TRUE;
  668. }
  669. if (!strcasecmp (word[3], "GET"))
  670. {
  671. dcc = find_dcc (word[4], word[5], TYPE_RECV);
  672. dcc_abort (sess, dcc);
  673. goodtype = TRUE;
  674. }
  675. if (!strcasecmp (word[3], "CHAT"))
  676. {
  677. dcc = find_dcc (word[4], "", TYPE_CHATRECV);
  678. if (!dcc)
  679. dcc = find_dcc (word[4], "", TYPE_CHATSEND);
  680. dcc_abort (sess, dcc);
  681. goodtype = TRUE;
  682. }
  683. if (!goodtype)
  684. return FALSE;
  685. if (!dcc)
  686. EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
  687. return TRUE;
  688. }
  689. return FALSE;
  690. }
  691. if ((!strcasecmp (type, "CHAT")) || (!strcasecmp (type, "PCHAT")))
  692. {
  693. char *nick = word[3];
  694. int passive = (!strcasecmp(type, "PCHAT")) ? 1 : 0;
  695. if (*nick)
  696. dcc_chat (sess, nick, passive);
  697. return TRUE;
  698. }
  699. if (!strcasecmp (type, "LIST"))
  700. {
  701. dcc_show_list (sess);
  702. return TRUE;
  703. }
  704. if (!strcasecmp (type, "GET"))
  705. {
  706. char *nick = word[3];
  707. char *file = word[4];
  708. if (!*file)
  709. {
  710. if (*nick)
  711. dcc_get_nick (sess, nick);
  712. } else
  713. {
  714. dcc = find_dcc (nick, file, TYPE_RECV);
  715. if (dcc)
  716. dcc_get (dcc);
  717. else
  718. EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
  719. }
  720. return TRUE;
  721. }
  722. if ((!strcasecmp (type, "SEND")) || (!strcasecmp (type, "PSEND")))
  723. {
  724. int i = 3, maxcps;
  725. char *nick, *file;
  726. int passive = (!strcasecmp(type, "PSEND")) ? 1 : 0;
  727. nick = word[i];
  728. if (!*nick)
  729. return FALSE;
  730. maxcps = prefs.dcc_max_send_cps;
  731. if (!strncasecmp(nick, "-maxcps=", 8))
  732. {
  733. maxcps = atoi(nick + 8);
  734. i++;
  735. nick = word[i];
  736. if (!*nick)
  737. return FALSE;
  738. }
  739. i++;
  740. file = word[i];
  741. if (!*file)
  742. {
  743. fe_dcc_send_filereq (sess, nick, maxcps, passive);
  744. return TRUE;
  745. }
  746. do
  747. {
  748. dcc_send (sess, nick, file, maxcps, passive);
  749. i++;
  750. file = word[i];
  751. }
  752. while (*file);
  753. return TRUE;
  754. }
  755. return FALSE;
  756. }
  757. dcc_show_list (sess);
  758. return TRUE;
  759. }
  760. static int
  761. cmd_debug (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  762. {
  763. struct session *s;
  764. struct server *v;
  765. GSList *list = sess_list;
  766. PrintText (sess, "Session T Channel WaitChan WillChan Server\n");
  767. while (list)
  768. {
  769. s = (struct session *) list->data;
  770. sprintf (tbuf, "%p %1x %-10.10s %-10.10s %-10.10s %p\n",
  771. s, s->type, s->channel, s->waitchannel,
  772. s->willjoinchannel, s->server);
  773. PrintText (sess, tbuf);
  774. list = list->next;
  775. }
  776. list = serv_list;
  777. PrintText (sess, "Server Sock Name\n");
  778. while (list)
  779. {
  780. v = (struct server *) list->data;
  781. sprintf (tbuf, "%p %-5d %s\n",
  782. v, v->sok, v->servername);
  783. PrintText (sess, tbuf);
  784. list = list->next;
  785. }
  786. sprintf (tbuf,
  787. "\nfront_session: %p\n"
  788. "current_tab: %p\n\n",
  789. sess->server->front_session, current_tab);
  790. PrintText (sess, tbuf);
  791. #ifdef USE_DEBUG
  792. sprintf (tbuf, "current mem: %d\n\n", current_mem_usage);
  793. PrintText (sess, tbuf);
  794. #endif /* !MEMORY_DEBUG */
  795. return TRUE;
  796. }
  797. static int
  798. cmd_delbutton (struct session *sess, char *tbuf, char *word[],
  799. char *word_eol[])
  800. {
  801. if (*word[2])
  802. {
  803. if (sess->type == SESS_DIALOG)
  804. {
  805. if (list_delentry (&dlgbutton_list, word[2]))
  806. fe_dlgbuttons_update (sess);
  807. } else
  808. {
  809. if (list_delentry (&button_list, word[2]))
  810. fe_buttons_update (sess);
  811. }
  812. return TRUE;
  813. }
  814. return FALSE;
  815. }
  816. static int
  817. cmd_dehop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  818. {
  819. int i = 2;
  820. while (1)
  821. {
  822. if (!*word[i])
  823. {
  824. if (i == 2)
  825. return FALSE;
  826. send_channel_modes (sess, tbuf, word, 2, i, '-', 'h', 0);
  827. return TRUE;
  828. }
  829. i++;
  830. }
  831. }
  832. static int
  833. cmd_deop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  834. {
  835. int i = 2;
  836. while (1)
  837. {
  838. if (!*word[i])
  839. {
  840. if (i == 2)
  841. return FALSE;
  842. send_channel_modes (sess, tbuf, word, 2, i, '-', 'o', 0);
  843. return TRUE;
  844. }
  845. i++;
  846. }
  847. }
  848. typedef struct
  849. {
  850. char **nicks;
  851. int i;
  852. session *sess;
  853. char *reason;
  854. char *tbuf;
  855. } multidata;
  856. static int
  857. mdehop_cb (struct User *user, multidata *data)
  858. {
  859. if (user->hop && !user->me)
  860. {
  861. data->nicks[data->i] = user->nick;
  862. data->i++;
  863. }
  864. return TRUE;
  865. }
  866. static int
  867. cmd_mdehop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  868. {
  869. char **nicks = malloc (sizeof (char *) * sess->hops);
  870. multidata data;
  871. data.nicks = nicks;
  872. data.i = 0;
  873. tree_foreach (sess->usertree, (tree_traverse_func *)mdehop_cb, &data);
  874. send_channel_modes (sess, tbuf, nicks, 0, data.i, '-', 'h', 0);
  875. free (nicks);
  876. return TRUE;
  877. }
  878. static int
  879. mdeop_cb (struct User *user, multidata *data)
  880. {
  881. if (user->op && !user->me)
  882. {
  883. data->nicks[data->i] = user->nick;
  884. data->i++;
  885. }
  886. return TRUE;
  887. }
  888. static int
  889. cmd_mdeop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  890. {
  891. char **nicks = malloc (sizeof (char *) * sess->ops);
  892. multidata data;
  893. data.nicks = nicks;
  894. data.i = 0;
  895. tree_foreach (sess->usertree, (tree_traverse_func *)mdeop_cb, &data);
  896. send_channel_modes (sess, tbuf, nicks, 0, data.i, '-', 'o', 0);
  897. free (nicks);
  898. return TRUE;
  899. }
  900. GSList *menu_list = NULL;
  901. static void
  902. menu_free (menu_entry *me)
  903. {
  904. free (me->path);
  905. if (me->label)
  906. free (me->label);
  907. if (me->cmd)
  908. free (me->cmd);
  909. if (me->ucmd)
  910. free (me->ucmd);
  911. if (me->group)
  912. free (me->group);
  913. if (me->icon)
  914. free (me->icon);
  915. free (me);
  916. }
  917. /* strings equal? but ignore underscores */
  918. int
  919. menu_streq (const char *s1, const char *s2, int def)
  920. {
  921. /* for separators */
  922. if (s1 == NULL && s2 == NULL)
  923. return 0;
  924. if (s1 == NULL || s2 == NULL)
  925. return 1;
  926. while (*s1)
  927. {
  928. if (*s1 == '_')
  929. s1++;
  930. if (*s2 == '_')
  931. s2++;
  932. if (*s1 != *s2)
  933. return 1;
  934. s1++;
  935. s2++;
  936. }
  937. if (!*s2)
  938. return 0;
  939. return def;
  940. }
  941. static menu_entry *
  942. menu_entry_find (char *path, char *label)
  943. {
  944. GSList *list;
  945. menu_entry *me;
  946. list = menu_list;
  947. while (list)
  948. {
  949. me = list->data;
  950. if (!strcmp (path, me->path))
  951. {
  952. if (me->label && label && !strcmp (label, me->label))
  953. return me;
  954. }
  955. list = list->next;
  956. }
  957. return NULL;
  958. }
  959. static void
  960. menu_del_children (char *path, char *label)
  961. {
  962. GSList *list, *next;
  963. menu_entry *me;
  964. char buf[512];
  965. if (!label)
  966. label = "";
  967. if (path[0])
  968. snprintf (buf, sizeof (buf), "%s/%s", path, label);
  969. else
  970. snprintf (buf, sizeof (buf), "%s", label);
  971. list = menu_list;
  972. while (list)
  973. {
  974. me = list->data;
  975. next = list->next;
  976. if (!menu_streq (buf, me->path, 0))
  977. {
  978. menu_list = g_slist_remove (menu_list, me);
  979. menu_free (me);
  980. }
  981. list = next;
  982. }
  983. }
  984. static int
  985. menu_del (char *path, char *label)
  986. {
  987. GSList *list;
  988. menu_entry *me;
  989. list = menu_list;
  990. while (list)
  991. {
  992. me = list->data;
  993. if (!menu_streq (me->label, label, 1) && !menu_streq (me->path, path, 1))
  994. {
  995. menu_list = g_slist_remove (menu_list, me);
  996. fe_menu_del (me);
  997. menu_free (me);
  998. /* delete this item's children, if any */
  999. menu_del_children (path, label);
  1000. return 1;
  1001. }
  1002. list = list->next;
  1003. }
  1004. return 0;
  1005. }
  1006. static char
  1007. menu_is_mainmenu_root (char *path, gint16 *offset)
  1008. {
  1009. static const char *menus[] = {"\x4$TAB","\x5$TRAY","\x4$URL","\x5$NICK","\x5$CHAN"};
  1010. int i;
  1011. for (i = 0; i < 5; i++)
  1012. {
  1013. if (!strncmp (path, menus[i] + 1, menus[i][0]))
  1014. {
  1015. *offset = menus[i][0] + 1; /* number of bytes to offset the root */
  1016. return 0; /* is not main menu */
  1017. }
  1018. }
  1019. *offset = 0;
  1020. return 1; /* is main menu */
  1021. }
  1022. static void
  1023. menu_add (char *path, char *label, char *cmd, char *ucmd, int pos, int state, int markup, int enable, int mod, int key, char *group, char *icon)
  1024. {
  1025. menu_entry *me;
  1026. /* already exists? */
  1027. me = menu_entry_find (path, label);
  1028. if (me)
  1029. {
  1030. /* update only */
  1031. me->state = state;
  1032. me->enable = enable;
  1033. fe_menu_update (me);
  1034. return;
  1035. }
  1036. me = malloc (sizeof (menu_entry));
  1037. me->pos = pos;
  1038. me->modifier = mod;
  1039. me->is_main = menu_is_mainmenu_root (path, &me->root_offset);
  1040. me->state = state;
  1041. me->markup = markup;
  1042. me->enable = enable;
  1043. me->key = key;
  1044. me->path = strdup (path);
  1045. me->label = NULL;
  1046. me->cmd = NULL;
  1047. me->ucmd = NULL;
  1048. me->group = NULL;
  1049. me->icon = NULL;
  1050. if (label)
  1051. me->label = strdup (label);
  1052. if (cmd)
  1053. me->cmd = strdup (cmd);
  1054. if (ucmd)
  1055. me->ucmd = strdup (ucmd);
  1056. if (group)
  1057. me->group = strdup (group);
  1058. if (icon)
  1059. me->icon = strdup (icon);
  1060. menu_list = g_slist_append (menu_list, me);
  1061. label = fe_menu_add (me);
  1062. if (label)
  1063. {
  1064. /* FE has given us a stripped label */
  1065. free (me->label);
  1066. me->label = strdup (label);
  1067. g_free (label); /* this is from pango */
  1068. }
  1069. }
  1070. static int
  1071. cmd_menu (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1072. {
  1073. int idx = 2;
  1074. int len;
  1075. int pos = 0xffff;
  1076. int state;
  1077. int toggle = FALSE;
  1078. int enable = TRUE;
  1079. int markup = FALSE;
  1080. int key = 0;
  1081. int mod = 0;
  1082. char *label;
  1083. char *group = NULL;
  1084. char *icon = NULL;
  1085. if (!word[2][0] || !word[3][0])
  1086. return FALSE;
  1087. /* -eX enabled or not? */
  1088. if (word[idx][0] == '-' && word[idx][1] == 'e')
  1089. {
  1090. enable = atoi (word[idx] + 2);
  1091. idx++;
  1092. }
  1093. /* -i<ICONFILE> */
  1094. if (word[idx][0] == '-' && word[idx][1] == 'i')
  1095. {
  1096. icon = word[idx] + 2;
  1097. idx++;
  1098. }
  1099. /* -k<mod>,<key> key binding */
  1100. if (word[idx][0] == '-' && word[idx][1] == 'k')
  1101. {
  1102. char *comma = strchr (word[idx], ',');
  1103. if (!comma)
  1104. return FALSE;
  1105. mod = atoi (word[idx] + 2);
  1106. key = atoi (comma + 1);
  1107. idx++;
  1108. }
  1109. /* -m to specify PangoMarkup language */
  1110. if (word[idx][0] == '-' && word[idx][1] == 'm')
  1111. {
  1112. markup = TRUE;
  1113. idx++;
  1114. }
  1115. /* -pX to specify menu position */
  1116. if (word[idx][0] == '-' && word[idx][1] == 'p')
  1117. {
  1118. pos = atoi (word[idx] + 2);
  1119. idx++;
  1120. }
  1121. /* -rSTATE,GROUP to specify a radio item */
  1122. if (word[idx][0] == '-' && word[idx][1] == 'r')
  1123. {
  1124. state = atoi (word[idx] + 2);
  1125. group = word[idx] + 4;
  1126. idx++;
  1127. }
  1128. /* -tX to specify toggle item with default state */
  1129. if (word[idx][0] == '-' && word[idx][1] == 't')
  1130. {
  1131. state = atoi (word[idx] + 2);
  1132. idx++;
  1133. toggle = TRUE;
  1134. }
  1135. if (word[idx+1][0] == 0)
  1136. return FALSE;
  1137. /* the path */
  1138. path_part (word[idx+1], tbuf, 512);
  1139. len = strlen (tbuf);
  1140. if (len)
  1141. tbuf[len - 1] = 0;
  1142. /* the name of the item */
  1143. label = file_part (word[idx + 1]);
  1144. if (label[0] == '-' && label[1] == 0)
  1145. label = NULL; /* separator */
  1146. if (markup)
  1147. {
  1148. char *p; /* to force pango closing tags through */
  1149. for (p = label; *p; p++)
  1150. if (*p == 3)
  1151. *p = '/';
  1152. }
  1153. if (!strcasecmp (word[idx], "ADD"))
  1154. {
  1155. if (toggle)
  1156. {
  1157. menu_add (tbuf, label, word[idx + 2], word[idx + 3], pos, state, markup, enable, mod, key, NULL, NULL);
  1158. } else
  1159. {
  1160. if (word[idx + 2][0])
  1161. menu_add (tbuf, label, word[idx + 2], NULL, pos, state, markup, enable, mod, key, group, icon);
  1162. else
  1163. menu_add (tbuf, label, NULL, NULL, pos, state, markup, enable, mod, key, group, icon);
  1164. }
  1165. return TRUE;
  1166. }
  1167. if (!strcasecmp (word[idx], "DEL"))
  1168. {
  1169. menu_del (tbuf, label);
  1170. return TRUE;
  1171. }
  1172. return FALSE;
  1173. }
  1174. static int
  1175. mkick_cb (struct User *user, multidata *data)
  1176. {
  1177. if (!user->op && !user->me)
  1178. data->sess->server->p_kick (data->sess->server, data->sess->channel, user->nick, data->reason);
  1179. return TRUE;
  1180. }
  1181. static int
  1182. mkickops_cb (struct User *user, multidata *data)
  1183. {
  1184. if (user->op && !user->me)
  1185. data->sess->server->p_kick (data->sess->server, data->sess->channel, user->nick, data->reason);
  1186. return TRUE;
  1187. }
  1188. static int
  1189. cmd_mkick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1190. {
  1191. multidata data;
  1192. data.sess = sess;
  1193. data.reason = word_eol[2];
  1194. tree_foreach (sess->usertree, (tree_traverse_func *)mkickops_cb, &data);
  1195. tree_foreach (sess->usertree, (tree_traverse_func *)mkick_cb, &data);
  1196. return TRUE;
  1197. }
  1198. static int
  1199. cmd_devoice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1200. {
  1201. int i = 2;
  1202. while (1)
  1203. {
  1204. if (!*word[i])
  1205. {
  1206. if (i == 2)
  1207. return FALSE;
  1208. send_channel_modes (sess, tbuf, word, 2, i, '-', 'v', 0);
  1209. return TRUE;
  1210. }
  1211. i++;
  1212. }
  1213. }
  1214. static int
  1215. cmd_discon (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1216. {
  1217. sess->server->disconnect (sess, TRUE, -1);
  1218. return TRUE;
  1219. }
  1220. static int
  1221. cmd_dns (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1222. {
  1223. #ifdef WIN32
  1224. PrintText (sess, "DNS is not implemented in Windows.\n");
  1225. return TRUE;
  1226. #else
  1227. char *nick = word[2];
  1228. struct User *user;
  1229. if (*nick)
  1230. {
  1231. if (strchr (nick, '.') == NULL)
  1232. {
  1233. user = userlist_find (sess, nick);
  1234. if (user && user->hostname)
  1235. {
  1236. do_dns (sess, user->nick, user->hostname);
  1237. } else
  1238. {
  1239. sess->server->p_get_ip (sess->server, nick);
  1240. sess->server->doing_dns = TRUE;
  1241. }
  1242. } else
  1243. {
  1244. snprintf (tbuf, TBUFSIZE, "exec -d %s %s", prefs.dnsprogram, nick);
  1245. handle_command (sess, tbuf, FALSE);
  1246. }
  1247. return TRUE;
  1248. }
  1249. return FALSE;
  1250. #endif
  1251. }
  1252. static int
  1253. cmd_echo (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1254. {
  1255. PrintText (sess, word_eol[2]);
  1256. return TRUE;
  1257. }
  1258. #ifndef WIN32
  1259. static void
  1260. exec_check_process (struct session *sess)
  1261. {
  1262. int val;
  1263. if (sess->running_exec == NULL)
  1264. return;
  1265. val = waitpid (sess->running_exec->childpid, NULL, WNOHANG);
  1266. if (val == -1 || val > 0)
  1267. {
  1268. close (sess->running_exec->myfd);
  1269. fe_input_remove (sess->running_exec->iotag);
  1270. free (sess->running_exec);
  1271. sess->running_exec = NULL;
  1272. }
  1273. }
  1274. #ifndef __EMX__
  1275. static int
  1276. cmd_execs (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1277. {
  1278. int r;
  1279. exec_check_process (sess);
  1280. if (sess->running_exec == NULL)
  1281. {
  1282. EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1283. return FALSE;
  1284. }
  1285. r = kill (sess->running_exec->childpid, SIGSTOP);
  1286. if (r == -1)
  1287. PrintText (sess, "Error in kill(2)\n");
  1288. return TRUE;
  1289. }
  1290. static int
  1291. cmd_execc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1292. {
  1293. int r;
  1294. exec_check_process (sess);
  1295. if (sess->running_exec == NULL)
  1296. {
  1297. EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1298. return FALSE;
  1299. }
  1300. r = kill (sess->running_exec->childpid, SIGCONT);
  1301. if (r == -1)
  1302. PrintText (sess, "Error in kill(2)\n");
  1303. return TRUE;
  1304. }
  1305. static int
  1306. cmd_execk (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1307. {
  1308. int r;
  1309. exec_check_process (sess);
  1310. if (sess->running_exec == NULL)
  1311. {
  1312. EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1313. return FALSE;
  1314. }
  1315. if (strcmp (word[2], "-9") == 0)
  1316. r = kill (sess->running_exec->childpid, SIGKILL);
  1317. else
  1318. r = kill (sess->running_exec->childpid, SIGTERM);
  1319. if (r == -1)
  1320. PrintText (sess, "Error in kill(2)\n");
  1321. return TRUE;
  1322. }
  1323. /* OS/2 Can't have the /EXECW command because it uses pipe(2) not socketpair
  1324. and thus it is simplex --AGL */
  1325. static int
  1326. cmd_execw (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1327. {
  1328. int len;
  1329. char *temp;
  1330. exec_check_process (sess);
  1331. if (sess->running_exec == NULL)
  1332. {
  1333. EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1334. return FALSE;
  1335. }
  1336. len = strlen(word_eol[2]);
  1337. temp = malloc(len + 2);
  1338. sprintf(temp, "%s\n", word_eol[2]);
  1339. PrintText(sess, temp);
  1340. write(sess->running_exec->myfd, temp, len + 1);
  1341. free(temp);
  1342. return TRUE;
  1343. }
  1344. #endif /* !__EMX__ */
  1345. /* convert ANSI escape color codes to mIRC codes */
  1346. static short escconv[] =
  1347. /* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 */
  1348. { 1,4,3,5,2,10,6,1, 1,7,9,8,12,11,13,1 };
  1349. static void
  1350. exec_handle_colors (char *buf, int len)
  1351. {
  1352. char numb[16];
  1353. char *nbuf;
  1354. int i = 0, j = 0, k = 0, firstn = 0, col, colf = 0, colb = 0;
  1355. int esc = FALSE, backc = FALSE, bold = FALSE;
  1356. /* any escape codes in this text? */
  1357. if (strchr (buf, 27) == 0)
  1358. return;
  1359. nbuf = malloc (len + 1);
  1360. while (i < len)
  1361. {
  1362. switch (buf[i])
  1363. {
  1364. case '\r':
  1365. break;
  1366. case 27:
  1367. esc = TRUE;
  1368. break;
  1369. case ';':
  1370. if (!esc)
  1371. goto norm;
  1372. backc = TRUE;
  1373. numb[k] = 0;
  1374. firstn = atoi (numb);
  1375. k = 0;
  1376. break;
  1377. case '[':
  1378. if (!esc)
  1379. goto norm;
  1380. break;
  1381. default:
  1382. if (esc)
  1383. {
  1384. if (buf[i] >= 'A' && buf[i] <= 'z')
  1385. {
  1386. if (buf[i] == 'm')
  1387. {
  1388. /* ^[[0m */
  1389. if (k == 0 || (numb[0] == '0' && k == 1))
  1390. {
  1391. nbuf[j] = '\017';
  1392. j++;
  1393. bold = FALSE;
  1394. goto cont;
  1395. }
  1396. numb[k] = 0;
  1397. col = atoi (numb);
  1398. backc = FALSE;
  1399. if (firstn == 1)
  1400. bold = TRUE;
  1401. if (firstn >= 30 && firstn <= 37)
  1402. colf = firstn - 30;
  1403. if (col >= 40)
  1404. {
  1405. colb = col - 40;
  1406. backc = TRUE;
  1407. }
  1408. if (col >= 30 && col <= 37)
  1409. colf = col - 30;
  1410. if (bold)
  1411. colf += 8;
  1412. if (backc)
  1413. {
  1414. colb = escconv[colb % 14];
  1415. colf = escconv[colf % 14];
  1416. j += sprintf (&nbuf[j], "\003%d,%02d", colf, colb);
  1417. } else
  1418. {
  1419. colf = escconv[colf % 14];
  1420. j += sprintf (&nbuf[j], "\003%02d", colf);
  1421. }
  1422. }
  1423. cont: esc = FALSE;
  1424. backc = FALSE;
  1425. k = 0;
  1426. } else
  1427. {
  1428. if (isdigit ((unsigned char) buf[i]) && k < (sizeof (numb) - 1))
  1429. {
  1430. numb[k] = buf[i];
  1431. k++;
  1432. }
  1433. }
  1434. } else
  1435. {
  1436. norm: nbuf[j] = buf[i];
  1437. j++;
  1438. }
  1439. }
  1440. i++;
  1441. }
  1442. nbuf[j] = 0;
  1443. memcpy (buf, nbuf, j + 1);
  1444. free (nbuf);
  1445. }
  1446. #ifndef HAVE_MEMRCHR
  1447. static void *
  1448. memrchr (const void *block, int c, size_t size)
  1449. {
  1450. unsigned char *p;
  1451. for (p = (unsigned char *)block + size; p != block; p--)
  1452. if (*p == c)
  1453. return p;
  1454. return 0;
  1455. }
  1456. #endif
  1457. static gboolean
  1458. exec_data (GIOChannel *source, GIOCondition condition, struct nbexec *s)
  1459. {
  1460. char *buf, *readpos, *rest;
  1461. int rd, len;
  1462. int sok = s->myfd;
  1463. len = s->buffill;
  1464. if (len) {
  1465. /* append new data to buffered incomplete line */
  1466. buf = malloc(len + 2050);
  1467. memcpy(buf, s->linebuf, len);
  1468. readpos = buf + len;
  1469. free(s->linebuf);
  1470. s->linebuf = NULL;
  1471. }
  1472. else
  1473. readpos = buf = malloc(2050);
  1474. rd = read (sok, readpos, 2048);
  1475. if (rd < 1)
  1476. {
  1477. /* The process has died */
  1478. kill(s->childpid, SIGKILL);
  1479. if (len) {
  1480. buf[len] = '\0';
  1481. exec_handle_colors(buf, len);
  1482. if (s->tochannel)
  1483. {
  1484. /* must turn off auto-completion temporarily */
  1485. unsigned int old = prefs.nickcompletion;
  1486. prefs.nickcompletion = 0;
  1487. handle_multiline (s->sess, buf, FALSE, TRUE);
  1488. prefs.nickcompletion = old;
  1489. }
  1490. else
  1491. PrintText (s->sess, buf);
  1492. }
  1493. free(buf);
  1494. waitpid (s->childpid, NULL, 0);
  1495. s->sess->running_exec = NULL;
  1496. fe_input_remove (s->iotag);
  1497. close (sok);
  1498. free (s);
  1499. return TRUE;
  1500. }
  1501. len += rd;
  1502. buf[len] = '\0';
  1503. rest = memrchr(buf, '\n', len);
  1504. if (rest)
  1505. rest++;
  1506. else
  1507. rest = buf;
  1508. if (*rest) {
  1509. s->buffill = len - (rest - buf); /* = strlen(rest) */
  1510. s->linebuf = malloc(s->buffill);
  1511. memcpy(s->linebuf, rest, s->buffill);
  1512. *rest = '\0';
  1513. len -= s->buffill; /* possibly 0 */
  1514. }
  1515. else
  1516. s->buffill = 0;
  1517. if (len) {
  1518. exec_handle_colors (buf, len);
  1519. if (s->tochannel)
  1520. handle_multiline (s->sess, buf, FALSE, TRUE);
  1521. else
  1522. PrintText (s->sess, buf);
  1523. }
  1524. free(buf);
  1525. return TRUE;
  1526. }
  1527. static int
  1528. cmd_exec (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1529. {
  1530. int tochannel = FALSE;
  1531. char *cmd = word_eol[2];
  1532. int fds[2], pid = 0;
  1533. struct nbexec *s;
  1534. int shell = TRUE;
  1535. int fd;
  1536. if (*cmd)
  1537. {
  1538. exec_check_process (sess);
  1539. if (sess->running_exec != NULL)
  1540. {
  1541. EMIT_SIGNAL (XP_TE_ALREADYPROCESS, sess, NULL, NULL, NULL, NULL, 0);
  1542. return TRUE;
  1543. }
  1544. if (!strcmp (word[2], "-d"))
  1545. {
  1546. if (!*word[3])
  1547. return FALSE;
  1548. cmd = word_eol[3];
  1549. shell = FALSE;
  1550. }
  1551. else if (!strcmp (word[2], "-o"))
  1552. {
  1553. if (!*word[3])
  1554. return FALSE;
  1555. cmd = word_eol[3];
  1556. tochannel = TRUE;
  1557. }
  1558. if (shell)
  1559. {
  1560. if (access ("/bin/sh", X_OK) != 0)
  1561. {
  1562. fe_message (_("I need /bin/sh to run!\n"), FE_MSG_ERROR);
  1563. return TRUE;
  1564. }
  1565. }
  1566. #ifdef __EMX__ /* if os/2 */
  1567. if (pipe (fds) < 0)
  1568. {
  1569. PrintText (sess, "Pipe create error\n");
  1570. return FALSE;
  1571. }
  1572. setmode (fds[0], O_BINARY);
  1573. setmode (fds[1], O_BINARY);
  1574. #else
  1575. if (socketpair (PF_UNIX, SOCK_STREAM, 0, fds) == -1)
  1576. {
  1577. PrintText (sess, "socketpair(2) failed\n");
  1578. return FALSE;
  1579. }
  1580. #endif
  1581. s = (struct nbexec *) malloc (sizeof (struct nbexec));
  1582. memset(s, 0, sizeof(*s));
  1583. s->myfd = fds[0];
  1584. s->tochannel = tochannel;
  1585. s->sess = sess;
  1586. pid = fork ();
  1587. if (pid == 0)
  1588. {
  1589. /* This is the child's context */
  1590. close (0);
  1591. close (1);
  1592. close (2);
  1593. /* Close parent's end of pipe */
  1594. close(s->myfd);
  1595. /* Copy the child end of the pipe to stdout and stderr */
  1596. dup2 (fds[1], 1);
  1597. dup2 (fds[1], 2);
  1598. /* Also copy it to stdin so we can write to it */
  1599. dup2 (fds[1], 0);
  1600. /* Now close all open file descriptors except stdin, stdout and stderr */
  1601. for (fd = 3; fd < 1024; fd++) close(fd);
  1602. /* Now we call /bin/sh to run our cmd ; made it more friendly -DC1 */
  1603. if (shell)
  1604. {
  1605. execl ("/bin/sh", "sh", "-c", cmd, NULL);
  1606. } else
  1607. {
  1608. char **argv;
  1609. int argc;
  1610. my_poptParseArgvString (cmd, &argc, &argv);
  1611. execvp (argv[0], argv);
  1612. }
  1613. /* not reached unless error */
  1614. /*printf("exec error\n");*/
  1615. fflush (stdout);
  1616. fflush (stdin);
  1617. _exit (0);
  1618. }
  1619. if (pid == -1)
  1620. {
  1621. /* Parent context, fork() failed */
  1622. PrintText (sess, "Error in fork(2)\n");
  1623. close(fds[0]);
  1624. close(fds[1]);
  1625. } else
  1626. {
  1627. /* Parent path */
  1628. close(fds[1]);
  1629. s->childpid = pid;
  1630. s->iotag = fe_input_add (s->myfd, FIA_READ|FIA_EX, exec_data, s);
  1631. sess->running_exec = s;
  1632. return TRUE;
  1633. }
  1634. }
  1635. return FALSE;
  1636. }
  1637. #endif
  1638. static int
  1639. cmd_flushq (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1640. {
  1641. sprintf (tbuf, "Flushing server send queue, %d bytes.\n", sess->server->sendq_len);
  1642. PrintText (sess, tbuf);
  1643. sess->server->flush_queue (sess->server);
  1644. return TRUE;
  1645. }
  1646. static int
  1647. cmd_quit (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1648. {
  1649. if (*word_eol[2])
  1650. sess->quitreason = word_eol[2];
  1651. sess->server->disconnect (sess, TRUE, -1);
  1652. sess->quitreason = NULL;
  1653. return 2;
  1654. }
  1655. static int
  1656. cmd_gate (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1657. {
  1658. char *server_name = word[2];
  1659. server *serv = sess->server;
  1660. if (*server_name)
  1661. {
  1662. char *port = word[3];
  1663. #ifdef USE_OPENSSL
  1664. serv->use_ssl = FALSE;
  1665. #endif
  1666. server_fill_her_up (serv);
  1667. if (*port)
  1668. serv->connect (serv, server_name, atoi (port), TRUE);
  1669. else
  1670. serv->connect (serv, server_name, 23, TRUE);
  1671. return TRUE;
  1672. }
  1673. return FALSE;
  1674. }
  1675. typedef struct
  1676. {
  1677. char *cmd;
  1678. session *sess;
  1679. } getvalinfo;
  1680. static void
  1681. get_int_cb (int cancel, int val, getvalinfo *info)
  1682. {
  1683. char buf[512];
  1684. if (!cancel)
  1685. {
  1686. snprintf (buf, sizeof (buf), "%s %d", info->cmd, val);
  1687. if (is_session (info->sess))
  1688. handle_command (info->sess, buf, FALSE);
  1689. }
  1690. free (info->cmd);
  1691. free (info);
  1692. }
  1693. static int
  1694. cmd_getint (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1695. {
  1696. getvalinfo *info;
  1697. if (!word[4][0])
  1698. return FALSE;
  1699. info = malloc (sizeof (*info));
  1700. info->cmd = strdup (word[3]);
  1701. info->sess = sess;
  1702. fe_get_int (word[4], atoi (word[2]), get_int_cb, info);
  1703. return TRUE;
  1704. }
  1705. static void
  1706. get_file_cb (char *cmd, char *file)
  1707. {
  1708. char buf[1024 + 128];
  1709. /* execute the command once per file, then once more with
  1710. no args */
  1711. if (file)
  1712. {
  1713. snprintf (buf, sizeof (buf), "%s %s", cmd, file);
  1714. handle_command (current_sess, buf, FALSE);
  1715. }
  1716. else
  1717. {
  1718. handle_command (current_sess, cmd, FALSE);
  1719. free (cmd);
  1720. }
  1721. }
  1722. static int
  1723. cmd_getfile (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1724. {
  1725. int idx = 2;
  1726. int flags = 0;
  1727. if (!word[3][0])
  1728. return FALSE;
  1729. if (!strcmp (word[2], "-folder"))
  1730. {
  1731. flags |= FRF_CHOOSEFOLDER;
  1732. idx++;
  1733. }
  1734. if (!strcmp (word[idx], "-multi"))
  1735. {
  1736. flags |= FRF_MULTIPLE;
  1737. idx++;
  1738. }
  1739. if (!strcmp (word[idx], "-save"))
  1740. {
  1741. flags |= FRF_WRITE;
  1742. idx++;
  1743. }
  1744. fe_get_file (word[idx+1], word[idx+2], (void *)get_file_cb, strdup (word[idx]), flags);
  1745. return TRUE;
  1746. }
  1747. static void
  1748. get_str_cb (int cancel, char *val, getvalinfo *info)
  1749. {
  1750. char buf[512];
  1751. if (!cancel)
  1752. {
  1753. snprintf (buf, sizeof (buf), "%s %s", info->cmd, val);
  1754. if (is_session (info->sess))
  1755. handle_command (info->sess, buf, FALSE);
  1756. }
  1757. free (info->cmd);
  1758. free (info);
  1759. }
  1760. static int
  1761. cmd_getstr (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1762. {
  1763. getvalinfo *info;
  1764. if (!word[4][0])
  1765. return FALSE;
  1766. info = malloc (sizeof (*info));
  1767. info->cmd = strdup (word[3]);
  1768. info->sess = sess;
  1769. fe_get_str (word[4], word[2], get_str_cb, info);
  1770. return TRUE;
  1771. }
  1772. static int
  1773. cmd_ghost (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1774. {
  1775. if (!word[2][0])
  1776. return FALSE;
  1777. sess->server->p_ns_ghost (sess->server, word[2], word[3]);
  1778. return TRUE;
  1779. }
  1780. static int
  1781. cmd_gui (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1782. {
  1783. switch (str_ihash (word[2]))
  1784. {
  1785. case 0x058b836e: fe_ctrl_gui (sess, 8, 0); break; /* APPLY */
  1786. case 0xac1eee45: fe_ctrl_gui (sess, 7, 2); break; /* ATTACH */
  1787. case 0x05a72f63: fe_ctrl_gui (sess, 4, atoi (word[3])); break; /* COLOR */
  1788. case 0xb06a1793: fe_ctrl_gui (sess, 7, 1); break; /* DETACH */
  1789. case 0x05cfeff0: fe_ctrl_gui (sess, 3, 0); break; /* FLASH */
  1790. case 0x05d154d8: fe_ctrl_gui (sess, 2, 0); break; /* FOCUS */
  1791. case 0x0030dd42: fe_ctrl_gui (sess, 0, 0); break; /* HIDE */
  1792. case 0x61addbe3: fe_ctrl_gui (sess, 5, 0); break; /* ICONIFY */
  1793. case 0xc0851aaa: fe_message (word[3], FE_MSG_INFO|FE_MSG_MARKUP); break; /* MSGBOX */
  1794. case 0x0035dafd: fe_ctrl_gui (sess, 1, 0); break; /* SHOW */
  1795. case 0x0033155f: /* MENU */
  1796. if (!strcasecmp (word[3], "TOGGLE"))
  1797. fe_ctrl_gui (sess, 6, 0);
  1798. else
  1799. return FALSE;
  1800. break;
  1801. default:
  1802. return FALSE;
  1803. }
  1804. return TRUE;
  1805. }
  1806. typedef struct
  1807. {
  1808. int longfmt;
  1809. int i, t;
  1810. char *buf;
  1811. } help_list;
  1812. static void
  1813. show_help_line (session *sess, help_list *hl, char *name, char *usage)
  1814. {
  1815. int j, len, max;
  1816. char *p;
  1817. if (name[0] == '.') /* hidden command? */
  1818. return;
  1819. if (hl->longfmt) /* long format for /HELP -l */
  1820. {
  1821. if (!usage || usage[0] == 0)
  1822. PrintTextf (sess, " \0034%s\003 :\n", name);
  1823. else
  1824. PrintTextf (sess, " \0034%s\003 : %s\n", name, _(usage));
  1825. return;
  1826. }
  1827. /* append the name into buffer, but convert to uppercase */
  1828. len = strlen (hl->buf);
  1829. p = name;
  1830. while (*p)
  1831. {
  1832. hl->buf[len] = toupper ((unsigned char) *p);
  1833. len++;
  1834. p++;
  1835. }
  1836. hl->buf[len] = 0;
  1837. hl->t++;
  1838. if (hl->t == 5)
  1839. {
  1840. hl->t = 0;
  1841. strcat (hl->buf, "\n");
  1842. PrintText (sess, hl->buf);
  1843. hl->buf[0] = ' ';
  1844. hl->buf[1] = ' ';
  1845. hl->buf[2] = 0;
  1846. } else
  1847. {
  1848. /* append some spaces after the command name */
  1849. max = strlen (name);
  1850. if (max < 10)
  1851. {
  1852. max = 10 - max;
  1853. for (j = 0; j < max; j++)
  1854. {
  1855. hl->buf[len] = ' ';
  1856. len++;
  1857. hl->buf[len] = 0;
  1858. }
  1859. }
  1860. }
  1861. }
  1862. static int
  1863. cmd_help (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1864. {
  1865. int i = 0, longfmt = 0;
  1866. char *helpcmd = "";
  1867. GSList *list;
  1868. if (tbuf)
  1869. helpcmd = word[2];
  1870. if (*helpcmd && strcmp (helpcmd, "-l") == 0)
  1871. longfmt = 1;
  1872. if (*helpcmd && !longfmt)
  1873. {
  1874. help (sess, tbuf, helpcmd, FALSE);
  1875. } else
  1876. {
  1877. struct popup *pop;
  1878. char *buf = malloc (4096);
  1879. help_list hl;
  1880. hl.longfmt = longfmt;
  1881. hl.buf = buf;
  1882. PrintTextf (sess, "\n%s\n\n", _("Commands Available:"));
  1883. buf[0] = ' ';
  1884. buf[1] = ' ';
  1885. buf[2] = 0;
  1886. hl.t = 0;
  1887. hl.i = 0;
  1888. while (xc_cmds[i].name)
  1889. {
  1890. show_help_line (sess, &hl, xc_cmds[i].name, xc_cmds[i].help);
  1891. i++;
  1892. }
  1893. strcat (buf, "\n");
  1894. PrintText (sess, buf);
  1895. PrintTextf (sess, "\n%s\n\n", _("User defined commands:"));
  1896. buf[0] = ' ';
  1897. buf[1] = ' ';
  1898. buf[2] = 0;
  1899. hl.t = 0;
  1900. hl.i = 0;
  1901. list = command_list;
  1902. while (list)
  1903. {
  1904. pop = list->data;
  1905. show_help_line (sess, &hl, pop->name, pop->cmd);
  1906. list = list->next;
  1907. }
  1908. strcat (buf, "\n");
  1909. PrintText (sess, buf);
  1910. PrintTextf (sess, "\n%s\n\n", _("Plugin defined commands:"));
  1911. buf[0] = ' ';
  1912. buf[1] = ' ';
  1913. buf[2] = 0;
  1914. hl.t = 0;
  1915. hl.i = 0;
  1916. plugin_command_foreach (sess, &hl, (void *)show_help_line);
  1917. strcat (buf, "\n");
  1918. PrintText (sess, buf);
  1919. free (buf);
  1920. PrintTextf (sess, "\n%s\n\n", _("Type /HELP <command> for more information, or /HELP -l"));
  1921. }
  1922. return TRUE;
  1923. }
  1924. static int
  1925. cmd_id (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1926. {
  1927. if (word[2][0])
  1928. {
  1929. sess->server->p_ns_identify (sess->server, word[2]);
  1930. return TRUE;
  1931. }
  1932. return FALSE;
  1933. }
  1934. static int
  1935. cmd_ignore (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  1936. {
  1937. int i;
  1938. int type = 0;
  1939. int quiet = 0;
  1940. char *mask;
  1941. if (!*word[2])
  1942. {
  1943. ignore_showlist (sess);
  1944. return TRUE;
  1945. }
  1946. if (!*word[3])
  1947. return FALSE;
  1948. i = 3;
  1949. while (1)
  1950. {
  1951. if (!*word[i])
  1952. {
  1953. if (type == 0)
  1954. return FALSE;
  1955. mask = word[2];
  1956. if (strchr (mask, '?') == NULL &&
  1957. strchr (mask, '*') == NULL &&
  1958. userlist_find (sess, mask))
  1959. {
  1960. mask = tbuf;
  1961. snprintf (tbuf, TBUFSIZE, "%s!*@*", word[2]);
  1962. }
  1963. i = ignore_add (mask, type);
  1964. if (quiet)
  1965. return TRUE;
  1966. switch (i)
  1967. {
  1968. case 1:
  1969. EMIT_SIGNAL (XP_TE_IGNOREADD, sess, mask, NULL, NULL, NULL, 0);
  1970. break;
  1971. case 2: /* old ignore changed */
  1972. EMIT_SIGNAL (XP_TE_IGNORECHANGE, sess, mask, NULL, NULL, NULL, 0);
  1973. }
  1974. return TRUE;
  1975. }
  1976. if (!strcasecmp (word[i], "UNIGNORE"))
  1977. type |= IG_UNIG;
  1978. else if (!strcasecmp (word[i], "ALL"))
  1979. type |= IG_PRIV | IG_NOTI | IG_CHAN | IG_CTCP | IG_INVI | IG_DCC;
  1980. else if (!strcasecmp (word[i], "PRIV"))
  1981. type |= IG_PRIV;
  1982. else if (!strcasecmp (word[i], "NOTI"))
  1983. type |= IG_NOTI;
  1984. else if (!strcasecmp (word[i], "CHAN"))
  1985. type |= IG_CHAN;
  1986. else if (!strcasecmp (word[i], "CTCP"))
  1987. type |= IG_CTCP;
  1988. else if (!strcasecmp (word[i], "INVI"))
  1989. type |= IG_INVI;
  1990. else if (!strcasecmp (word[i], "QUIET"))
  1991. quiet = 1;
  1992. else if (!strcasecmp (word[i], "NOSAVE"))
  1993. type |= IG_NOSAVE;
  1994. else if (!strcasecmp (word[i], "DCC"))
  1995. type |= IG_DCC;
  1996. else
  1997. {
  1998. sprintf (tbuf, _("Unknown arg '%s' ignored."), word[i]);
  1999. PrintText (sess, tbuf);
  2000. }
  2001. i++;
  2002. }
  2003. }
  2004. static int
  2005. cmd_invite (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2006. {
  2007. if (!*word[2])
  2008. return FALSE;
  2009. if (*word[3])
  2010. sess->server->p_invite (sess->server, word[3], word[2]);
  2011. else
  2012. sess->server->p_invite (sess->server, sess->channel, word[2]);
  2013. return TRUE;
  2014. }
  2015. static int
  2016. cmd_join (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2017. {
  2018. char *chan = word[2];
  2019. if (*chan)
  2020. {
  2021. char *po, *pass = word[3];
  2022. sess->server->p_join (sess->server, chan, pass);
  2023. if (sess->channel[0] == 0 && sess->waitchannel[0])
  2024. {
  2025. po = strchr (chan, ',');
  2026. if (po)
  2027. *po = 0;
  2028. safe_strcpy (sess->waitchannel, chan, CHANLEN);
  2029. }
  2030. return TRUE;
  2031. }
  2032. return FALSE;
  2033. }
  2034. static int
  2035. cmd_kick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2036. {
  2037. char *nick = word[2];
  2038. char *reason = word_eol[3];
  2039. if (*nick)
  2040. {
  2041. sess->server->p_kick (sess->server, sess->channel, nick, reason);
  2042. return TRUE;
  2043. }
  2044. return FALSE;
  2045. }
  2046. static int
  2047. cmd_kickban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2048. {
  2049. char *nick = word[2];
  2050. char *reason = word_eol[3];
  2051. struct User *user;
  2052. if (*nick)
  2053. {
  2054. /* if the reason is a 1 digit number, treat it as a bantype */
  2055. user = userlist_find (sess, nick);
  2056. if (isdigit ((unsigned char) reason[0]) && reason[1] == 0)
  2057. {
  2058. ban (sess, tbuf, nick, reason, (user && user->op));
  2059. reason[0] = 0;
  2060. } else
  2061. ban (sess, tbuf, nick, "", (user && user->op));
  2062. sess->server->p_kick (sess->server, sess->channel, nick, reason);
  2063. return TRUE;
  2064. }
  2065. return FALSE;
  2066. }
  2067. static int
  2068. cmd_killall (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2069. {
  2070. xchat_exit();
  2071. return 2;
  2072. }
  2073. static int
  2074. cmd_lagcheck (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2075. {
  2076. lag_check ();
  2077. return TRUE;
  2078. }
  2079. static void
  2080. lastlog (session *sess, char *search, gboolean regexp)
  2081. {
  2082. session *lastlog_sess;
  2083. if (!is_session (sess))
  2084. return;
  2085. lastlog_sess = find_dialog (sess->server, "(lastlog)");
  2086. if (!lastlog_sess)
  2087. lastlog_sess = new_ircwindow (sess->server, "(lastlog)", SESS_DIALOG, 0);
  2088. lastlog_sess->lastlog_sess = sess;
  2089. lastlog_sess->lastlog_regexp = regexp; /* remember the search type */
  2090. fe_text_clear (lastlog_sess, 0);
  2091. fe_lastlog (sess, lastlog_sess, search, regexp);
  2092. }
  2093. static int
  2094. cmd_lastlog (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2095. {
  2096. if (*word_eol[2])
  2097. {
  2098. if (!strcmp (word[2], "-r"))
  2099. lastlog (sess, word_eol[3], TRUE);
  2100. else
  2101. lastlog (sess, word_eol[2], FALSE);
  2102. return TRUE;
  2103. }
  2104. return FALSE;
  2105. }
  2106. static int
  2107. cmd_list (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2108. {
  2109. sess->server->p_list_channels (sess->server, word_eol[2], 1);
  2110. return TRUE;
  2111. }
  2112. gboolean
  2113. load_perform_file (session *sess, char *file)
  2114. {
  2115. char tbuf[1024 + 4];
  2116. char *nl;
  2117. FILE *fp;
  2118. fp = xchat_fopen_file (file, "r", XOF_FULLPATH);
  2119. if (!fp)
  2120. return FALSE;
  2121. tbuf[1024] = 0;
  2122. while (fgets (tbuf, 1024, fp))
  2123. {
  2124. nl = strchr (tbuf, '\n');
  2125. if (nl == tbuf) /* skip empty commands */
  2126. continue;
  2127. if (nl)
  2128. *nl = 0;
  2129. if (tbuf[0] == prefs.cmdchar[0])
  2130. handle_command (sess, tbuf + 1, TRUE);
  2131. else
  2132. handle_command (sess, tbuf, TRUE);
  2133. }
  2134. fclose (fp);
  2135. return TRUE;
  2136. }
  2137. static int
  2138. cmd_load (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2139. {
  2140. char *error, *arg, *file;
  2141. int len;
  2142. if (!word[2][0])
  2143. return FALSE;
  2144. if (strcmp (word[2], "-e") == 0)
  2145. {
  2146. file = expand_homedir (word[3]);
  2147. if (!load_perform_file (sess, file))
  2148. {
  2149. PrintTextf (sess, _("Cannot access %s\n"), file);
  2150. PrintText (sess, errorstring (errno));
  2151. }
  2152. free (file);
  2153. return TRUE;
  2154. }
  2155. #ifdef USE_PLUGIN
  2156. len = strlen (word[2]);
  2157. #ifdef WIN32
  2158. if (len > 4 && strcasecmp (".dll", word[2] + len - 4) == 0)
  2159. #else
  2160. #if defined(__hpux)
  2161. if (len > 3 && strcasecmp (".sl", word[2] + len - 3) == 0)
  2162. #else
  2163. if (len > 3 && strcasecmp (".so", word[2] + len - 3) == 0)
  2164. #endif
  2165. #endif
  2166. {
  2167. arg = NULL;
  2168. if (word_eol[3][0])
  2169. arg = word_eol[3];
  2170. file = expand_homedir (word[2]);
  2171. error = plugin_load (sess, file, arg);
  2172. free (file);
  2173. if (error)
  2174. PrintText (sess, error);
  2175. return TRUE;
  2176. }
  2177. #endif
  2178. sprintf (tbuf, "Unknown file type %s. Maybe you need to install the Perl or Python plugin?\n", word[2]);
  2179. PrintText (sess, tbuf);
  2180. return FALSE;
  2181. }
  2182. static int
  2183. cmd_me (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2184. {
  2185. char *act = word_eol[2];
  2186. if (!(*act))
  2187. return FALSE;
  2188. if (sess->type == SESS_SERVER)
  2189. {
  2190. notj_msg (sess);
  2191. return TRUE;
  2192. }
  2193. snprintf (tbuf, TBUFSIZE, "\001ACTION %s\001\r", act);
  2194. /* first try through DCC CHAT */
  2195. if (dcc_write_chat (sess->channel, tbuf))
  2196. {
  2197. /* print it to screen */
  2198. inbound_action (sess, sess->channel, sess->server->nick, "", act, TRUE, FALSE);
  2199. } else
  2200. {
  2201. /* DCC CHAT failed, try through server */
  2202. if (sess->server->connected)
  2203. {
  2204. sess->server->p_action (sess->server, sess->channel, act);
  2205. /* print it to screen */
  2206. inbound_action (sess, sess->channel, sess->server->nick, "", act, TRUE, FALSE);
  2207. } else
  2208. {
  2209. notc_msg (sess);
  2210. }
  2211. }
  2212. return TRUE;
  2213. }
  2214. static int
  2215. cmd_mode (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2216. {
  2217. /* +channel channels are dying, let those servers whine about modes.
  2218. * return info about current channel if available and no info is given */
  2219. if ((*word[2] == '+') || (*word[2] == 0) || (!is_channel(sess->server, word[2]) &&
  2220. !(rfc_casecmp(sess->server->nick, word[2]) == 0)))
  2221. {
  2222. if(sess->channel[0] == 0)
  2223. return FALSE;
  2224. sess->server->p_mode (sess->server, sess->channel, word_eol[2]);
  2225. }
  2226. else
  2227. sess->server->p_mode (sess->server, word[2], word_eol[3]);
  2228. return TRUE;
  2229. }
  2230. static int
  2231. mop_cb (struct User *user, multidata *data)
  2232. {
  2233. if (!user->op)
  2234. {
  2235. data->nicks[data->i] = user->nick;
  2236. data->i++;
  2237. }
  2238. return TRUE;
  2239. }
  2240. static int
  2241. cmd_mop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2242. {
  2243. char **nicks = malloc (sizeof (char *) * (sess->total - sess->ops));
  2244. multidata data;
  2245. data.nicks = nicks;
  2246. data.i = 0;
  2247. tree_foreach (sess->usertree, (tree_traverse_func *)mop_cb, &data);
  2248. send_channel_modes (sess, tbuf, nicks, 0, data.i, '+', 'o', 0);
  2249. free (nicks);
  2250. return TRUE;
  2251. }
  2252. static int
  2253. cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2254. {
  2255. char *nick = word[2];
  2256. char *msg = word_eol[3];
  2257. struct session *newsess;
  2258. if (*nick)
  2259. {
  2260. if (*msg)
  2261. {
  2262. if (strcmp (nick, ".") == 0)
  2263. { /* /msg the last nick /msg'ed */
  2264. if (sess->lastnick[0])
  2265. nick = sess->lastnick;
  2266. } else
  2267. {
  2268. safe_strcpy (sess->lastnick, nick, NICKLEN); /* prime the last nick memory */
  2269. }
  2270. if (*nick == '=')
  2271. {
  2272. nick++;
  2273. if (!dcc_write_chat (nick, msg))
  2274. {
  2275. EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
  2276. return TRUE;
  2277. }
  2278. } else
  2279. {
  2280. if (!sess->server->connected)
  2281. {
  2282. notc_msg (sess);
  2283. return TRUE;
  2284. }
  2285. sess->server->p_message (sess->server, nick, msg);
  2286. }
  2287. newsess = find_dialog (sess->server, nick);
  2288. if (!newsess)
  2289. newsess = find_channel (sess->server, nick);
  2290. if (newsess)
  2291. inbound_chanmsg (newsess->server, NULL, newsess->channel,
  2292. newsess->server->nick, msg, TRUE, FALSE);
  2293. else
  2294. {
  2295. /* mask out passwords */
  2296. if (strcasecmp (nick, "nickserv") == 0 &&
  2297. strncasecmp (msg, "identify ", 9) == 0)
  2298. msg = "identify ****";
  2299. EMIT_SIGNAL (XP_TE_MSGSEND, sess, nick, msg, NULL, NULL, 0);
  2300. }
  2301. return TRUE;
  2302. }
  2303. }
  2304. return FALSE;
  2305. }
  2306. static int
  2307. cmd_names (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2308. {
  2309. if (*word[2])
  2310. sess->server->p_names (sess->server, word[2]);
  2311. else
  2312. sess->server->p_names (sess->server, sess->channel);
  2313. return TRUE;
  2314. }
  2315. static int
  2316. cmd_nctcp (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2317. {
  2318. if (*word_eol[3])
  2319. {
  2320. sess->server->p_nctcp (sess->server, word[2], word_eol[3]);
  2321. return TRUE;
  2322. }
  2323. return FALSE;
  2324. }
  2325. static int
  2326. cmd_newserver (struct session *sess, char *tbuf, char *word[],
  2327. char *word_eol[])
  2328. {
  2329. if (strcmp (word[2], "-noconnect") == 0)
  2330. {
  2331. new_ircwindow (NULL, word[3], SESS_SERVER, 0);
  2332. return TRUE;
  2333. }
  2334. sess = new_ircwindow (NULL, NULL, SESS_SERVER, 0);
  2335. cmd_server (sess, tbuf, word, word_eol);
  2336. return TRUE;
  2337. }
  2338. static int
  2339. cmd_nick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2340. {
  2341. char *nick = word[2];
  2342. if (*nick)
  2343. {
  2344. if (sess->server->connected)
  2345. sess->server->p_change_nick (sess->server, nick);
  2346. else
  2347. inbound_newnick (sess->server, sess->server->nick, nick, TRUE);
  2348. return TRUE;
  2349. }
  2350. return FALSE;
  2351. }
  2352. static int
  2353. cmd_notice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2354. {
  2355. if (*word[2] && *word_eol[3])
  2356. {
  2357. sess->server->p_notice (sess->server, word[2], word_eol[3]);
  2358. EMIT_SIGNAL (XP_TE_NOTICESEND, sess, word[2], word_eol[3], NULL, NULL, 0);
  2359. return TRUE;
  2360. }
  2361. return FALSE;
  2362. }
  2363. static int
  2364. cmd_notify (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2365. {
  2366. int i = 1;
  2367. char *net = NULL;
  2368. if (*word[2])
  2369. {
  2370. if (strcmp (word[2], "-n") == 0) /* comma sep network list */
  2371. {
  2372. net = word[3];
  2373. i += 2;
  2374. }
  2375. while (1)
  2376. {
  2377. i++;
  2378. if (!*word[i])
  2379. break;
  2380. if (notify_deluser (word[i]))
  2381. {
  2382. EMIT_SIGNAL (XP_TE_DELNOTIFY, sess, word[i], NULL, NULL, NULL, 0);
  2383. return TRUE;
  2384. }
  2385. if (net && strcmp (net, "ASK") == 0)
  2386. fe_notify_ask (word[i], NULL);
  2387. else
  2388. {
  2389. notify_adduser (word[i], net);
  2390. EMIT_SIGNAL (XP_TE_ADDNOTIFY, sess, word[i], NULL, NULL, NULL, 0);
  2391. }
  2392. }
  2393. } else
  2394. notify_showlist (sess);
  2395. return TRUE;
  2396. }
  2397. static int
  2398. cmd_op (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2399. {
  2400. int i = 2;
  2401. while (1)
  2402. {
  2403. if (!*word[i])
  2404. {
  2405. if (i == 2)
  2406. return FALSE;
  2407. send_channel_modes (sess, tbuf, word, 2, i, '+', 'o', 0);
  2408. return TRUE;
  2409. }
  2410. i++;
  2411. }
  2412. }
  2413. static int
  2414. cmd_part (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2415. {
  2416. char *chan = word[2];
  2417. char *reason = word_eol[3];
  2418. if (!*chan)
  2419. chan = sess->channel;
  2420. if ((*chan) && is_channel (sess->server, chan))
  2421. {
  2422. if (reason[0] == 0)
  2423. reason = NULL;
  2424. server_sendpart (sess->server, chan, reason);
  2425. return TRUE;
  2426. }
  2427. return FALSE;
  2428. }
  2429. static int
  2430. cmd_ping (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2431. {
  2432. char timestring[64];
  2433. unsigned long tim;
  2434. char *to = word[2];
  2435. tim = make_ping_time ();
  2436. snprintf (timestring, sizeof (timestring), "%lu", tim);
  2437. sess->server->p_ping (sess->server, to, timestring);
  2438. return TRUE;
  2439. }
  2440. void
  2441. open_query (server *serv, char *nick, gboolean focus_existing)
  2442. {
  2443. session *sess;
  2444. sess = find_dialog (serv, nick);
  2445. if (!sess)
  2446. new_ircwindow (serv, nick, SESS_DIALOG, 1);
  2447. else if (focus_existing)
  2448. fe_ctrl_gui (sess, 2, 0); /* bring-to-front */
  2449. }
  2450. static int
  2451. cmd_query (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2452. {
  2453. char *nick = word[2];
  2454. gboolean focus = TRUE;
  2455. if (strcmp (word[2], "-nofocus") == 0)
  2456. {
  2457. nick = word[3];
  2458. focus = FALSE;
  2459. }
  2460. if (*nick && !is_channel (sess->server, nick))
  2461. {
  2462. open_query (sess->server, nick, focus);
  2463. return TRUE;
  2464. }
  2465. return FALSE;
  2466. }
  2467. static int
  2468. cmd_quote (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2469. {
  2470. char *raw = word_eol[2];
  2471. return sess->server->p_raw (sess->server, raw);
  2472. }
  2473. static int
  2474. cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2475. {
  2476. int tmp = prefs.recon_delay;
  2477. GSList *list;
  2478. server *serv = sess->server;
  2479. prefs.recon_delay = 0;
  2480. if (!strcasecmp (word[2], "ALL"))
  2481. {
  2482. list = serv_list;
  2483. while (list)
  2484. {
  2485. serv = list->data;
  2486. if (serv->connected)
  2487. serv->auto_reconnect (serv, TRUE, -1);
  2488. list = list->next;
  2489. }
  2490. }
  2491. /* If it isn't "ALL" and there is something
  2492. there it *should* be a server they are trying to connect to*/
  2493. else if (*word[2])
  2494. {
  2495. int offset = 0;
  2496. #ifdef USE_OPENSSL
  2497. int use_ssl = FALSE;
  2498. if (strcmp (word[2], "-ssl") == 0)
  2499. {
  2500. use_ssl = TRUE;
  2501. offset++; /* args move up by 1 word */
  2502. }
  2503. serv->use_ssl = use_ssl;
  2504. serv->accept_invalid_cert = TRUE;
  2505. #endif
  2506. if (*word[4+offset])
  2507. safe_strcpy (serv->password, word[4+offset], sizeof (serv->password));
  2508. if (*word[3+offset])
  2509. serv->port = atoi (word[3+offset]);
  2510. safe_strcpy (serv->hostname, word[2+offset], sizeof (serv->hostname));
  2511. serv->auto_reconnect (serv, TRUE, -1);
  2512. }
  2513. else
  2514. {
  2515. serv->auto_reconnect (serv, TRUE, -1);
  2516. }
  2517. prefs.recon_delay = tmp;
  2518. return TRUE;
  2519. }
  2520. static int
  2521. cmd_recv (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2522. {
  2523. if (*word_eol[2])
  2524. {
  2525. sess->server->p_inline (sess->server, word_eol[2], strlen (word_eol[2]));
  2526. return TRUE;
  2527. }
  2528. return FALSE;
  2529. }
  2530. static int
  2531. cmd_say (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2532. {
  2533. char *speech = word_eol[2];
  2534. if (*speech)
  2535. {
  2536. handle_say (sess, speech, FALSE);
  2537. return TRUE;
  2538. }
  2539. return FALSE;
  2540. }
  2541. static int
  2542. cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2543. {
  2544. guint32 addr;
  2545. socklen_t len;
  2546. struct sockaddr_in SAddr;
  2547. if (!word[2][0])
  2548. return FALSE;
  2549. addr = dcc_get_my_address ();
  2550. if (addr == 0)
  2551. {
  2552. /* use the one from our connected server socket */
  2553. memset (&SAddr, 0, sizeof (struct sockaddr_in));
  2554. len = sizeof (SAddr);
  2555. getsockname (sess->server->sok, (struct sockaddr *) &SAddr, &len);
  2556. addr = SAddr.sin_addr.s_addr;
  2557. }
  2558. addr = ntohl (addr);
  2559. if ((addr & 0xffff0000) == 0xc0a80000 || /* 192.168.x.x */
  2560. (addr & 0xff000000) == 0x0a000000) /* 10.x.x.x */
  2561. /* we got a private net address, let's PSEND or it'll fail */
  2562. snprintf (tbuf, 512, "DCC PSEND %s", word_eol[2]);
  2563. else
  2564. snprintf (tbuf, 512, "DCC SEND %s", word_eol[2]);
  2565. handle_command (sess, tbuf, FALSE);
  2566. return TRUE;
  2567. }
  2568. static int
  2569. cmd_setcursor (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2570. {
  2571. int delta = FALSE;
  2572. if (*word[2])
  2573. {
  2574. if (word[2][0] == '-' || word[2][0] == '+')
  2575. delta = TRUE;
  2576. fe_set_inputbox_cursor (sess, delta, atoi (word[2]));
  2577. return TRUE;
  2578. }
  2579. return FALSE;
  2580. }
  2581. static int
  2582. cmd_settab (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2583. {
  2584. if (*word_eol[2])
  2585. {
  2586. strcpy (tbuf, sess->channel);
  2587. safe_strcpy (sess->channel, word_eol[2], CHANLEN);
  2588. fe_set_channel (sess);
  2589. strcpy (sess->channel, tbuf);
  2590. }
  2591. return TRUE;
  2592. }
  2593. static int
  2594. cmd_settext (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2595. {
  2596. fe_set_inputbox_contents (sess, word_eol[2]);
  2597. return TRUE;
  2598. }
  2599. static int
  2600. cmd_splay (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2601. {
  2602. if (*word[2])
  2603. {
  2604. sound_play (word[2], FALSE);
  2605. return TRUE;
  2606. }
  2607. return FALSE;
  2608. }
  2609. static int
  2610. parse_irc_url (char *url, char *server_name[], char *port[], char *channel[], int *use_ssl)
  2611. {
  2612. char *co;
  2613. #ifdef USE_OPENSSL
  2614. if (strncasecmp ("ircs://", url, 7) == 0)
  2615. {
  2616. *use_ssl = TRUE;
  2617. *server_name = url + 7;
  2618. goto urlserv;
  2619. }
  2620. #endif
  2621. if (strncasecmp ("irc://", url, 6) == 0)
  2622. {
  2623. *server_name = url + 6;
  2624. #ifdef USE_OPENSSL
  2625. urlserv:
  2626. #endif
  2627. /* check for port */
  2628. co = strchr (*server_name, ':');
  2629. if (co)
  2630. {
  2631. *port = co + 1;
  2632. *co = 0;
  2633. } else
  2634. co = *server_name;
  2635. /* check for channel - mirc style */
  2636. co = strchr (co + 1, '/');
  2637. if (co)
  2638. {
  2639. *co = 0;
  2640. co++;
  2641. if (*co == '#')
  2642. *channel = co+1;
  2643. else
  2644. *channel = co;
  2645. }
  2646. return TRUE;
  2647. }
  2648. return FALSE;
  2649. }
  2650. static int
  2651. cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2652. {
  2653. int offset = 0;
  2654. char *server_name = NULL;
  2655. char *port = NULL;
  2656. char *pass = NULL;
  2657. char *channel = NULL;
  2658. int use_ssl = FALSE;
  2659. int is_url = TRUE;
  2660. server *serv = sess->server;
  2661. #ifdef USE_OPENSSL
  2662. /* BitchX uses -ssl, mIRC uses -e, let's support both */
  2663. if (strcmp (word[2], "-ssl") == 0 || strcmp (word[2], "-e") == 0)
  2664. {
  2665. use_ssl = TRUE;
  2666. offset++; /* args move up by 1 word */
  2667. }
  2668. #endif
  2669. if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &use_ssl))
  2670. {
  2671. is_url = FALSE;
  2672. server_name = word[2 + offset];
  2673. }
  2674. if (port)
  2675. pass = word[3 + offset];
  2676. else
  2677. {
  2678. port = word[3 + offset];
  2679. pass = word[4 + offset];
  2680. }
  2681. if (!(*server_name))
  2682. return FALSE;
  2683. sess->server->network = NULL;
  2684. /* dont clear it for /servchan */
  2685. if (strncasecmp (word_eol[1], "SERVCHAN ", 9))
  2686. sess->willjoinchannel[0] = 0;
  2687. if (channel)
  2688. {
  2689. sess->willjoinchannel[0] = '#';
  2690. safe_strcpy ((sess->willjoinchannel + 1), channel, (CHANLEN - 1));
  2691. }
  2692. /* support +7000 style ports like mIRC */
  2693. if (port[0] == '+')
  2694. {
  2695. port++;
  2696. #ifdef USE_OPENSSL
  2697. use_ssl = TRUE;
  2698. #endif
  2699. }
  2700. if (*pass)
  2701. {
  2702. safe_strcpy (serv->password, pass, sizeof (serv->password));
  2703. }
  2704. #ifdef USE_OPENSSL
  2705. serv->use_ssl = use_ssl;
  2706. serv->accept_invalid_cert = TRUE;
  2707. #endif
  2708. /* try to connect by Network name */
  2709. if (servlist_connect_by_netname (sess, server_name, !is_url))
  2710. return TRUE;
  2711. if (*port)
  2712. {
  2713. serv->connect (serv, server_name, atoi (port), FALSE);
  2714. } else
  2715. {
  2716. /* -1 for default port */
  2717. serv->connect (serv, server_name, -1, FALSE);
  2718. }
  2719. /* try to associate this connection with a listed network */
  2720. if (!serv->network)
  2721. /* search for this hostname in the entire server list */
  2722. serv->network = servlist_net_find_from_server (server_name);
  2723. /* may return NULL, but that's OK */
  2724. return TRUE;
  2725. }
  2726. static int
  2727. cmd_servchan (struct session *sess, char *tbuf, char *word[],
  2728. char *word_eol[])
  2729. {
  2730. int offset = 0;
  2731. #ifdef USE_OPENSSL
  2732. if (strcmp (word[2], "-ssl") == 0)
  2733. offset++;
  2734. #endif
  2735. if (*word[4 + offset])
  2736. {
  2737. safe_strcpy (sess->willjoinchannel, word[4 + offset], CHANLEN);
  2738. return cmd_server (sess, tbuf, word, word_eol);
  2739. }
  2740. return FALSE;
  2741. }
  2742. static int
  2743. cmd_topic (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2744. {
  2745. if (word[2][0] && is_channel (sess->server, word[2]))
  2746. sess->server->p_topic (sess->server, word[2], word_eol[3]);
  2747. else
  2748. sess->server->p_topic (sess->server, sess->channel, word_eol[2]);
  2749. return TRUE;
  2750. }
  2751. static int
  2752. cmd_tray (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2753. {
  2754. if (strcmp (word[2], "-b") == 0)
  2755. {
  2756. fe_tray_set_balloon (word[3], word[4][0] ? word[4] : NULL);
  2757. return TRUE;
  2758. }
  2759. if (strcmp (word[2], "-t") == 0)
  2760. {
  2761. fe_tray_set_tooltip (word[3][0] ? word[3] : NULL);
  2762. return TRUE;
  2763. }
  2764. if (strcmp (word[2], "-i") == 0)
  2765. {
  2766. fe_tray_set_icon (atoi (word[3]));
  2767. return TRUE;
  2768. }
  2769. if (strcmp (word[2], "-f") != 0)
  2770. return FALSE;
  2771. if (!word[3][0])
  2772. {
  2773. fe_tray_set_file (NULL); /* default xchat icon */
  2774. return TRUE;
  2775. }
  2776. if (!word[4][0])
  2777. {
  2778. fe_tray_set_file (word[3]); /* fixed custom icon */
  2779. return TRUE;
  2780. }
  2781. /* flash between 2 icons */
  2782. fe_tray_set_flash (word[4], word[5][0] ? word[5] : NULL, atoi (word[3]));
  2783. return TRUE;
  2784. }
  2785. static int
  2786. cmd_unignore (struct session *sess, char *tbuf, char *word[],
  2787. char *word_eol[])
  2788. {
  2789. char *mask = word[2];
  2790. char *arg = word[3];
  2791. if (*mask)
  2792. {
  2793. if (ignore_del (mask, NULL))
  2794. {
  2795. if (strcasecmp (arg, "QUIET"))
  2796. EMIT_SIGNAL (XP_TE_IGNOREREMOVE, sess, mask, NULL, NULL, NULL, 0);
  2797. }
  2798. return TRUE;
  2799. }
  2800. return FALSE;
  2801. }
  2802. static int
  2803. cmd_unload (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2804. {
  2805. #ifdef USE_PLUGIN
  2806. int len, by_file = FALSE;
  2807. len = strlen (word[2]);
  2808. #ifdef WIN32
  2809. if (len > 4 && strcasecmp (word[2] + len - 4, ".dll") == 0)
  2810. #else
  2811. #if defined(__hpux)
  2812. if (len > 3 && strcasecmp (word[2] + len - 3, ".sl") == 0)
  2813. #else
  2814. if (len > 3 && strcasecmp (word[2] + len - 3, ".so") == 0)
  2815. #endif
  2816. #endif
  2817. by_file = TRUE;
  2818. switch (plugin_kill (word[2], by_file))
  2819. {
  2820. case 0:
  2821. PrintText (sess, _("No such plugin found.\n"));
  2822. break;
  2823. case 1:
  2824. return TRUE;
  2825. case 2:
  2826. PrintText (sess, _("That plugin is refusing to unload.\n"));
  2827. break;
  2828. }
  2829. #endif
  2830. return FALSE;
  2831. }
  2832. static server *
  2833. find_server_from_hostname (char *hostname)
  2834. {
  2835. GSList *list = serv_list;
  2836. server *serv;
  2837. while (list)
  2838. {
  2839. serv = list->data;
  2840. if (!strcasecmp (hostname, serv->hostname) && serv->connected)
  2841. return serv;
  2842. list = list->next;
  2843. }
  2844. return NULL;
  2845. }
  2846. static server *
  2847. find_server_from_net (void *net)
  2848. {
  2849. GSList *list = serv_list;
  2850. server *serv;
  2851. while (list)
  2852. {
  2853. serv = list->data;
  2854. if (serv->network == net && serv->connected)
  2855. return serv;
  2856. list = list->next;
  2857. }
  2858. return NULL;
  2859. }
  2860. static void
  2861. url_join_only (server *serv, char *tbuf, char *channel)
  2862. {
  2863. /* already connected, JOIN only. FIXME: support keys? */
  2864. tbuf[0] = '#';
  2865. /* tbuf is 4kb */
  2866. safe_strcpy ((tbuf + 1), channel, 256);
  2867. serv->p_join (serv, tbuf, "");
  2868. }
  2869. static int
  2870. cmd_url (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2871. {
  2872. if (word[2][0])
  2873. {
  2874. char *server_name = NULL;
  2875. char *port = NULL;
  2876. char *channel = NULL;
  2877. char *url = g_strdup (word[2]);
  2878. int use_ssl = FALSE;
  2879. void *net;
  2880. server *serv;
  2881. if (parse_irc_url (url, &server_name, &port, &channel, &use_ssl))
  2882. {
  2883. /* maybe we're already connected to this net */
  2884. /* check for "FreeNode" */
  2885. net = servlist_net_find (server_name, NULL, strcasecmp);
  2886. /* check for "irc.eu.freenode.net" */
  2887. if (!net)
  2888. net = servlist_net_find_from_server (server_name);
  2889. if (net)
  2890. {
  2891. /* found the network, but are we connected? */
  2892. serv = find_server_from_net (net);
  2893. if (serv)
  2894. {
  2895. url_join_only (serv, tbuf, channel);
  2896. g_free (url);
  2897. return TRUE;
  2898. }
  2899. }
  2900. else
  2901. {
  2902. /* an un-listed connection */
  2903. serv = find_server_from_hostname (server_name);
  2904. if (serv)
  2905. {
  2906. url_join_only (serv, tbuf, channel);
  2907. g_free (url);
  2908. return TRUE;
  2909. }
  2910. }
  2911. /* not connected to this net, open new window */
  2912. cmd_newserver (sess, tbuf, word, word_eol);
  2913. } else
  2914. fe_open_url (word[2]);
  2915. g_free (url);
  2916. return TRUE;
  2917. }
  2918. return FALSE;
  2919. }
  2920. static int
  2921. userlist_cb (struct User *user, session *sess)
  2922. {
  2923. time_t lt;
  2924. if (!user->lasttalk)
  2925. lt = 0;
  2926. else
  2927. lt = time (0) - user->lasttalk;
  2928. PrintTextf (sess,
  2929. "\00306%s\t\00314[\00310%-38s\00314] \017ov\0033=\017%d%d away=%u lt\0033=\017%d\n",
  2930. user->nick, user->hostname, user->op, user->voice, user->away, lt);
  2931. return TRUE;
  2932. }
  2933. static int
  2934. cmd_uselect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  2935. {
  2936. int idx = 2;
  2937. int clear = TRUE;
  2938. int scroll = FALSE;
  2939. if (strcmp (word[2], "-a") == 0) /* ADD (don't clear selections) */
  2940. {
  2941. clear = FALSE;
  2942. idx++;
  2943. }
  2944. if (strcmp (word[idx], "-s") == 0) /* SCROLL TO */
  2945. {
  2946. scroll = TRUE;
  2947. idx++;
  2948. }
  2949. /* always valid, no args means clear the selection list */
  2950. fe_uselect (sess, word + idx, clear, scroll);
  2951. return TRUE;
  2952. }
  2953. static int
  2954. cmd_userlist (struct session *sess, char *tbuf, char *word[],
  2955. char *word_eol[])
  2956. {
  2957. tree_foreach (sess->usertree, (tree_traverse_func *)userlist_cb, sess);
  2958. return TRUE;
  2959. }
  2960. static int
  2961. wallchop_cb (struct User *user, multidata *data)
  2962. {
  2963. if (user->op)
  2964. {
  2965. if (data->i)
  2966. strcat (data->tbuf, ",");
  2967. strcat (data->tbuf, user->nick);
  2968. data->i++;
  2969. }
  2970. if (data->i == 5)
  2971. {
  2972. data->i = 0;
  2973. sprintf (data->tbuf + strlen (data->tbuf),
  2974. " :[@%s] %s", data->sess->channel, data->reason);
  2975. data->sess->server->p_raw (data->sess->server, data->tbuf);
  2976. strcpy (data->tbuf, "NOTICE ");
  2977. }
  2978. return TRUE;
  2979. }
  2980. static int
  2981. cmd_wallchop (struct session *sess, char *tbuf, char *word[],
  2982. char *word_eol[])
  2983. {
  2984. multidata data;
  2985. if (!(*word_eol[2]))
  2986. return FALSE;
  2987. strcpy (tbuf, "NOTICE ");
  2988. data.reason = word_eol[2];
  2989. data.tbuf = tbuf;
  2990. data.i = 0;
  2991. data.sess = sess;
  2992. tree_foreach (sess->usertree, (tree_traverse_func*)wallchop_cb, &data);
  2993. if (data.i)
  2994. {
  2995. sprintf (tbuf + strlen (tbuf),
  2996. " :[@%s] %s", sess->channel, word_eol[2]);
  2997. sess->server->p_raw (sess->server, tbuf);
  2998. }
  2999. return TRUE;
  3000. }
  3001. static int
  3002. cmd_wallchan (struct session *sess, char *tbuf, char *word[],
  3003. char *word_eol[])
  3004. {
  3005. GSList *list;
  3006. if (*word_eol[2])
  3007. {
  3008. list = sess_list;
  3009. while (list)
  3010. {
  3011. sess = list->data;
  3012. if (sess->type == SESS_CHANNEL)
  3013. {
  3014. inbound_chanmsg (sess->server, NULL, sess->channel,
  3015. sess->server->nick, word_eol[2], TRUE, FALSE);
  3016. sess->server->p_message (sess->server, sess->channel, word_eol[2]);
  3017. }
  3018. list = list->next;
  3019. }
  3020. return TRUE;
  3021. }
  3022. return FALSE;
  3023. }
  3024. static int
  3025. cmd_hop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  3026. {
  3027. int i = 2;
  3028. while (1)
  3029. {
  3030. if (!*word[i])
  3031. {
  3032. if (i == 2)
  3033. return FALSE;
  3034. send_channel_modes (sess, tbuf, word, 2, i, '+', 'h', 0);
  3035. return TRUE;
  3036. }
  3037. i++;
  3038. }
  3039. }
  3040. static int
  3041. cmd_voice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
  3042. {
  3043. int i = 2;
  3044. while (1)
  3045. {
  3046. if (!*word[i])
  3047. {
  3048. if (i == 2)
  3049. return FALSE;
  3050. send_channel_modes (sess, tbuf, word, 2, i, '+', 'v', 0);
  3051. return TRUE;
  3052. }
  3053. i++;
  3054. }
  3055. }
  3056. /* *MUST* be kept perfectly sorted for the bsearch to work */
  3057. const struct commands xc_cmds[] = {
  3058. {"ADDBUTTON", cmd_addbutton, 0, 0, 1,
  3059. N_("ADDBUTTON <name> <action>, adds a button under the user-list")},
  3060. {"ALLCHAN", cmd_allchannels, 0, 0, 1,
  3061. N_("ALLCHAN <cmd>, sends a command to all channels you're in")},
  3062. {"ALLCHANL", cmd_allchannelslocal, 0, 0, 1,
  3063. N_("ALLCHANL <cmd>, sends a command to all channels you're in")},
  3064. {"ALLSERV", cmd_allservers, 0, 0, 1,
  3065. N_("ALLSERV <cmd>, sends a command to all servers you're in")},
  3066. {"AWAY", cmd_away, 1, 0, 1, N_("AWAY [<reason>], sets you away")},
  3067. {"BACK", cmd_back, 1, 0, 1, N_("BACK, sets you back (not away)")},
  3068. {"BAN", cmd_ban, 1, 1, 1,
  3069. N_("BAN <mask> [<bantype>], bans everyone matching the mask from the current channel. If they are already on the channel this doesn't kick them (needs chanop)")},
  3070. {"CHANOPT", cmd_chanopt, 0, 0, 1, N_("CHANOPT [-quiet] <variable> [<value>]")},
  3071. {"CHARSET", cmd_charset, 0, 0, 1, 0},
  3072. {"CLEAR", cmd_clear, 0, 0, 1, N_("CLEAR [ALL|HISTORY], Clears the current text window or command history")},
  3073. {"CLOSE", cmd_close, 0, 0, 1, N_("CLOSE, Closes the current window/tab")},
  3074. {"COUNTRY", cmd_country, 0, 0, 1,
  3075. N_("COUNTRY [-s] <code|wildcard>, finds a country code, eg: au = australia")},
  3076. {"CTCP", cmd_ctcp, 1, 0, 1,
  3077. N_("CTCP <nick> <message>, send the CTCP message to nick, common messages are VERSION and USERINFO")},
  3078. {"CYCLE", cmd_cycle, 1, 1, 1,
  3079. N_("CYCLE [<channel>], parts the current or given channel and immediately rejoins")},
  3080. {"DCC", cmd_dcc, 0, 0, 1,
  3081. N_("\n"
  3082. "DCC GET <nick> - accept an offered file\n"
  3083. "DCC SEND [-maxcps=#] <nick> [file] - send a file to someone\n"
  3084. "DCC PSEND [-maxcps=#] <nick> [file] - send a file using passive mode\n"
  3085. "DCC LIST - show DCC list\n"
  3086. "DCC CHAT <nick> - offer DCC CHAT to someone\n"
  3087. "DCC PCHAT <nick> - offer DCC CHAT using passive mode\n"
  3088. "DCC CLOSE <type> <nick> <file> example:\n"
  3089. " /dcc close send johnsmith file.tar.gz")},
  3090. {"DEBUG", cmd_debug, 0, 0, 1, 0},
  3091. {"DEHOP", cmd_dehop, 1, 1, 1,
  3092. N_("DEHOP <nick>, removes chanhalf-op status from the nick on the current channel (needs chanop)")},
  3093. {"DELBUTTON", cmd_delbutton, 0, 0, 1,
  3094. N_("DELBUTTON <name>, deletes a button from under the user-list")},
  3095. {"DEOP", cmd_deop, 1, 1, 1,
  3096. N_("DEOP <nick>, removes chanop status from the nick on the current channel (needs chanop)")},
  3097. {"DEVOICE", cmd_devoice, 1, 1, 1,
  3098. N_("DEVOICE <nick>, removes voice status from the nick on the current channel (needs chanop)")},
  3099. {"DISCON", cmd_discon, 0, 0, 1, N_("DISCON, Disconnects from server")},
  3100. {"DNS", cmd_dns, 0, 0, 1, N_("DNS <nick|host|ip>, Finds a users IP number")},
  3101. {"ECHO", cmd_echo, 0, 0, 1, N_("ECHO <text>, Prints text locally")},
  3102. #ifndef WIN32
  3103. {"EXEC", cmd_exec, 0, 0, 1,
  3104. N_("EXEC [-o] <command>, runs the command. If -o flag is used then output is sent to current channel, else is printed to current text box")},
  3105. #ifndef __EMX__
  3106. {"EXECCONT", cmd_execc, 0, 0, 1, N_("EXECCONT, sends the process SIGCONT")},
  3107. #endif
  3108. {"EXECKILL", cmd_execk, 0, 0, 1,
  3109. N_("EXECKILL [-9], kills a running exec in the current session. If -9 is given the process is SIGKILL'ed")},
  3110. #ifndef __EMX__
  3111. {"EXECSTOP", cmd_execs, 0, 0, 1, N_("EXECSTOP, sends the process SIGSTOP")},
  3112. {"EXECWRITE", cmd_execw, 0, 0, 1, N_("EXECWRITE, sends data to the processes stdin")},
  3113. #endif
  3114. #endif
  3115. {"FLUSHQ", cmd_flushq, 0, 0, 1,
  3116. N_("FLUSHQ, flushes the current server's send queue")},
  3117. {"GATE", cmd_gate, 0, 0, 1,
  3118. N_("GATE <host> [<port>], proxies through a host, port defaults to 23")},
  3119. {"GETFILE", cmd_getfile, 0, 0, 1, "GETFILE [-folder] [-multi] [-save] <command> <title> [<initial>]"},
  3120. {"GETINT", cmd_getint, 0, 0, 1, "GETINT <default> <command> <prompt>"},
  3121. {"GETSTR", cmd_getstr, 0, 0, 1, "GETSTR <default> <command> <prompt>"},
  3122. {"GHOST", cmd_ghost, 1, 0, 1, N_("GHOST <nick> [password], Kills a ghosted nickname")},
  3123. {"GUI", cmd_gui, 0, 0, 1, "GUI [APPLY|ATTACH|DETACH|SHOW|HIDE|FOCUS|FLASH|ICONIFY|COLOR <n>]\n"
  3124. " GUI [MSGBOX <text>|MENU TOGGLE]"},
  3125. {"HELP", cmd_help, 0, 0, 1, 0},
  3126. {"HOP", cmd_hop, 1, 1, 1,
  3127. N_("HOP <nick>, gives chanhalf-op status to the nick (needs chanop)")},
  3128. {"ID", cmd_id, 1, 0, 1, N_("ID <password>, identifies yourself to nickserv")},
  3129. {"IGNORE", cmd_ignore, 0, 0, 1,
  3130. N_("IGNORE <mask> <types..> <options..>\n"
  3131. " mask - host mask to ignore, eg: *!*@*.aol.com\n"
  3132. " types - types of data to ignore, one or all of:\n"
  3133. " PRIV, CHAN, NOTI, CTCP, DCC, INVI, ALL\n"
  3134. " options - NOSAVE, QUIET")},
  3135. {"INVITE", cmd_invite, 1, 0, 1,
  3136. N_("INVITE <nick> [<channel>], invites someone to a channel, by default the current channel (needs chanop)")},
  3137. {"JOIN", cmd_join, 1, 0, 0, N_("JOIN <channel>, joins the channel")},
  3138. {"KICK", cmd_kick, 1, 1, 1,
  3139. N_("KICK <nick>, kicks the nick from the current channel (needs chanop)")},
  3140. {"KICKBAN", cmd_kickban, 1, 1, 1,
  3141. N_("KICKBAN <nick>, bans then kicks the nick from the current channel (needs chanop)")},
  3142. {"KILLALL", cmd_killall, 0, 0, 1, "KILLALL, immediately exit"},
  3143. {"LAGCHECK", cmd_lagcheck, 0, 0, 1,
  3144. N_("LAGCHECK, forces a new lag check")},
  3145. {"LASTLOG", cmd_lastlog, 0, 0, 1,
  3146. N_("LASTLOG <string>, searches for a string in the buffer")},
  3147. {"LIST", cmd_list, 1, 0, 1, 0},
  3148. {"LOAD", cmd_load, 0, 0, 1, N_("LOAD [-e] <file>, loads a plugin or script")},
  3149. {"MDEHOP", cmd_mdehop, 1, 1, 1,
  3150. N_("MDEHOP, Mass deop's all chanhalf-ops in the current channel (needs chanop)")},
  3151. {"MDEOP", cmd_mdeop, 1, 1, 1,
  3152. N_("MDEOP, Mass deop's all chanops in the current channel (needs chanop)")},
  3153. {"ME", cmd_me, 0, 0, 1,
  3154. N_("ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps)")},
  3155. {"MENU", cmd_menu, 0, 0, 1, "MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command]\n"
  3156. " See http://xchat.org/docs/menu/ for more details."},
  3157. {"MKICK", cmd_mkick, 1, 1, 1,
  3158. N_("MKICK, Mass kicks everyone except you in the current channel (needs chanop)")},
  3159. {"MODE", cmd_mode, 1, 0, 1, 0},
  3160. {"MOP", cmd_mop, 1, 1, 1,
  3161. N_("MOP, Mass op's all users in the current channel (needs chanop)")},
  3162. {"MSG", cmd_msg, 0, 0, 1, N_("MSG <nick> <message>, sends a private message")},
  3163. {"NAMES", cmd_names, 1, 0, 1,
  3164. N_("NAMES, Lists the nicks on the current channel")},
  3165. {"NCTCP", cmd_nctcp, 1, 0, 1,
  3166. N_("NCTCP <nick> <message>, Sends a CTCP notice")},
  3167. {"NEWSERVER", cmd_newserver, 0, 0, 1, N_("NEWSERVER [-noconnect] <hostname> [<port>]")},
  3168. {"NICK", cmd_nick, 0, 0, 1, N_("NICK <nickname>, sets your nick")},
  3169. {"NOTICE", cmd_notice, 1, 0, 1,
  3170. N_("NOTICE <nick/channel> <message>, sends a notice. Notices are a type of message that should be auto reacted to")},
  3171. {"NOTIFY", cmd_notify, 0, 0, 1,
  3172. N_("NOTIFY [-n network1[,network2,...]] [<nick>], displays your notify list or adds someone to it")},
  3173. {"OP", cmd_op, 1, 1, 1,
  3174. N_("OP <nick>, gives chanop status to the nick (needs chanop)")},
  3175. {"PART", cmd_part, 1, 1, 0,
  3176. N_("PART [<channel>] [<reason>], leaves the channel, by default the current one")},
  3177. {"PING", cmd_ping, 1, 0, 1,
  3178. N_("PING <nick | channel>, CTCP pings nick or channel")},
  3179. {"QUERY", cmd_query, 0, 0, 1,
  3180. N_("QUERY [-nofocus] <nick>, opens up a new privmsg window to someone")},
  3181. {"QUIT", cmd_quit, 0, 0, 1,
  3182. N_("QUIT [<reason>], disconnects from the current server")},
  3183. {"QUOTE", cmd_quote, 1, 0, 1,
  3184. N_("QUOTE <text>, sends the text in raw form to the server")},
  3185. #ifdef USE_OPENSSL
  3186. {"RECONNECT", cmd_reconnect, 0, 0, 1,
  3187. N_("RECONNECT [-ssl] [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
  3188. #else
  3189. {"RECONNECT", cmd_reconnect, 0, 0, 1,
  3190. N_("RECONNECT [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
  3191. #endif
  3192. {"RECV", cmd_recv, 1, 0, 1, N_("RECV <text>, send raw data to xchat, as if it was received from the irc server")},
  3193. {"SAY", cmd_say, 0, 0, 1,
  3194. N_("SAY <text>, sends the text to the object in the current window")},
  3195. {"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
  3196. #ifdef USE_OPENSSL
  3197. {"SERVCHAN", cmd_servchan, 0, 0, 1,
  3198. N_("SERVCHAN [-ssl] <host> <port> <channel>, connects and joins a channel")},
  3199. #else
  3200. {"SERVCHAN", cmd_servchan, 0, 0, 1,
  3201. N_("SERVCHAN <host> <port> <channel>, connects and joins a channel")},
  3202. #endif
  3203. #ifdef USE_OPENSSL
  3204. {"SERVER", cmd_server, 0, 0, 1,
  3205. N_("SERVER [-ssl] <host> [<port>] [<password>], connects to a server, the default port is 6667 for normal connections, and 9999 for ssl connections")},
  3206. #else
  3207. {"SERVER", cmd_server, 0, 0, 1,
  3208. N_("SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667")},
  3209. #endif
  3210. {"SET", cmd_set, 0, 0, 1, N_("SET [-e] [-off|-on] [-quiet] <variable> [<value>]")},
  3211. {"SETCURSOR", cmd_setcursor, 0, 0, 1, N_("SETCURSOR [-|+]<position>")},
  3212. {"SETTAB", cmd_settab, 0, 0, 1, 0},
  3213. {"SETTEXT", cmd_settext, 0, 0, 1, 0},
  3214. {"SPLAY", cmd_splay, 0, 0, 1, "SPLAY <soundfile>"},
  3215. {"TOPIC", cmd_topic, 1, 1, 1,
  3216. N_("TOPIC [<topic>], sets the topic if one is given, else shows the current topic")},
  3217. {"TRAY", cmd_tray, 0, 0, 1,
  3218. N_("\nTRAY -f <timeout> <file1> [<file2>] Blink tray between two icons.\n"
  3219. "TRAY -f <filename> Set tray to a fixed icon.\n"
  3220. "TRAY -i <number> Blink tray with an internal icon.\n"
  3221. "TRAY -t <text> Set the tray tooltip.\n"
  3222. "TRAY -b <title> <text> Set the tray balloon."
  3223. )},
  3224. {"UNBAN", cmd_unban, 1, 1, 1,
  3225. N_("UNBAN <mask> [<mask>...], unbans the specified masks.")},
  3226. {"UNIGNORE", cmd_unignore, 0, 0, 1, N_("UNIGNORE <mask> [QUIET]")},
  3227. {"UNLOAD", cmd_unload, 0, 0, 1, N_("UNLOAD <name>, unloads a plugin or script")},
  3228. {"URL", cmd_url, 0, 0, 1, N_("URL <url>, opens a URL in your browser")},
  3229. {"USELECT", cmd_uselect, 0, 1, 0,
  3230. N_("USELECT [-a] [-s] <nick1> <nick2> etc, highlights nick(s) in channel userlist")},
  3231. {"USERLIST", cmd_userlist, 1, 1, 1, 0},
  3232. {"VOICE", cmd_voice, 1, 1, 1,
  3233. N_("VOICE <nick>, gives voice status to someone (needs chanop)")},
  3234. {"WALLCHAN", cmd_wallchan, 1, 1, 1,
  3235. N_("WALLCHAN <message>, writes the message to all channels")},
  3236. {"WALLCHOP", cmd_wallchop, 1, 1, 1,
  3237. N_("WALLCHOP <message>, sends the message to all chanops on the current channel")},
  3238. {0, 0, 0, 0, 0, 0}
  3239. };
  3240. static int
  3241. command_compare (const void *a, const void *b)
  3242. {
  3243. return strcasecmp (a, ((struct commands *)b)->name);
  3244. }
  3245. static struct commands *
  3246. find_internal_command (char *name)
  3247. {
  3248. /* the "-1" is to skip the NULL terminator */
  3249. return bsearch (name, xc_cmds, (sizeof (xc_cmds) /
  3250. sizeof (xc_cmds[0])) - 1, sizeof (xc_cmds[0]), command_compare);
  3251. }
  3252. static void
  3253. help (session *sess, char *tbuf, char *helpcmd, int quiet)
  3254. {
  3255. struct commands *cmd;
  3256. if (plugin_show_help (sess, helpcmd))
  3257. return;
  3258. cmd = find_internal_command (helpcmd);
  3259. if (cmd)
  3260. {
  3261. if (cmd->help)
  3262. {
  3263. snprintf (tbuf, TBUFSIZE, _("Usage: %s\n"), _(cmd->help));
  3264. PrintText (sess, tbuf);
  3265. } else
  3266. {
  3267. if (!quiet)
  3268. PrintText (sess, _("\nNo help available on that command.\n"));
  3269. }
  3270. return;
  3271. }
  3272. if (!quiet)
  3273. PrintText (sess, _("No such command.\n"));
  3274. }
  3275. /* inserts %a, %c, %d etc into buffer. Also handles &x %x for word/word_eol. *
  3276. * returns 2 on buffer overflow
  3277. * returns 1 on success *
  3278. * returns 0 on bad-args-for-user-command *
  3279. * - word/word_eol args might be NULL *
  3280. * - this beast is used for UserCommands, UserlistButtons and CTCP replies */
  3281. int
  3282. auto_insert (char *dest, int destlen, unsigned char *src, char *word[],
  3283. char *word_eol[], char *a, char *c, char *d, char *e, char *h,
  3284. char *n, char *s)
  3285. {
  3286. int num;
  3287. char buf[32];
  3288. time_t now;
  3289. struct tm *tm_ptr;
  3290. char *utf;
  3291. gsize utf_len;
  3292. char *orig = dest;
  3293. destlen--;
  3294. while (src[0])
  3295. {
  3296. if (src[0] == '%' || src[0] == '&')
  3297. {
  3298. if (isdigit ((unsigned char) src[1]))
  3299. {
  3300. if (isdigit ((unsigned char) src[2]) && isdigit ((unsigned char) src[3]))
  3301. {
  3302. buf[0] = src[1];
  3303. buf[1] = src[2];
  3304. buf[2] = src[3];
  3305. buf[3] = 0;
  3306. dest[0] = atoi (buf);
  3307. utf = g_locale_to_utf8 (dest, 1, 0, &utf_len, 0);
  3308. if (utf)
  3309. {
  3310. if ((dest - orig) + utf_len >= destlen)
  3311. {
  3312. g_free (utf);
  3313. return 2;
  3314. }
  3315. memcpy (dest, utf, utf_len);
  3316. g_free (utf);
  3317. dest += utf_len;
  3318. }
  3319. src += 3;
  3320. } else
  3321. {
  3322. if (word)
  3323. {
  3324. src++;
  3325. num = src[0] - '0'; /* ascii to decimal */
  3326. if (*word[num] == 0)
  3327. return 0;
  3328. if (src[-1] == '%')
  3329. utf = word[num];
  3330. else
  3331. utf = word_eol[num];
  3332. /* avoid recusive usercommand overflow */
  3333. if ((dest - orig) + strlen (utf) >= destlen)
  3334. return 2;
  3335. strcpy (dest, utf);
  3336. dest += strlen (dest);
  3337. }
  3338. }
  3339. } else
  3340. {
  3341. if (src[0] == '&')
  3342. goto lamecode;
  3343. src++;
  3344. utf = NULL;
  3345. switch (src[0])
  3346. {
  3347. case '%':
  3348. if ((dest - orig) + 2 >= destlen)
  3349. return 2;
  3350. dest[0] = '%';
  3351. dest[1] = 0;
  3352. dest++;
  3353. break;
  3354. case 'a':
  3355. utf = a; break;
  3356. case 'c':
  3357. utf = c; break;
  3358. case 'd':
  3359. utf = d; break;
  3360. case 'e':
  3361. utf = e; break;
  3362. case 'h':
  3363. utf = h; break;
  3364. case 'm':
  3365. utf = get_cpu_str (); break;
  3366. case 'n':
  3367. utf = n; break;
  3368. case 's':
  3369. utf = s; break;
  3370. case 't':
  3371. now = time (0);
  3372. utf = ctime (&now);
  3373. utf[19] = 0;
  3374. break;
  3375. case 'v':
  3376. utf = PACKAGE_VERSION; break;
  3377. break;
  3378. case 'y':
  3379. now = time (0);
  3380. tm_ptr = localtime (&now);
  3381. snprintf (buf, sizeof (buf), "%4d%02d%02d", 1900 +
  3382. tm_ptr->tm_year, 1 + tm_ptr->tm_mon, tm_ptr->tm_mday);
  3383. utf = buf;
  3384. break;
  3385. default:
  3386. src--;
  3387. goto lamecode;
  3388. }
  3389. if (utf)
  3390. {
  3391. if ((dest - orig) + strlen (utf) >= destlen)
  3392. return 2;
  3393. strcpy (dest, utf);
  3394. dest += strlen (dest);
  3395. }
  3396. }
  3397. src++;
  3398. } else
  3399. {
  3400. utf_len = g_utf8_skip[src[0]];
  3401. if ((dest - orig) + utf_len >= destlen)
  3402. return 2;
  3403. if (utf_len == 1)
  3404. {
  3405. lamecode:
  3406. dest[0] = src[0];
  3407. dest++;
  3408. src++;
  3409. } else
  3410. {
  3411. memcpy (dest, src, utf_len);
  3412. dest += utf_len;
  3413. src += utf_len;
  3414. }
  3415. }
  3416. }
  3417. dest[0] = 0;
  3418. return 1;
  3419. }
  3420. void
  3421. check_special_chars (char *cmd, int do_ascii) /* check for %X */
  3422. {
  3423. int occur = 0;
  3424. int len = strlen (cmd);
  3425. char *buf, *utf;
  3426. char tbuf[4];
  3427. int i = 0, j = 0;
  3428. gsize utf_len;
  3429. if (!len)
  3430. return;
  3431. buf = malloc (len + 1);
  3432. if (buf)
  3433. {
  3434. while (cmd[j])
  3435. {
  3436. switch (cmd[j])
  3437. {
  3438. case '%':
  3439. occur++;
  3440. if ( do_ascii &&
  3441. j + 3 < len &&
  3442. (isdigit ((unsigned char) cmd[j + 1]) && isdigit ((unsigned char) cmd[j + 2]) &&
  3443. isdigit ((unsigned char) cmd[j + 3])))
  3444. {
  3445. tbuf[0] = cmd[j + 1];
  3446. tbuf[1] = cmd[j + 2];
  3447. tbuf[2] = cmd[j + 3];
  3448. tbuf[3] = 0;
  3449. buf[i] = atoi (tbuf);
  3450. utf = g_locale_to_utf8 (buf + i, 1, 0, &utf_len, 0);
  3451. if (utf)
  3452. {
  3453. memcpy (buf + i, utf, utf_len);
  3454. g_free (utf);
  3455. i += (utf_len - 1);
  3456. }
  3457. j += 3;
  3458. } else
  3459. {
  3460. switch (cmd[j + 1])
  3461. {
  3462. case 'R':
  3463. buf[i] = '\026';
  3464. break;
  3465. case 'U':
  3466. buf[i] = '\037';
  3467. break;
  3468. case 'B':
  3469. buf[i] = '\002';
  3470. break;
  3471. case 'C':
  3472. buf[i] = '\003';
  3473. break;
  3474. case 'O':
  3475. buf[i] = '\017';
  3476. break;
  3477. case 'H': /* CL: invisible text code */
  3478. buf[i] = HIDDEN_CHAR;
  3479. break;
  3480. case '%':
  3481. buf[i] = '%';
  3482. break;
  3483. default:
  3484. buf[i] = '%';
  3485. j--;
  3486. break;
  3487. }
  3488. j++;
  3489. break;
  3490. default:
  3491. buf[i] = cmd[j];
  3492. }
  3493. }
  3494. j++;
  3495. i++;
  3496. }
  3497. buf[i] = 0;
  3498. if (occur)
  3499. strcpy (cmd, buf);
  3500. free (buf);
  3501. }
  3502. }
  3503. typedef struct
  3504. {
  3505. char *nick;
  3506. int len;
  3507. struct User *best;
  3508. int bestlen;
  3509. char *space;
  3510. char *tbuf;
  3511. } nickdata;
  3512. static int
  3513. nick_comp_cb (struct User *user, nickdata *data)
  3514. {
  3515. int lenu;
  3516. if (!rfc_ncasecmp (user->nick, data->nick, data->len))
  3517. {
  3518. lenu = strlen (user->nick);
  3519. if (lenu == data->len)
  3520. {
  3521. snprintf (data->tbuf, TBUFSIZE, "%s%s", user->nick, data->space);
  3522. data->len = -1;
  3523. return FALSE;
  3524. } else if (lenu < data->bestlen)
  3525. {
  3526. data->bestlen = lenu;
  3527. data->best = user;
  3528. }
  3529. }
  3530. return TRUE;
  3531. }
  3532. static void
  3533. perform_nick_completion (struct session *sess, char *cmd, char *tbuf)
  3534. {
  3535. int len;
  3536. char *space = strchr (cmd, ' ');
  3537. if (space && space != cmd)
  3538. {
  3539. if (space[-1] == prefs.nick_suffix[0] && space - 1 != cmd)
  3540. {
  3541. len = space - cmd - 1;
  3542. if (len < NICKLEN)
  3543. {
  3544. char nick[NICKLEN];
  3545. nickdata data;
  3546. memcpy (nick, cmd, len);
  3547. nick[len] = 0;
  3548. data.nick = nick;
  3549. data.len = len;
  3550. data.bestlen = INT_MAX;
  3551. data.best = NULL;
  3552. data.tbuf = tbuf;
  3553. data.space = space - 1;
  3554. tree_foreach (sess->usertree, (tree_traverse_func *)nick_comp_cb, &data);
  3555. if (data.len == -1)
  3556. return;
  3557. if (data.best)
  3558. {
  3559. snprintf (tbuf, TBUFSIZE, "%s%s", data.best->nick, space - 1);
  3560. return;
  3561. }
  3562. }
  3563. }
  3564. }
  3565. strcpy (tbuf, cmd);
  3566. }
  3567. static void
  3568. user_command (session * sess, char *tbuf, char *cmd, char *word[],
  3569. char *word_eol[])
  3570. {
  3571. if (!auto_insert (tbuf, 2048, cmd, word, word_eol, "", sess->channel, "",
  3572. server_get_network (sess->server, TRUE), "",
  3573. sess->server->nick, ""))
  3574. {
  3575. PrintText (sess, _("Bad arguments for user command.\n"));
  3576. return;
  3577. }
  3578. handle_command (sess, tbuf, TRUE);
  3579. }
  3580. /* handle text entered without a CMDchar prefix */
  3581. static void
  3582. handle_say (session *sess, char *text, int check_spch)
  3583. {
  3584. struct DCC *dcc;
  3585. char *word[PDIWORDS+1];
  3586. char *word_eol[PDIWORDS+1];
  3587. char pdibuf_static[1024];
  3588. char newcmd_static[1024];
  3589. char *pdibuf = pdibuf_static;
  3590. char *newcmd = newcmd_static;
  3591. int len;
  3592. int newcmdlen = sizeof newcmd_static;
  3593. if (strcmp (sess->channel, "(lastlog)") == 0)
  3594. {
  3595. lastlog (sess->lastlog_sess, text, sess->lastlog_regexp);
  3596. return;
  3597. }
  3598. len = strlen (text);
  3599. if (len >= sizeof pdibuf_static)
  3600. pdibuf = malloc (len + 1);
  3601. if (len + NICKLEN >= newcmdlen)
  3602. newcmd = malloc (newcmdlen = len + NICKLEN + 1);
  3603. if (check_spch && prefs.perc_color)
  3604. check_special_chars (text, prefs.perc_ascii);
  3605. /* Python relies on this */
  3606. word[PDIWORDS] = NULL;
  3607. word_eol[PDIWORDS] = NULL;
  3608. /* split the text into words and word_eol */
  3609. process_data_init (pdibuf, text, word, word_eol, TRUE, FALSE);
  3610. /* a command of "" can be hooked for non-commands */
  3611. if (plugin_emit_command (sess, "", word, word_eol))
  3612. goto xit;
  3613. /* incase a plugin did /close */
  3614. if (!is_session (sess))
  3615. goto xit;
  3616. if (!sess->channel[0] || sess->type == SESS_SERVER || sess->type == SESS_NOTICES || sess->type == SESS_SNOTICES)
  3617. {
  3618. notj_msg (sess);
  3619. goto xit;
  3620. }
  3621. if (prefs.nickcompletion)
  3622. perform_nick_completion (sess, text, newcmd);
  3623. else
  3624. safe_strcpy (newcmd, text, newcmdlen);
  3625. text = newcmd;
  3626. if (sess->type == SESS_DIALOG)
  3627. {
  3628. /* try it via dcc, if possible */
  3629. dcc = dcc_write_chat (sess->channel, text);
  3630. if (dcc)
  3631. {
  3632. inbound_chanmsg (sess->server, NULL, sess->channel,
  3633. sess->server->nick, text, TRUE, FALSE);
  3634. set_topic (sess, net_ip (dcc->addr), net_ip (dcc->addr));
  3635. goto xit;
  3636. }
  3637. }
  3638. if (sess->server->connected)
  3639. {
  3640. unsigned int max;
  3641. unsigned char t = 0;
  3642. /* maximum allowed message text */
  3643. /* :nickname!username@host.com PRIVMSG #channel :text\r\n */
  3644. max = 512;
  3645. max -= 16; /* :, !, @, " PRIVMSG ", " ", :, \r, \n */
  3646. max -= strlen (sess->server->nick);
  3647. max -= strlen (sess->channel);
  3648. if (sess->me && sess->me->hostname)
  3649. max -= strlen (sess->me->hostname);
  3650. else
  3651. {
  3652. max -= 9; /* username */
  3653. max -= 65; /* max possible hostname and '@' */
  3654. }
  3655. if (strlen (text) > max)
  3656. {
  3657. int i = 0, size;
  3658. /* traverse the utf8 string and find the nearest cut point that
  3659. doesn't split 1 char in half */
  3660. while (1)
  3661. {
  3662. size = g_utf8_skip[((unsigned char *)text)[i]];
  3663. if ((i + size) >= max)
  3664. break;
  3665. i += size;
  3666. }
  3667. max = i;
  3668. t = text[max];
  3669. text[max] = 0; /* insert a NULL terminator to shorten it */
  3670. }
  3671. inbound_chanmsg (sess->server, sess, sess->channel, sess->server->nick,
  3672. text, TRUE, FALSE);
  3673. sess->server->p_message (sess->server, sess->channel, text);
  3674. if (t)
  3675. {
  3676. text[max] = t;
  3677. handle_say (sess, text + max, FALSE);
  3678. }
  3679. } else
  3680. {
  3681. notc_msg (sess);
  3682. }
  3683. xit:
  3684. if (pdibuf != pdibuf_static)
  3685. free (pdibuf);
  3686. if (newcmd != newcmd_static)
  3687. free (newcmd);
  3688. }
  3689. /* handle a command, without the '/' prefix */
  3690. int
  3691. handle_command (session *sess, char *cmd, int check_spch)
  3692. {
  3693. struct popup *pop;
  3694. int user_cmd = FALSE;
  3695. GSList *list;
  3696. char *word[PDIWORDS+1];
  3697. char *word_eol[PDIWORDS+1];
  3698. static int command_level = 0;
  3699. struct commands *int_cmd;
  3700. char pdibuf_static[1024];
  3701. char tbuf_static[TBUFSIZE];
  3702. char *pdibuf;
  3703. char *tbuf;
  3704. int len;
  3705. int ret = TRUE;
  3706. if (command_level > 99)
  3707. {
  3708. fe_message (_("Too many recursive usercommands, aborting."), FE_MSG_ERROR);
  3709. return TRUE;
  3710. }
  3711. command_level++;
  3712. /* anything below MUST DEC command_level before returning */
  3713. len = strlen (cmd);
  3714. if (len >= sizeof (pdibuf_static))
  3715. pdibuf = malloc (len + 1);
  3716. else
  3717. pdibuf = pdibuf_static;
  3718. if ((len * 2) >= sizeof (tbuf_static))
  3719. tbuf = malloc ((len * 2) + 1);
  3720. else
  3721. tbuf = tbuf_static;
  3722. /* split the text into words and word_eol */
  3723. process_data_init (pdibuf, cmd, word, word_eol, TRUE, TRUE);
  3724. /* ensure an empty string at index 32 for cmd_deop etc */
  3725. /* (internal use only, plugins can still only read 1-31). */
  3726. word[PDIWORDS] = "\000\000";
  3727. word_eol[PDIWORDS] = "\000\000";
  3728. int_cmd = find_internal_command (word[1]);
  3729. /* redo it without quotes processing, for some commands like /JOIN */
  3730. if (int_cmd && !int_cmd->handle_quotes)
  3731. process_data_init (pdibuf, cmd, word, word_eol, FALSE, FALSE);
  3732. if (check_spch && prefs.perc_color)
  3733. check_special_chars (cmd, prefs.perc_ascii);
  3734. if (plugin_emit_command (sess, word[1], word, word_eol))
  3735. goto xit;
  3736. /* incase a plugin did /close */
  3737. if (!is_session (sess))
  3738. goto xit;
  3739. /* first see if it's a userCommand */
  3740. list = command_list;
  3741. while (list)
  3742. {
  3743. pop = (struct popup *) list->data;
  3744. if (!strcasecmp (pop->name, word[1]))
  3745. {
  3746. user_command (sess, tbuf, pop->cmd, word, word_eol);
  3747. user_cmd = TRUE;
  3748. }
  3749. list = list->next;
  3750. }
  3751. if (user_cmd)
  3752. goto xit;
  3753. /* now check internal commands */
  3754. int_cmd = find_internal_command (word[1]);
  3755. if (int_cmd)
  3756. {
  3757. if (int_cmd->needserver && !sess->server->connected)
  3758. {
  3759. notc_msg (sess);
  3760. } else if (int_cmd->needchannel && !sess->channel[0])
  3761. {
  3762. notj_msg (sess);
  3763. } else
  3764. {
  3765. switch (int_cmd->callback (sess, tbuf, word, word_eol))
  3766. {
  3767. case FALSE:
  3768. help (sess, tbuf, int_cmd->name, TRUE);
  3769. break;
  3770. case 2:
  3771. ret = FALSE;
  3772. goto xit;
  3773. }
  3774. }
  3775. } else
  3776. {
  3777. /* unknown command, just send it to the server and hope */
  3778. if (!sess->server->connected)
  3779. PrintText (sess, _("Unknown Command. Try /help\n"));
  3780. else
  3781. sess->server->p_raw (sess->server, cmd);
  3782. }
  3783. xit:
  3784. command_level--;
  3785. if (pdibuf != pdibuf_static)
  3786. free (pdibuf);
  3787. if (tbuf != tbuf_static)
  3788. free (tbuf);
  3789. return ret;
  3790. }
  3791. /* handle one line entered into the input box */
  3792. static int
  3793. handle_user_input (session *sess, char *text, int history, int nocommand)
  3794. {
  3795. if (*text == '\0')
  3796. return 1;
  3797. if (history)
  3798. history_add (&sess->history, text);
  3799. /* is it NOT a command, just text? */
  3800. if (nocommand || text[0] != prefs.cmdchar[0])
  3801. {
  3802. handle_say (sess, text, TRUE);
  3803. return 1;
  3804. }
  3805. /* check for // */
  3806. if (text[0] == prefs.cmdchar[0] && text[1] == prefs.cmdchar[0])
  3807. {
  3808. handle_say (sess, text + 1, TRUE);
  3809. return 1;
  3810. }
  3811. if (prefs.cmdchar[0] == '/')
  3812. {
  3813. int i;
  3814. const char *unix_dirs [] = {
  3815. "/bin/", "/boot/", "/dev/",
  3816. "/etc/", "/home/", "/lib/",
  3817. "/lost+found/", "/mnt/", "/opt/",
  3818. "/proc/", "/root/", "/sbin/",
  3819. "/tmp/", "/usr/", "/var/",
  3820. "/gnome/", NULL};
  3821. for (i = 0; unix_dirs[i] != NULL; i++)
  3822. if (strncmp (text, unix_dirs[i], strlen (unix_dirs[i]))==0)
  3823. {
  3824. handle_say (sess, text, TRUE);
  3825. return 1;
  3826. }
  3827. }
  3828. return handle_command (sess, text + 1, TRUE);
  3829. }
  3830. /* changed by Steve Green. Macs sometimes paste with imbedded \r */
  3831. void
  3832. handle_multiline (session *sess, char *cmd, int history, int nocommand)
  3833. {
  3834. while (*cmd)
  3835. {
  3836. char *cr = cmd + strcspn (cmd, "\n\r");
  3837. int end_of_string = *cr == 0;
  3838. *cr = 0;
  3839. if (!handle_user_input (sess, cmd, history, nocommand))
  3840. return;
  3841. if (end_of_string)
  3842. break;
  3843. cmd = cr + 1;
  3844. }
  3845. }
  3846. /*void
  3847. handle_multiline (session *sess, char *cmd, int history, int nocommand)
  3848. {
  3849. char *cr;
  3850. cr = strchr (cmd, '\n');
  3851. if (cr)
  3852. {
  3853. while (1)
  3854. {
  3855. if (cr)
  3856. *cr = 0;
  3857. if (!handle_user_input (sess, cmd, history, nocommand))
  3858. return;
  3859. if (!cr)
  3860. break;
  3861. cmd = cr + 1;
  3862. if (*cmd == 0)
  3863. break;
  3864. cr = strchr (cmd, '\n');
  3865. }
  3866. } else
  3867. {
  3868. handle_user_input (sess, cmd, history, nocommand);
  3869. }
  3870. }*/